--- 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
--- 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"""
Binary file src/pyams_alchemy/locales/fr/LC_MESSAGES/pyams_alchemy.mo has changed
--- 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 <tflorac@ulthar.net>\n"
"Language-Team: French <traduc@traduc.org>\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"
--- 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 <EMAIL@ADDRESS>, 2015.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS\n"
"Language-Team: LANGUAGE <LL@li.org>\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 ""
--- 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)
--- 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',