diff --git a/README.md b/README.md index b289679..26f85e5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) + # Requirements You need to have Python 3 and Poetry installed. To install Poetry, follow the instructions [here](https://python-poetry.org/docs/#installation). diff --git a/advlabdb/__init__.py b/advlabdb/__init__.py index 2a96bc6..71b7352 100644 --- a/advlabdb/__init__.py +++ b/advlabdb/__init__.py @@ -1,16 +1,16 @@ from flask import Flask -from flask_sqlalchemy import SQLAlchemy +from flask_admin import Admin from flask_security import Security, SQLAlchemyUserDatastore from flask_security.models import fsqla_v2 as fsqla -from flask_admin import Admin +from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) -app.debug = True # DEBUG +app.debug = True # DEBUG -app.config["SERVER_NAME"] = "127.0.0.1:5000" # DEBUG +app.config["SERVER_NAME"] = "127.0.0.1:5000" # DEBUG app.config["SECRET_KEY"] = "dev" -app.config["SECURITY_PASSWORD_SALT"] = "devSalt" # os.environ.get("SECURITY_PASSWORD_SALT", "") +app.config["SECURITY_PASSWORD_SALT"] = "devSalt" # os.environ.get("SECURITY_PASSWORD_SALT", "") app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///../advLab.db" db = SQLAlchemy(app) @@ -18,10 +18,13 @@ db = SQLAlchemy(app) fsqla.FsModels.set_db_info(db) from advlabdb import customClasses -admin = Admin(app, - name="Admin@AdvLabDB", - template_mode="bootstrap3", - index_view=customClasses.SecureAdminIndexView(template="admin_index.html")) + +admin = Admin( + app, + name="Admin@AdvLabDB", + template_mode="bootstrap3", + index_view=customClasses.SecureAdminIndexView(template="admin_index.html"), +) from advlabdb import models @@ -29,5 +32,4 @@ from advlabdb import models user_datastore = SQLAlchemyUserDatastore(db, models.User, models.Role) Security(app, user_datastore) -from advlabdb import routes -from advlabdb import modelViews +from advlabdb import modelViews, routes diff --git a/advlabdb/configUtils.py b/advlabdb/configUtils.py index 85f0ac5..27db8dc 100644 --- a/advlabdb/configUtils.py +++ b/advlabdb/configUtils.py @@ -1,8 +1,9 @@ import json + def getConfig(label): with open("config.json", "r") as f: - return json.load(f)[label] # TODO error handling + return json.load(f)[label] # TODO error handling def setConfig(label, value, new=False): diff --git a/advlabdb/customClasses.py b/advlabdb/customClasses.py index b11f3e3..d30f235 100644 --- a/advlabdb/customClasses.py +++ b/advlabdb/customClasses.py @@ -1,6 +1,6 @@ from flask_admin import AdminIndexView -from flask_security import current_user from flask_admin.contrib.sqla import ModelView +from flask_security import current_user def adminViewIsAccessible(): diff --git a/advlabdb/modelViews.py b/advlabdb/modelViews.py index 7fd4735..37f4511 100644 --- a/advlabdb/modelViews.py +++ b/advlabdb/modelViews.py @@ -1,15 +1,35 @@ -from flask import url_for, flash, request -from flask_admin.menu import MenuLink +from flask import flash, request, url_for from flask_admin.contrib.sqla.filters import BaseSQLAFilter +from flask_admin.menu import MenuLink from flask_security import hash_password from wtforms import BooleanField, SelectField, TextField from wtforms.validators import DataRequired, Email -from advlabdb import admin, app, user_datastore, db -from advlabdb.utils import randomPassword, userActiveSemester, partFromLabelInUserActiveSemester, setActiveSemester -from advlabdb.customClasses import SecureModelView -from advlabdb.models import User, Role, Semester, Part, Student, PartStudent, Group, GroupExperiment, Experiment, Assistant, Appointment, PartExperiment, ExperimentMark +from advlabdb import admin, app, db, user_datastore from advlabdb.configUtils import getConfig +from advlabdb.customClasses import SecureModelView +from advlabdb.models import ( + Appointment, + Assistant, + Experiment, + ExperimentMark, + Group, + GroupExperiment, + Part, + PartExperiment, + PartStudent, + Role, + Semester, + Student, + User, +) +from advlabdb.utils import ( + partFromLabelInUserActiveSemester, + randomPassword, + setActiveSemester, + userActiveSemester, +) + class UserModelView(SecureModelView): column_list = ["email", "active", "roles", "assistant"] @@ -20,7 +40,7 @@ class UserModelView(SecureModelView): form_args = { "email": {"validators": [Email()]}, "active": {"default": True}, - "roles": {"validators": [DataRequired(message="A role is required!")]} + "roles": {"validators": [DataRequired(message="A role is required!")]}, } def create_model(self, form): @@ -35,7 +55,9 @@ class UserModelView(SecureModelView): model = user_datastore.create_user(email=email, password=passwordHash, roles=roles) db.session.commit() - flash(f"{email} registered with roles: {', '.join([role.name for role in form.roles.data])}.", category="success") + flash( + f"{email} registered with roles: {', '.join([role.name for role in form.roles.data])}.", category="success" + ) flash(f"Random password: {password}", category="warning") return model @@ -61,9 +83,13 @@ class SemesterModelView(SecureModelView): model.createParts() if is_created: - admin.add_link(MenuLink(name=model.label, - url=url_for("set_semester") + "?semester_id=" + str(model.id), - category="Active semester")) + admin.add_link( + MenuLink( + name=model.label, + url=url_for("set_semester") + "?semester_id=" + str(model.id), + category="Active semester", + ) + ) setActiveSemester(model.id) @@ -90,15 +116,19 @@ class StudentModelView(SecureModelView): partChoices = ["-"] + getConfig("partsLabels") form_extra_fields = { - "new_part_student_part": SelectField("Part", choices=list(zip(partChoices, partChoices)), default=partChoices[0]), - "new_part_student_group_number": TextField("Group number") + "new_part_student_part": SelectField( + "Part", choices=list(zip(partChoices, partChoices)), default=partChoices[0] + ), + "new_part_student_group_number": TextField("Group number"), } def validate_form(self, form): if request.method == "POST": partLabel = form.new_part_student_part.data groupNumber = form.new_part_student_group_number.data - if (partLabel != self.partChoices[0] and groupNumber == "") or (partLabel == self.partChoices[0] and groupNumber != ""): + if (partLabel != self.partChoices[0] and groupNumber == "") or ( + partLabel == self.partChoices[0] and groupNumber != "" + ): flash("You have to assign both part and group if you want to add a part student!", "danger") return False if partLabel != self.partChoices[0] and not partFromLabelInUserActiveSemester(partLabel): @@ -174,6 +204,10 @@ admin.add_view(RoleModelView(Role, db.session)) with app.app_context(): semesters = Semester.query.all()[::-1] for semester in semesters: - admin.add_link(MenuLink(name=semester.label, - url=url_for("set_semester") + "?semester_id=" + str(semester.id), - category="Active semester")) + admin.add_link( + MenuLink( + name=semester.label, + url=url_for("set_semester") + "?semester_id=" + str(semester.id), + category="Active semester", + ) + ) diff --git a/advlabdb/models.py b/advlabdb/models.py index 8fea6f8..5f5530e 100644 --- a/advlabdb/models.py +++ b/advlabdb/models.py @@ -7,7 +7,7 @@ https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/ """ # Imports -from flask_security.models.fsqla_v2 import FsUserMixin, FsRoleMixin +from flask_security.models.fsqla_v2 import FsRoleMixin, FsUserMixin # Importing the database instance from advlabdb import db @@ -69,7 +69,7 @@ class Experiment(db.Model): building = db.Column(db.String(100), nullable=False) responsibility = db.Column(db.String(200), nullable=True) duration_in_days = db.Column(db.Integer, nullable=False) - deprecated = db.Column(db.Boolean, nullable=False, default=False) # To not be deleted! + deprecated = db.Column(db.Boolean, nullable=False, default=False) # To not be deleted! oral_weighting = db.Column(db.Float, nullable=False) protocol_weighting = db.Column(db.Float, nullable=False) final_weighting = db.Column(db.Float, nullable=False) @@ -80,11 +80,11 @@ class Experiment(db.Model): # Helper table for the many to many relationship between Assistant and PartExperiment -experiment_assistant = db.Table("experiment_assistant", - db.Column("part_experiment_id", db.Integer, db.ForeignKey("part_experiment.id"), - primary_key=True), - db.Column("assistant_id", db.Integer, db.ForeignKey("assistant.id"), - primary_key=True)) +experiment_assistant = db.Table( + "experiment_assistant", + db.Column("part_experiment_id", db.Integer, db.ForeignKey("part_experiment.id"), primary_key=True), + db.Column("assistant_id", db.Integer, db.ForeignKey("assistant.id"), primary_key=True), +) class PartExperiment(db.Model): @@ -92,8 +92,9 @@ class PartExperiment(db.Model): id = db.Column(db.Integer, primary_key=True) experiment_id = db.Column(db.Integer, db.ForeignKey("experiment.id"), nullable=False) part_id = db.Column(db.Integer, db.ForeignKey("part.id"), nullable=False) - assistants = db.relationship("Assistant", secondary=experiment_assistant, lazy=True, - backref=db.backref("part_experiments", lazy=True)) + assistants = db.relationship( + "Assistant", secondary=experiment_assistant, lazy=True, backref=db.backref("part_experiments", lazy=True) + ) group_experiments = db.relationship("GroupExperiment", backref="part_experiment", lazy=True) @@ -116,15 +117,15 @@ class Assistant(db.Model): class Appointment(db.Model): id = db.Column(db.Integer, primary_key=True) - date = db.Column(db.DateTime, nullable=False) # To be specified with the python package "datetime" - special = db.Column(db.Boolean, nullable=False) # In the break or not + date = db.Column(db.DateTime, nullable=False) # To be specified with the python package "datetime" + special = db.Column(db.Boolean, nullable=False) # In the break or not group_experiment_id = db.Column(db.Integer, db.ForeignKey("group_experiment.id"), nullable=False) assistant_id = db.Column(db.Integer, db.ForeignKey("assistant.id"), nullable=False) class Part(db.Model): id = db.Column(db.Integer, primary_key=True) - label = db.Column(db.String(100), nullable=False) # A/1, A/2, B/1, B/2 + label = db.Column(db.String(100), nullable=False) # A/1, A/2, B/1, B/2 semester_id = db.Column(db.Integer, db.ForeignKey("semester.id"), nullable=False) part_experiments = db.relationship("PartExperiment", backref="part", lazy=True) part_students = db.relationship("PartStudent", backref="part", lazy=True) @@ -136,7 +137,7 @@ class Part(db.Model): class Semester(db.Model): id = db.Column(db.Integer, primary_key=True) - label = db.Column(db.String(100), nullable=False, unique=True) # WS2122 for example + label = db.Column(db.String(100), nullable=False, unique=True) # WS2122 for example parts = db.relationship("Part", backref="semester", lazy=True) def __repr__(self): @@ -155,8 +156,9 @@ class ExperimentMark(db.Model): protocol_mark = db.Column(db.Integer, nullable=True) part_student_id = db.Column(db.Integer, db.ForeignKey("part_student.id"), nullable=False) group_experiment_id = db.Column(db.Integer, db.ForeignKey("group_experiment.id"), nullable=False) - assistant_id = db.Column(db.Integer, db.ForeignKey("assistant.id"), - nullable=True) # The assistant who gives the mark + assistant_id = db.Column( + db.Integer, db.ForeignKey("assistant.id"), nullable=True + ) # The assistant who gives the mark class User(db.Model, FsUserMixin): diff --git a/advlabdb/routes.py b/advlabdb/routes.py index 1809fb2..fd250cf 100644 --- a/advlabdb/routes.py +++ b/advlabdb/routes.py @@ -1,9 +1,9 @@ -from advlabdb import app, db -from flask import render_template, request, url_for, flash, redirect +from flask import flash, redirect, render_template, request, url_for from flask_security import auth_required, current_user -from advlabdb.utils import titleToTemplate, userActiveSemester, setActiveSemester +from advlabdb import app, db from advlabdb.models import Semester +from advlabdb.utils import setActiveSemester, titleToTemplate, userActiveSemester @app.context_processor @@ -12,8 +12,15 @@ def util_processor(): semesters = Semester.query.all() items = [] for semester in semesters: - items.append('
  • ' + semester.label + '
  • ') + items.append( + '
  • ' + + semester.label + + "
  • " + ) return items def navbarItems(title): @@ -42,14 +49,15 @@ def util_processor(): else: active = "" - items.append('' + page + '') + items.append('' + page + "") return items - return dict(semesterDropDownItems=semesterDropDownItems, - userActiveSemester=userActiveSemester, - navbarItems=navbarItems, - current_user=current_user, - ) + return dict( + semesterDropDownItems=semesterDropDownItems, + userActiveSemester=userActiveSemester, + navbarItems=navbarItems, + current_user=current_user, + ) @app.route("/") diff --git a/advlabdb/utils.py b/advlabdb/utils.py index 5af0f62..c18ad4f 100644 --- a/advlabdb/utils.py +++ b/advlabdb/utils.py @@ -1,10 +1,11 @@ from random import choice -from string import digits, ascii_letters -from flask_security import current_user -from flask import flash +from string import ascii_letters, digits + +from flask import flash +from flask_security import current_user -from advlabdb.models import Semester from advlabdb import db +from advlabdb.models import Semester def makeTable(headerAndDataList, rows, tableId="table"): @@ -20,13 +21,16 @@ def makeTable(headerAndDataList, rows, tableId="table"): return cell def td(cell): - return '' + cellString(cell) + '' + return "" + cellString(cell) + "" def th(cell): - return '' + cellString(cell) + '' + return '' + cellString(cell) + "" - table = ''' -''' +""" + ) for i in headerAndDataList: table += th(i[0]) - table += ''' + table += """ -\n''' +\n""" for row in rows: - table += '' + table += "" for i in headerAndDataList: table += td(eval(i[1])) - table += '\n' + table += "\n" - table += ''' + table += """


    -
    ''' +
    """ return table @@ -66,7 +71,7 @@ def appointmentDate(date): def randomPassword(): - return ''.join(choice(ascii_letters + digits) for i in range(12)) + return "".join(choice(ascii_letters + digits) for i in range(12)) def titleToTemplate(page): diff --git a/copy_admin_templates.py b/copy_admin_templates.py index 9239e4d..8a9de8a 100644 --- a/copy_admin_templates.py +++ b/copy_admin_templates.py @@ -1,5 +1,6 @@ from os.path import exists from shutil import copytree, rmtree + from flask_admin import __file__ as flaskAdminPath @@ -13,7 +14,9 @@ def copyAdminTemplates(): dist = "advlabdb/templates/admin" if exists(dist): while True: - ans = input(f"The directory {dist} already exists. Enter 'o' to override it and update the templates or enter 's' to stop the process: ").lower() + ans = input( + f"The directory {dist} already exists. Enter 'o' to override it and update the templates or enter 's' to stop the process: " + ).lower() if ans == "s": print("Process stopped!") return False diff --git a/poetry.lock b/poetry.lock index 758dac4..74e676e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,33 @@ +[[package]] +name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "black" +version = "21.5b2" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +appdirs = "*" +click = ">=7.1.2" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.8.1,<1" +regex = ">=2020.1.8" +toml = ">=0.10.1" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +python2 = ["typed-ast (>=1.4.2)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "blinker" version = "1.4" @@ -187,6 +217,19 @@ category = "main" optional = false python-versions = ">=3.5" +[[package]] +name = "isort" +version = "5.8.0" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.6,<4.0" + +[package.extras] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] + [[package]] name = "itsdangerous" version = "2.0.1" @@ -225,6 +268,14 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "passlib" version = "1.7.4" @@ -239,6 +290,14 @@ bcrypt = ["bcrypt (>=3.1.0)"] build_docs = ["sphinx (>=1.6)", "sphinxcontrib-fulltoc (>=1.2.0)", "cloud-sptheme (>=1.10.1)"] totp = ["cryptography"] +[[package]] +name = "pathspec" +version = "0.8.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + [[package]] name = "pycodestyle" version = "2.7.0" @@ -255,6 +314,14 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "regex" +version = "2021.4.4" +description = "Alternative regular expression module, to replace re." +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "sqlalchemy" version = "1.4.17" @@ -286,6 +353,14 @@ postgresql_psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql (<1)", "pymysql"] sqlcipher = ["sqlcipher3-binary"] +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + [[package]] name = "werkzeug" version = "2.0.1" @@ -315,10 +390,18 @@ locale = ["Babel (>=1.3)"] [metadata] lock-version = "1.1" -python-versions = ">=3.9" -content-hash = "e938a304735e2b3e8ec26364f2494860d7d3e7df506f0d6f832f9fe123fbd54a" +python-versions = "^3.9" +content-hash = "db7a8f38d58cc2d8c8a1f7ca99dc8d3ab7a544b1b1899022c2bae7ffe5fa3aa2" [metadata.files] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] +black = [ + {file = "black-21.5b2-py3-none-any.whl", hash = "sha256:e5cf21ebdffc7a9b29d73912b6a6a9a4df4ce70220d523c21647da2eae0751ef"}, + {file = "black-21.5b2.tar.gz", hash = "sha256:1fc0e0a2c8ae7d269dfcf0c60a89afa299664f3e811395d40b1922dff8f854b5"}, +] blinker = [ {file = "blinker-1.4.tar.gz", hash = "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"}, ] @@ -423,6 +506,10 @@ idna = [ {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, ] +isort = [ + {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"}, + {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"}, +] itsdangerous = [ {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"}, {file = "itsdangerous-2.0.1.tar.gz", hash = "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"}, @@ -471,10 +558,18 @@ mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] passlib = [ {file = "passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1"}, {file = "passlib-1.7.4.tar.gz", hash = "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04"}, ] +pathspec = [ + {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, + {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, +] pycodestyle = [ {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, @@ -483,6 +578,49 @@ pyflakes = [ {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] +regex = [ + {file = "regex-2021.4.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a"}, + {file = "regex-2021.4.4-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7"}, + {file = "regex-2021.4.4-cp36-cp36m-win32.whl", hash = "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29"}, + {file = "regex-2021.4.4-cp36-cp36m-win_amd64.whl", hash = "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79"}, + {file = "regex-2021.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e"}, + {file = "regex-2021.4.4-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439"}, + {file = "regex-2021.4.4-cp37-cp37m-win32.whl", hash = "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d"}, + {file = "regex-2021.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3"}, + {file = "regex-2021.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f"}, + {file = "regex-2021.4.4-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87"}, + {file = "regex-2021.4.4-cp38-cp38-win32.whl", hash = "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac"}, + {file = "regex-2021.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2"}, + {file = "regex-2021.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c"}, + {file = "regex-2021.4.4-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042"}, + {file = "regex-2021.4.4-cp39-cp39-win32.whl", hash = "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6"}, + {file = "regex-2021.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07"}, + {file = "regex-2021.4.4.tar.gz", hash = "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb"}, +] sqlalchemy = [ {file = "SQLAlchemy-1.4.17-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c367ed95d41df584f412a9419b5ece85b0d6c2a08a51ae13ae47ef74ff9a9349"}, {file = "SQLAlchemy-1.4.17-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fdad4a33140b77df61d456922b7974c1f1bb2c35238f6809f078003a620c4734"}, @@ -515,6 +653,10 @@ sqlalchemy = [ {file = "SQLAlchemy-1.4.17-cp39-cp39-win_amd64.whl", hash = "sha256:7eb55d5583076c03aaf1510473fad2a61288490809049cb31028af56af7068ee"}, {file = "SQLAlchemy-1.4.17.tar.gz", hash = "sha256:651cdb3adcee13624ba22d5ff3e96f91e16a115d2ca489ddc16a8e4c217e8509"}, ] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] werkzeug = [ {file = "Werkzeug-2.0.1-py3-none-any.whl", hash = "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"}, {file = "Werkzeug-2.0.1.tar.gz", hash = "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42"}, diff --git a/pyproject.toml b/pyproject.toml index e8a06d9..f2df1e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = ["Mohamad Bitar "] readme = "README.md" [tool.poetry.dependencies] -python = ">=3.9" +python = "^3.9" Flask = ">=2.0.1" Flask-SQLAlchemy = ">=2.5.1" SQLAlchemy = ">=1.4.17" @@ -17,7 +17,15 @@ Flask-Admin = ">=1.5.8" [tool.poetry.dev-dependencies] flake8 = "*" +black = "*" +isort = "*" [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" + +[tool.black] +line-length = 120 + +[tool.isort] +profile = "black" diff --git a/testDB.py b/testDB.py index fc79c0a..1407a0b 100644 --- a/testDB.py +++ b/testDB.py @@ -1,5 +1,7 @@ from datetime import datetime + from flask_security import hash_password + from advlabdb import app, db, user_datastore from advlabdb.models import * @@ -41,11 +43,29 @@ with app.app_context(): db.session.add(ps2) db.session.add(ps3) - ex1 = Experiment(number=1, name="exp", room="123", building="phy", responsibility="none", duration_in_days=2, - oral_weighting=0.5, protocol_weighting=0.5, final_weighting=1) + ex1 = Experiment( + number=1, + name="exp", + room="123", + building="phy", + responsibility="none", + duration_in_days=2, + oral_weighting=0.5, + protocol_weighting=0.5, + final_weighting=1, + ) - ex2 = Experiment(number=2, name="exp2", room="123", building="phy", responsibility="none", duration_in_days=2, - oral_weighting=0.5, protocol_weighting=0.5, final_weighting=1) + ex2 = Experiment( + number=2, + name="exp2", + room="123", + building="phy", + responsibility="none", + duration_in_days=2, + oral_weighting=0.5, + protocol_weighting=0.5, + final_weighting=1, + ) db.session.add(ex1) db.session.add(ex2) @@ -70,8 +90,14 @@ with app.app_context(): us1 = user_datastore.create_user(email="test@protonmail.com", password=hash_password("h1"), roles=["assistant"]) us2 = user_datastore.create_user(email="test2@protonmail.com", password=hash_password("h2"), roles=["assistant"]) - as1 = Assistant(first_name="As1", last_name="l", email="test@test.com", phone_number="012333212", - mobile_phone_number="012334123", user=us1) + as1 = Assistant( + first_name="As1", + last_name="l", + email="test@test.com", + phone_number="012333212", + mobile_phone_number="012334123", + user=us1, + ) as2 = Assistant(first_name="As2", last_name="l", email="test2@test.com", user=us2) as1.part_experiments.append(px1)