root/galaxy-central/eggs/SQLAlchemy-0.5.6_dev_r6498-py2.6.egg/sqlalchemy/util.py @ 3

リビジョン 3, 45.8 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# util.py
2# Copyright (C) 2005, 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com
3#
4# This module is part of SQLAlchemy and is released under
5# the MIT License: http://www.opensource.org/licenses/mit-license.php
6
7import inspect, itertools, operator, sys, warnings, weakref
8import __builtin__
9types = __import__('types')
10
11from sqlalchemy import exc
12
13try:
14    import threading
15except ImportError:
16    import dummy_threading as threading
17
18py3k = getattr(sys, 'py3kwarning', False) or sys.version_info >= (3, 0)
19
20if py3k:
21    set_types = set
22elif sys.version_info < (2, 6):
23    import sets
24    set_types = set, sets.Set
25else:
26    # 2.6 deprecates sets.Set, but we still need to be able to detect them
27    # in user code and as return values from DB-APIs
28    ignore = ('ignore', None, DeprecationWarning, None, 0)
29    try:
30        warnings.filters.insert(0, ignore)
31    except Exception:
32        import sets
33    else:
34        import sets
35        warnings.filters.remove(ignore)
36
37    set_types = set, sets.Set
38
39EMPTY_SET = frozenset()
40
41if py3k:
42    import pickle
43else:
44    try:
45        import cPickle as pickle
46    except ImportError:
47        import pickle
48
49# a controversial feature, required by MySQLdb currently
50def buffer(x):
51    return x
52   
53buffer = getattr(__builtin__, 'buffer', buffer)
54       
55if sys.version_info >= (2, 5):
56    class PopulateDict(dict):
57        """A dict which populates missing values via a creation function.
58
59        Note the creation function takes a key, unlike
60        collections.defaultdict.
61
62        """
63
64        def __init__(self, creator):
65            self.creator = creator
66           
67        def __missing__(self, key):
68            self[key] = val = self.creator(key)
69            return val
70else:
71    class PopulateDict(dict):
72        """A dict which populates missing values via a creation function."""
73
74        def __init__(self, creator):
75            self.creator = creator
76           
77        def __getitem__(self, key):
78            try:
79                return dict.__getitem__(self, key)
80            except KeyError:
81                self[key] = value = self.creator(key)
82                return value
83
84if py3k:
85    def callable(fn):
86        return hasattr(fn, '__call__')
87else:
88    callable = __builtin__.callable
89
90if py3k:
91    from functools import reduce
92else:
93    reduce = __builtin__.reduce
94
95try:
96    from collections import defaultdict
97except ImportError:
98    class defaultdict(dict):
99        def __init__(self, default_factory=None, *a, **kw):
100            if (default_factory is not None and
101                not hasattr(default_factory, '__call__')):
102                raise TypeError('first argument must be callable')
103            dict.__init__(self, *a, **kw)
104            self.default_factory = default_factory
105        def __getitem__(self, key):
106            try:
107                return dict.__getitem__(self, key)
108            except KeyError:
109                return self.__missing__(key)
110        def __missing__(self, key):
111            if self.default_factory is None:
112                raise KeyError(key)
113            self[key] = value = self.default_factory()
114            return value
115        def __reduce__(self):
116            if self.default_factory is None:
117                args = tuple()
118            else:
119                args = self.default_factory,
120            return type(self), args, None, None, self.iteritems()
121        def copy(self):
122            return self.__copy__()
123        def __copy__(self):
124            return type(self)(self.default_factory, self)
125        def __deepcopy__(self, memo):
126            import copy
127            return type(self)(self.default_factory,
128                              copy.deepcopy(self.items()))
129        def __repr__(self):
130            return 'defaultdict(%s, %s)' % (self.default_factory,
131                                            dict.__repr__(self))
132
133       
134def to_list(x, default=None):
135    if x is None:
136        return default
137    if not isinstance(x, (list, tuple)):
138        return [x]
139    else:
140        return x
141
142def to_set(x):
143    if x is None:
144        return set()
145    if not isinstance(x, set):
146        return set(to_list(x))
147    else:
148        return x
149
150def to_column_set(x):
151    if x is None:
152        return column_set()
153    if not isinstance(x, column_set):
154        return column_set(to_list(x))
155    else:
156        return x
157
158
159try:
160    from functools import update_wrapper
161except ImportError:
162    def update_wrapper(wrapper, wrapped,
163                       assigned=('__doc__', '__module__', '__name__'),
164                       updated=('__dict__',)):
165        for attr in assigned:
166            setattr(wrapper, attr, getattr(wrapped, attr))
167        for attr in updated:
168            getattr(wrapper, attr).update(getattr(wrapped, attr, ()))
169        return wrapper
170
171try:
172    from functools import partial
173except:
174    def partial(func, *args, **keywords):
175        def newfunc(*fargs, **fkeywords):
176            newkeywords = keywords.copy()
177            newkeywords.update(fkeywords)
178            return func(*(args + fargs), **newkeywords)
179        return newfunc
180
181
182def accepts_a_list_as_starargs(list_deprecation=None):
183    def decorate(fn):
184
185        spec = inspect.getargspec(fn)
186        assert spec[1], 'Decorated function does not accept *args'
187
188        def _deprecate():
189            if list_deprecation:
190                if list_deprecation == 'pending':
191                    warning_type = exc.SAPendingDeprecationWarning
192                else:
193                    warning_type = exc.SADeprecationWarning
194                msg = (
195                    "%s%s now accepts multiple %s arguments as a "
196                    "variable argument list.  Supplying %s as a single "
197                    "list is deprecated and support will be removed "
198                    "in a future release." % (
199                        fn.func_name,
200                        inspect.formatargspec(*spec),
201                        spec[1], spec[1]))
202                warnings.warn(msg, warning_type, stacklevel=3)
203
204        def go(fn, *args, **kw):
205            if isinstance(args[-1], list):
206                _deprecate()
207                return fn(*(list(args[0:-1]) + args[-1]), **kw)
208            else:
209                return fn(*args, **kw)
210         
211        return decorator(go)(fn)
212
213    return decorate
214
215def unique_symbols(used, *bases):
216    used = set(used)
217    for base in bases:
218        pool = itertools.chain((base,),
219                               itertools.imap(lambda i: base + str(i),
220                                              xrange(1000)))
221        for sym in pool:
222            if sym not in used:
223                used.add(sym)
224                yield sym
225                break
226        else:
227            raise NameError("exhausted namespace for symbol base %s" % base)
228
229def decorator(target):
230    """A signature-matching decorator factory."""
231
232    def decorate(fn):
233        spec = inspect.getargspec(fn)
234        names = tuple(spec[0]) + spec[1:3] + (fn.func_name,)
235        targ_name, fn_name = unique_symbols(names, 'target', 'fn')
236
237        metadata = dict(target=targ_name, fn=fn_name)
238        metadata.update(format_argspec_plus(spec, grouped=False))
239
240        code = 'lambda %(args)s: %(target)s(%(fn)s, %(apply_kw)s)' % (
241                metadata)
242        decorated = eval(code, {targ_name:target, fn_name:fn})
243        decorated.func_defaults = getattr(fn, 'im_func', fn).func_defaults
244        return update_wrapper(decorated, fn)
245    return update_wrapper(decorate, target)
246
247
248if sys.version_info >= (2, 5):
249    def decode_slice(slc):
250        """decode a slice object as sent to __getitem__.
251
252        takes into account the 2.5 __index__() method, basically.
253
254        """
255        ret = []
256        for x in slc.start, slc.stop, slc.step:
257            if hasattr(x, '__index__'):
258                x = x.__index__()
259            ret.append(x)
260        return tuple(ret)
261else:
262    def decode_slice(slc):
263        return (slc.start, slc.stop, slc.step)
264
265def flatten_iterator(x):
266    """Given an iterator of which further sub-elements may also be
267    iterators, flatten the sub-elements into a single iterator.
268
269    """
270    for elem in x:
271        if not isinstance(elem, basestring) and hasattr(elem, '__iter__'):
272            for y in flatten_iterator(elem):
273                yield y
274        else:
275            yield elem
276
277def get_cls_kwargs(cls):
278    """Return the full set of inherited kwargs for the given `cls`.
279
280    Probes a class's __init__ method, collecting all named arguments.  If the
281    __init__ defines a \**kwargs catch-all, then the constructor is presumed to
282    pass along unrecognized keywords to it's base classes, and the collection
283    process is repeated recursively on each of the bases.
284   
285    """
286
287    for c in cls.__mro__:
288        if '__init__' in c.__dict__:
289            stack = set([c])
290            break
291    else:
292        return []
293
294    args = set()
295    while stack:
296        class_ = stack.pop()
297        ctr = class_.__dict__.get('__init__', False)
298        if not ctr or not isinstance(ctr, types.FunctionType):
299            continue
300        names, _, has_kw, _ = inspect.getargspec(ctr)
301        args.update(names)
302        if has_kw:
303            stack.update(class_.__bases__)
304    args.discard('self')
305    return list(args)
306
307def get_func_kwargs(func):
308    """Return the full set of legal kwargs for the given `func`."""
309    return inspect.getargspec(func)[0]
310
311def format_argspec_plus(fn, grouped=True):
312    """Returns a dictionary of formatted, introspected function arguments.
313
314    A enhanced variant of inspect.formatargspec to support code generation.
315
316    fn
317       An inspectable callable or tuple of inspect getargspec() results.
318    grouped
319      Defaults to True; include (parens, around, argument) lists
320
321    Returns:
322
323    args
324      Full inspect.formatargspec for fn
325    self_arg
326      The name of the first positional argument, varargs[0], or None
327      if the function defines no positional arguments.
328    apply_pos
329      args, re-written in calling rather than receiving syntax.  Arguments are
330      passed positionally.
331    apply_kw
332      Like apply_pos, except keyword-ish args are passed as keywords.
333
334    Example::
335
336      >>> format_argspec_plus(lambda self, a, b, c=3, **d: 123)
337      {'args': '(self, a, b, c=3, **d)',
338       'self_arg': 'self',
339       'apply_kw': '(self, a, b, c=c, **d)',
340       'apply_pos': '(self, a, b, c, **d)'}
341
342    """
343    spec = callable(fn) and inspect.getargspec(fn) or fn
344    args = inspect.formatargspec(*spec)
345    if spec[0]:
346        self_arg = spec[0][0]
347    elif spec[1]:
348        self_arg = '%s[0]' % spec[1]
349    else:
350        self_arg = None
351    apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2])
352    defaulted_vals = spec[3] is not None and spec[0][0-len(spec[3]):] or ()
353    apply_kw = inspect.formatargspec(spec[0], spec[1], spec[2], defaulted_vals,
354                                     formatvalue=lambda x: '=' + x)
355    if grouped:
356        return dict(args=args, self_arg=self_arg,
357                    apply_pos=apply_pos, apply_kw=apply_kw)
358    else:
359        return dict(args=args[1:-1], self_arg=self_arg,
360                    apply_pos=apply_pos[1:-1], apply_kw=apply_kw[1:-1])
361
362def format_argspec_init(method, grouped=True):
363    """format_argspec_plus with considerations for typical __init__ methods
364
365    Wraps format_argspec_plus with error handling strategies for typical
366    __init__ cases::
367
368      object.__init__ -> (self)
369      other unreflectable (usually C) -> (self, *args, **kwargs)
370
371    """
372    try:
373        return format_argspec_plus(method, grouped=grouped)
374    except TypeError:
375        self_arg = 'self'
376        if method is object.__init__:
377            args = grouped and '(self)' or 'self'
378        else:
379            args = (grouped and '(self, *args, **kwargs)'
380                            or 'self, *args, **kwargs')
381        return dict(self_arg='self', args=args, apply_pos=args, apply_kw=args)
382
383def getargspec_init(method):
384    """inspect.getargspec with considerations for typical __init__ methods
385
386    Wraps inspect.getargspec with error handling for typical __init__ cases::
387
388      object.__init__ -> (self)
389      other unreflectable (usually C) -> (self, *args, **kwargs)
390
391    """
392    try:
393        return inspect.getargspec(method)
394    except TypeError:
395        if method is object.__init__:
396            return (['self'], None, None, None)
397        else:
398            return (['self'], 'args', 'kwargs', None)
399
400   
401def unbound_method_to_callable(func_or_cls):
402    """Adjust the incoming callable such that a 'self' argument is not required."""
403
404    if isinstance(func_or_cls, types.MethodType) and not func_or_cls.im_self:
405        return func_or_cls.im_func
406    else:
407        return func_or_cls
408
409def class_hierarchy(cls):
410    """Return an unordered sequence of all classes related to cls.
411
412    Traverses diamond hierarchies.
413
414    Fibs slightly: subclasses of builtin types are not returned.  Thus
415    class_hierarchy(class A(object)) returns (A, object), not A plus every
416    class systemwide that derives from object.
417
418    Old-style classes are discarded and hierarchies rooted on them
419    will not be descended.
420
421    """
422    if isinstance(cls, types.ClassType):
423        return list()
424    hier = set([cls])
425    process = list(cls.__mro__)
426    while process:
427        c = process.pop()
428        if isinstance(c, types.ClassType):
429            continue
430        for b in (_ for _ in c.__bases__
431                  if _ not in hier and not isinstance(_, types.ClassType)):
432            process.append(b)
433            hier.add(b)
434        if c.__module__ == '__builtin__' or not hasattr(c, '__subclasses__'):
435            continue
436        for s in [_ for _ in c.__subclasses__() if _ not in hier]:
437            process.append(s)
438            hier.add(s)
439    return list(hier)
440
441def iterate_attributes(cls):
442    """iterate all the keys and attributes associated with a class, without using getattr().
443
444    Does not use getattr() so that class-sensitive descriptors (i.e. property.__get__())
445    are not called.
446
447    """
448    keys = dir(cls)
449    for key in keys:
450        for c in cls.__mro__:
451            if key in c.__dict__:
452                yield (key, c.__dict__[key])
453                break
454
455# from paste.deploy.converters
456def asbool(obj):
457    if isinstance(obj, (str, unicode)):
458        obj = obj.strip().lower()
459        if obj in ['true', 'yes', 'on', 'y', 't', '1']:
460            return True
461        elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
462            return False
463        else:
464            raise ValueError("String is not true/false: %r" % obj)
465    return bool(obj)
466
467def coerce_kw_type(kw, key, type_, flexi_bool=True):
468    """If 'key' is present in dict 'kw', coerce its value to type 'type\_' if
469    necessary.  If 'flexi_bool' is True, the string '0' is considered false
470    when coercing to boolean.
471    """
472
473    if key in kw and type(kw[key]) is not type_ and kw[key] is not None:
474        if type_ is bool and flexi_bool:
475            kw[key] = asbool(kw[key])
476        else:
477            kw[key] = type_(kw[key])
478
479def duck_type_collection(specimen, default=None):
480    """Given an instance or class, guess if it is or is acting as one of
481    the basic collection types: list, set and dict.  If the __emulates__
482    property is present, return that preferentially.
483    """
484
485    if hasattr(specimen, '__emulates__'):
486        # canonicalize set vs sets.Set to a standard: the builtin set
487        if (specimen.__emulates__ is not None and
488            issubclass(specimen.__emulates__, set_types)):
489            return set
490        else:
491            return specimen.__emulates__
492
493    isa = isinstance(specimen, type) and issubclass or isinstance
494    if isa(specimen, list):
495        return list
496    elif isa(specimen, set_types):
497        return set
498    elif isa(specimen, dict):
499        return dict
500
501    if hasattr(specimen, 'append'):
502        return list
503    elif hasattr(specimen, 'add'):
504        return set
505    elif hasattr(specimen, 'set'):
506        return dict
507    else:
508        return default
509
510def dictlike_iteritems(dictlike):
511    """Return a (key, value) iterator for almost any dict-like object."""
512
513    if hasattr(dictlike, 'iteritems'):
514        return dictlike.iteritems()
515    elif hasattr(dictlike, 'items'):
516        return iter(dictlike.items())
517
518    getter = getattr(dictlike, '__getitem__', getattr(dictlike, 'get', None))
519    if getter is None:
520        raise TypeError(
521            "Object '%r' is not dict-like" % dictlike)
522
523    if hasattr(dictlike, 'iterkeys'):
524        def iterator():
525            for key in dictlike.iterkeys():
526                yield key, getter(key)
527        return iterator()
528    elif hasattr(dictlike, 'keys'):
529        return iter((key, getter(key)) for key in dictlike.keys())
530    else:
531        raise TypeError(
532            "Object '%r' is not dict-like" % dictlike)
533
534def assert_arg_type(arg, argtype, name):
535    if isinstance(arg, argtype):
536        return arg
537    else:
538        if isinstance(argtype, tuple):
539            raise exc.ArgumentError("Argument '%s' is expected to be one of type %s, got '%s'" % (name, ' or '.join("'%s'" % str(a) for a in argtype), str(type(arg))))
540        else:
541            raise exc.ArgumentError("Argument '%s' is expected to be of type '%s', got '%s'" % (name, str(argtype), str(type(arg))))
542
543_creation_order = 1
544def set_creation_order(instance):
545    """Assign a '_creation_order' sequence to the given instance.
546
547    This allows multiple instances to be sorted in order of creation
548    (typically within a single thread; the counter is not particularly
549    threadsafe).
550
551    """
552    global _creation_order
553    instance._creation_order = _creation_order
554    _creation_order +=1
555
556def warn_exception(func, *args, **kwargs):
557    """executes the given function, catches all exceptions and converts to a warning."""
558    try:
559        return func(*args, **kwargs)
560    except:
561        warn("%s('%s') ignored" % sys.exc_info()[0:2])
562
563def monkeypatch_proxied_specials(into_cls, from_cls, skip=None, only=None,
564                                 name='self.proxy', from_instance=None):
565    """Automates delegation of __specials__ for a proxying type."""
566
567    if only:
568        dunders = only
569    else:
570        if skip is None:
571            skip = ('__slots__', '__del__', '__getattribute__',
572                    '__metaclass__', '__getstate__', '__setstate__')
573        dunders = [m for m in dir(from_cls)
574                   if (m.startswith('__') and m.endswith('__') and
575                       not hasattr(into_cls, m) and m not in skip)]
576    for method in dunders:
577        try:
578            fn = getattr(from_cls, method)
579            if not hasattr(fn, '__call__'):
580                continue
581            fn = getattr(fn, 'im_func', fn)
582        except AttributeError:
583            continue
584        try:
585            spec = inspect.getargspec(fn)
586            fn_args = inspect.formatargspec(spec[0])
587            d_args = inspect.formatargspec(spec[0][1:])
588        except TypeError:
589            fn_args = '(self, *args, **kw)'
590            d_args = '(*args, **kw)'
591
592        py = ("def %(method)s%(fn_args)s: "
593              "return %(name)s.%(method)s%(d_args)s" % locals())
594
595        env = from_instance is not None and {name: from_instance} or {}
596        exec py in env
597        try:
598            env[method].func_defaults = fn.func_defaults
599        except AttributeError:
600            pass
601        setattr(into_cls, method, env[method])
602
603
604class OrderedProperties(object):
605    """An object that maintains the order in which attributes are set upon it.
606
607    Also provides an iterator and a very basic getitem/setitem
608    interface to those attributes.
609
610    (Not really a dict, since it iterates over values, not keys.  Not really
611    a list, either, since each value must have a key associated; hence there is
612    no append or extend.)
613    """
614
615    def __init__(self):
616        self.__dict__['_data'] = OrderedDict()
617
618    def __len__(self):
619        return len(self._data)
620
621    def __iter__(self):
622        return self._data.itervalues()
623
624    def __add__(self, other):
625        return list(self) + list(other)
626
627    def __setitem__(self, key, object):
628        self._data[key] = object
629
630    def __getitem__(self, key):
631        return self._data[key]
632
633    def __delitem__(self, key):
634        del self._data[key]
635
636    def __setattr__(self, key, object):
637        self._data[key] = object
638
639    def __getstate__(self):
640        return {'_data': self.__dict__['_data']}
641
642    def __setstate__(self, state):
643        self.__dict__['_data'] = state['_data']
644
645    def __getattr__(self, key):
646        try:
647            return self._data[key]
648        except KeyError:
649            raise AttributeError(key)
650
651    def __contains__(self, key):
652        return key in self._data
653
654    def update(self, value):
655        self._data.update(value)
656
657    def get(self, key, default=None):
658        if key in self:
659            return self[key]
660        else:
661            return default
662
663    def keys(self):
664        return self._data.keys()
665
666    def has_key(self, key):
667        return self._data.has_key(key)
668
669    def clear(self):
670        self._data.clear()
671
672
673class OrderedDict(dict):
674    """A dict that returns keys/values/items in the order they were added."""
675
676    def __init__(self, ____sequence=None, **kwargs):
677        self._list = []
678        if ____sequence is None:
679            if kwargs:
680                self.update(**kwargs)
681        else:
682            self.update(____sequence, **kwargs)
683
684    def clear(self):
685        self._list = []
686        dict.clear(self)
687
688    def copy(self):
689        return self.__copy__()
690
691    def __copy__(self):
692        return OrderedDict(self)
693
694    def sort(self, *arg, **kw):
695        self._list.sort(*arg, **kw)
696
697    def update(self, ____sequence=None, **kwargs):
698        if ____sequence is not None:
699            if hasattr(____sequence, 'keys'):
700                for key in ____sequence.keys():
701                    self.__setitem__(key, ____sequence[key])
702            else:
703                for key, value in ____sequence:
704                    self[key] = value
705        if kwargs:
706            self.update(kwargs)
707
708    def setdefault(self, key, value):
709        if key not in self:
710            self.__setitem__(key, value)
711            return value
712        else:
713            return self.__getitem__(key)
714
715    def __iter__(self):
716        return iter(self._list)
717
718    def values(self):
719        return [self[key] for key in self._list]
720
721    def itervalues(self):
722        return iter(self.values())
723
724    def keys(self):
725        return list(self._list)
726
727    def iterkeys(self):
728        return iter(self.keys())
729
730    def items(self):
731        return [(key, self[key]) for key in self.keys()]
732
733    def iteritems(self):
734        return iter(self.items())
735
736    def __setitem__(self, key, object):
737        if key not in self:
738            self._list.append(key)
739        dict.__setitem__(self, key, object)
740
741    def __delitem__(self, key):
742        dict.__delitem__(self, key)
743        self._list.remove(key)
744
745    def pop(self, key, *default):
746        present = key in self
747        value = dict.pop(self, key, *default)
748        if present:
749            self._list.remove(key)
750        return value
751
752    def popitem(self):
753        item = dict.popitem(self)
754        self._list.remove(item[0])
755        return item
756
757class OrderedSet(set):
758    def __init__(self, d=None):
759        set.__init__(self)
760        self._list = []
761        if d is not None:
762            self.update(d)
763
764    def add(self, element):
765        if element not in self:
766            self._list.append(element)
767        set.add(self, element)
768
769    def remove(self, element):
770        set.remove(self, element)
771        self._list.remove(element)
772
773    def insert(self, pos, element):
774        if element not in self:
775            self._list.insert(pos, element)
776        set.add(self, element)
777
778    def discard(self, element):
779        if element in self:
780            self._list.remove(element)
781            set.remove(self, element)
782
783    def clear(self):
784        set.clear(self)
785        self._list = []
786
787    def __getitem__(self, key):
788        return self._list[key]
789
790    def __iter__(self):
791        return iter(self._list)
792
793    def __repr__(self):
794        return '%s(%r)' % (self.__class__.__name__, self._list)
795
796    __str__ = __repr__
797
798    def update(self, iterable):
799        add = self.add
800        for i in iterable:
801            add(i)
802        return self
803
804    __ior__ = update
805
806    def union(self, other):
807        result = self.__class__(self)
808        result.update(other)
809        return result
810
811    __or__ = union
812
813    def intersection(self, other):
814        other = set(other)
815        return self.__class__(a for a in self if a in other)
816
817    __and__ = intersection
818
819    def symmetric_difference(self, other):
820        other = set(other)
821        result = self.__class__(a for a in self if a not in other)
822        result.update(a for a in other if a not in self)
823        return result
824
825    __xor__ = symmetric_difference
826
827    def difference(self, other):
828        other = set(other)
829        return self.__class__(a for a in self if a not in other)
830
831    __sub__ = difference
832
833    def intersection_update(self, other):
834        other = set(other)
835        set.intersection_update(self, other)
836        self._list = [ a for a in self._list if a in other]
837        return self
838
839    __iand__ = intersection_update
840
841    def symmetric_difference_update(self, other):
842        set.symmetric_difference_update(self, other)
843        self._list =  [ a for a in self._list if a in self]
844        self._list += [ a for a in other._list if a in self]
845        return self
846
847    __ixor__ = symmetric_difference_update
848
849    def difference_update(self, other):
850        set.difference_update(self, other)
851        self._list = [ a for a in self._list if a in self]
852        return self
853
854    __isub__ = difference_update
855
856
857class IdentitySet(object):
858    """A set that considers only object id() for uniqueness.
859
860    This strategy has edge cases for builtin types- it's possible to have
861    two 'foo' strings in one of these sets, for example.  Use sparingly.
862   
863    """
864
865    _working_set = set
866   
867    def __init__(self, iterable=None):
868        self._members = dict()
869        if iterable:
870            for o in iterable:
871                self.add(o)
872
873    def add(self, value):
874        self._members[id(value)] = value
875
876    def __contains__(self, value):
877        return id(value) in self._members
878
879    def remove(self, value):
880        del self._members[id(value)]
881
882    def discard(self, value):
883        try:
884            self.remove(value)
885        except KeyError:
886            pass
887
888    def pop(self):
889        try:
890            pair = self._members.popitem()
891            return pair[1]
892        except KeyError:
893            raise KeyError('pop from an empty set')
894
895    def clear(self):
896        self._members.clear()
897
898    def __cmp__(self, other):
899        raise TypeError('cannot compare sets using cmp()')
900
901    def __eq__(self, other):
902        if isinstance(other, IdentitySet):
903            return self._members == other._members
904        else:
905            return False
906
907    def __ne__(self, other):
908        if isinstance(other, IdentitySet):
909            return self._members != other._members
910        else:
911            return True
912
913    def issubset(self, iterable):
914        other = type(self)(iterable)
915
916        if len(self) > len(other):
917            return False
918        for m in itertools.ifilterfalse(other._members.has_key,
919                                        self._members.iterkeys()):
920            return False
921        return True
922
923    def __le__(self, other):
924        if not isinstance(other, IdentitySet):
925            return NotImplemented
926        return self.issubset(other)
927
928    def __lt__(self, other):
929        if not isinstance(other, IdentitySet):
930            return NotImplemented
931        return len(self) < len(other) and self.issubset(other)
932
933    def issuperset(self, iterable):
934        other = type(self)(iterable)
935
936        if len(self) < len(other):
937            return False
938
939        for m in itertools.ifilterfalse(self._members.has_key,
940                                        other._members.iterkeys()):
941            return False
942        return True
943
944    def __ge__(self, other):
945        if not isinstance(other, IdentitySet):
946            return NotImplemented
947        return self.issuperset(other)
948
949    def __gt__(self, other):
950        if not isinstance(other, IdentitySet):
951            return NotImplemented
952        return len(self) > len(other) and self.issuperset(other)
953
954    def union(self, iterable):
955        result = type(self)()
956        # testlib.pragma exempt:__hash__
957        result._members.update(
958            self._working_set(self._member_id_tuples()).union(_iter_id(iterable)))
959        return result
960
961    def __or__(self, other):
962        if not isinstance(other, IdentitySet):
963            return NotImplemented
964        return self.union(other)
965
966    def update(self, iterable):
967        self._members = self.union(iterable)._members
968
969    def __ior__(self, other):
970        if not isinstance(other, IdentitySet):
971            return NotImplemented
972        self.update(other)
973        return self
974
975    def difference(self, iterable):
976        result = type(self)()
977        # testlib.pragma exempt:__hash__
978        result._members.update(
979            self._working_set(self._member_id_tuples()).difference(_iter_id(iterable)))
980        return result
981
982    def __sub__(self, other):
983        if not isinstance(other, IdentitySet):
984            return NotImplemented
985        return self.difference(other)
986
987    def difference_update(self, iterable):
988        self._members = self.difference(iterable)._members
989
990    def __isub__(self, other):
991        if not isinstance(other, IdentitySet):
992            return NotImplemented
993        self.difference_update(other)
994        return self
995
996    def intersection(self, iterable):
997        result = type(self)()
998        # testlib.pragma exempt:__hash__
999        result._members.update(
1000            self._working_set(self._member_id_tuples()).intersection(_iter_id(iterable)))
1001        return result
1002
1003    def __and__(self, other):
1004        if not isinstance(other, IdentitySet):
1005            return NotImplemented
1006        return self.intersection(other)
1007
1008    def intersection_update(self, iterable):
1009        self._members = self.intersection(iterable)._members
1010
1011    def __iand__(self, other):
1012        if not isinstance(other, IdentitySet):
1013            return NotImplemented
1014        self.intersection_update(other)
1015        return self
1016
1017    def symmetric_difference(self, iterable):
1018        result = type(self)()
1019        # testlib.pragma exempt:__hash__
1020        result._members.update(
1021            self._working_set(self._member_id_tuples()).symmetric_difference(_iter_id(iterable)))
1022        return result
1023   
1024    def _member_id_tuples(self):
1025        return ((id(v), v) for v in self._members.itervalues())
1026       
1027    def __xor__(self, other):
1028        if not isinstance(other, IdentitySet):
1029            return NotImplemented
1030        return self.symmetric_difference(other)
1031
1032    def symmetric_difference_update(self, iterable):
1033        self._members = self.symmetric_difference(iterable)._members
1034
1035    def __ixor__(self, other):
1036        if not isinstance(other, IdentitySet):
1037            return NotImplemented
1038        self.symmetric_difference(other)
1039        return self
1040
1041    def copy(self):
1042        return type(self)(self._members.itervalues())
1043
1044    __copy__ = copy
1045
1046    def __len__(self):
1047        return len(self._members)
1048
1049    def __iter__(self):
1050        return self._members.itervalues()
1051
1052    def __hash__(self):
1053        raise TypeError('set objects are unhashable')
1054
1055    def __repr__(self):
1056        return '%s(%r)' % (type(self).__name__, self._members.values())
1057
1058
1059class OrderedIdentitySet(IdentitySet):
1060    class _working_set(OrderedSet):
1061        # a testing pragma: exempt the OIDS working set from the test suite's
1062        # "never call the user's __hash__" assertions.  this is a big hammer,
1063        # but it's safe here: IDS operates on (id, instance) tuples in the
1064        # working set.
1065        __sa_hash_exempt__ = True
1066   
1067    def __init__(self, iterable=None):
1068        IdentitySet.__init__(self)
1069        self._members = OrderedDict()
1070        if iterable:
1071            for o in iterable:
1072                self.add(o)
1073
1074def _iter_id(iterable):
1075    """Generator: ((id(o), o) for o in iterable)."""
1076
1077    for item in iterable:
1078        yield id(item), item
1079
1080# define collections that are capable of storing
1081# ColumnElement objects as hashable keys/elements.
1082column_set = set
1083column_dict = dict
1084ordered_column_set = OrderedSet
1085populate_column_dict = PopulateDict
1086
1087def unique_list(seq, compare_with=set):
1088    seen = compare_with()
1089    return [x for x in seq if x not in seen and not seen.add(x)]   
1090
1091class UniqueAppender(object):
1092    """Appends items to a collection ensuring uniqueness.
1093
1094    Additional appends() of the same object are ignored.  Membership is
1095    determined by identity (``is a``) not equality (``==``).
1096    """
1097
1098    def __init__(self, data, via=None):
1099        self.data = data
1100        self._unique = IdentitySet()
1101        if via:
1102            self._data_appender = getattr(data, via)
1103        elif hasattr(data, 'append'):
1104            self._data_appender = data.append
1105        elif hasattr(data, 'add'):
1106            # TODO: we think its a set here.  bypass unneeded uniquing logic ?
1107            self._data_appender = data.add
1108
1109    def append(self, item):
1110        if item not in self._unique:
1111            self._data_appender(item)
1112            self._unique.add(item)
1113
1114    def __iter__(self):
1115        return iter(self.data)
1116
1117
1118class ScopedRegistry(object):
1119    """A Registry that can store one or multiple instances of a single
1120    class on a per-thread scoped basis, or on a customized scope.
1121
1122    createfunc
1123      a callable that returns a new object to be placed in the registry
1124
1125    scopefunc
1126      a callable that will return a key to store/retrieve an object.
1127    """
1128
1129    def __init__(self, createfunc, scopefunc):
1130        self.createfunc = createfunc
1131        self.scopefunc = scopefunc
1132        self.registry = {}
1133
1134    def __call__(self):
1135        key = self.scopefunc()
1136        try:
1137            return self.registry[key]
1138        except KeyError:
1139            return self.registry.setdefault(key, self.createfunc())
1140
1141    def has(self):
1142        return self.scopefunc() in self.registry
1143
1144    def set(self, obj):
1145        self.registry[self.scopefunc()] = obj
1146
1147    def clear(self):
1148        try:
1149            del self.registry[self.scopefunc()]
1150        except KeyError:
1151            pass
1152
1153class ThreadLocalRegistry(ScopedRegistry):
1154    def __init__(self, createfunc):
1155        self.createfunc = createfunc
1156        self.registry = threading.local()
1157
1158    def __call__(self):
1159        try:
1160            return self.registry.value
1161        except AttributeError:
1162            val = self.registry.value = self.createfunc()
1163            return val
1164
1165    def has(self):
1166        return hasattr(self.registry, "value")
1167
1168    def set(self, obj):
1169        self.registry.value = obj
1170
1171    def clear(self):
1172        try:
1173            del self.registry.value
1174        except AttributeError:
1175            pass
1176
1177class _symbol(object):
1178    def __init__(self, name):
1179        """Construct a new named symbol."""
1180        assert isinstance(name, str)
1181        self.name = name
1182    def __reduce__(self):
1183        return symbol, (self.name,)
1184    def __repr__(self):
1185        return "<symbol '%s>" % self.name
1186_symbol.__name__ = 'symbol'
1187
1188
1189class symbol(object):
1190    """A constant symbol.
1191
1192    >>> symbol('foo') is symbol('foo')
1193    True
1194    >>> symbol('foo')
1195    <symbol 'foo>
1196
1197    A slight refinement of the MAGICCOOKIE=object() pattern.  The primary
1198    advantage of symbol() is its repr().  They are also singletons.
1199
1200    Repeated calls of symbol('name') will all return the same instance.
1201
1202    """
1203    symbols = {}
1204    _lock = threading.Lock()
1205
1206    def __new__(cls, name):
1207        cls._lock.acquire()
1208        try:
1209            sym = cls.symbols.get(name)
1210            if sym is None:
1211                cls.symbols[name] = sym = _symbol(name)
1212            return sym
1213        finally:
1214            symbol._lock.release()
1215
1216
1217def as_interface(obj, cls=None, methods=None, required=None):
1218    """Ensure basic interface compliance for an instance or dict of callables.
1219
1220    Checks that ``obj`` implements public methods of ``cls`` or has members
1221    listed in ``methods``.  If ``required`` is not supplied, implementing at
1222    least one interface method is sufficient.  Methods present on ``obj`` that
1223    are not in the interface are ignored.
1224
1225    If ``obj`` is a dict and ``dict`` does not meet the interface
1226    requirements, the keys of the dictionary are inspected. Keys present in
1227    ``obj`` that are not in the interface will raise TypeErrors.
1228
1229    Raises TypeError if ``obj`` does not meet the interface criteria.
1230
1231    In all passing cases, an object with callable members is returned.  In the
1232    simple case, ``obj`` is returned as-is; if dict processing kicks in then
1233    an anonymous class is returned.
1234
1235    obj
1236      A type, instance, or dictionary of callables.
1237    cls
1238      Optional, a type.  All public methods of cls are considered the
1239      interface.  An ``obj`` instance of cls will always pass, ignoring
1240      ``required``..
1241    methods
1242      Optional, a sequence of method names to consider as the interface.
1243    required
1244      Optional, a sequence of mandatory implementations. If omitted, an
1245      ``obj`` that provides at least one interface method is considered
1246      sufficient.  As a convenience, required may be a type, in which case
1247      all public methods of the type are required.
1248
1249    """
1250    if not cls and not methods:
1251        raise TypeError('a class or collection of method names are required')
1252
1253    if isinstance(cls, type) and isinstance(obj, cls):
1254        return obj
1255
1256    interface = set(methods or [m for m in dir(cls) if not m.startswith('_')])
1257    implemented = set(dir(obj))
1258
1259    complies = operator.ge
1260    if isinstance(required, type):
1261        required = interface
1262    elif not required:
1263        required = set()
1264        complies = operator.gt
1265    else:
1266        required = set(required)
1267
1268    if complies(implemented.intersection(interface), required):
1269        return obj
1270
1271    # No dict duck typing here.
1272    if not type(obj) is dict:
1273        qualifier = complies is operator.gt and 'any of' or 'all of'
1274        raise TypeError("%r does not implement %s: %s" % (
1275            obj, qualifier, ', '.join(interface)))
1276
1277    class AnonymousInterface(object):
1278        """A callable-holding shell."""
1279
1280    if cls:
1281        AnonymousInterface.__name__ = 'Anonymous' + cls.__name__
1282    found = set()
1283
1284    for method, impl in dictlike_iteritems(obj):
1285        if method not in interface:
1286            raise TypeError("%r: unknown in this interface" % method)
1287        if not callable(impl):
1288            raise TypeError("%r=%r is not callable" % (method, impl))
1289        setattr(AnonymousInterface, method, staticmethod(impl))
1290        found.add(method)
1291
1292    if complies(found, required):
1293        return AnonymousInterface
1294
1295    raise TypeError("dictionary does not contain required keys %s" %
1296                    ', '.join(required - found))
1297
1298def function_named(fn, name):
1299    """Return a function with a given __name__.
1300
1301    Will assign to __name__ and return the original function if possible on
1302    the Python implementation, otherwise a new function will be constructed.
1303
1304    """
1305    try:
1306        fn.__name__ = name
1307    except TypeError:
1308        fn = types.FunctionType(fn.func_code, fn.func_globals, name,
1309                          fn.func_defaults, fn.func_closure)
1310    return fn
1311
1312class memoized_property(object):
1313    """A read-only @property that is only evaluated once."""
1314    def __init__(self, fget, doc=None):
1315        self.fget = fget
1316        self.__doc__ = doc or fget.__doc__
1317        self.__name__ = fget.__name__
1318
1319    def __get__(self, obj, cls):
1320        if obj is None:
1321            return None
1322        obj.__dict__[self.__name__] = result = self.fget(obj)
1323        return result
1324
1325
1326class memoized_instancemethod(object):
1327    """Decorate a method memoize its return value.
1328
1329    Best applied to no-arg methods: memoization is not sensitive to
1330    argument values, and will always return the same value even when
1331    called with different arguments.
1332
1333    """
1334    def __init__(self, fget, doc=None):
1335        self.fget = fget
1336        self.__doc__ = doc or fget.__doc__
1337        self.__name__ = fget.__name__
1338
1339    def __get__(self, obj, cls):
1340        if obj is None:
1341            return None
1342        def oneshot(*args, **kw):
1343            result = self.fget(obj, *args, **kw)
1344            memo = lambda *a, **kw: result
1345            memo.__name__ = self.__name__
1346            memo.__doc__ = self.__doc__
1347            obj.__dict__[self.__name__] = memo
1348            return result
1349        oneshot.__name__ = self.__name__
1350        oneshot.__doc__ = self.__doc__
1351        return oneshot
1352
1353def reset_memoized(instance, name):
1354    instance.__dict__.pop(name, None)
1355
1356class WeakIdentityMapping(weakref.WeakKeyDictionary):
1357    """A WeakKeyDictionary with an object identity index.
1358
1359    Adds a .by_id dictionary to a regular WeakKeyDictionary.  Trades
1360    performance during mutation operations for accelerated lookups by id().
1361
1362    The usual cautions about weak dictionaries and iteration also apply to
1363    this subclass.
1364
1365    """
1366    _none = symbol('none')
1367
1368    def __init__(self):
1369        weakref.WeakKeyDictionary.__init__(self)
1370        self.by_id = {}
1371        self._weakrefs = {}
1372
1373    def __setitem__(self, object, value):
1374        oid = id(object)
1375        self.by_id[oid] = value
1376        if oid not in self._weakrefs:
1377            self._weakrefs[oid] = self._ref(object)
1378        weakref.WeakKeyDictionary.__setitem__(self, object, value)
1379
1380    def __delitem__(self, object):
1381        del self._weakrefs[id(object)]
1382        del self.by_id[id(object)]
1383        weakref.WeakKeyDictionary.__delitem__(self, object)
1384
1385    def setdefault(self, object, default=None):
1386        value = weakref.WeakKeyDictionary.setdefault(self, object, default)
1387        oid = id(object)
1388        if value is default:
1389            self.by_id[oid] = default
1390        if oid not in self._weakrefs:
1391            self._weakrefs[oid] = self._ref(object)
1392        return value
1393
1394    def pop(self, object, default=_none):
1395        if default is self._none:
1396            value = weakref.WeakKeyDictionary.pop(self, object)
1397        else:
1398            value = weakref.WeakKeyDictionary.pop(self, object, default)
1399        if id(object) in self.by_id:
1400            del self._weakrefs[id(object)]
1401            del self.by_id[id(object)]
1402        return value
1403
1404    def popitem(self):
1405        item = weakref.WeakKeyDictionary.popitem(self)
1406        oid = id(item[0])
1407        del self._weakrefs[oid]
1408        del self.by_id[oid]
1409        return item
1410
1411    def clear(self):
1412        self._weakrefs.clear()
1413        self.by_id.clear()
1414        weakref.WeakKeyDictionary.clear(self)
1415
1416    def update(self, *a, **kw):
1417        raise NotImplementedError
1418
1419    def _cleanup(self, wr, key=None):
1420        if key is None:
1421            key = wr.key
1422        try:
1423            del self._weakrefs[key]
1424        except (KeyError, AttributeError):  # pragma: no cover
1425            pass                            # pragma: no cover
1426        try:
1427            del self.by_id[key]
1428        except (KeyError, AttributeError):  # pragma: no cover
1429            pass                            # pragma: no cover
1430           
1431    class _keyed_weakref(weakref.ref):
1432        def __init__(self, object, callback):
1433            weakref.ref.__init__(self, object, callback)
1434            self.key = id(object)
1435
1436    def _ref(self, object):
1437        return self._keyed_weakref(object, self._cleanup)
1438
1439
1440def warn(msg):
1441    if isinstance(msg, basestring):
1442        warnings.warn(msg, exc.SAWarning, stacklevel=3)
1443    else:
1444        warnings.warn(msg, stacklevel=3)
1445
1446def warn_deprecated(msg):
1447    warnings.warn(msg, exc.SADeprecationWarning, stacklevel=3)
1448
1449def warn_pending_deprecation(msg):
1450    warnings.warn(msg, exc.SAPendingDeprecationWarning, stacklevel=3)
1451
1452def deprecated(message=None, add_deprecation_to_docstring=True):
1453    """Decorates a function and issues a deprecation warning on use.
1454
1455    message
1456      If provided, issue message in the warning.  A sensible default
1457      is used if not provided.
1458
1459    add_deprecation_to_docstring
1460      Default True.  If False, the wrapped function's __doc__ is left
1461      as-is.  If True, the 'message' is prepended to the docs if
1462      provided, or sensible default if message is omitted.
1463    """
1464
1465    if add_deprecation_to_docstring:
1466        header = message is not None and message or 'Deprecated.'
1467    else:
1468        header = None
1469
1470    if message is None:
1471        message = "Call to deprecated function %(func)s"
1472
1473    def decorate(fn):
1474        return _decorate_with_warning(
1475            fn, exc.SADeprecationWarning,
1476            message % dict(func=fn.__name__), header)
1477    return decorate
1478
1479def pending_deprecation(version, message=None,
1480                        add_deprecation_to_docstring=True):
1481    """Decorates a function and issues a pending deprecation warning on use.
1482
1483    version
1484      An approximate future version at which point the pending deprecation
1485      will become deprecated.  Not used in messaging.
1486
1487    message
1488      If provided, issue message in the warning.  A sensible default
1489      is used if not provided.
1490
1491    add_deprecation_to_docstring
1492      Default True.  If False, the wrapped function's __doc__ is left
1493      as-is.  If True, the 'message' is prepended to the docs if
1494      provided, or sensible default if message is omitted.
1495    """
1496
1497    if add_deprecation_to_docstring:
1498        header = message is not None and message or 'Deprecated.'
1499    else:
1500        header = None
1501
1502    if message is None:
1503        message = "Call to deprecated function %(func)s"
1504
1505    def decorate(fn):
1506        return _decorate_with_warning(
1507            fn, exc.SAPendingDeprecationWarning,
1508            message % dict(func=fn.__name__), header)
1509    return decorate
1510
1511def _decorate_with_warning(func, wtype, message, docstring_header=None):
1512    """Wrap a function with a warnings.warn and augmented docstring."""
1513
1514    @decorator
1515    def warned(fn, *args, **kwargs):
1516        warnings.warn(wtype(message), stacklevel=3)
1517        return fn(*args, **kwargs)
1518
1519    doc = func.__doc__ is not None and func.__doc__ or ''
1520    if docstring_header is not None:
1521        docstring_header %= dict(func=func.__name__)
1522        docs = doc and doc.expandtabs().split('\n') or []
1523        indent = ''
1524        for line in docs[1:]:
1525            text = line.lstrip()
1526            if text:
1527                indent = line[0:len(line) - len(text)]
1528                break
1529        point = min(len(docs), 1)
1530        docs.insert(point, '\n' + indent + docstring_header.rstrip())
1531        doc = '\n'.join(docs)
1532
1533    decorated = warned(func)
1534    decorated.__doc__ = doc
1535    return decorated
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。