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)