summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/util.py
diff options
context:
space:
mode:
authorJason Kirtland <jek@discorporate.us>2008-04-04 19:07:30 +0000
committerJason Kirtland <jek@discorporate.us>2008-04-04 19:07:30 +0000
commitafd8431d4d6527d32d43f0a6c11d75ba2b0adcaf (patch)
tree88f13aaf756078b1eb7c10c5647a1885b9eaeac5 /lib/sqlalchemy/util.py
parentde209ded31c3914d70e5372b0c49b6fd84639d48 (diff)
downloadsqlalchemy-afd8431d4d6527d32d43f0a6c11d75ba2b0adcaf.tar.gz
- Pool listeners may now be specified as a duck-type of PoolListener or a dict of callables, your choice.
Diffstat (limited to 'lib/sqlalchemy/util.py')
-rw-r--r--lib/sqlalchemy/util.py83
1 files changed, 82 insertions, 1 deletions
diff --git a/lib/sqlalchemy/util.py b/lib/sqlalchemy/util.py
index 36b40a04d..740e97e3f 100644
--- a/lib/sqlalchemy/util.py
+++ b/lib/sqlalchemy/util.py
@@ -4,7 +4,7 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-import inspect, itertools, new, sets, sys, warnings, weakref
+import inspect, itertools, new, operator, sets, sys, warnings, weakref
import __builtin__
types = __import__('types')
@@ -1060,6 +1060,87 @@ class symbol(object):
symbol._lock.release()
+def as_interface(obj, cls=None, methods=None, required=None):
+ """Ensure basic interface compliance for an instance or dict of callables.
+
+ Checks that ``obj`` implements public methods of ``cls`` or has members
+ listed in ``methods``. If ``required`` is not supplied, implementing at
+ least one interface method is sufficient. Methods present on ``obj`` that
+ are not in the interface are ignored.
+
+ If ``obj`` is a dict and ``dict`` does not meet the interface
+ requirements, the keys of the dictionary are inspected. Keys present in
+ ``obj`` that are not in the interface will raise TypeErrors.
+
+ Raises TypeError if ``obj`` does not meet the interface criteria.
+
+ In all passing cases, an object with callable members is returned. In the
+ simple case, ``obj`` is returned as-is; if dict processing kicks in then
+ an anonymous class is returned.
+
+ obj
+ A type, instance, or dictionary of callables.
+ cls
+ Optional, a type. All public methods of cls are considered the
+ interface. An ``obj`` instance of cls will always pass, ignoring
+ ``required``..
+ methods
+ Optional, a sequence of method names to consider as the interface.
+ required
+ Optional, a sequence of mandatory implementations. If omitted, an
+ ``obj`` that provides at least one interface method is considered
+ sufficient. As a convenience, required may be a type, in which case
+ all public methods of the type are required.
+
+ """
+ if not cls and not methods:
+ raise TypeError('a class or collection of method names are required')
+
+ if isinstance(cls, type) and isinstance(obj, cls):
+ return obj
+
+ interface = Set(methods or [m for m in dir(cls) if not m.startswith('_')])
+ implemented = Set(dir(obj))
+
+ complies = operator.ge
+ if isinstance(required, type):
+ required = interface
+ elif not required:
+ required = Set()
+ complies = operator.gt
+ else:
+ required = Set(required)
+
+ if complies(implemented.intersection(interface), required):
+ return obj
+
+ # No dict duck typing here.
+ if not type(obj) is dict:
+ qualifier = complies is operator.gt and 'any of' or 'all of'
+ raise TypeError("%r does not implement %s: %s" % (
+ obj, qualifier, ', '.join(interface)))
+
+ class AnonymousInterface(object):
+ """A callable-holding shell."""
+
+ if cls:
+ AnonymousInterface.__name__ = 'Anonymous' + cls.__name__
+ found = Set()
+
+ for method, impl in dictlike_iteritems(obj):
+ if method not in interface:
+ raise TypeError("%r: unknown in this interface" % method)
+ if not callable(impl):
+ raise TypeError("%r=%r is not callable" % (method, impl))
+ setattr(AnonymousInterface, method, staticmethod(impl))
+ found.add(method)
+
+ if complies(found, required):
+ return AnonymousInterface
+
+ raise TypeError("dictionary does not contain required keys %s" %
+ ', '.join(required - found))
+
def function_named(fn, name):
"""Return a function with a given __name__.