diff options
author | Jason Kirtland <jek@discorporate.us> | 2008-04-04 19:07:30 +0000 |
---|---|---|
committer | Jason Kirtland <jek@discorporate.us> | 2008-04-04 19:07:30 +0000 |
commit | afd8431d4d6527d32d43f0a6c11d75ba2b0adcaf (patch) | |
tree | 88f13aaf756078b1eb7c10c5647a1885b9eaeac5 /lib/sqlalchemy/util.py | |
parent | de209ded31c3914d70e5372b0c49b6fd84639d48 (diff) | |
download | sqlalchemy-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.py | 83 |
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__. |