Update Rules authored by Christoph Deneke's avatar Christoph Deneke
Over time, some general coding rules have been established and some common patterns created. If you find one in the code and it is not here, you can update the document.
## Overview
Here some general thoughts on coding rules:
- Follow [PEP8](https://www.python.org/dev/peps/pep-0008/), if possible. Also read [PEP20](https://www.python.org/dev/peps/pep-0020/) and follow it by idea and spirit.
- Use variable names that are self-explaining and consisted. Some database scheme names are currently not following this and should be renames (lot of work)
- If possible, do typing of new functions. Do typing (or correct typing) in docstrings. Hint: flask render_template returns a string (str) and flask redirect returns a response object (from werkzeug.wrappers.response import Response).
Before submit to git:
- Code should be formatted by "black" with 105 character per line.
- Code should be checked by pylint and seen, if the complains make sense. It has problems with SQLAlchemy as it contains a lot of "Meta" stuff - we started a pylintrc to suppress some of the false positives.
- Docstrings should be checked with pydocstyle using the "numpy" style.
- Code is in parts typed and we have a working mypy.ini. Hence, run mypy and see, if there are any (new) problems.
- Run the tests with pytest.
## Variables
We have a set of reserved variables that should be used throughout the project:
| Variable| What for| Exception|
| ------ | ------ |------|
| sid, s_id| ESS IDs | None |
| mid, m_id | PPM IDs| None|
| rid, r_id | Report IDs | None |
|did, d_id | Document ids | None |
| pid, pid | parent document ids | None |
| sample | ESS database record | Functions in the sample.py module|
| measurement | PPM database record | Functions in the measurement.py module |
| report | Report database entry | Functions in the report.py module|
| user | User database entry | some like new_user, s_user |
Remember: Special cases aren't special enough to break the rules.
Beside this, more relaxed, the use of following things is suggested:
| Variable| What for|
| ------ | ------ |
| mtype | Measurement type database entry |
| ttype | Template type |
| d_type | Directory type (Sample, Measurement or Report)|
## Documentation
All functions should have a docsstring following the [numpy style](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard).
We encourage to do typing of the variable inside the docstring. We use sphinx to automatically create a HTML documentation of the API. Needs more work and improvement. To make our life easier, we use markdown files for sphinx.
We use the read_the_docs theme as it makes much nicer output.
## Database access and transaction
We use Flask-SQLALchemy for all database accesses and transaction. No direct SQL or no direct SQLAlchemy.
If we have more complex database transaction, i.e. more then one line like a query, the database_transaction module should be used. It already contains general functions for create and update of most database schemes.
To ensure that things are really written to the database, we implemented a context manger for the database and it should be used for anything that changes the database (updates, delete and create of entries). The common pattern is
~~~~
import ResearchNotes.database_transactions as dbt
with dbt.Transaction(db):
g.user.password = generate_password_hash(password)
~~~~
or if you need a session it should be named db_session (to seperate from login_session) and inside the database_transaction.py module:
~~~~
with Transaction(database) as db_session:
db_session.add(doc)
~~~~
The create and update functions for the database entries in database_transaction normally take as input database: `database: SQLAlchemy, db_model: db_model_class, info_dict: dict`
**There should be no direct commits by db.session.commit().**
Some times the db_model_object is created and just passed to the function. We might want to change this.
## Working with the session cookie
To avoid confusion with the database session, the session cookie from flask is importat as `login_session` and should be addressed like this
~~~~
from flask import session as login_session
login_session.clear()
login_session["user_id"] = fuser.id
Over time, some general coding rules have been established and some common patterns created. If you find one in the code and it is not here, you can update the document.
## Overview
Here are some general thoughts on coding rules:
- Follow [PEP8](https://www.python.org/dev/peps/pep-0008/), if possible. Also read [PEP20](https://www.python.org/dev/peps/pep-0020/) and follow it by idea and spirit.
- Use variable names that are self-explaining and consisted. Some database scheme names are currently not following this and should be renamed (lot of work)
- If possible, do typing of new functions. Do typing (or correct typing) in docstrings. Hint: flask render_template returns a string (str) and flask redirect returns a response object (from werkzeug.wrappers.response import Response).
Before submit to git:
- Code should be formatted by "black" with 105 character per line.
- Code should be checked by pylint and seen if the complaints make sense. It has problems with SQLAlchemy as it contains a lot of "Meta" stuff - we started a pylintrc to suppress some of the false positives.
- Docstrings should be checked with pydocstyle using the "numpy" style.
- Code is in parts typed, and we have a working mypy.ini. Hence, run mypy and see, if there are any (new) problems.
- Run the tests with pytest.
## Variables
We have a set of reserved variables that should be used throughout the project:
| Variable| What for| Exception|
| ------ | ------ |------|
| sid, s_id| ESS IDs | None |
| mid, m_id | PPM IDs| None|
| rid, r_id | Report IDs | None |
|did, d_id | Document ids | None |
| pid, pid | parent document ids | None |
| sample | ESS database record | Functions in the sample.py module|
| measurement | PPM database record | Functions in the measurement.py module |
| report | Report database entry | Functions in the report.py module|
| user | User database entry | some like new_user, s_user |
Remember: Special cases aren't special enough to break the rules.
Besides this, more relaxed, the use of following things is suggested:
| Variable| What for|
| ------ | ------ |
| mtype | Measurement type database entry |
| ttype | Template type |
| d_type | Directory type (Sample, Measurement or Report)|
## Documentation
All functions should have a docsstring following the [numpy style](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard).
We encourage to do typing of the variable inside the docstring. We use sphinx to automatically create an HTML documentation of the API. Needs more work and improvement. To make our life easier, we use markdown files for sphinx.
We use the read_the_docs theme, as it makes much nicer output.
## Database access and transaction
We use Flask-SQLALchemy for all database accesses and transaction. No direct SQL or no direct SQLAlchemy.
If we have more complex database transaction, i.e. more than one line like a query, the database_transaction module should be used. It already contains general functions for create and update of most database schemes.
To ensure that things are really written to the database, we implemented a context manger for the database, and it should be used for anything that changes the database (updates, delete and create of entries). The common pattern is
~~~~
import ResearchNotes.database_transactions as dbt
with dbt.Transaction(db):
g.user.password = generate_password_hash(password)
~~~~
or if you need a session it should be named db_session (to seperate from login_session) and inside the database_transaction.py module:
~~~~
with Transaction(database) as db_session:
db_session.add(doc)
~~~~
The create and update functions for the database entries in database_transaction normally take as input database: `database: SQLAlchemy, db_model: db_model_class, info_dict: dict`
**There should be no direct commits by db.session.commit().**
Sometimes the db_model_object is created and just passed to the function. We might want to change this.
## Working with the session cookie
To avoid confusion with the database session, the session cookie from flask is imported as `login_session` and should be addressed like this
~~~~
from flask import session as login_session
login_session.clear()
login_session["user_id"] = fuser.id
~~~~
\ No newline at end of file