-
Notifications
You must be signed in to change notification settings - Fork 47
Architecture
As I don't know if anyone will ever read this, I'll keep this very high level for now, where I feel it's necessary.
lute
is the app module. Each subfolder under it is either a blueprint or a utility/service package:
-
backup
: the/backup
routes and service -
bing
: the/bing
routes and service ... etc
Special things:
-
db
: database setup and migrations, and demo data management -
dev_api
: special/dangerous routes used during testing only (not loaded if app ENV = prod) -
models
: the Sqlalchemy models -
parse
: parsing -
utils
: utils
The classes in lute.models
are Sqlalchemy classes. Most of these have simple methods for things like finding, loading, etc.
Some DB models (e.g. lute.models.language.Language
) are used throughout the application, as they're pretty much just data classes with little functionality.
There are two more useful domain models:
lute.term.model.Term
lute.book.model.Book
These are used more frequently in the code as they provide useful domain-level abstractions. They both have corresponding lute.X.model.Repository
objects that translate these models to and from the DB/Sqlalchemy models.
Lute shows some data as tabular data in datatables, which just use Sqlalchemy to query the db directly without models. The lute.utils.data_tables
module helps with that.
Except for parsing and rendering, the model for Lute is pretty simple:
- a route in a blueprint's
routes
module receives an incoming requests - the route delegates to some kind of
service
module in the blueprint - the
service
deals with either DB or domain models as needed, and commits to thelute.db
via usual Flask-Sqlalchemy methods.
- The user studies
lute.models.language.Language
- The user creates
lute.book.model.Book
(domain object), which is saved as alute.models.Book
db object. ADbBook
has one or morelute.models.book.Text
objects, which are the pages in theBook
. - The user reads the text in the
lute.read
routes, and createslute.term.model.Term
objects, which are saved in the database aslute.models.term.Term
objects.
- The main entry point is
lute.main
which initializes the db and app. -
lute.main
callslute.config.app_config.AppConfig
to get the configuration from thelute/config/config.yml
. The config.yml file is pre-written for Docker, or the prod example is used.AppConfig
is used in several places in the code to re-read the config file. Among other things, the config gives the name of the folder where the user's data will be stored; this is suppliedy by the libraryPlatformDirs
if it's not configured. -
lute.main
callslute.app_setup
, the app factory.app_setup
:- calls
lute.db.setup.main
to run db migrations and backups as needed. Migrations are handled bylute.db.setup.migrator
, using files inlute/db/schema/
. - loads all of the blueprints into the app.
- calls
-
lute.main
hands the configured app off to waitress.
- Parsers are defined in
lute.parse
, with a baseAbstractParser
subclassed by other parsers. The parsers are loaded into alute.parse.registry
which is consulted at runtime to determine which parsers are supported in the current environment. - Any time a page is requested or a new
Term
is created, the appropriate parser is found from theparse.registry
. The parser uses theLanguage
to get a list ofParsedTokens
. - If rendering, the list of
ParsedTokens
is given to thelute.read.render.renderable_calculator
to determine which tokens, and which parts of tokens, should actually be rendered. - When rendered, the
lute/static/js/lute.js
file adds javascript event handlers for each of the word elements in the rendered HTML. These handlers get/post back to various bluescript routes.
This wiki is for developer documentation. User documentation is in the user manual
Thanks!