Convert to a django-list structure
This commit is contained in:
parent
61a1ae62ab
commit
a05cfe3337
28
.drone.yml
Normal file
28
.drone.yml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- IMAGE: 3.6-stretch
|
||||||
|
TOXENV: py36
|
||||||
|
- IMAGE: 3.7-stretch
|
||||||
|
TOXENV: py37
|
||||||
|
- IMAGE: 3.8-buster
|
||||||
|
TOXENV: py38
|
||||||
|
- IMAGE: 3.8-buster
|
||||||
|
TOXENV: lint
|
||||||
|
- IMAGE: 3.8-buster
|
||||||
|
TOXENV: sort
|
||||||
|
- IMAGE: 3.8-buster
|
||||||
|
TOXENV: format
|
||||||
|
- IMAGE: 3.8-buster
|
||||||
|
TOXENV: type
|
||||||
|
- IMAGE: 3.8-buster
|
||||||
|
TOXENV: docs
|
||||||
|
- IMAGE: 3.8-buster
|
||||||
|
TOXENV: metadata-release
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
build:
|
||||||
|
image: python:${IMAGE}
|
||||||
|
commands:
|
||||||
|
- pip install tox==3.14.6
|
||||||
|
- tox -e ${TOXENV}
|
7
.envrc.sample
Normal file
7
.envrc.sample
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export CELERY_BROKER_URL=redis://localhost:6379/1
|
||||||
|
export CELERY_RESULT_BACKEND=redis://localhost:6379/1
|
||||||
|
export ENV=development
|
||||||
|
export REDIS_HOST=localhost
|
||||||
|
export REDIS_PORT=6379
|
||||||
|
export REDIS_SESSION_DB=0
|
||||||
|
export SERVER_PORT=0.0.0.0:8000
|
1
CHANGELOG.md
Normal file
1
CHANGELOG.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Change log
|
26
Dockerfile
Normal file
26
Dockerfile
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
FROM python:3.8-alpine
|
||||||
|
|
||||||
|
ENV APP_ROOT /magic_app/
|
||||||
|
ENV CELERY_USER celery
|
||||||
|
|
||||||
|
WORKDIR ${APP_ROOT}
|
||||||
|
COPY . ${APP_ROOT}
|
||||||
|
|
||||||
|
RUN apk add --update \
|
||||||
|
build-base \
|
||||||
|
curl \
|
||||||
|
git \
|
||||||
|
libffi-dev \
|
||||||
|
libsasl \
|
||||||
|
python3-dev
|
||||||
|
|
||||||
|
|
||||||
|
RUN addgroup -S ${CELERY_USER}
|
||||||
|
RUN adduser -D \
|
||||||
|
-h ${APP_ROOT} \
|
||||||
|
-s /usr/sbin/nologin \
|
||||||
|
-G ${CELERY_USER} ${CELERY_USER}
|
||||||
|
|
||||||
|
RUN pip install "poetry>=1.0.9,<2.0"
|
||||||
|
|
||||||
|
RUN poetry install
|
141
LICENSE
141
LICENSE
@ -1,5 +1,5 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
@ -7,17 +7,15 @@
|
|||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
software and other kinds of works.
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
The licenses for most software and other practical works are designed
|
||||||
to take away your freedom to share and change the works. By contrast,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
our General Public Licenses are intended to guarantee your freedom to
|
||||||
share and change all versions of a program--to make sure it remains free
|
share and change all versions of a program--to make sure it remains free
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
software for all its users.
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
When we speak of free software, we are referring to freedom, not
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you
|
|||||||
want it, that you can change the software or use pieces of it in new
|
want it, that you can change the software or use pieces of it in new
|
||||||
free programs, and that you know you can do these things.
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
Developers that use our General Public Licenses protect your rights
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
you this License which gives you legal permission to copy, distribute
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
and/or modify the software.
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
A secondary benefit of defending all users' freedom is that
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
improvements made in alternate versions of the program, if they
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
receive widespread use, become available for other developers to
|
||||||
or can get the source code. And you must show them these terms so they
|
incorporate. Many developers of free software are heartened and
|
||||||
know their rights.
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
The GNU Affero General Public License is designed specifically to
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
ensure that, in such cases, the modified source code becomes available
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
An older license, called the Affero General Public License and
|
||||||
that there is no warranty for this free software. For both users' and
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
changed, so that their problems will not be attributed erroneously to
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
authors of previous versions.
|
this license.
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
The precise terms and conditions for copying, distribution and
|
||||||
modification follow.
|
modification follow.
|
||||||
@ -72,7 +60,7 @@ modification follow.
|
|||||||
|
|
||||||
0. Definitions.
|
0. Definitions.
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
works, such as semiconductor masks.
|
works, such as semiconductor masks.
|
||||||
@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey
|
|||||||
the Program, the only way you could satisfy both those terms and this
|
the Program, the only way you could satisfy both those terms and this
|
||||||
License would be to refrain entirely from conveying the Program.
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
Notwithstanding any other provision of this License, you have
|
||||||
permission to link or combine any covered work with a work licensed
|
permission to link or combine any covered work with a work licensed
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
under version 3 of the GNU General Public License into a single
|
||||||
combined work, and to convey the resulting work. The terms of this
|
combined work, and to convey the resulting work. The terms of this
|
||||||
License will continue to apply to the part which is the covered work,
|
License will continue to apply to the part which is the covered work,
|
||||||
but the special requirements of the GNU Affero General Public License,
|
but the work with which it is combined will remain governed by version
|
||||||
section 13, concerning interaction through a network will apply to the
|
3 of the GNU General Public License.
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
the GNU General Public License from time to time. Such new versions will
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
address new problems or concerns.
|
address new problems or concerns.
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
Each version is given a distinguishing version number. If the
|
||||||
Program specifies that a certain numbered version of the GNU General
|
Program specifies that a certain numbered version of the GNU Affero General
|
||||||
Public License "or any later version" applies to it, you have the
|
Public License "or any later version" applies to it, you have the
|
||||||
option of following the terms and conditions either of that numbered
|
option of following the terms and conditions either of that numbered
|
||||||
version or of any later version published by the Free Software
|
version or of any later version published by the Free Software
|
||||||
Foundation. If the Program does not specify a version number of the
|
Foundation. If the Program does not specify a version number of the
|
||||||
GNU General Public License, you may choose any version ever published
|
GNU Affero General Public License, you may choose any version ever published
|
||||||
by the Free Software Foundation.
|
by the Free Software Foundation.
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
If the Program specifies that a proxy can decide which future
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
versions of the GNU Affero General Public License can be used, that proxy's
|
||||||
public statement of acceptance of a version permanently authorizes you
|
public statement of acceptance of a version permanently authorizes you
|
||||||
to choose that version for the Program.
|
to choose that version for the Program.
|
||||||
|
|
||||||
@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found.
|
|||||||
Copyright (C) <year> <name of author>
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
If your software can interact with users remotely through a computer
|
||||||
notice like this when it starts in an interactive mode:
|
network, you should also make sure that it provides a way for users to
|
||||||
|
get its source. For example, if your program is a web application, its
|
||||||
<program> Copyright (C) <year> <name of author>
|
interface could display a "Source" link that leads users to an archive
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
of the code. There are many ways you could offer source, and different
|
||||||
This is free software, and you are welcome to redistribute it
|
solutions will be better for different programs; see section 13 for the
|
||||||
under certain conditions; type `show c' for details.
|
specific requirements.
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||||
<https://www.gnu.org/licenses/>.
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
||||||
|
41
README.md
41
README.md
@ -1,42 +1,7 @@
|
|||||||
# Magic App
|
# magic-app
|
||||||
|
|
||||||
A swarm of dreams.
|
A swarm of dreams.
|
||||||
|
|
||||||
## first.py
|
# Development
|
||||||
|
|
||||||
Ideas contained within...
|
TODO.
|
||||||
|
|
||||||
- List apps from an `app.json` (points to https://git.autonomic.zone/compose-stacks)
|
|
||||||
- Clone selected app template and parse configuration for inputs (env vars and secrets)
|
|
||||||
- Generate a form so those values can be filled out and allow it to be saved
|
|
||||||
- Save the form inputs to a `db.json` (as a start)
|
|
||||||
- Deploy an applicaiton to a local swarm (assumes access to local docker socket)
|
|
||||||
- Create an "edit app" page where the `db.json` is re-called and can be updated
|
|
||||||
- Make sure re-deploy works (taking care of updating secret and app versions)
|
|
||||||
|
|
||||||
## second.py
|
|
||||||
|
|
||||||
More ideas...
|
|
||||||
|
|
||||||
- Don't try to be smart with the auto-generation, hard-code everything. We
|
|
||||||
maintain the app template (`compose.yml`) and this code anyway, so we just
|
|
||||||
need to be aware of each other and keep in sync. This would optimise for
|
|
||||||
trust and collaboration and not "smart" code.
|
|
||||||
- Hard-code the secrets/configs required to make the code for generating
|
|
||||||
versions simpler as well.
|
|
||||||
|
|
||||||
## MVP screens
|
|
||||||
|
|
||||||
- **App selection screen**: a list of apps, you choose which one you want
|
|
||||||
- **Install app screen**:a form for installing the application
|
|
||||||
- **Edit app screen**: re-load the configuration for an app, ability to update it
|
|
||||||
- **Delete app screen**: remove the app
|
|
||||||
|
|
||||||
### Development
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ python3 -m venv .venv
|
|
||||||
$ source .venv/bin/activate
|
|
||||||
$ pip install -r requirements.txt
|
|
||||||
$ python first.py / second.py / third.py
|
|
||||||
```
|
|
||||||
|
9
celworker.py
Normal file
9
celworker.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
"""Bootstrap the application for Celery."""
|
||||||
|
from os import environ
|
||||||
|
|
||||||
|
from magic_app.app import celery, create_app # noqa
|
||||||
|
from magic_app.config import CONFIG
|
||||||
|
|
||||||
|
config = CONFIG[environ["ENV"]]
|
||||||
|
app = create_app(config=config)
|
||||||
|
app.app_context().push()
|
1
magic_app/__init__.py
Normal file
1
magic_app/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""The main application package."""
|
61
magic_app/app.py
Normal file
61
magic_app/app.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
"""The main application factory."""
|
||||||
|
from logging import DEBUG, ERROR, getLogger
|
||||||
|
|
||||||
|
from celery import Celery
|
||||||
|
from flask import Flask
|
||||||
|
from redis import Redis
|
||||||
|
|
||||||
|
from magic_app.config import Base, Production
|
||||||
|
|
||||||
|
celery = Celery(__name__, broker=Base.CELERY_BROKER_URL)
|
||||||
|
|
||||||
|
|
||||||
|
def create_app(config=Production):
|
||||||
|
"""Main application factory."""
|
||||||
|
app = Flask(__name__.split(".")[0])
|
||||||
|
app.config.from_object(config)
|
||||||
|
|
||||||
|
celery.conf.update(app.config)
|
||||||
|
|
||||||
|
configure_redis(app)
|
||||||
|
configure_views(app)
|
||||||
|
configure_logging(app)
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
def configure_redis(app):
|
||||||
|
"""Configure Redis connection."""
|
||||||
|
from magic_app.session import RedisSessionDB
|
||||||
|
|
||||||
|
host = (Base.REDIS_HOST,)
|
||||||
|
port = (Base.REDIS_PORT,)
|
||||||
|
db_num = Base.REDIS_SESSION_DB
|
||||||
|
|
||||||
|
if app.debug:
|
||||||
|
from fakeredis import FakeRedis
|
||||||
|
|
||||||
|
connection = FakeRedis()
|
||||||
|
else:
|
||||||
|
connection = Redis(host=host, port=port, db=db_num)
|
||||||
|
|
||||||
|
app.config["SESSION"] = RedisSessionDB(connection)
|
||||||
|
|
||||||
|
|
||||||
|
def configure_views(app):
|
||||||
|
"""Configure API resource views."""
|
||||||
|
from magic_app.views import home
|
||||||
|
|
||||||
|
app.register_blueprint(home)
|
||||||
|
|
||||||
|
|
||||||
|
def configure_logging(app):
|
||||||
|
"""Configure application logging."""
|
||||||
|
app_logger = getLogger(__name__)
|
||||||
|
|
||||||
|
if not app.debug:
|
||||||
|
app_logger.setLevel(ERROR)
|
||||||
|
else:
|
||||||
|
app_logger.setLevel(DEBUG)
|
||||||
|
|
||||||
|
app.logging = app_logger
|
48
magic_app/config.py
Normal file
48
magic_app/config.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
"""The Application settings."""
|
||||||
|
from os import environ, pardir
|
||||||
|
from os.path import abspath, dirname, join
|
||||||
|
|
||||||
|
|
||||||
|
class Base:
|
||||||
|
"""The base configuration."""
|
||||||
|
|
||||||
|
DEBUG = False
|
||||||
|
JSON_AS_ASCII = False
|
||||||
|
|
||||||
|
APP_DIR = abspath(dirname(__file__))
|
||||||
|
PROJECT_ROOT = abspath(join(APP_DIR, pardir))
|
||||||
|
SWAGGER_DIR = abspath(join(PROJECT_ROOT, "swagger_docs"))
|
||||||
|
|
||||||
|
REDIS_HOST = environ["REDIS_HOST"]
|
||||||
|
REDIS_PORT = environ["REDIS_PORT"]
|
||||||
|
REDIS_SESSION_DB = int(environ["REDIS_SESSION_DB"])
|
||||||
|
|
||||||
|
CELERY_BROKER_URL = environ["CELERY_BROKER_URL"]
|
||||||
|
CELERY_RESULT_BACKEND = environ["CELERY_RESULT_BACKEND"]
|
||||||
|
|
||||||
|
|
||||||
|
class Development(Base):
|
||||||
|
"""The Development configuration."""
|
||||||
|
|
||||||
|
ENV = "development"
|
||||||
|
DEBUG = True
|
||||||
|
CELERY_ALWAYS_EAGER = True
|
||||||
|
|
||||||
|
|
||||||
|
class Testing(Base):
|
||||||
|
"""The testing configuration."""
|
||||||
|
|
||||||
|
ENV = "testing"
|
||||||
|
|
||||||
|
|
||||||
|
class Production(Base):
|
||||||
|
"""The production configuration."""
|
||||||
|
|
||||||
|
ENV = "production"
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG = {
|
||||||
|
"development": Development,
|
||||||
|
"testing": Testing,
|
||||||
|
"production": Production,
|
||||||
|
}
|
32
magic_app/session.py
Normal file
32
magic_app/session.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
"""Session management interface module."""
|
||||||
|
from json import dumps, loads
|
||||||
|
|
||||||
|
|
||||||
|
class RedisSessionDB(dict):
|
||||||
|
"""Dict interface for Redis session management."""
|
||||||
|
|
||||||
|
def __init__(self, connection):
|
||||||
|
self.connection = connection
|
||||||
|
|
||||||
|
def keys(self):
|
||||||
|
return self.connection.keys()
|
||||||
|
|
||||||
|
def flushall(self):
|
||||||
|
self.connection.flushall()
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
value = self.connection.get(key)
|
||||||
|
if value is None:
|
||||||
|
raise KeyError(key)
|
||||||
|
utf8ified = str(value, "utf-8")
|
||||||
|
return loads(utf8ified)
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
value = dumps(value)
|
||||||
|
self.connection.set(key, value)
|
||||||
|
|
||||||
|
def __contains__(self, item):
|
||||||
|
return self.connection.exists(item)
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
self.connection.delete(key)
|
7
magic_app/tasks.py
Normal file
7
magic_app/tasks.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"""Celery tasks module."""
|
||||||
|
from magic_app.app import celery
|
||||||
|
|
||||||
|
|
||||||
|
@celery.task
|
||||||
|
def hello_world():
|
||||||
|
print("Hello, World")
|
7
magic_app/templates/base.html
Normal file
7
magic_app/templates/base.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<html>
|
||||||
|
<head></head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
||||||
|
</html>
|
9
magic_app/views.py
Normal file
9
magic_app/views.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
"""View routing."""
|
||||||
|
from flask import Blueprint
|
||||||
|
|
||||||
|
home = Blueprint("home", __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@home.route("/")
|
||||||
|
def hello_world():
|
||||||
|
return "Hello, World"
|
4
mypy.ini
Normal file
4
mypy.ini
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[mypy]
|
||||||
|
python_version = 3.8
|
||||||
|
platform = linux
|
||||||
|
ignore_missing_imports = True
|
698
poetry.lock
generated
Normal file
698
poetry.lock
generated
Normal file
@ -0,0 +1,698 @@
|
|||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Low-level AMQP client for Python (fork of amqplib)."
|
||||||
|
name = "amqp"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "2.6.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
vine = ">=1.1.3,<5.0.0a1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||||
|
name = "appdirs"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "1.4.4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Classes Without Boilerplate"
|
||||||
|
name = "attrs"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
version = "19.3.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
|
||||||
|
dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
|
||||||
|
docs = ["sphinx", "zope.interface"]
|
||||||
|
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Python multiprocessing fork with improvements and bugfixes"
|
||||||
|
name = "billiard"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "3.6.3.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "The uncompromising code formatter."
|
||||||
|
name = "black"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
version = "19.10b0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
appdirs = "*"
|
||||||
|
attrs = ">=18.1.0"
|
||||||
|
click = ">=6.5"
|
||||||
|
pathspec = ">=0.6,<1"
|
||||||
|
regex = "*"
|
||||||
|
toml = ">=0.9.4"
|
||||||
|
typed-ast = ">=1.4.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Distributed Task Queue."
|
||||||
|
name = "celery"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "4.4.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
billiard = ">=3.6.3.0,<4.0"
|
||||||
|
future = ">=0.18.0"
|
||||||
|
kombu = ">=4.6.10,<4.7"
|
||||||
|
pytz = ">0.0-dev"
|
||||||
|
vine = "1.3.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
arangodb = ["pyArango (>=1.3.2)"]
|
||||||
|
auth = ["cryptography"]
|
||||||
|
azureblockblob = ["azure-storage (0.36.0)", "azure-common (1.1.5)", "azure-storage-common (1.1.0)"]
|
||||||
|
brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"]
|
||||||
|
cassandra = ["cassandra-driver (<3.21.0)"]
|
||||||
|
consul = ["python-consul"]
|
||||||
|
cosmosdbsql = ["pydocumentdb (2.3.2)"]
|
||||||
|
couchbase = ["couchbase-cffi (<3.0.0)", "couchbase (<3.0.0)"]
|
||||||
|
couchdb = ["pycouchdb"]
|
||||||
|
django = ["Django (>=1.11)"]
|
||||||
|
dynamodb = ["boto3 (>=1.9.178)"]
|
||||||
|
elasticsearch = ["elasticsearch"]
|
||||||
|
eventlet = ["eventlet (>=0.24.1)"]
|
||||||
|
gevent = ["gevent"]
|
||||||
|
librabbitmq = ["librabbitmq (>=1.5.0)"]
|
||||||
|
lzma = ["backports.lzma"]
|
||||||
|
memcache = ["pylibmc"]
|
||||||
|
mongodb = ["pymongo (>=3.3.0)"]
|
||||||
|
msgpack = ["msgpack"]
|
||||||
|
pymemcache = ["python-memcached"]
|
||||||
|
pyro = ["pyro4"]
|
||||||
|
redis = ["redis (>=3.2.0)"]
|
||||||
|
riak = ["riak (>=2.0)"]
|
||||||
|
s3 = ["boto3 (>=1.9.125)"]
|
||||||
|
slmq = ["softlayer-messaging (>=1.0.3)"]
|
||||||
|
solar = ["ephem"]
|
||||||
|
sqlalchemy = ["sqlalchemy"]
|
||||||
|
sqs = ["boto3 (>=1.9.125)", "pycurl (7.43.0.5)"]
|
||||||
|
tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"]
|
||||||
|
yaml = ["PyYAML (>=3.10)"]
|
||||||
|
zookeeper = ["kazoo (>=1.3.1)"]
|
||||||
|
zstd = ["zstandard"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Composable command line interface toolkit"
|
||||||
|
name = "click"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "7.1.2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Fake implementation of redis API for testing purposes."
|
||||||
|
name = "fakeredis"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
version = "1.4.1"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
redis = "<3.6.0"
|
||||||
|
six = ">=1.12"
|
||||||
|
sortedcontainers = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
aioredis = ["aioredis"]
|
||||||
|
lua = ["lupa"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "the modular source code checker: pep8 pyflakes and co"
|
||||||
|
name = "flake8"
|
||||||
|
optional = false
|
||||||
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
||||||
|
version = "3.8.3"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
mccabe = ">=0.6.0,<0.7.0"
|
||||||
|
pycodestyle = ">=2.6.0a1,<2.7.0"
|
||||||
|
pyflakes = ">=2.2.0,<2.3.0"
|
||||||
|
|
||||||
|
[package.dependencies.importlib-metadata]
|
||||||
|
python = "<3.8"
|
||||||
|
version = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "A simple framework for building complex web applications."
|
||||||
|
name = "flask"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "1.1.2"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Jinja2 = ">=2.10.1"
|
||||||
|
Werkzeug = ">=0.15"
|
||||||
|
click = ">=5.1"
|
||||||
|
itsdangerous = ">=0.24"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
|
||||||
|
docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"]
|
||||||
|
dotenv = ["python-dotenv"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Simple integration of Flask and WTForms."
|
||||||
|
name = "flask-wtf"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.14.3"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Flask = "*"
|
||||||
|
WTForms = "*"
|
||||||
|
itsdangerous = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Clean single-source support for Python 3 and 2"
|
||||||
|
name = "future"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
|
version = "0.18.2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "WSGI HTTP Server for UNIX"
|
||||||
|
name = "gunicorn"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.4"
|
||||||
|
version = "20.0.4"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
setuptools = ">=3.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
eventlet = ["eventlet (>=0.9.7)"]
|
||||||
|
gevent = ["gevent (>=0.13)"]
|
||||||
|
setproctitle = ["setproctitle"]
|
||||||
|
tornado = ["tornado (>=0.2)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Read metadata from Python packages"
|
||||||
|
marker = "python_version < \"3.8\""
|
||||||
|
name = "importlib-metadata"
|
||||||
|
optional = false
|
||||||
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||||
|
version = "1.7.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
zipp = ">=0.5"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx", "rst.linker"]
|
||||||
|
testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "A Python utility / library to sort Python imports."
|
||||||
|
name = "isort"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6,<4.0"
|
||||||
|
version = "5.0.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
pipfile_deprecated_finder = ["pipreqs", "requirementslib", "tomlkit (>=0.5.3)"]
|
||||||
|
requirements_deprecated_finder = ["pipreqs", "pip-api"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Various helpers to pass data to untrusted environments and back."
|
||||||
|
name = "itsdangerous"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
version = "1.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "A very fast and expressive template engine."
|
||||||
|
name = "jinja2"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "2.11.2"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
MarkupSafe = ">=0.23"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
i18n = ["Babel (>=0.8)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Messaging library for Python."
|
||||||
|
name = "kombu"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "4.6.11"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
amqp = ">=2.6.0,<2.7"
|
||||||
|
|
||||||
|
[package.dependencies.importlib-metadata]
|
||||||
|
python = "<3.8"
|
||||||
|
version = ">=0.18"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
azureservicebus = ["azure-servicebus (>=0.21.1)"]
|
||||||
|
azurestoragequeues = ["azure-storage-queue"]
|
||||||
|
consul = ["python-consul (>=0.6.0)"]
|
||||||
|
librabbitmq = ["librabbitmq (>=1.5.2)"]
|
||||||
|
mongodb = ["pymongo (>=3.3.0)"]
|
||||||
|
msgpack = ["msgpack"]
|
||||||
|
pyro = ["pyro4"]
|
||||||
|
qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"]
|
||||||
|
redis = ["redis (>=3.3.11)"]
|
||||||
|
slmq = ["softlayer-messaging (>=1.0.3)"]
|
||||||
|
sqlalchemy = ["sqlalchemy"]
|
||||||
|
sqs = ["boto3 (>=1.4.4)", "pycurl (7.43.0.2)"]
|
||||||
|
yaml = ["PyYAML (>=3.10)"]
|
||||||
|
zookeeper = ["kazoo (>=1.3.1)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Safely add untrusted strings to HTML/XML markup."
|
||||||
|
name = "markupsafe"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
|
||||||
|
version = "1.1.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "McCabe checker, plugin for flake8"
|
||||||
|
name = "mccabe"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.6.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Utility library for gitignore style pattern matching of file paths."
|
||||||
|
name = "pathspec"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "0.8.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Python style guide checker"
|
||||||
|
name = "pycodestyle"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
version = "2.6.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "passive checker of Python programs"
|
||||||
|
name = "pyflakes"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
version = "2.2.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "World timezone definitions, modern and historical"
|
||||||
|
name = "pytz"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2020.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Python client for Redis key-value store"
|
||||||
|
name = "redis"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "3.5.3"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
hiredis = ["hiredis (>=0.1.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Alternative regular expression module, to replace re."
|
||||||
|
name = "regex"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2020.6.8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
|
||||||
|
name = "ruamel.yaml"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.16.10"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
[package.dependencies."ruamel.yaml.clib"]
|
||||||
|
python = "<3.9"
|
||||||
|
version = ">=0.1.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["ryd"]
|
||||||
|
jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
|
||||||
|
marker = "platform_python_implementation == \"CPython\" and python_version < \"3.9\""
|
||||||
|
name = "ruamel.yaml.clib"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.2.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Python 2 and 3 compatibility utilities"
|
||||||
|
name = "six"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
|
version = "1.15.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set"
|
||||||
|
name = "sortedcontainers"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2.2.2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||||
|
name = "toml"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "0.10.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "dev"
|
||||||
|
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
||||||
|
name = "typed-ast"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "1.4.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Promises, promises, promises."
|
||||||
|
name = "vine"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
version = "1.3.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "The comprehensive WSGI web application library."
|
||||||
|
name = "werkzeug"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
version = "1.0.1"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"]
|
||||||
|
watchdog = ["watchdog"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "A flexible forms validation and rendering library for Python web development."
|
||||||
|
name = "wtforms"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
version = "2.3.1"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
MarkupSafe = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
email = ["email-validator"]
|
||||||
|
ipaddress = ["ipaddress"]
|
||||||
|
locale = ["Babel (>=1.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
category = "main"
|
||||||
|
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||||
|
marker = "python_version < \"3.8\""
|
||||||
|
name = "zipp"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
version = "3.1.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
||||||
|
testing = ["jaraco.itertools", "func-timeout"]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
content-hash = "5b4178ff61e370e7f1ea8005c263dad7a00915c8494536db6cddbc8642df9ee3"
|
||||||
|
python-versions = "^3.6"
|
||||||
|
|
||||||
|
[metadata.files]
|
||||||
|
amqp = [
|
||||||
|
{file = "amqp-2.6.0-py2.py3-none-any.whl", hash = "sha256:bb68f8d2bced8f93ccfd07d96c689b716b3227720add971be980accfc2952139"},
|
||||||
|
{file = "amqp-2.6.0.tar.gz", hash = "sha256:24dbaff8ce4f30566bb88976b398e8c4e77637171af3af6f1b9650f48890e60b"},
|
||||||
|
]
|
||||||
|
appdirs = [
|
||||||
|
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
||||||
|
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
||||||
|
]
|
||||||
|
attrs = [
|
||||||
|
{file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
|
||||||
|
{file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
|
||||||
|
]
|
||||||
|
billiard = [
|
||||||
|
{file = "billiard-3.6.3.0-py3-none-any.whl", hash = "sha256:bff575450859a6e0fbc2f9877d9b715b0bbc07c3565bb7ed2280526a0cdf5ede"},
|
||||||
|
{file = "billiard-3.6.3.0.tar.gz", hash = "sha256:d91725ce6425f33a97dfa72fb6bfef0e47d4652acd98a032bd1a7fbf06d5fa6a"},
|
||||||
|
]
|
||||||
|
black = [
|
||||||
|
{file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"},
|
||||||
|
{file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"},
|
||||||
|
]
|
||||||
|
celery = [
|
||||||
|
{file = "celery-4.4.6-py2.py3-none-any.whl", hash = "sha256:ef17d7dffde7fc73ecab3a3b6389d93d3213bac53fa7f28e68e33647ad50b916"},
|
||||||
|
{file = "celery-4.4.6.tar.gz", hash = "sha256:fd77e4248bb1b7af5f7922dd8e81156f540306e3a5c4b1c24167c1f5f06025da"},
|
||||||
|
]
|
||||||
|
click = [
|
||||||
|
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
|
||||||
|
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
|
||||||
|
]
|
||||||
|
fakeredis = [
|
||||||
|
{file = "fakeredis-1.4.1-py3-none-any.whl", hash = "sha256:647b2593d349d9d4e566c8dadb2e4c71ba35be5bdc4f1f7ac2d565a12a965053"},
|
||||||
|
{file = "fakeredis-1.4.1.tar.gz", hash = "sha256:4d170886865a91dbc8b7f8cbd4e5d488f4c5f2f25dfae127f001617bbe9e8f97"},
|
||||||
|
]
|
||||||
|
flake8 = [
|
||||||
|
{file = "flake8-3.8.3-py2.py3-none-any.whl", hash = "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c"},
|
||||||
|
{file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"},
|
||||||
|
]
|
||||||
|
flask = [
|
||||||
|
{file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"},
|
||||||
|
{file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"},
|
||||||
|
]
|
||||||
|
flask-wtf = [
|
||||||
|
{file = "Flask-WTF-0.14.3.tar.gz", hash = "sha256:d417e3a0008b5ba583da1763e4db0f55a1269d9dd91dcc3eb3c026d3c5dbd720"},
|
||||||
|
{file = "Flask_WTF-0.14.3-py2.py3-none-any.whl", hash = "sha256:57b3faf6fe5d6168bda0c36b0df1d05770f8e205e18332d0376ddb954d17aef2"},
|
||||||
|
]
|
||||||
|
future = [
|
||||||
|
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
|
||||||
|
]
|
||||||
|
gunicorn = [
|
||||||
|
{file = "gunicorn-20.0.4-py2.py3-none-any.whl", hash = "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c"},
|
||||||
|
{file = "gunicorn-20.0.4.tar.gz", hash = "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626"},
|
||||||
|
]
|
||||||
|
importlib-metadata = [
|
||||||
|
{file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"},
|
||||||
|
{file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"},
|
||||||
|
]
|
||||||
|
isort = [
|
||||||
|
{file = "isort-5.0.2-py3-none-any.whl", hash = "sha256:52530356f89f009c3e8e0bb36d3e0dc6ddb0a59926cb918d488e35582ecbfe36"},
|
||||||
|
{file = "isort-5.0.2.tar.gz", hash = "sha256:ba8e494fc13974ec02a623c4aaead306bb86a3102a1df8d399748445f32a78f2"},
|
||||||
|
]
|
||||||
|
itsdangerous = [
|
||||||
|
{file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"},
|
||||||
|
{file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"},
|
||||||
|
]
|
||||||
|
jinja2 = [
|
||||||
|
{file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"},
|
||||||
|
{file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"},
|
||||||
|
]
|
||||||
|
kombu = [
|
||||||
|
{file = "kombu-4.6.11-py2.py3-none-any.whl", hash = "sha256:be48cdffb54a2194d93ad6533d73f69408486483d189fe9f5990ee24255b0e0a"},
|
||||||
|
{file = "kombu-4.6.11.tar.gz", hash = "sha256:ca1b45faac8c0b18493d02a8571792f3c40291cf2bcf1f55afed3d8f3aa7ba74"},
|
||||||
|
]
|
||||||
|
markupsafe = [
|
||||||
|
{file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"},
|
||||||
|
{file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"},
|
||||||
|
{file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"},
|
||||||
|
]
|
||||||
|
mccabe = [
|
||||||
|
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
|
||||||
|
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
|
||||||
|
]
|
||||||
|
pathspec = [
|
||||||
|
{file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"},
|
||||||
|
{file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"},
|
||||||
|
]
|
||||||
|
pycodestyle = [
|
||||||
|
{file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"},
|
||||||
|
{file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"},
|
||||||
|
]
|
||||||
|
pyflakes = [
|
||||||
|
{file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"},
|
||||||
|
{file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"},
|
||||||
|
]
|
||||||
|
pytz = [
|
||||||
|
{file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"},
|
||||||
|
{file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"},
|
||||||
|
]
|
||||||
|
redis = [
|
||||||
|
{file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"},
|
||||||
|
{file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"},
|
||||||
|
]
|
||||||
|
regex = [
|
||||||
|
{file = "regex-2020.6.8-cp27-cp27m-win32.whl", hash = "sha256:fbff901c54c22425a5b809b914a3bfaf4b9570eee0e5ce8186ac71eb2025191c"},
|
||||||
|
{file = "regex-2020.6.8-cp27-cp27m-win_amd64.whl", hash = "sha256:112e34adf95e45158c597feea65d06a8124898bdeac975c9087fe71b572bd938"},
|
||||||
|
{file = "regex-2020.6.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:92d8a043a4241a710c1cf7593f5577fbb832cf6c3a00ff3fc1ff2052aff5dd89"},
|
||||||
|
{file = "regex-2020.6.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bae83f2a56ab30d5353b47f9b2a33e4aac4de9401fb582b55c42b132a8ac3868"},
|
||||||
|
{file = "regex-2020.6.8-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b2ba0f78b3ef375114856cbdaa30559914d081c416b431f2437f83ce4f8b7f2f"},
|
||||||
|
{file = "regex-2020.6.8-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:95fa7726d073c87141f7bbfb04c284901f8328e2d430eeb71b8ffdd5742a5ded"},
|
||||||
|
{file = "regex-2020.6.8-cp36-cp36m-win32.whl", hash = "sha256:e3cdc9423808f7e1bb9c2e0bdb1c9dc37b0607b30d646ff6faf0d4e41ee8fee3"},
|
||||||
|
{file = "regex-2020.6.8-cp36-cp36m-win_amd64.whl", hash = "sha256:c78e66a922de1c95a208e4ec02e2e5cf0bb83a36ceececc10a72841e53fbf2bd"},
|
||||||
|
{file = "regex-2020.6.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:08997a37b221a3e27d68ffb601e45abfb0093d39ee770e4257bd2f5115e8cb0a"},
|
||||||
|
{file = "regex-2020.6.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2f6f211633ee8d3f7706953e9d3edc7ce63a1d6aad0be5dcee1ece127eea13ae"},
|
||||||
|
{file = "regex-2020.6.8-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:55b4c25cbb3b29f8d5e63aeed27b49fa0f8476b0d4e1b3171d85db891938cc3a"},
|
||||||
|
{file = "regex-2020.6.8-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:89cda1a5d3e33ec9e231ece7307afc101b5217523d55ef4dc7fb2abd6de71ba3"},
|
||||||
|
{file = "regex-2020.6.8-cp37-cp37m-win32.whl", hash = "sha256:690f858d9a94d903cf5cada62ce069b5d93b313d7d05456dbcd99420856562d9"},
|
||||||
|
{file = "regex-2020.6.8-cp37-cp37m-win_amd64.whl", hash = "sha256:1700419d8a18c26ff396b3b06ace315b5f2a6e780dad387e4c48717a12a22c29"},
|
||||||
|
{file = "regex-2020.6.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:654cb773b2792e50151f0e22be0f2b6e1c3a04c5328ff1d9d59c0398d37ef610"},
|
||||||
|
{file = "regex-2020.6.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:52e1b4bef02f4040b2fd547357a170fc1146e60ab310cdbdd098db86e929b387"},
|
||||||
|
{file = "regex-2020.6.8-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:cf59bbf282b627130f5ba68b7fa3abdb96372b24b66bdf72a4920e8153fc7910"},
|
||||||
|
{file = "regex-2020.6.8-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5aaa5928b039ae440d775acea11d01e42ff26e1561c0ffcd3d805750973c6baf"},
|
||||||
|
{file = "regex-2020.6.8-cp38-cp38-win32.whl", hash = "sha256:97712e0d0af05febd8ab63d2ef0ab2d0cd9deddf4476f7aa153f76feef4b2754"},
|
||||||
|
{file = "regex-2020.6.8-cp38-cp38-win_amd64.whl", hash = "sha256:6ad8663c17db4c5ef438141f99e291c4d4edfeaacc0ce28b5bba2b0bf273d9b5"},
|
||||||
|
{file = "regex-2020.6.8.tar.gz", hash = "sha256:e9b64e609d37438f7d6e68c2546d2cb8062f3adb27e6336bc129b51be20773ac"},
|
||||||
|
]
|
||||||
|
"ruamel.yaml" = [
|
||||||
|
{file = "ruamel.yaml-0.16.10-py2.py3-none-any.whl", hash = "sha256:0962fd7999e064c4865f96fb1e23079075f4a2a14849bcdc5cdba53a24f9759b"},
|
||||||
|
{file = "ruamel.yaml-0.16.10.tar.gz", hash = "sha256:099c644a778bf72ffa00524f78dd0b6476bca94a1da344130f4bf3381ce5b954"},
|
||||||
|
]
|
||||||
|
"ruamel.yaml.clib" = [
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9c6d040d0396c28d3eaaa6cb20152cb3b2f15adf35a0304f4f40a3cf9f1d2448"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d55386129291b96483edcb93b381470f7cd69f97585829b048a3d758d31210a"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp27-cp27m-win32.whl", hash = "sha256:8073c8b92b06b572e4057b583c3d01674ceaf32167801fe545a087d7a1e8bf52"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp27-cp27m-win_amd64.whl", hash = "sha256:615b0396a7fad02d1f9a0dcf9f01202bf9caefee6265198f252c865f4227fcc6"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:a0ff786d2a7dbe55f9544b3f6ebbcc495d7e730df92a08434604f6f470b899c5"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:ea4362548ee0cbc266949d8a441238d9ad3600ca9910c3fe4e82ee3a50706973"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:77556a7aa190be9a2bd83b7ee075d3df5f3c5016d395613671487e79b082d784"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp35-cp35m-win32.whl", hash = "sha256:392b7c371312abf27fb549ec2d5e0092f7ef6e6c9f767bfb13e83cb903aca0fd"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp35-cp35m-win_amd64.whl", hash = "sha256:ed5b3698a2bb241b7f5cbbe277eaa7fe48b07a58784fba4f75224fd066d253ad"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7aee724e1ff424757b5bd8f6c5bbdb033a570b2b4683b17ace4dbe61a99a657b"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d0d3ac228c9bbab08134b4004d748cf9f8743504875b3603b3afbb97e3472947"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp36-cp36m-win32.whl", hash = "sha256:f9dcc1ae73f36e8059589b601e8e4776b9976effd76c21ad6a855a74318efd6e"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1e77424825caba5553bbade750cec2277ef130647d685c2b38f68bc03453bac6"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d10e9dd744cf85c219bf747c75194b624cc7a94f0c80ead624b06bfa9f61d3bc"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:550168c02d8de52ee58c3d8a8193d5a8a9491a5e7b2462d27ac5bf63717574c9"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp37-cp37m-win32.whl", hash = "sha256:57933a6986a3036257ad7bf283529e7c19c2810ff24c86f4a0cfeb49d2099919"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b1b7fcee6aedcdc7e62c3a73f238b3d080c7ba6650cd808bce8d7761ec484070"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:be018933c2f4ee7de55e7bd7d0d801b3dfb09d21dad0cce8a97995fd3e44be30"},
|
||||||
|
{file = "ruamel.yaml.clib-0.2.0.tar.gz", hash = "sha256:b66832ea8077d9b3f6e311c4a53d06273db5dc2db6e8a908550f3c14d67e718c"},
|
||||||
|
]
|
||||||
|
six = [
|
||||||
|
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
|
||||||
|
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
|
||||||
|
]
|
||||||
|
sortedcontainers = [
|
||||||
|
{file = "sortedcontainers-2.2.2-py2.py3-none-any.whl", hash = "sha256:c633ebde8580f241f274c1f8994a665c0e54a17724fecd0cae2f079e09c36d3f"},
|
||||||
|
{file = "sortedcontainers-2.2.2.tar.gz", hash = "sha256:4e73a757831fc3ca4de2859c422564239a31d8213d09a2a666e375807034d2ba"},
|
||||||
|
]
|
||||||
|
toml = [
|
||||||
|
{file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"},
|
||||||
|
{file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"},
|
||||||
|
]
|
||||||
|
typed-ast = [
|
||||||
|
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
|
||||||
|
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"},
|
||||||
|
{file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"},
|
||||||
|
{file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"},
|
||||||
|
{file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"},
|
||||||
|
{file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"},
|
||||||
|
{file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"},
|
||||||
|
{file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"},
|
||||||
|
{file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"},
|
||||||
|
{file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"},
|
||||||
|
{file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"},
|
||||||
|
{file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"},
|
||||||
|
{file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"},
|
||||||
|
{file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"},
|
||||||
|
{file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"},
|
||||||
|
{file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"},
|
||||||
|
{file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"},
|
||||||
|
{file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"},
|
||||||
|
{file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"},
|
||||||
|
{file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"},
|
||||||
|
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
|
||||||
|
]
|
||||||
|
vine = [
|
||||||
|
{file = "vine-1.3.0-py2.py3-none-any.whl", hash = "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"},
|
||||||
|
{file = "vine-1.3.0.tar.gz", hash = "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87"},
|
||||||
|
]
|
||||||
|
werkzeug = [
|
||||||
|
{file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"},
|
||||||
|
{file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"},
|
||||||
|
]
|
||||||
|
wtforms = [
|
||||||
|
{file = "WTForms-2.3.1-py2.py3-none-any.whl", hash = "sha256:6ff8635f4caeed9f38641d48cfe019d0d3896f41910ab04494143fc027866e1b"},
|
||||||
|
{file = "WTForms-2.3.1.tar.gz", hash = "sha256:861a13b3ae521d6700dac3b2771970bd354a63ba7043ecc3a82b5288596a1972"},
|
||||||
|
]
|
||||||
|
zipp = [
|
||||||
|
{file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"},
|
||||||
|
{file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"},
|
||||||
|
]
|
38
pyproject.toml
Normal file
38
pyproject.toml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "magic-app"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "A swarm of dreams"
|
||||||
|
authors = ["Autonomic Co-operative <helo@autonomic.zone>"]
|
||||||
|
maintainers = ["Autonomic Co-operative <helo@autonomic.zone>"]
|
||||||
|
license = "AGPLv3"
|
||||||
|
readme = "README.md"
|
||||||
|
homepage = "https://git.autonomic.zone/autonomic-cooperative/magic-app"
|
||||||
|
repository = "https://git.autonomic.zone/autonomic-cooperative/magic-app"
|
||||||
|
documentation = "https://git.autonomic.zone/autonomic-cooperative/magic-app"
|
||||||
|
keywords = ["docker", "swarm", "packaging"]
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
"ruamel.yaml" = "^0.16.10"
|
||||||
|
celery = "^4.4.6"
|
||||||
|
flask = "^1.1.2"
|
||||||
|
flask-wtf = "^0.14.3"
|
||||||
|
python = "^3.6"
|
||||||
|
redis = "^3.5.3"
|
||||||
|
|
||||||
|
[tool.poetry.dev-dependencies]
|
||||||
|
black = "^19.10b0"
|
||||||
|
fakeredis = "^1.4.1"
|
||||||
|
flake8 = "^3.8.3"
|
||||||
|
isort = "^5.0.2"
|
||||||
|
|
||||||
|
[tool.poetry.urls]
|
||||||
|
issues = "https://git.autonomic.zone/autonomic-cooperative/magic-app/issues"
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
line-length = 80
|
||||||
|
target-version = ["py38"]
|
||||||
|
include = '\.pyi?$'
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry>=1.0.9,<2.0"]
|
||||||
|
build-backend = "poetry.masonry.api"
|
13
setup.cfg
Normal file
13
setup.cfg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[tool:pytest]
|
||||||
|
testpaths = test
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
max-line-length = 80
|
||||||
|
|
||||||
|
[isort]
|
||||||
|
include_trailing_comma = True
|
||||||
|
known_first_party = magic_app
|
||||||
|
known_third_party = pytest
|
||||||
|
line_length = 80
|
||||||
|
multi_line_output = 3
|
||||||
|
skip = .venv, .tox
|
27
spikes/README.md
Normal file
27
spikes/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Run It
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ python3 -m venv .venv
|
||||||
|
$ source .venv/bin/activate
|
||||||
|
$ pip install -r requirements.txt
|
||||||
|
$ python first.py / second.py / third.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## first.py
|
||||||
|
|
||||||
|
- List apps from an `app.json` (points to https://git.autonomic.zone/compose-stacks)
|
||||||
|
- Clone selected app template and parse configuration for inputs (env vars and secrets)
|
||||||
|
- Generate a form so those values can be filled out and allow it to be saved
|
||||||
|
- Save the form inputs to a `db.json` (as a start)
|
||||||
|
- Deploy an applicaiton to a local swarm (assumes access to local docker socket)
|
||||||
|
- Create an "edit app" page where the `db.json` is re-called and can be updated
|
||||||
|
- Make sure re-deploy works (taking care of updating secret and app versions)
|
||||||
|
|
||||||
|
## second.py
|
||||||
|
|
||||||
|
- Don't try to be smart with the auto-generation, hard-code everything. We
|
||||||
|
maintain the app template (`compose.yml`) and this code anyway, so we just
|
||||||
|
need to be aware of each other and keep in sync. This would optimise for
|
||||||
|
trust and collaboration and not "smart" code.
|
||||||
|
- Hard-code the secrets/configs required to make the code for generating
|
||||||
|
versions simpler as well.
|
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
54
tox.ini
Normal file
54
tox.ini
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
[tox]
|
||||||
|
envlist =
|
||||||
|
{py36,py37,py38}
|
||||||
|
lint
|
||||||
|
sort
|
||||||
|
format
|
||||||
|
type
|
||||||
|
skip_missing_interpreters = True
|
||||||
|
isolated_build = True
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
description = run the unit tests
|
||||||
|
deps =
|
||||||
|
pytest
|
||||||
|
pytest-cov
|
||||||
|
pytest-mock
|
||||||
|
commands = pytest test/ --cov={toxinidir}/magic_app/ --no-cov-on-fail {posargs}
|
||||||
|
|
||||||
|
[testenv:lint]
|
||||||
|
description = lint the source
|
||||||
|
skipdist = True
|
||||||
|
deps = flake8
|
||||||
|
commands = flake8 {posargs} magic_app/ test/
|
||||||
|
|
||||||
|
[testenv:sort]
|
||||||
|
description = sort the source
|
||||||
|
skipdist = True
|
||||||
|
deps = isort
|
||||||
|
commands = isort {posargs:-rc -c} -sp setup.cfg magic_app/ test/
|
||||||
|
|
||||||
|
[testenv:format]
|
||||||
|
description = format the source
|
||||||
|
skipdist = True
|
||||||
|
basepython = python3.8
|
||||||
|
deps = black
|
||||||
|
commands = black {posargs:--check} magic_app/ test/
|
||||||
|
|
||||||
|
[testenv:type]
|
||||||
|
description = type check the source
|
||||||
|
basepython = python3.8
|
||||||
|
skipdist = True
|
||||||
|
deps = mypy
|
||||||
|
commands = mypy magic_app/ test/
|
||||||
|
|
||||||
|
[testenv:release]
|
||||||
|
description = make a release
|
||||||
|
deps = {[testenv:metadata-release]deps}
|
||||||
|
commands =
|
||||||
|
rm -rf {toxworkdir}/dist
|
||||||
|
python -m setup sdist --dist-dir {toxworkdir}/dist bdist_wheel
|
||||||
|
python -m setup sdist --dist-dir {toxworkdir}/dist bdist_egg
|
||||||
|
twine upload {toxworkdir}/dist/*
|
||||||
|
whitelist_externals =
|
||||||
|
rm
|
Reference in New Issue
Block a user