From 3e823337773ddff98071be2dd38da37f827664dc Mon Sep 17 00:00:00 2001 From: Holger Frey Date: Fri, 20 Mar 2020 11:55:21 +0100 Subject: [PATCH] setting up pyramid app: sql engine --- development.ini | 80 +++++++++++++++++++++++++++++++++++++++++++++++ ordr3/__init__.py | 13 ++++++++ ordr3/adapters.py | 75 +++++++++++++++++++++++++++++++++++++++++++- production.ini | 68 ++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 1 + 5 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 development.ini create mode 100644 production.ini diff --git a/development.ini b/development.ini new file mode 100644 index 0000000..d8246e4 --- /dev/null +++ b/development.ini @@ -0,0 +1,80 @@ +### +# app configuration +# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +### + +[app:main] +use = egg:ordr3 + +pyramid.reload_templates = true +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en +pyramid.includes = + pyramid_debugtoolbar + +sqlalchemy.url = sqlite:///%(here)s/ordr3.sqlite + +retry.attempts = 3 + +# By default, the toolbar only appears for clients from IP addresses +# '127.0.0.1' and '::1'. +# debugtoolbar.hosts = 127.0.0.1 ::1 + +[pshell] +setup = ordr3.pshell.setup + +### +# wsgi server configuration +### + +[alembic] +# path to migration scripts +script_location = ordr3/alembic +file_template = %%(year)d%%(month).2d%%(day).2d_%%(rev)s +# file_template = %%(rev)s_%%(slug)s + +[server:main] +use = egg:waitress#main +listen = localhost:6543 + +### +# logging configuration +# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +### + +[loggers] +keys = root, ordr3, sqlalchemy + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_ordr3] +level = DEBUG +handlers = +qualname = ordr3 + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine +# "level = INFO" logs SQL queries. +# "level = DEBUG" logs SQL queries and results. +# "level = WARN" logs neither. (Recommended for production systems.) + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s diff --git a/ordr3/__init__.py b/ordr3/__init__.py index c99602a..484e80e 100644 --- a/ordr3/__init__.py +++ b/ordr3/__init__.py @@ -4,3 +4,16 @@ A rewrite of our CPI ordering system. """ __version__ = "0.0.1" + + +from pyramid.config import Configurator + + +def main(global_config, **settings): + """ This function returns a Pyramid WSGI application. + """ + with Configurator(settings=settings) as config: + config.include("pyramid_jinja2") + config.include(".adapters") + config.scan() + return config.make_wsgi_app() diff --git a/ordr3/adapters.py b/ordr3/adapters.py index 6929457..a3aaecd 100644 --- a/ordr3/adapters.py +++ b/ordr3/adapters.py @@ -2,6 +2,7 @@ from datetime import datetime +import zope.sqlalchemy from sqlalchemy import ( Enum, Text, @@ -11,8 +12,9 @@ from sqlalchemy import ( Integer, DateTime, ForeignKey, + engine_from_config, ) -from sqlalchemy.orm import mapper, relationship +from sqlalchemy.orm import mapper, relationship, sessionmaker from sqlalchemy.schema import MetaData from . import models @@ -76,6 +78,7 @@ user_table = Table( def start_mappers(): + """ maps data base tables to model objects """ mapper( models.OrderItem, order_table, @@ -87,3 +90,73 @@ def start_mappers(): ) mapper(models.LogEntry, log_table) mapper(models.User, user_table) + + +def get_engine(settings, prefix="sqlalchemy."): + """ returns a sqlalchemy engine from a settings dict """ + return engine_from_config(settings, prefix) + + +def get_session_factory(engine): + """ returns a sqlalchemy session factory for a db enging """ + factory = sessionmaker() + factory.configure(bind=engine) + return factory + + +def get_tm_session(session_factory, transaction_manager): + """ + Get a ``sqlalchemy.orm.Session`` instance backed by a transaction. + + This function will hook the session to the transaction manager which + will take care of committing any changes. + + - When using pyramid_tm it will automatically be committed or aborted + depending on whether an exception is raised. + + - When using scripts you should wrap the session in a manager yourself. + For example:: + + import transaction + + engine = get_engine(settings) + session_factory = get_session_factory(engine) + with transaction.manager: + dbsession = get_tm_session(session_factory, transaction.manager) + + """ + dbsession = session_factory() + zope.sqlalchemy.register( + dbsession, transaction_manager=transaction_manager + ) + return dbsession + + +def includeme(config): + """ + Initialize the model for a Pyramid app. + + Activate this setup using ``config.include('ordr3.adapters')``. + + """ + settings = config.get_settings() + settings["tm.manager_hook"] = "pyramid_tm.explicit_manager" + + # use pyramid_tm to hook the transaction lifecycle to the request + config.include("pyramid_tm") + + # use pyramid_retry to retry a request when transient exceptions occur + config.include("pyramid_retry") + + session_factory = get_session_factory(get_engine(settings)) + config.registry["dbsession_factory"] = session_factory + + # make request.dbsession available for use in Pyramid + config.add_request_method( + # r.tm is the transaction manager used by pyramid_tm + lambda r: get_tm_session(session_factory, r.tm), + "dbsession", + reify=True, + ) + + start_mappers() diff --git a/production.ini b/production.ini new file mode 100644 index 0000000..a9bf657 --- /dev/null +++ b/production.ini @@ -0,0 +1,68 @@ +### +# app configuration +# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html +### + +[app:main] +use = egg:ordr3 + +pyramid.reload_templates = false +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en + +sqlalchemy.url = sqlite:///%(here)s/ordr3.sqlite + +retry.attempts = 3 + +[pshell] +setup = ordr3.pshell.setup + +### +# wsgi server configuration +### + +[server:main] +use = egg:waitress#main +listen = *:6543 + +### +# logging configuration +# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html +### + +[loggers] +keys = root, ordr3, sqlalchemy + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console + +[logger_ordr3] +level = WARN +handlers = +qualname = ordr3 + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine +# "level = INFO" logs SQL queries. +# "level = DEBUG" logs SQL queries and results. +# "level = WARN" logs neither. (Recommended for production systems.) + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s diff --git a/pyproject.toml b/pyproject.toml index 5bb8e84..28a3e62 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ requires = [ "pyramid_jinja2 >= 2.7", "pyramid_mailer >= 0.15.1", "pyramid_tm >= 2.4", + "pyramid_retry >= 2.1", "sqlalchemy >= 1.3.15", "transaction >= 3.0.0", "waitress >= 1.4.3",