# the_works – a publication management tool for writers This software project * supports managing texts and publications with multiple languages, pseudonyms, genres, publishers, series, editions, and more * supports storage of cover images * focuses on ease-of-use, safety, and speed * written and field-tested by an actual writer the_works also is * based on common technologies like Python, SQL, and HTML/JavaScript * underlying frameworks are Flask and SQLAlchemy * includes test coverage (using pytest) ## Configuration ### From the environment When the_works is started, the app first reads all environment variables prefixed with "FLASK_" (e.g. "FLASK_APP"). Any variables in the file `.flaskenv` will be added to the environment beforehand ("python-dotenv" must be installed). This can be used to determine the mode to run the app in (development, production etc.). Note that only those environment variables get added to the_works' configuration that begin with "FLASK_". Ths is true whether they were added on the command line, defined in`.flaskenv`, or even added by using Python's `os.environ`. ### From the_works/config.py The main configuration happens inside the file `the_works/config.py`. All static variables defined in the class "Config" will be added as key-value-pairs to the_works' configuration dict. In addition to "Config", the_works will then read all values from either "DevelopmentConfig", "ProductionConfig", or "TestingConfig". These classes are all subclasses of "Config". the_works determines which subclass to use by reading the Flask configuration setting "APP_MODE". If "APP_MODE" is one of either "development", "production", or "testing", the corresponding subclass will be used. If "APP_MODE" is set to a different value or not at all, "DevelopentConfig" will be used as default. Note that if a value is defined in both "Config" and one of its subclasses, the value from the subclass will supersede the one from the base class. ### Settings for the_works The following settings are specific to the_works: * `APP_MODE = development | production | testing` – detemines witch configuration to use in addition to the base config; default is development ### Useful Flask settings * `APP = ` – set this bevore running flask on the command line if you want to omit `--app the_works` * either `SQLALCHEMY_DATABASE_URI` or `SQLALCHEMY_DATABASE_URI` must be set or flask-sqlalchemy will throw an error; for URI syntax see the [SQLAlchemy docs](https://docs.sqlalchemy.org/en/20/core/engines.html#database-urls) * see the list of builtin configuration values in the [Flask docs](https://flask.palletsprojects.com/en/stable/config/#builtin-configuration-values) ## Flask commands Execute commands with `python -m flask --app the_works `. You can omit `--app` by setting the environment variable "FLASK_APP" to "the_works" (see [here](#useful-flask-settings)) Available commands: * `run`: Serve app (don't use for production). * `shell`: start a shell within the app context (I can i.e. import specific table models and test ORM data structures) ## Dependencies ### Python Packages Required pip packages * flask * python-dotenv * flask-sqlalchemy * Pillow * pytest See also `requirements.txt`. ### CSS and Javascript resources * any regular (not classless) stylesheet from [PicoCSS](https://picocss.com) for general styling * `SwitchColorMode.js` from [Yohn's fork of PicoCSS](https://yohn.github.io/PicoCSS/) to enable color mode switching * [DataTables](https://datatables.net/) (JS and CSS components) to enable ordering and filtering result tables * DataTables requires [jQuery](https://jquery.com/), which can either be bundled with DataTables itself or installed as a separate resource ### Icons some icons from heroicons.com ## Other useful stuff ### Export database schema Method 1: `sqlite3 the_works.sqlite .schema > outputfile.sql` Method 2: Open DB in SQLitebrowser and use File -> Export -> Database to SQL file … * keep original CREATE statements * export schema only * overwrite old schema (DROP TABLE, then CREATE TABLE) ### Generate `requirements.txt` I use [pipreqs](https://pypi.org/project/pipreqs/) to generate the file `requirements.txt`. The package scans all source files for import statements and uses those to extract all required Pip packages. See `pipreqs -h` for usage info. ### Outdated: Generate SQLAlchemy code from an existing database ~~Right now~~ In earlier stages, the_works reflects an existing database in order to infer the underlying data models for SQLAlchemy. Of course, this only works if all the tables already exist in the database. If the_works is run with an empty database (this happens when running tests, for example), the app will create fresh tables in the database. The necessary information about the tables can be generated from an existing database with the help of [sqlacodegen](https://pypi.org/project/sqlacodegen/). Just run this command inside the project's root directory: `sqlacodegen --generator tables sqlite:///path/to/good/db.sqlite > ./the_works/tables.py` The tool sqlacodegen can also generate Python code declaring the data models directly. This would make the use of reflection obsolete. The command would be: `sqlacodegen --generator declarative sqlite:///path/to/good/db.sqlite > outputfile.py`