18
from compat import update_wrapper, set_types, threading
18
from compat import update_wrapper, set_types, threading, callable, inspect_getfullargspec, py3k
19
19
from sqlalchemy import exc
21
21
def _unique_symbols(used, *bases):
39
39
if not inspect.isfunction(fn):
40
40
raise Exception("not a decoratable function")
41
spec = inspect.getargspec(fn)
41
spec = inspect_getfullargspec(fn)
42
42
names = tuple(spec[0]) + spec[1:3] + (fn.func_name,)
43
43
targ_name, fn_name = _unique_symbols(names, 'target', 'fn')
149
149
'apply_pos': '(self, a, b, c, **d)'}
152
spec = callable(fn) and inspect.getargspec(fn) or fn
153
spec = inspect_getfullargspec(fn)
155
# we accept an existing argspec...
153
157
args = inspect.formatargspec(*spec)
155
159
self_arg = spec[0][0]
157
161
self_arg = '%s[0]' % spec[1]
160
apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2])
161
defaulted_vals = spec[3] is not None and spec[0][0-len(spec[3]):] or ()
162
apply_kw = inspect.formatargspec(spec[0], spec[1], spec[2], defaulted_vals,
166
apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2], None, spec[4])
169
num_defaults += len(spec[3])
171
num_defaults += len(spec[4])
172
name_args = spec[0] + spec[4]
174
apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2])
177
num_defaults += len(spec[3])
181
defaulted_vals = name_args[0-num_defaults:]
185
apply_kw = inspect.formatargspec(name_args, spec[1], spec[2], defaulted_vals,
163
186
formatvalue=lambda x: '=' + x)
165
188
return dict(args=args, self_arg=self_arg,
237
260
for arg in args[1:-default_len]:
238
261
yield repr(getattr(obj, arg, None))
239
262
for (arg, defval) in zip(args[-default_len:], defaults):
240
val = getattr(obj, arg, None)
242
yield '%s=%r' % (arg, val)
264
val = getattr(obj, arg, None)
266
yield '%s=%r' % (arg, val)
243
269
return "%s(%s)" % (obj.__class__.__name__, ", ".join(genargs()))
245
271
class portable_instancemethod(object):
493
519
class group_expirable_memoized_property(object):
494
520
"""A family of @memoized_properties that can be expired in tandem."""
522
def __init__(self, attributes=()):
497
523
self.attributes = []
525
self.attributes.extend(attributes)
499
527
def expire_instance(self, instance):
500
528
"""Expire all memoized properties for *instance*."""
506
534
self.attributes.append(fn.__name__)
507
535
return memoized_property(fn)
537
def method(self, fn):
538
self.attributes.append(fn.__name__)
539
return memoized_instancemethod(fn)
509
541
class importlater(object):
510
542
"""Deferred import object.
518
550
from mypackage.somemodule import somesubmod
520
552
except evaluted upon attribute access to "somesubmod".
554
importlater() currently requires that resolve_all() be
555
called, typically at the bottom of a package's __init__.py.
556
This is so that __import__ still called only at
557
module import time, and not potentially within
558
a non-main thread later on.
523
564
def __init__(self, path, addtl=None):
524
565
self._il_path = path
525
566
self._il_addtl = addtl
567
importlater._unresolved.add(self)
570
def resolve_all(cls):
571
for m in list(importlater._unresolved):
575
def _full_path(self):
577
return self._il_path + "." + self._il_addtl
527
581
@memoized_property
528
582
def module(self):
583
if self in importlater._unresolved:
585
"importlater.resolve_all() hasn't been called")
587
m = self._initial_import
529
588
if self._il_addtl:
530
m = __import__(self._il_path, globals(), locals(),
533
return getattr(m, self._il_addtl)
534
except AttributeError:
536
"Module %s has no attribute '%s'" %
537
(self._il_path, self._il_addtl)
589
m = getattr(m, self._il_addtl)
540
m = __import__(self._il_path)
541
591
for token in self._il_path.split(".")[1:]:
542
592
m = getattr(m, token)
596
importlater._unresolved.discard(self)
598
self._initial_import = __import__(
599
self._il_path, globals(), locals(),
602
self._initial_import = __import__(self._il_path)
545
604
def __getattr__(self, key):
606
raise ImportError("Could not resolve module %s"
547
609
attr = getattr(self.module, key)
548
610
except AttributeError:
549
611
raise AttributeError(
550
612
"Module %s has no attribute '%s'" %
613
(self._full_path, key)
553
615
self.__dict__[key] = attr
676
"""Return a threadsafe counter function."""
678
lock = threading.Lock()
679
counter = itertools.count(1L)
681
# avoid the 2to3 "next" transformation...
685
return counter.next()
613
691
def duck_type_collection(specimen, default=None):
614
692
"""Given an instance or class, guess if it is or is acting as one of
615
693
the basic collection types: list, set and dict. If the __emulates__