diff options
| author | Gertjan van den Burg <gertjanvandenburg@gmail.com> | 2019-03-18 14:10:12 +0000 |
|---|---|---|
| committer | Gertjan van den Burg <gertjanvandenburg@gmail.com> | 2019-03-18 14:10:12 +0000 |
| commit | 2158c8e86ff4417973dd7ca650fab91e32c4e56a (patch) | |
| tree | e26d9e43f712e6f140dc744287431e6e46c9b143 | |
| download | AnnotateChange-2158c8e86ff4417973dd7ca650fab91e32c4e56a.tar.gz AnnotateChange-2158c8e86ff4417973dd7ca650fab91e32c4e56a.zip | |
initial commit
| -rw-r--r-- | README.rst | 0 | ||||
| -rw-r--r-- | annotate_change_v2.py | 1 | ||||
| -rw-r--r-- | app/__init__.py | 13 | ||||
| -rw-r--r-- | app/config.py | 11 | ||||
| -rw-r--r-- | app/forms.py | 12 | ||||
| -rw-r--r-- | app/models.py | 59 | ||||
| -rw-r--r-- | app/routes.py | 24 | ||||
| -rw-r--r-- | app/templates/base.html | 27 | ||||
| -rw-r--r-- | app/templates/index.html | 5 | ||||
| -rw-r--r-- | app/templates/login.html | 24 | ||||
| -rwxr-xr-x | flask.sh | 10 | ||||
| -rw-r--r-- | migrations/README | 1 | ||||
| -rw-r--r-- | migrations/alembic.ini | 45 | ||||
| -rw-r--r-- | migrations/env.py | 95 | ||||
| -rw-r--r-- | migrations/script.py.mako | 24 | ||||
| -rw-r--r-- | poetry.lock | 257 | ||||
| -rw-r--r-- | pyproject.toml | 19 |
17 files changed, 627 insertions, 0 deletions
diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/README.rst diff --git a/annotate_change_v2.py b/annotate_change_v2.py new file mode 100644 index 0000000..d099b92 --- /dev/null +++ b/annotate_change_v2.py @@ -0,0 +1 @@ +from app import app diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..996b683 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,13 @@ +__version__ = "0.1.0" + +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate +from .config import Config + +app = Flask(__name__) +app.config.from_object(Config) +db = SQLAlchemy(app) +migrate = Migrate(app, db) + +from app import routes, models diff --git a/app/config.py b/app/config.py new file mode 100644 index 0000000..c33cf25 --- /dev/null +++ b/app/config.py @@ -0,0 +1,11 @@ +import os + +# TODO: change these things to an instance path +basedir = os.path.abspath(os.path.dirname(__file__)) + +class Config(object): + SECRET_KEY = os.environ.get("SECRET_KEY") or "you-will-never-guess" + + SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL") or "sqlite:///" + os.path.join(basedir, "app.db") + SQLALCHEMY_TRACK_MODIFICATIONS = False + diff --git a/app/forms.py b/app/forms.py new file mode 100644 index 0000000..919db70 --- /dev/null +++ b/app/forms.py @@ -0,0 +1,12 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField, BooleanField, SubmitField +from wtforms.validators import DataRequired + +class LoginForm(FlaskForm): + username = StringField("Username", validators=[DataRequired()]) + password = PasswordField("Password", validators=[DataRequired()]) + remember_me = BooleanField("Remember Me") + submit = SubmitField("Sign In") + + + diff --git a/app/models.py b/app/models.py new file mode 100644 index 0000000..9d11ffb --- /dev/null +++ b/app/models.py @@ -0,0 +1,59 @@ + +import datetime + + +from app import db + + +class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(80), unique=True, nullable=False) + email = db.Column(db.String(), unique=True, nullable=False) + password_hash = db.Column(db.String(128), nullable=False) + last_active = db.Column( + db.DateTime(), nullable=False, default=datetime.datetime.utcnow + ) + + def __repr__(self): + return "<User %r>" % self.username + + +class Dataset(db.Model): + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(), unique=True, nullable=False) + created = db.Column( + db.DateTime, nullable=False, default=datetime.datetime.utcnow + ) + md5sum = db.Column(db.String(32), unique=True, nullable=False) + + def __repr__(self): + return "<Dataset %r>" % self.name + + +class Task(db.Model): + id = db.Column(db.Integer, primary_key=True) + annotator_id = db.Column(db.Integer, nullable=False) + dataset_id = db.Column(db.Integer, nullable=False) + done = db.Column(db.Boolean, nullable=False, default=False) + annotated_on = db.Column(db.DateTime, nullable=True) + + user = db.relation("User") + annotator_id = db.Column(db.Integer, db.ForeignKey("user.id")) + + dataset = db.relation("Dataset") + dataset_id = db.Column(db.Integer, db.ForeignKey("dataset.id")) + + def __repr__(self): + return "<Task (%r, %r)>" % (self.annotator_id, self.dataset_id) + + +class Annotation(db.Model): + id = db.Column(db.Integer, primary_key=True) + time_start = db.Column(db.Integer) + time_end = db.Column(db.Integer) + + task = db.relation("Task") + task_id = db.Column(db.Integer, db.ForeignKey("task.id")) + + def __repr__(self): + return "<Annotation %r>" % self.id diff --git a/app/routes.py b/app/routes.py new file mode 100644 index 0000000..2f9d9b8 --- /dev/null +++ b/app/routes.py @@ -0,0 +1,24 @@ + +from flask import render_template, flash, redirect, url_for +from app import app +from app.forms import LoginForm + + +@app.route("/") +@app.route("/index") +def index(): + user = {"username": "Gertjan"} + return render_template("index.html", title="Home", user=user) + + +@app.route("/login", methods=("GET", "POST")) +def login(): + form = LoginForm() + if form.validate_on_submit(): + flash( + "Login requested for user {}, remember_me={}".format( + form.username.data, form.remember_me.data + ) + ) + return redirect(url_for("index")) + return render_template("login.html", title="Sign In", form=form) diff --git a/app/templates/base.html b/app/templates/base.html new file mode 100644 index 0000000..c40482d --- /dev/null +++ b/app/templates/base.html @@ -0,0 +1,27 @@ +<html> + <head> + {% if title %} + <title>{{ title }} - Annotate Change</title> + {% else %} + <title>Welcome to Annotate Change</title> + {% endif %} + </head> + <body> + <div>Annotate Change: + <a href="{{ url_for('index') }}">Home</a> + <a href="{{ url_for('login') }}">Login</a> + </div> + <hr> + {% with messages = get_flashed_messages() %} + {% if messages %} + <ul> + {% for message in messages %} + <li>{{ message}}</li> + {% endfor %} + </ul> + {% endif %} + {% endwith %} + {% block content %} + {% endblock %} + </body> +</html> diff --git a/app/templates/index.html b/app/templates/index.html new file mode 100644 index 0000000..f111cd6 --- /dev/null +++ b/app/templates/index.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} + +{% block content %} +<h1>Hi, {{ user.username }}!</h1> +{% endblock %} diff --git a/app/templates/login.html b/app/templates/login.html new file mode 100644 index 0000000..21e0161 --- /dev/null +++ b/app/templates/login.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} + +{% block content %} + <h1>Sign In</h1> + <form action="" method="post" novalidate> + {{ form.hidden_tag() }} + <p> + {{ form.username.label }}<br> + {{ form.username(size=32) }} + {% for error in form.username.errors %} + <span style="color: red;">[{{ error }}]</span> + {% endfor %} + </p> + <p> + {{ form.password.label }}<br> + {{ form.password(size=32) }} + {% for error in form.username.errors %} + <span style="color: red;">[{{ error }}]</span> + {% endfor %} + </p> + <p>{{ form.remember_me() }} {{ form.remember_me.label }}</p> + <p>{{ form.submit() }}</p> + </form> +{% endblock %} diff --git a/flask.sh b/flask.sh new file mode 100755 index 0000000..1b947db --- /dev/null +++ b/flask.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +export FLASK_APP=annotate_change_v2.py +export FLASK_ENV=development + +echo "FLASK_APP = ${FLASK_APP}" +echo "FLASK_ENV = ${FLASK_ENV}" +echo "Running: flask $*" + +poetry run flask $* diff --git a/migrations/README b/migrations/README new file mode 100644 index 0000000..98e4f9c --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration.
\ No newline at end of file diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 0000000..f8ed480 --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,45 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 0000000..169d487 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,95 @@ +from __future__ import with_statement + +import logging +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +from flask import current_app +config.set_main_option('sqlalchemy.url', + current_app.config.get('SQLALCHEMY_DATABASE_URI')) +target_metadata = current_app.extensions['migrate'].db.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=target_metadata, literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata, + process_revision_directives=process_revision_directives, + **current_app.extensions['migrate'].configure_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 0000000..2c01563 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..d2492e5 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,257 @@ +[[package]] +category = "main" +description = "A database migration tool for SQLAlchemy." +name = "alembic" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.0.8" + +[package.dependencies] +Mako = "*" +SQLAlchemy = ">=0.9.0" +python-dateutil = "*" +python-editor = ">=0.3" + +[[package]] +category = "dev" +description = "Atomic file writes." +name = "atomicwrites" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.3.0" + +[[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.1.0" + +[[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.*" +version = "7.0" + +[[package]] +category = "dev" +description = "Cross-platform colored terminal text." +marker = "sys_platform == \"win32\"" +name = "colorama" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.4.1" + +[[package]] +category = "main" +description = "A simple framework for building complex web applications." +name = "flask" +optional = false +python-versions = "*" +version = "1.0.2" + +[package.dependencies] +Jinja2 = ">=2.10" +Werkzeug = ">=0.14" +click = ">=5.1" +itsdangerous = ">=0.24" + +[[package]] +category = "main" +description = "SQLAlchemy database migrations for Flask applications using Alembic" +name = "flask-migrate" +optional = false +python-versions = "*" +version = "2.4.0" + +[package.dependencies] +Flask = ">=0.9" +Flask-SQLAlchemy = ">=1.0" +alembic = ">=0.7" + +[[package]] +category = "main" +description = "Adds SQLAlchemy support to your Flask application" +name = "flask-sqlalchemy" +optional = false +python-versions = "*" +version = "2.3.2" + +[package.dependencies] +Flask = ">=0.10" +SQLAlchemy = ">=0.8.0" + +[[package]] +category = "main" +description = "Simple integration of Flask and WTForms." +name = "flask-wtf" +optional = false +python-versions = "*" +version = "0.14.2" + +[package.dependencies] +Flask = "*" +WTForms = "*" + +[[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 small but fast and easy to use stand-alone template engine written in pure python." +name = "jinja2" +optional = false +python-versions = "*" +version = "2.10" + +[package.dependencies] +MarkupSafe = ">=0.23" + +[[package]] +category = "main" +description = "A super-fast templating language that borrows the best ideas from the existing templating languages." +name = "mako" +optional = false +python-versions = "*" +version = "1.0.7" + +[package.dependencies] +MarkupSafe = ">=0.9.2" + +[[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 = "More routines for operating on iterables, beyond itertools" +name = "more-itertools" +optional = false +python-versions = ">=3.4" +version = "6.0.0" + +[[package]] +category = "dev" +description = "plugin and hook calling mechanisms for python" +name = "pluggy" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "0.9.0" + +[[package]] +category = "dev" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +name = "py" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.8.0" + +[[package]] +category = "dev" +description = "pytest: simple powerful testing with Python" +name = "pytest" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "3.10.1" + +[package.dependencies] +atomicwrites = ">=1.0" +attrs = ">=17.4.0" +colorama = "*" +more-itertools = ">=4.0.0" +pluggy = ">=0.7" +py = ">=1.5.0" +setuptools = "*" +six = ">=1.10.0" + +[[package]] +category = "main" +description = "Extensions to the standard Python datetime module" +name = "python-dateutil" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +version = "2.8.0" + +[package.dependencies] +six = ">=1.5" + +[[package]] +category = "main" +description = "Programmatically open an editor, capture the result." +name = "python-editor" +optional = false +python-versions = "*" +version = "1.0.4" + +[[package]] +category = "main" +description = "Python 2 and 3 compatibility utilities" +name = "six" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" +version = "1.12.0" + +[[package]] +category = "main" +description = "Database Abstraction Library" +name = "sqlalchemy" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.3.1" + +[[package]] +category = "main" +description = "The comprehensive WSGI web application library." +name = "werkzeug" +optional = false +python-versions = "*" +version = "0.14.1" + +[[package]] +category = "main" +description = "A flexible forms validation and rendering library for Python web development." +name = "wtforms" +optional = false +python-versions = "*" +version = "2.2.1" + +[metadata] +content-hash = "71d5d24e1ceaef122c936d2bf4afdf2eeecd408f93268332605e045c7a054472" +python-versions = "^3.7" + +[metadata.hashes] +alembic = ["505d41e01dc0c9e6d85c116d0d35dbb0a833dcb490bf483b75abeb06648864e8"] +atomicwrites = ["03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", "75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"] +attrs = ["69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", "f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"] +click = ["2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"] +colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"] +flask = ["2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", "a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"] +flask-migrate = ["a361578cb829681f860e4de5ed2c48886264512f0c16144e404c36ddc95ab49c", "c24d105c5d6cc670de20f8cbfb909e04f4e04b8784d0df070005944de1f21549"] +flask-sqlalchemy = ["3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b", "5971b9852b5888655f11db634e87725a9031e170f37c0ce7851cf83497f56e53"] +flask-wtf = ["5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36", "d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac"] +itsdangerous = ["321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", "b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"] +jinja2 = ["74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", "f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"] +mako = ["4e02fde57bd4abb5ec400181e4c314f56ac3e49ba4fb8b0d50bba18cb27d25ae"] +markupsafe = ["00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", "09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", "62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", "88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", "98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", "ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", "b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", "ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"] +more-itertools = ["0125e8f60e9e031347105eb1682cef932f5e97d7b9a1a28d9bf00c22a5daef40", "590044e3942351a1bdb1de960b739ff4ce277960f2425ad4509446dbace8d9d1"] +pluggy = ["19ecf9ce9db2fce065a7a0586e07cfb4ac8614fe96edf628a264b1c70116cf8f", "84d306a647cc805219916e62aab89caa97a33a1dd8c342e87a37f91073cd4746"] +py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"] +pytest = ["3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec", "e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"] +python-dateutil = ["7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", "c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"] +python-editor = ["1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d", "51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b", "5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8", "c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77", "ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522"] +six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] +sqlalchemy = ["781fb7b9d194ed3fc596b8f0dd4623ff160e3e825dd8c15472376a438c19598b"] +werkzeug = ["c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", "d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"] +wtforms = ["0cdbac3e7f6878086c334aa25dc5a33869a3954e9d1e015130d65a69309b3b61", "e3ee092c827582c50877cdbd49e9ce6d2c5c1f6561f849b3b068c1b8029626f1"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3154708 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "annotate_change_v2" +version = "0.1.0" +description = "" +authors = ["Gertjan van den Burg <gertjanvandenburg@gmail.com>"] + +[tool.poetry.dependencies] +python = "^3.7" +flask = "^1.0" +flask-wtf = "^0.14.2" +flask-sqlalchemy = "^2.3" +flask-migrate = "^2.4" + +[tool.poetry.dev-dependencies] +pytest = "^3.0" + +[build-system] +requires = ["poetry>=0.12"] +build-backend = "poetry.masonry.api" |
