Initial
This commit is contained in:
2
.coveragerc
Normal file
2
.coveragerc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[run]
|
||||||
|
source = base
|
||||||
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
*.pyc
|
||||||
|
.coverage
|
||||||
|
geckodriver.log
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
django_test.egg-info/
|
||||||
|
|
||||||
|
env/
|
||||||
|
tmp/
|
||||||
1
INSTALL.rst
Normal file
1
INSTALL.rst
Normal file
@@ -0,0 +1 @@
|
|||||||
|
NOT IMPLEMENTED YET
|
||||||
3
MANIFEST.in
Normal file
3
MANIFEST.in
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
recursive-include base/console_scripts/django_project_config *.py
|
||||||
|
recursive-include base/static *
|
||||||
|
recursive-include base/templates *
|
||||||
19
README.rst
Normal file
19
README.rst
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
ABOUT
|
||||||
|
=====
|
||||||
|
This is the heinzel django project.
|
||||||
|
|
||||||
|
|
||||||
|
REQUIREMENTS
|
||||||
|
============
|
||||||
|
See INSTALL.rst
|
||||||
|
|
||||||
|
|
||||||
|
INSTALLATION
|
||||||
|
============
|
||||||
|
See INSTALL.rst
|
||||||
|
|
||||||
|
|
||||||
|
LICENCE
|
||||||
|
=======
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted.
|
||||||
0
base/__init__.py
Normal file
0
base/__init__.py
Normal file
0
base/console_scripts/__init__.py
Normal file
0
base/console_scripts/__init__.py
Normal file
95
base/console_scripts/admin.py
Normal file
95
base/console_scripts/admin.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import pkg_resources
|
||||||
|
import sys
|
||||||
|
|
||||||
|
DJANGO_MAIN_MODULE = 'main'
|
||||||
|
VERSION = '0.1'
|
||||||
|
|
||||||
|
|
||||||
|
class AdminCommand(object):
|
||||||
|
@staticmethod
|
||||||
|
def _setup_argparser():
|
||||||
|
kwargs = {
|
||||||
|
'description': 'Tool to manage your test django installation.',
|
||||||
|
}
|
||||||
|
parser = argparse.ArgumentParser(**kwargs)
|
||||||
|
|
||||||
|
parser.add_argument('-V', '--version', action='version',
|
||||||
|
version='%(prog)s ' + VERSION)
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(dest='subcmd', metavar='CMD',
|
||||||
|
title='subcommands',
|
||||||
|
description="Use '%(prog)s CMD -h' to show help for a subcommand")
|
||||||
|
subparser = subparsers.add_parser('setup', help='Setup the installation.')
|
||||||
|
subparser.add_argument('path', metavar='PATH',
|
||||||
|
help='A directory, where the project files will be installed.')
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def _parse_args(self, argv=None):
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv[1:]
|
||||||
|
if not argv:
|
||||||
|
argv = ['--help']
|
||||||
|
|
||||||
|
return self._argparser.parse_args(argv)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _subcmd_setup(cmd_args):
|
||||||
|
django_main_module = DJANGO_MAIN_MODULE
|
||||||
|
django_base_dir = cmd_args.path
|
||||||
|
|
||||||
|
sys.stdout.write('Setup installation in \'{path}\'...\n'.format(path=django_base_dir))
|
||||||
|
|
||||||
|
if os.path.exists(django_base_dir):
|
||||||
|
if not os.path.isdir(django_base_dir):
|
||||||
|
sys.stderr.write('{path}: Not a directory.\n'.format(path=django_base_dir))
|
||||||
|
return os.EX_USAGE
|
||||||
|
else:
|
||||||
|
os.makedirs(django_base_dir)
|
||||||
|
|
||||||
|
sys.stdout.write('Creating django project...\n')
|
||||||
|
django_cmd = 'django-admin startproject {name} "{path}"'.format(name=django_main_module,
|
||||||
|
path=django_base_dir)
|
||||||
|
exitval = os.system(django_cmd)
|
||||||
|
if exitval != os.EX_OK:
|
||||||
|
return exitval
|
||||||
|
|
||||||
|
sys.stdout.write('Configure django project...\n')
|
||||||
|
|
||||||
|
input_file = os.path.join('django_project_config', 'additional_settings.py')
|
||||||
|
output_file = os.path.join(django_base_dir, django_main_module, 'settings.py')
|
||||||
|
with open(output_file, 'ab') as f:
|
||||||
|
f.write(pkg_resources.resource_string(__package__, input_file))
|
||||||
|
|
||||||
|
sys.stdout.write('Creating directories...\n')
|
||||||
|
dirs = [
|
||||||
|
os.path.join(django_base_dir, 'var', 'log'),
|
||||||
|
os.path.join(django_base_dir, 'var', 'www', 'static'),
|
||||||
|
]
|
||||||
|
|
||||||
|
for d in dirs:
|
||||||
|
sys.stdout.write(' - %s\n' % d)
|
||||||
|
os.makedirs(d)
|
||||||
|
|
||||||
|
return os.EX_OK
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._argparser = self._setup_argparser()
|
||||||
|
|
||||||
|
def __call__(self, argv=None):
|
||||||
|
cmd_args = self._parse_args(argv)
|
||||||
|
subcmd = cmd_args.subcmd
|
||||||
|
method_name = '_subcmd_{}'.format(subcmd)
|
||||||
|
method = getattr(self, method_name)
|
||||||
|
exitval = method(cmd_args)
|
||||||
|
return exitval
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
cmd = AdminCommand()
|
||||||
|
exitval = cmd()
|
||||||
|
sys.exit(exitval)
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
|
||||||
|
#
|
||||||
|
# Additional settings for django-test
|
||||||
|
#
|
||||||
|
|
||||||
|
BASE_VAR_DIR = os.path.join(BASE_DIR, 'var')
|
||||||
|
LOG_DIR = os.path.join(BASE_VAR_DIR, 'log')
|
||||||
|
|
||||||
|
INSTALLED_APPS += [
|
||||||
|
'django_extensions',
|
||||||
|
# Our main app
|
||||||
|
'base',
|
||||||
|
]
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'base.urls'
|
||||||
|
STATIC_ROOT = os.path.join(BASE_VAR_DIR, 'www', 'static')
|
||||||
|
|
||||||
|
LOGGING = {
|
||||||
|
'version': 1,
|
||||||
|
'disable_existing_loggers': False,
|
||||||
|
'formatters': {
|
||||||
|
'default': {
|
||||||
|
'format': '%(asctime)s - %(name)s - %(levelname)s: %(message)s'
|
||||||
|
},
|
||||||
|
'verbose': {
|
||||||
|
'format': ('%(asctime)s -- %(processName)s[%(process)d]:%(threadName)s[%(thread)d] -- '
|
||||||
|
'%(name)s -- %(module)s...%(funcName)s() -- %(pathname)s:%(lineno)d -- '
|
||||||
|
'%(levelname)s: %(message)s')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'filters': {
|
||||||
|
'require_debug_true': {
|
||||||
|
'()': 'django.utils.log.RequireDebugTrue',
|
||||||
|
},
|
||||||
|
'require_debug_false': {
|
||||||
|
'()': 'django.utils.log.RequireDebugFalse',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'handlers': {
|
||||||
|
'null': {
|
||||||
|
'class': 'logging.NullHandler',
|
||||||
|
},
|
||||||
|
'console_debug': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'filters': ['require_debug_true'],
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
},
|
||||||
|
'console_default': {
|
||||||
|
'level': 'INFO',
|
||||||
|
'filters': ['require_debug_false'],
|
||||||
|
'class': 'logging.StreamHandler',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'loggers': {
|
||||||
|
'django': {
|
||||||
|
'level': 'INFO',
|
||||||
|
'propagate': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'root': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'handlers': ['console_debug', 'console_default'],
|
||||||
|
},
|
||||||
|
}
|
||||||
3719
base/static/base/bootstrap/css/bootstrap-grid.css
vendored
Normal file
3719
base/static/base/bootstrap/css/bootstrap-grid.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
base/static/base/bootstrap/css/bootstrap-grid.css.map
Normal file
1
base/static/base/bootstrap/css/bootstrap-grid.css.map
Normal file
File diff suppressed because one or more lines are too long
7
base/static/base/bootstrap/css/bootstrap-grid.min.css
vendored
Normal file
7
base/static/base/bootstrap/css/bootstrap-grid.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
331
base/static/base/bootstrap/css/bootstrap-reboot.css
vendored
Normal file
331
base/static/base/bootstrap/css/bootstrap-reboot.css
vendored
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2019 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2019 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #212529;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
[tabindex="-1"]:focus {
|
||||||
|
outline: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr[title],
|
||||||
|
abbr[data-original-title] {
|
||||||
|
text-decoration: underline;
|
||||||
|
-webkit-text-decoration: underline dotted;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
cursor: help;
|
||||||
|
border-bottom: 0;
|
||||||
|
-webkit-text-decoration-skip-ink: none;
|
||||||
|
text-decoration-skip-ink: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
address {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-style: normal;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol,
|
||||||
|
ul,
|
||||||
|
dl {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol ol,
|
||||||
|
ul ul,
|
||||||
|
ol ul,
|
||||||
|
ul ol {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
position: relative;
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #007bff;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #0056b3;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):not([tabindex]) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):not([tabindex]):focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre,
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
vertical-align: middle;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
caption {
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
color: #6c757d;
|
||||||
|
text-align: left;
|
||||||
|
caption-side: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:focus {
|
||||||
|
outline: 1px dotted;
|
||||||
|
outline: 5px auto -webkit-focus-ring-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button,
|
||||||
|
select,
|
||||||
|
optgroup,
|
||||||
|
textarea {
|
||||||
|
margin: 0;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
word-wrap: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
[type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(:disabled),
|
||||||
|
[type="button"]:not(:disabled),
|
||||||
|
[type="reset"]:not(:disabled),
|
||||||
|
[type="submit"]:not(:disabled) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
padding: 0;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"],
|
||||||
|
input[type="checkbox"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="date"],
|
||||||
|
input[type="time"],
|
||||||
|
input[type="datetime-local"],
|
||||||
|
input[type="month"] {
|
||||||
|
-webkit-appearance: listbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
outline-offset: -2px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
font: inherit;
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
output {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
||||||
1
base/static/base/bootstrap/css/bootstrap-reboot.css.map
Normal file
1
base/static/base/bootstrap/css/bootstrap-reboot.css.map
Normal file
File diff suppressed because one or more lines are too long
8
base/static/base/bootstrap/css/bootstrap-reboot.min.css
vendored
Normal file
8
base/static/base/bootstrap/css/bootstrap-reboot.min.css
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2019 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2019 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||||
|
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
||||||
File diff suppressed because one or more lines are too long
10038
base/static/base/bootstrap/css/bootstrap.css
vendored
Normal file
10038
base/static/base/bootstrap/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
base/static/base/bootstrap/css/bootstrap.css.map
Normal file
1
base/static/base/bootstrap/css/bootstrap.css.map
Normal file
File diff suppressed because one or more lines are too long
7
base/static/base/bootstrap/css/bootstrap.min.css
vendored
Normal file
7
base/static/base/bootstrap/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
base/static/base/bootstrap/css/bootstrap.min.css.map
Normal file
1
base/static/base/bootstrap/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
7013
base/static/base/bootstrap/js/bootstrap.bundle.js
vendored
Normal file
7013
base/static/base/bootstrap/js/bootstrap.bundle.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
base/static/base/bootstrap/js/bootstrap.bundle.js.map
Normal file
1
base/static/base/bootstrap/js/bootstrap.bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
7
base/static/base/bootstrap/js/bootstrap.bundle.min.js
vendored
Normal file
7
base/static/base/bootstrap/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4435
base/static/base/bootstrap/js/bootstrap.js
vendored
Normal file
4435
base/static/base/bootstrap/js/bootstrap.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
base/static/base/bootstrap/js/bootstrap.js.map
Normal file
1
base/static/base/bootstrap/js/bootstrap.js.map
Normal file
File diff suppressed because one or more lines are too long
7
base/static/base/bootstrap/js/bootstrap.min.js
vendored
Normal file
7
base/static/base/bootstrap/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
base/static/base/bootstrap/js/bootstrap.min.js.map
Normal file
1
base/static/base/bootstrap/js/bootstrap.min.js.map
Normal file
File diff suppressed because one or more lines are too long
14
base/static/base/css/local.css
Normal file
14
base/static/base/css/local.css
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#page-header {
|
||||||
|
padding-left: 1rem;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-bottom-width: 2px;
|
||||||
|
border-bottom-color: #000;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-footer {
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
#page-footer > div.signum {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
5
base/static/base/js/jquery.min.js
vendored
Normal file
5
base/static/base/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
33
base/templates/base/base.html
Normal file
33
base/templates/base/base.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
{% load static %}
|
||||||
|
<html lang="{{ LANGUAGE_CODE|default:'de' }}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
|
<link type="text/css" href="{% static 'base/bootstrap/css/bootstrap.min.css' %}" rel="stylesheet" />
|
||||||
|
<link type="text/css" href="{% static 'base/css/local.css' %}" rel="stylesheet" />
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{% static 'base/js/jquery.min.js' %}"></script>
|
||||||
|
<script type="text/javascript" src="{% static 'base/bootstrap/js/bootstrap.min.js' %}"></script>
|
||||||
|
|
||||||
|
<title>django-test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="page">
|
||||||
|
<div id="page-header">
|
||||||
|
<h1>
|
||||||
|
<a href="{% url 'root' %}">django-test</a>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="page-body">
|
||||||
|
{% block page-body %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="page-footer">
|
||||||
|
<div class="signum">{% block signum %}{% include 'signum.html' %}{% endblock %}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
15
base/templates/base/root.html
Normal file
15
base/templates/base/root.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{% extends "base/base.html" %}
|
||||||
|
|
||||||
|
{% block page-body %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="jumbotron">
|
||||||
|
<h1>Hello,</h1>
|
||||||
|
<p>
|
||||||
|
my name is {{ hostname|capfirst }} and I am your server right now.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
By the way, my clock says {{ time|time:'TIME_FORMAT'|default:'nothing' }}.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock page-body %}
|
||||||
1
base/templates/signum.html
Normal file
1
base/templates/signum.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<a href="mailto:heinzel@heinzelwelt.de">heinzel@heinzelwelt.de</a>
|
||||||
0
base/tests/__init__.py
Normal file
0
base/tests/__init__.py
Normal file
31
base/tests/test_scripts.py
Normal file
31
base/tests/test_scripts.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from django.test import SimpleTestCase
|
||||||
|
|
||||||
|
from ..console_scripts.admin import DJANGO_MAIN_MODULE, AdminCommand
|
||||||
|
|
||||||
|
from .utils import mkdtemp
|
||||||
|
|
||||||
|
|
||||||
|
class AdminTestCase(SimpleTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(AdminTestCase, self).setUp()
|
||||||
|
self.tmp_dir = mkdtemp(prefix='AdminTestCase')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(AdminTestCase, self).tearDown()
|
||||||
|
if os.path.isdir(self.tmp_dir):
|
||||||
|
shutil.rmtree(self.tmp_dir)
|
||||||
|
|
||||||
|
def test_setup(self):
|
||||||
|
path = self.tmp_dir
|
||||||
|
cmd = AdminCommand()
|
||||||
|
argv = ['setup', path]
|
||||||
|
exitval = cmd(argv)
|
||||||
|
self.assertEqual(exitval, os.EX_OK)
|
||||||
|
self.assertTrue(os.path.isfile(os.path.join(path, 'manage.py')))
|
||||||
|
self.assertTrue(os.path.isfile(os.path.join(path, DJANGO_MAIN_MODULE, 'settings.py')))
|
||||||
|
self.assertTrue(os.path.isdir(os.path.join(path, 'var', 'log')))
|
||||||
|
self.assertTrue(os.path.isdir(os.path.join(path, 'var', 'www', 'static')))
|
||||||
76
base/tests/test_templates.py
Normal file
76
base/tests/test_templates.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template.context import Context
|
||||||
|
from django.test import SimpleTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTemplateTestCase(SimpleTestCase):
|
||||||
|
def assertInHTML_multi(self, response, needles, format_kwargs=None):
|
||||||
|
content = response.content.decode('utf-8')
|
||||||
|
for needle in needles:
|
||||||
|
if format_kwargs is not None:
|
||||||
|
needle = needle.format(**format_kwargs)
|
||||||
|
self.assertInHTML(needle, content)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(BaseTemplateTestCase, self).setUp()
|
||||||
|
self.response = self.client.get('/')
|
||||||
|
self.static_url = settings.STATIC_URL
|
||||||
|
self.base_prefix = 'base/'
|
||||||
|
|
||||||
|
def test_template_usage(self):
|
||||||
|
response = self.response
|
||||||
|
self.assertTemplateUsed(response, 'base/base.html')
|
||||||
|
|
||||||
|
def test_local_css_link(self):
|
||||||
|
response = self.response
|
||||||
|
|
||||||
|
format_kwargs = {
|
||||||
|
'static_url': self.static_url,
|
||||||
|
'base_prefix': self.base_prefix,
|
||||||
|
}
|
||||||
|
|
||||||
|
needles = (
|
||||||
|
'<link type="text/css" href="{static_url}{base_prefix}css/local.css" rel="stylesheet" />',
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertInHTML_multi(response, needles, format_kwargs)
|
||||||
|
|
||||||
|
def test_bootstrap_css_links(self):
|
||||||
|
response = self.response
|
||||||
|
|
||||||
|
format_kwargs = {
|
||||||
|
'static_url': self.static_url,
|
||||||
|
'base_prefix': self.base_prefix,
|
||||||
|
}
|
||||||
|
|
||||||
|
needles = (
|
||||||
|
# bootstrap css
|
||||||
|
'<link type="text/css" href="{static_url}{base_prefix}bootstrap/css/bootstrap.min.css"'
|
||||||
|
' rel="stylesheet" />',
|
||||||
|
# jquery.js file
|
||||||
|
'<script type="text/javascript" src="{static_url}{base_prefix}js/jquery.min.js"></script>',
|
||||||
|
# bootstrap js file
|
||||||
|
'<script type="text/javascript" src="{static_url}{base_prefix}bootstrap/js/bootstrap.min.js"></script>',
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertInHTML_multi(response, needles, format_kwargs)
|
||||||
|
|
||||||
|
def test_page_footer(self):
|
||||||
|
response = self.response
|
||||||
|
self.assertTemplateUsed(response, 'signum.html')
|
||||||
|
for template in response.templates:
|
||||||
|
if template.name == 'signum.html':
|
||||||
|
signum = template.render(Context({}))
|
||||||
|
break
|
||||||
|
else: # pragma: no cover
|
||||||
|
self.fail('Cannot find signum template.')
|
||||||
|
|
||||||
|
needle = """
|
||||||
|
<div id="page-footer">
|
||||||
|
<div class="signum">{signum}</div>
|
||||||
|
</div>
|
||||||
|
""".format(signum=signum)
|
||||||
|
|
||||||
|
self.assertInHTML(needle, response.content.decode('utf-8'))
|
||||||
31
base/tests/test_views.py
Normal file
31
base/tests/test_views.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import socket
|
||||||
|
from django.test import SimpleTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class DjangoAdminTestCase(SimpleTestCase):
|
||||||
|
def test_djangoadmin(self):
|
||||||
|
response = self.client.get('/djangoadmin', follow=True)
|
||||||
|
self.assertContains(response, 'Django administration')
|
||||||
|
|
||||||
|
|
||||||
|
class RootTestCase(SimpleTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(RootTestCase, self).setUp()
|
||||||
|
self.response = self.client.get('/')
|
||||||
|
|
||||||
|
def test_root_template(self):
|
||||||
|
response = self.response
|
||||||
|
self.assertTemplateUsed(response, 'base/root.html')
|
||||||
|
|
||||||
|
def test_root_context(self):
|
||||||
|
response = self.response
|
||||||
|
self.assertIn('hostname', response.context)
|
||||||
|
hostname = socket.gethostname()
|
||||||
|
self.assertEqual(response.context['hostname'], hostname)
|
||||||
|
|
||||||
|
def test_root_content(self):
|
||||||
|
response = self.response
|
||||||
|
hostname = socket.gethostname().capitalize()
|
||||||
|
self.assertContains(response, hostname)
|
||||||
12
base/tests/utils.py
Normal file
12
base/tests/utils.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import os
|
||||||
|
from tempfile import mkdtemp as _mkdtmp
|
||||||
|
|
||||||
|
|
||||||
|
def mkdtemp(prefix):
|
||||||
|
dirname = os.path.dirname
|
||||||
|
pkg_base_dir = dirname(dirname(dirname(__file__)))
|
||||||
|
tmp_dir = os.path.join(pkg_base_dir, 'tmp')
|
||||||
|
os.makedirs(tmp_dir, exist_ok=True)
|
||||||
|
return _mkdtmp(prefix=prefix, dir=tmp_dir)
|
||||||
11
base/urls.py
Normal file
11
base/urls.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', views.RootView.as_view(), name='root'),
|
||||||
|
path('djangoadmin/', admin.site.urls),
|
||||||
|
]
|
||||||
16
base/views.py
Normal file
16
base/views.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import socket
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.views import generic
|
||||||
|
|
||||||
|
|
||||||
|
class RootView(generic.TemplateView):
|
||||||
|
template_name = 'base/root.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
if 'hostname' not in kwargs:
|
||||||
|
kwargs['hostname'] = socket.gethostname()
|
||||||
|
if 'time' not in kwargs:
|
||||||
|
kwargs['time'] = timezone.now()
|
||||||
|
return super(RootView, self).get_context_data(**kwargs)
|
||||||
82
bin/coverage-html.py
Executable file
82
bin/coverage-html.py
Executable file
@@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import argparse
|
||||||
|
import coverage
|
||||||
|
import datetime
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class Command(object):
|
||||||
|
default_browser = 'firefox'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _setup_argparser():
|
||||||
|
kwargs = {
|
||||||
|
'description': 'Tool to create html coverage report.',
|
||||||
|
}
|
||||||
|
parser = argparse.ArgumentParser(**kwargs)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def _parse_args(self, argv=None):
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv[1:]
|
||||||
|
|
||||||
|
return self._argparser.parse_args(argv)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _create_report_directory(path=None):
|
||||||
|
if path is None:
|
||||||
|
timestamp = datetime.datetime.now().strftime('%Y%m%d-%H%M')
|
||||||
|
dirname = 'coverage-report-{}'.format(timestamp)
|
||||||
|
path = os.path.join('tmp', dirname)
|
||||||
|
os.makedirs(path)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def _remove_report_directory(self, path=None):
|
||||||
|
if path is None:
|
||||||
|
path = self._report_directory
|
||||||
|
if path is not None:
|
||||||
|
if os.path.isdir(path):
|
||||||
|
sys.stdout.write('Removing report directory {}\n'.format(path))
|
||||||
|
shutil.rmtree(path)
|
||||||
|
|
||||||
|
def _create_report(self, path):
|
||||||
|
return self._coverage.html_report(directory=path, skip_covered=True)
|
||||||
|
|
||||||
|
def _show_report(self, path):
|
||||||
|
start_file = os.path.join(path, 'index.html')
|
||||||
|
browser = os.environ.get('BROWSER', self.default_browser)
|
||||||
|
cmd = '{browser} --new-window "{file}"'.format(browser=browser, file=start_file)
|
||||||
|
return os.system(cmd)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._argparser = self._setup_argparser()
|
||||||
|
self._report_directory = self._create_report_directory()
|
||||||
|
self._coverage = coverage.Coverage()
|
||||||
|
self._coverage.load()
|
||||||
|
|
||||||
|
def __call__(self, argv=None):
|
||||||
|
self._parse_args(argv)
|
||||||
|
report_dir = self._report_directory
|
||||||
|
sys.stdout.write('Report directory: {}\n'.format(report_dir))
|
||||||
|
try:
|
||||||
|
self._create_report(report_dir)
|
||||||
|
except Exception as e1:
|
||||||
|
self._remove_report_directory(report_dir)
|
||||||
|
raise e1
|
||||||
|
|
||||||
|
exitval = self._show_report(report_dir)
|
||||||
|
return exitval
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
cmd = Command()
|
||||||
|
exitval = cmd()
|
||||||
|
sys.exit(exitval)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
117
setup.py
Normal file
117
setup.py
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
from setuptools import Command
|
||||||
|
|
||||||
|
|
||||||
|
class MyCommand(Command):
|
||||||
|
user_options = []
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SetupPythonEnvironment(MyCommand):
|
||||||
|
description = 'create a (virtual) python environment'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def run():
|
||||||
|
python_bin = sys.executable if sys.executable else 'python'
|
||||||
|
python_ver = sys.version_info.major
|
||||||
|
if python_ver == 2:
|
||||||
|
path = os.path.join('env', 'python2')
|
||||||
|
symlink_path = os.path.join('env', 'python')
|
||||||
|
venv_module = 'virtualenv'
|
||||||
|
prompt = '(py2-django) '
|
||||||
|
elif python_ver == 3:
|
||||||
|
path = os.path.join('env', 'python3')
|
||||||
|
symlink_path = os.path.join('env', 'python')
|
||||||
|
venv_module = 'venv'
|
||||||
|
prompt = 'py3-django'
|
||||||
|
else:
|
||||||
|
sys.stderr.write('Python {} is not supported.\n'.format(python_ver))
|
||||||
|
sys.exit(os.EX_USAGE)
|
||||||
|
|
||||||
|
sys.stdout.write('Creating new python environment in {path}\n'.format(path=path))
|
||||||
|
cmd = ('{bin} -m {venv_module}'
|
||||||
|
' --prompt="{prompt}"'
|
||||||
|
' {path}'.format(bin=python_bin, path=path,
|
||||||
|
venv_module=venv_module, prompt=prompt))
|
||||||
|
os.system(cmd)
|
||||||
|
|
||||||
|
if symlink_path and not os.path.exists(symlink_path):
|
||||||
|
symlink_dir = os.path.dirname(symlink_path)
|
||||||
|
relpath = os.path.relpath(path, symlink_dir)
|
||||||
|
os.symlink(relpath, symlink_path)
|
||||||
|
|
||||||
|
print('')
|
||||||
|
print('Depending on your operating system or command shell,')
|
||||||
|
print('you should activate the new environment for this shell session')
|
||||||
|
print('by running ONE of the following commands:')
|
||||||
|
print('- Windows: %s' % os.path.join(path, 'Scripts', 'activate'))
|
||||||
|
print('- C Shell: source %s/bin/activate.csh' % path)
|
||||||
|
print('- All others: source %s/bin/activate' % path)
|
||||||
|
|
||||||
|
|
||||||
|
class SetupDjangoEnvironment(MyCommand):
|
||||||
|
description = 'create a typical installation for developing'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def run():
|
||||||
|
# python_bin = sys.executable if sys.executable else 'python'
|
||||||
|
django_project_path = 'env/django'
|
||||||
|
# mgmt_script = os.path.join(django_project_path, 'manage.py')
|
||||||
|
|
||||||
|
sys.stdout.write('Install distribution in development mode...\n')
|
||||||
|
cmd = 'pip install -e .'
|
||||||
|
os.system(cmd)
|
||||||
|
|
||||||
|
sys.stdout.write('Setup django project in {}...\n'.format(django_project_path))
|
||||||
|
cmd = 'django-test-admin setup {}'.format(django_project_path)
|
||||||
|
os.system(cmd)
|
||||||
|
|
||||||
|
# sys.stdout.write('Make database migrations...\n')
|
||||||
|
# cmd = '{bin} {mgmt} makemigrations'.format(bin=python_bin, mgmt=mgmt_script)
|
||||||
|
# os.system(cmd)
|
||||||
|
|
||||||
|
# sys.stdout.write('Create database...\n')
|
||||||
|
# cmd = '{bin} {mgmt} migrate'.format(bin=python_bin, mgmt=mgmt_script)
|
||||||
|
# os.system(cmd)
|
||||||
|
|
||||||
|
# sys.stdout.write('Create superuser \'root\'...\n')
|
||||||
|
# cmd = ('{bin} {mgmt} createsuperuser'
|
||||||
|
# ' --username root').format(bin=python_bin, mgmt=mgmt_script)
|
||||||
|
# os.system(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='django-test',
|
||||||
|
version='1.0',
|
||||||
|
description='An example django based web application.',
|
||||||
|
url='https://heinzelwelt.de',
|
||||||
|
maintainer='Jens Kleineheismann',
|
||||||
|
maintainer_email='heinzel@heinzelwelt.de',
|
||||||
|
cmdclass={
|
||||||
|
'mkpyenv': SetupPythonEnvironment,
|
||||||
|
'mkdjangoenv': SetupDjangoEnvironment,
|
||||||
|
},
|
||||||
|
packages=find_packages(),
|
||||||
|
include_package_data=True,
|
||||||
|
test_suite='tests.test_suite',
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'django-test-admin = base.console_scripts.admin:main',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
install_requires=[
|
||||||
|
'coverage',
|
||||||
|
'django',
|
||||||
|
'django-extensions',
|
||||||
|
],
|
||||||
|
)
|
||||||
2
tests/__init__.py
Normal file
2
tests/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from .test_suite import TestSuite
|
||||||
|
test_suite = TestSuite()
|
||||||
71
tests/test_suite.py
Normal file
71
tests/test_suite.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import datetime
|
||||||
|
import django
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
from django.test.utils import get_runner
|
||||||
|
|
||||||
|
from base.console_scripts.admin import DJANGO_MAIN_MODULE
|
||||||
|
from base.tests.utils import mkdtemp
|
||||||
|
|
||||||
|
|
||||||
|
class DjangoEnvironment(object):
|
||||||
|
@staticmethod
|
||||||
|
def _install_djangoproject(path):
|
||||||
|
cmd = 'django-test-admin setup "{}"'.format(path)
|
||||||
|
os.system(cmd)
|
||||||
|
|
||||||
|
def __init__(self, path=None, remove_after=True):
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
self._remove_after = remove_after
|
||||||
|
self._original_sys_path = None
|
||||||
|
self._modified_sys_path = None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
if self.path is None:
|
||||||
|
prefix = 'testrun-{datetime}-'.format(
|
||||||
|
datetime=datetime.datetime.now().strftime('%Y%m%d-%H%M')
|
||||||
|
)
|
||||||
|
self.path = mkdtemp(prefix=prefix)
|
||||||
|
|
||||||
|
self._install_djangoproject(self.path)
|
||||||
|
|
||||||
|
self._original_sys_path = sys.path
|
||||||
|
sys.path.append(self.path)
|
||||||
|
self._modified_sys_path = sys.path
|
||||||
|
|
||||||
|
os.environ['DJANGO_SETTINGS_MODULE'] = '{}.settings'.format(DJANGO_MAIN_MODULE)
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
self.settings = settings
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
if self._modified_sys_path is not None and self._original_sys_path is not None:
|
||||||
|
if sys.path == self._modified_sys_path:
|
||||||
|
sys.path = self._original_sys_path
|
||||||
|
if self._remove_after:
|
||||||
|
shutil.rmtree(self.path)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSuite(object):
|
||||||
|
@staticmethod
|
||||||
|
def run():
|
||||||
|
tests = ['base']
|
||||||
|
test_tags = None
|
||||||
|
exclude_test_tags = None
|
||||||
|
|
||||||
|
with DjangoEnvironment() as env:
|
||||||
|
test_runner_class = get_runner(env.settings)
|
||||||
|
test_runner = test_runner_class(tags=test_tags, exclude_tags=exclude_test_tags)
|
||||||
|
failures = test_runner.run_tests(tests)
|
||||||
|
|
||||||
|
return bool(failures)
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
sys.exit(self.run())
|
||||||
Reference in New Issue
Block a user