# HG changeset patch # User Thierry Florac # Date 1477233493 -7200 # Node ID ce081139da7760a3f649dcea7e7486eeb476a687 # Parent 37d28950ea157fe90e495babeb4d46616d48732e Added 'use_pool' and 'echo_pool' attributes to engine interface diff -r 37d28950ea15 -r ce081139da77 src/pyams_alchemy/engine.py --- a/src/pyams_alchemy/engine.py Tue Jul 12 09:17:27 2016 +0200 +++ b/src/pyams_alchemy/engine.py Sun Oct 23 16:38:13 2016 +0200 @@ -23,7 +23,7 @@ from sqlalchemy.event import listens_for from sqlalchemy.orm.scoping import scoped_session from sqlalchemy.orm.session import sessionmaker -from sqlalchemy.pool import Pool +from sqlalchemy.pool import Pool, NullPool from threading import Thread, Lock # import interfaces @@ -110,18 +110,22 @@ name = FieldProperty(IAlchemyEngineUtility['name']) dsn = FieldProperty(IAlchemyEngineUtility['dsn']) echo = FieldProperty(IAlchemyEngineUtility['echo']) + use_pool = FieldProperty(IAlchemyEngineUtility['use_pool']) pool_size = FieldProperty(IAlchemyEngineUtility['pool_size']) pool_recycle = FieldProperty(IAlchemyEngineUtility['pool_recycle']) + echo_pool = FieldProperty(IAlchemyEngineUtility['echo_pool']) encoding = FieldProperty(IAlchemyEngineUtility['encoding']) convert_unicode = FieldProperty(IAlchemyEngineUtility['convert_unicode']) - def __init__(self, name='', dsn='', echo=False, pool_size=25, pool_recycle=-1, + def __init__(self, name='', dsn='', echo=False, use_pool=True, pool_size=25, pool_recycle=-1, echo_pool=False, encoding='utf-8', convert_unicode=False, **kwargs): self.name = name self.dsn = dsn self.echo = echo + self.use_pool = use_pool self.pool_size = pool_size self.pool_recycle = pool_recycle + self.echo_pool = echo_pool self.encoding = encoding self.convert_unicode = convert_unicode self.kw = PersistentDict() @@ -132,21 +136,32 @@ if (key != '_v_engine') and hasattr(self, '_v_engine'): delattr(self, '_v_engine') - def get_engine(self): - engine = getattr(self, '_v_engine', None) - if engine is not None: - return engine - kw = {} + def get_engine(self, use_pool=True): + kw = { } kw.update(self.kw) - self._v_engine = sqlalchemy.create_engine(self.dsn, - echo=self.echo, - pool_size=self.pool_size, - pool_recycle=self.pool_recycle, - encoding=self.encoding, - convert_unicode=self.convert_unicode, - strategy='threadlocal', - **kw) - return self._v_engine + if not (use_pool and self.use_pool): + # Always create a new engine when pooling is disabled to help engine disposal + return sqlalchemy.create_engine(self.dsn, + echo=self.echo, + poolclass=NullPool, + encoding=self.encoding, + convert_unicode=self.convert_unicode, + strategy='threadlocal', + **kw) + else: + # Store engine into volatile attributes when pooling is enabled + engine = getattr(self, '_v_engine', None) + if engine is None: + engine = self._v_engine = sqlalchemy.create_engine(self.dsn, + echo=self.echo, + pool_size=self.pool_size, + pool_recycle=self.pool_recycle, + echo_pool=self.echo_pool, + encoding=self.encoding, + convert_unicode=self.convert_unicode, + strategy='threadlocal', + **kw) + return engine class PersistentAlchemyEngineUtility(Persistent, AlchemyEngineUtility, Contained): @@ -167,16 +182,16 @@ manager.unregisterUtility(event.object, IAlchemyEngineUtility, name=event.object.name or '') -def get_engine(engine): +def get_engine(engine, use_pool=True): """Get engine matching given utility name""" if isinstance(engine, str): engine = query_utility(IAlchemyEngineUtility, name=engine) if engine is not None: - return engine.get_engine() + return engine.get_engine(use_pool) def get_session(engine, join=True, status=STATUS_ACTIVE, request=None, alias=None, - twophase=True, use_zope_extension=True): + twophase=True, use_zope_extension=True, use_pool=True): """Get a new SQLALchemy session Session is stored in request and in session storage @@ -188,7 +203,7 @@ session_data = get_request_data(request, REQUEST_SESSION_KEY, {}) session = session_data.get(alias) if session is None: - _engine = get_engine(engine) + _engine = get_engine(engine, use_pool) if use_zope_extension: factory = scoped_session(sessionmaker(bind=_engine, twophase=twophase, @@ -207,14 +222,14 @@ def get_user_session(engine, join=True, status=STATUS_ACTIVE, request=None, alias=None, - twophase=True, use_zope_extension=True): + twophase=True, use_zope_extension=True, use_pool=True): """Get a new SQLAlchemy session `engine` can be a session name or an already created session (in which case it's returned as-is). """ if isinstance(engine, str): - session = get_session(engine, join, status, request, alias, twophase, use_zope_extension) + session = get_session(engine, join, status, request, alias, twophase, use_zope_extension, use_pool) else: session = engine return session diff -r 37d28950ea15 -r ce081139da77 src/pyams_alchemy/interfaces/__init__.py --- a/src/pyams_alchemy/interfaces/__init__.py Tue Jul 12 09:17:27 2016 +0200 +++ b/src/pyams_alchemy/interfaces/__init__.py Sun Oct 23 16:38:13 2016 +0200 @@ -40,10 +40,16 @@ required=True, default=u'sqlite://') - echo = Bool(title=_('Echo SQL'), + echo = Bool(title=_('Echo SQL?'), + description=_("Log all SQL statements to system logger"), required=True, default=False) + use_pool = Bool(title=_("Use connections pool?"), + description=_("If 'no', collections pooling will be disabled"), + required=True, + default=True) + pool_size = Int(title=_("Pool size"), description=_("SQLAlchemy connections pool size"), required=False, @@ -54,6 +60,11 @@ required=False, default=-1) + echo_pool = Bool(title=_("Echo pool?"), + description=_("Log all pool checkouts/checkins to system logger?"), + required=True, + default=False) + encoding = Choice(title=_('Encoding'), required=True, vocabulary='PyAMS encodings', @@ -63,5 +74,5 @@ required=True, default=False) - def get_engine(self): + def get_engine(self, use_pool=True): """Get SQLAlchemy engine""" diff -r 37d28950ea15 -r ce081139da77 src/pyams_alchemy/locales/fr/LC_MESSAGES/pyams_alchemy.mo Binary file src/pyams_alchemy/locales/fr/LC_MESSAGES/pyams_alchemy.mo has changed diff -r 37d28950ea15 -r ce081139da77 src/pyams_alchemy/locales/fr/LC_MESSAGES/pyams_alchemy.po --- a/src/pyams_alchemy/locales/fr/LC_MESSAGES/pyams_alchemy.po Tue Jul 12 09:17:27 2016 +0200 +++ b/src/pyams_alchemy/locales/fr/LC_MESSAGES/pyams_alchemy.po Sun Oct 23 16:38:13 2016 +0200 @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE 1.0\n" -"POT-Creation-Date: 2015-03-04 14:16+0100\n" +"POT-Creation-Date: 2016-10-23 16:31+0200\n" "PO-Revision-Date: 2015-03-03 16:56+0100\n" "Last-Translator: Thierry Florac \n" "Language-Team: French \n" @@ -39,86 +39,106 @@ msgstr "Tracer les instructions SQL" #: src/pyams_alchemy/metadirectives.py:43 -#: src/pyams_alchemy/interfaces/__init__.py:47 +#: src/pyams_alchemy/interfaces/__init__.py:48 +msgid "Use connections pool?" +msgstr "Utiliser un pool ?" + +#: src/pyams_alchemy/metadirectives.py:44 +#: src/pyams_alchemy/interfaces/__init__.py:49 +msgid "If 'no', collections pooling will be disabled" +msgstr "Si 'non', l'utilisation d'un pool de connexions sera désactivé" + +#: src/pyams_alchemy/metadirectives.py:48 +#: src/pyams_alchemy/interfaces/__init__.py:53 msgid "Pool size" msgstr "Taille du pool" -#: src/pyams_alchemy/metadirectives.py:44 -#: src/pyams_alchemy/interfaces/__init__.py:48 +#: src/pyams_alchemy/metadirectives.py:49 +#: src/pyams_alchemy/interfaces/__init__.py:54 msgid "SQLAlchemy connections pool size" msgstr "Taille du pool de connexions SQLALchemy" -#: src/pyams_alchemy/metadirectives.py:48 -#: src/pyams_alchemy/interfaces/__init__.py:52 +#: src/pyams_alchemy/metadirectives.py:53 +#: src/pyams_alchemy/interfaces/__init__.py:58 msgid "Pool recycle time" msgstr "Durée de recyclage" -#: src/pyams_alchemy/metadirectives.py:49 -#: src/pyams_alchemy/interfaces/__init__.py:53 +#: src/pyams_alchemy/metadirectives.py:54 +#: src/pyams_alchemy/interfaces/__init__.py:59 msgid "SQLAlchemy connection recycle time (-1 for none)" msgstr "" -"Durée de vie des connexions avant leur recyclage ; indiquer -1 pour " +"Durée de vie (en secondes) des connexions avant leur recyclage ; indiquer -1 pour " "conserver les connexions" -#: src/pyams_alchemy/metadirectives.py:53 -#: src/pyams_alchemy/interfaces/__init__.py:57 +#: src/pyams_alchemy/metadirectives.py:58 +#: src/pyams_alchemy/interfaces/__init__.py:63 +msgid "Echo pool?" +msgstr "Traces du pool ?" + +#: src/pyams_alchemy/metadirectives.py:59 +#: src/pyams_alchemy/interfaces/__init__.py:64 +msgid "Log all pool checkouts/checkins to system logger?" +msgstr "Tracer toutes les entrées/sorties du pool de connexions dans le système de logs de l'application" + +#: src/pyams_alchemy/metadirectives.py:63 +#: src/pyams_alchemy/interfaces/__init__.py:68 msgid "Encoding" msgstr "Encodage" -#: src/pyams_alchemy/metadirectives.py:58 -#: src/pyams_alchemy/interfaces/__init__.py:62 +#: src/pyams_alchemy/metadirectives.py:68 +#: src/pyams_alchemy/interfaces/__init__.py:73 msgid "Convert Unicode" msgstr "Conversion Unicode" -#: src/pyams_alchemy/zmi/engine.py:55 +#: src/pyams_alchemy/zmi/engine.py:56 msgid "Add SQLAlchemy engine..." msgstr "Ajouter un moteur SQLAlchemy..." -#: src/pyams_alchemy/zmi/engine.py:65 +#: src/pyams_alchemy/zmi/engine.py:66 msgid "Utilities" msgstr "Utilitaires" -#: src/pyams_alchemy/zmi/engine.py:66 +#: src/pyams_alchemy/zmi/engine.py:67 msgid "Add SQLAlchemy engine" msgstr "Ajout d'un moteur SQLAlchemy" -#: src/pyams_alchemy/zmi/engine.py:112 +#: src/pyams_alchemy/zmi/engine.py:114 msgid "Update SQLAlchemy engine properties" msgstr "Modification des propriétés d'un moteur SQLAlchemy" -#: src/pyams_alchemy/zmi/engine.py:136 +#: src/pyams_alchemy/zmi/engine.py:138 msgid "Test connection..." msgstr "Tester la connexion..." -#: src/pyams_alchemy/zmi/engine.py:167 +#: src/pyams_alchemy/zmi/engine.py:169 msgid "Test SQLAlchemy engine" msgstr "Test d'un moteur SQLAlchemy" -#: src/pyams_alchemy/zmi/engine.py:203 +#: src/pyams_alchemy/zmi/engine.py:205 msgid "Query results" msgstr "Résultats de la requête" -#: src/pyams_alchemy/zmi/engine.py:146 +#: src/pyams_alchemy/zmi/engine.py:148 msgid "SQL query" msgstr "Requête SQL" -#: src/pyams_alchemy/zmi/engine.py:153 +#: src/pyams_alchemy/zmi/engine.py:155 msgid "Close" msgstr "Fermer" -#: src/pyams_alchemy/zmi/engine.py:154 +#: src/pyams_alchemy/zmi/engine.py:156 msgid "Execute SQL" msgstr "Exécuter" -#: src/pyams_alchemy/zmi/engine.py:91 +#: src/pyams_alchemy/zmi/engine.py:92 msgid "Specified engine name is already used!" msgstr "Le nom indiqué pour ce moteur est déjà utilisé !" -#: src/pyams_alchemy/zmi/engine.py:94 +#: src/pyams_alchemy/zmi/engine.py:95 msgid "An SQLAlchemy engine is already registered with this name!" msgstr "Un moteur SQLAlchemy est déjà enregistré avec ce nom !" -#: src/pyams_alchemy/zmi/engine.py:110 src/pyams_alchemy/zmi/engine.py:165 +#: src/pyams_alchemy/zmi/engine.py:112 src/pyams_alchemy/zmi/engine.py:167 #, python-format msgid "SQLAlchemy engine: {0}" msgstr "Moteur SQLAlchemy : {0}" @@ -132,5 +152,9 @@ msgstr "DSN" #: src/pyams_alchemy/interfaces/__init__.py:43 -msgid "Echo SQL" -msgstr "Écho SQL" +msgid "Echo SQL?" +msgstr "Traces SQL ?" + +#: src/pyams_alchemy/interfaces/__init__.py:44 +msgid "Log all SQL statements to system logger" +msgstr "Tracer toutes les instructions SQL dans le système de logs de l'application" diff -r 37d28950ea15 -r ce081139da77 src/pyams_alchemy/locales/pyams_alchemy.pot --- a/src/pyams_alchemy/locales/pyams_alchemy.pot Tue Jul 12 09:17:27 2016 +0200 +++ b/src/pyams_alchemy/locales/pyams_alchemy.pot Sun Oct 23 16:38:13 2016 +0200 @@ -1,12 +1,12 @@ # # SOME DESCRIPTIVE TITLE # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , 2015. +# FIRST AUTHOR , 2016. #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE 1.0\n" -"POT-Creation-Date: 2015-03-04 14:16+0100\n" +"POT-Creation-Date: 2016-10-23 16:31+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" @@ -39,84 +39,104 @@ msgstr "" #: ./src/pyams_alchemy/metadirectives.py:43 -#: ./src/pyams_alchemy/interfaces/__init__.py:47 -msgid "Pool size" +#: ./src/pyams_alchemy/interfaces/__init__.py:48 +msgid "Use connections pool?" msgstr "" #: ./src/pyams_alchemy/metadirectives.py:44 -#: ./src/pyams_alchemy/interfaces/__init__.py:48 -msgid "SQLAlchemy connections pool size" +#: ./src/pyams_alchemy/interfaces/__init__.py:49 +msgid "If 'no', collections pooling will be disabled" msgstr "" #: ./src/pyams_alchemy/metadirectives.py:48 -#: ./src/pyams_alchemy/interfaces/__init__.py:52 -msgid "Pool recycle time" +#: ./src/pyams_alchemy/interfaces/__init__.py:53 +msgid "Pool size" msgstr "" #: ./src/pyams_alchemy/metadirectives.py:49 -#: ./src/pyams_alchemy/interfaces/__init__.py:53 -msgid "SQLAlchemy connection recycle time (-1 for none)" +#: ./src/pyams_alchemy/interfaces/__init__.py:54 +msgid "SQLAlchemy connections pool size" msgstr "" #: ./src/pyams_alchemy/metadirectives.py:53 -#: ./src/pyams_alchemy/interfaces/__init__.py:57 -msgid "Encoding" +#: ./src/pyams_alchemy/interfaces/__init__.py:58 +msgid "Pool recycle time" +msgstr "" + +#: ./src/pyams_alchemy/metadirectives.py:54 +#: ./src/pyams_alchemy/interfaces/__init__.py:59 +msgid "SQLAlchemy connection recycle time (-1 for none)" msgstr "" #: ./src/pyams_alchemy/metadirectives.py:58 -#: ./src/pyams_alchemy/interfaces/__init__.py:62 +#: ./src/pyams_alchemy/interfaces/__init__.py:63 +msgid "Echo pool?" +msgstr "" + +#: ./src/pyams_alchemy/metadirectives.py:59 +#: ./src/pyams_alchemy/interfaces/__init__.py:64 +msgid "Log all pool checkouts/checkins to system logger?" +msgstr "" + +#: ./src/pyams_alchemy/metadirectives.py:63 +#: ./src/pyams_alchemy/interfaces/__init__.py:68 +msgid "Encoding" +msgstr "" + +#: ./src/pyams_alchemy/metadirectives.py:68 +#: ./src/pyams_alchemy/interfaces/__init__.py:73 msgid "Convert Unicode" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:55 +#: ./src/pyams_alchemy/zmi/engine.py:56 msgid "Add SQLAlchemy engine..." msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:65 -msgid "Utilities" -msgstr "" - #: ./src/pyams_alchemy/zmi/engine.py:66 +msgid "Utilities" +msgstr "" + +#: ./src/pyams_alchemy/zmi/engine.py:67 msgid "Add SQLAlchemy engine" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:112 +#: ./src/pyams_alchemy/zmi/engine.py:114 msgid "Update SQLAlchemy engine properties" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:136 +#: ./src/pyams_alchemy/zmi/engine.py:138 msgid "Test connection..." msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:167 +#: ./src/pyams_alchemy/zmi/engine.py:169 msgid "Test SQLAlchemy engine" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:203 +#: ./src/pyams_alchemy/zmi/engine.py:205 msgid "Query results" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:146 +#: ./src/pyams_alchemy/zmi/engine.py:148 msgid "SQL query" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:153 +#: ./src/pyams_alchemy/zmi/engine.py:155 msgid "Close" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:154 +#: ./src/pyams_alchemy/zmi/engine.py:156 msgid "Execute SQL" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:91 +#: ./src/pyams_alchemy/zmi/engine.py:92 msgid "Specified engine name is already used!" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:94 +#: ./src/pyams_alchemy/zmi/engine.py:95 msgid "An SQLAlchemy engine is already registered with this name!" msgstr "" -#: ./src/pyams_alchemy/zmi/engine.py:110 ./src/pyams_alchemy/zmi/engine.py:165 +#: ./src/pyams_alchemy/zmi/engine.py:112 ./src/pyams_alchemy/zmi/engine.py:167 #, python-format msgid "SQLAlchemy engine: {0}" msgstr "" @@ -130,5 +150,9 @@ msgstr "" #: ./src/pyams_alchemy/interfaces/__init__.py:43 -msgid "Echo SQL" +msgid "Echo SQL?" msgstr "" + +#: ./src/pyams_alchemy/interfaces/__init__.py:44 +msgid "Log all SQL statements to system logger" +msgstr "" diff -r 37d28950ea15 -r ce081139da77 src/pyams_alchemy/metaconfigure.py --- a/src/pyams_alchemy/metaconfigure.py Tue Jul 12 09:17:27 2016 +0200 +++ b/src/pyams_alchemy/metaconfigure.py Sun Oct 23 16:38:13 2016 +0200 @@ -23,7 +23,8 @@ from zope.component import zcml -def engine_directive(context, name='', dsn='', echo=False, pool_size=25, pool_recycle=-2, encoding='utf-8', - convert_unicode=False, **kwargs): - engine = AlchemyEngineUtility(name, dsn, echo, pool_size, pool_recycle, encoding, convert_unicode, **kwargs) +def engine_directive(context, name='', dsn='', echo=False, use_pool=True, pool_size=25, pool_recycle=-2, + echo_pool=False, encoding='utf-8', convert_unicode=False, **kwargs): + engine = AlchemyEngineUtility(name, dsn, echo, use_pool, pool_size, pool_recycle, echo_pool, encoding, + convert_unicode, **kwargs) zcml.utility(context, IAlchemyEngineUtility, engine, name=name) diff -r 37d28950ea15 -r ce081139da77 src/pyams_alchemy/metadirectives.py --- a/src/pyams_alchemy/metadirectives.py Tue Jul 12 09:17:27 2016 +0200 +++ b/src/pyams_alchemy/metadirectives.py Sun Oct 23 16:38:13 2016 +0200 @@ -40,6 +40,11 @@ required=False, default=False) + use_pool = Bool(title=_("Use connections pool?"), + description=_("If 'no', collections pooling will be disabled"), + required=True, + default=True) + pool_size = Int(title=_("Pool size"), description=_("SQLAlchemy connections pool size"), required=False, @@ -50,6 +55,11 @@ required=False, default=-1) + echo_pool = Bool(title=_("Echo pool?"), + description=_("Log all pool checkouts/checkins to system logger?"), + required=True, + default=False) + encoding = Choice(title=_('Encoding'), required=True, vocabulary='PyAMS encodings',