You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1942 lines
55KB

  1. # util/langhelpers.py
  2. # Copyright (C) 2005-2021 the SQLAlchemy authors and contributors
  3. # <see AUTHORS file>
  4. #
  5. # This module is part of SQLAlchemy and is released under
  6. # the MIT License: http://www.opensource.org/licenses/mit-license.php
  7. """Routines to help with the creation, loading and introspection of
  8. modules, classes, hierarchies, attributes, functions, and methods.
  9. """
  10. import collections
  11. from functools import update_wrapper
  12. import hashlib
  13. import inspect
  14. import itertools
  15. import operator
  16. import re
  17. import sys
  18. import textwrap
  19. import types
  20. import warnings
  21. from . import _collections
  22. from . import compat
  23. from .. import exc
  24. def md5_hex(x):
  25. if compat.py3k:
  26. x = x.encode("utf-8")
  27. m = hashlib.md5()
  28. m.update(x)
  29. return m.hexdigest()
  30. class safe_reraise(object):
  31. """Reraise an exception after invoking some
  32. handler code.
  33. Stores the existing exception info before
  34. invoking so that it is maintained across a potential
  35. coroutine context switch.
  36. e.g.::
  37. try:
  38. sess.commit()
  39. except:
  40. with safe_reraise():
  41. sess.rollback()
  42. """
  43. __slots__ = ("warn_only", "_exc_info")
  44. def __init__(self, warn_only=False):
  45. self.warn_only = warn_only
  46. def __enter__(self):
  47. self._exc_info = sys.exc_info()
  48. def __exit__(self, type_, value, traceback):
  49. # see #2703 for notes
  50. if type_ is None:
  51. exc_type, exc_value, exc_tb = self._exc_info
  52. self._exc_info = None # remove potential circular references
  53. if not self.warn_only:
  54. compat.raise_(
  55. exc_value,
  56. with_traceback=exc_tb,
  57. )
  58. else:
  59. if not compat.py3k and self._exc_info and self._exc_info[1]:
  60. # emulate Py3K's behavior of telling us when an exception
  61. # occurs in an exception handler.
  62. warn(
  63. "An exception has occurred during handling of a "
  64. "previous exception. The previous exception "
  65. "is:\n %s %s\n" % (self._exc_info[0], self._exc_info[1])
  66. )
  67. self._exc_info = None # remove potential circular references
  68. compat.raise_(value, with_traceback=traceback)
  69. def walk_subclasses(cls):
  70. seen = set()
  71. stack = [cls]
  72. while stack:
  73. cls = stack.pop()
  74. if cls in seen:
  75. continue
  76. else:
  77. seen.add(cls)
  78. stack.extend(cls.__subclasses__())
  79. yield cls
  80. def string_or_unprintable(element):
  81. if isinstance(element, compat.string_types):
  82. return element
  83. else:
  84. try:
  85. return str(element)
  86. except Exception:
  87. return "unprintable element %r" % element
  88. def clsname_as_plain_name(cls):
  89. return " ".join(
  90. n.lower() for n in re.findall(r"([A-Z][a-z]+)", cls.__name__)
  91. )
  92. def method_is_overridden(instance_or_cls, against_method):
  93. """Return True if the two class methods don't match."""
  94. if not isinstance(instance_or_cls, type):
  95. current_cls = instance_or_cls.__class__
  96. else:
  97. current_cls = instance_or_cls
  98. method_name = against_method.__name__
  99. current_method = getattr(current_cls, method_name)
  100. return current_method != against_method
  101. def decode_slice(slc):
  102. """decode a slice object as sent to __getitem__.
  103. takes into account the 2.5 __index__() method, basically.
  104. """
  105. ret = []
  106. for x in slc.start, slc.stop, slc.step:
  107. if hasattr(x, "__index__"):
  108. x = x.__index__()
  109. ret.append(x)
  110. return tuple(ret)
  111. def _unique_symbols(used, *bases):
  112. used = set(used)
  113. for base in bases:
  114. pool = itertools.chain(
  115. (base,),
  116. compat.itertools_imap(lambda i: base + str(i), range(1000)),
  117. )
  118. for sym in pool:
  119. if sym not in used:
  120. used.add(sym)
  121. yield sym
  122. break
  123. else:
  124. raise NameError("exhausted namespace for symbol base %s" % base)
  125. def map_bits(fn, n):
  126. """Call the given function given each nonzero bit from n."""
  127. while n:
  128. b = n & (~n + 1)
  129. yield fn(b)
  130. n ^= b
  131. def decorator(target):
  132. """A signature-matching decorator factory."""
  133. def decorate(fn):
  134. if not inspect.isfunction(fn) and not inspect.ismethod(fn):
  135. raise Exception("not a decoratable function")
  136. spec = compat.inspect_getfullargspec(fn)
  137. env = {}
  138. spec = _update_argspec_defaults_into_env(spec, env)
  139. names = tuple(spec[0]) + spec[1:3] + (fn.__name__,)
  140. targ_name, fn_name = _unique_symbols(names, "target", "fn")
  141. metadata = dict(target=targ_name, fn=fn_name)
  142. metadata.update(format_argspec_plus(spec, grouped=False))
  143. metadata["name"] = fn.__name__
  144. code = (
  145. """\
  146. def %(name)s(%(args)s):
  147. return %(target)s(%(fn)s, %(apply_kw)s)
  148. """
  149. % metadata
  150. )
  151. env.update({targ_name: target, fn_name: fn, "__name__": fn.__module__})
  152. decorated = _exec_code_in_env(code, env, fn.__name__)
  153. decorated.__defaults__ = getattr(fn, "__func__", fn).__defaults__
  154. decorated.__wrapped__ = fn
  155. return update_wrapper(decorated, fn)
  156. return update_wrapper(decorate, target)
  157. def _update_argspec_defaults_into_env(spec, env):
  158. """given a FullArgSpec, convert defaults to be symbol names in an env."""
  159. if spec.defaults:
  160. new_defaults = []
  161. i = 0
  162. for arg in spec.defaults:
  163. if type(arg).__module__ not in ("builtins", "__builtin__"):
  164. name = "x%d" % i
  165. env[name] = arg
  166. new_defaults.append(name)
  167. i += 1
  168. else:
  169. new_defaults.append(arg)
  170. elem = list(spec)
  171. elem[3] = tuple(new_defaults)
  172. return compat.FullArgSpec(*elem)
  173. else:
  174. return spec
  175. def _exec_code_in_env(code, env, fn_name):
  176. exec(code, env)
  177. return env[fn_name]
  178. def public_factory(target, location, class_location=None):
  179. """Produce a wrapping function for the given cls or classmethod.
  180. Rationale here is so that the __init__ method of the
  181. class can serve as documentation for the function.
  182. """
  183. if isinstance(target, type):
  184. fn = target.__init__
  185. callable_ = target
  186. doc = (
  187. "Construct a new :class:`%s` object. \n\n"
  188. "This constructor is mirrored as a public API function; "
  189. "see :func:`sqlalchemy%s` "
  190. "for a full usage and argument description."
  191. % (
  192. class_location if class_location else ".%s" % target.__name__,
  193. location,
  194. )
  195. )
  196. else:
  197. fn = callable_ = target
  198. doc = (
  199. "This function is mirrored; see :func:`sqlalchemy%s` "
  200. "for a description of arguments." % location
  201. )
  202. location_name = location.split(".")[-1]
  203. spec = compat.inspect_getfullargspec(fn)
  204. del spec[0][0]
  205. metadata = format_argspec_plus(spec, grouped=False)
  206. metadata["name"] = location_name
  207. code = (
  208. """\
  209. def %(name)s(%(args)s):
  210. return cls(%(apply_kw)s)
  211. """
  212. % metadata
  213. )
  214. env = {
  215. "cls": callable_,
  216. "symbol": symbol,
  217. "__name__": callable_.__module__,
  218. }
  219. exec(code, env)
  220. decorated = env[location_name]
  221. if hasattr(fn, "_linked_to"):
  222. linked_to, linked_to_location = fn._linked_to
  223. linked_to_doc = linked_to.__doc__
  224. if class_location is None:
  225. class_location = "%s.%s" % (target.__module__, target.__name__)
  226. linked_to_doc = inject_docstring_text(
  227. linked_to_doc,
  228. ".. container:: inherited_member\n\n "
  229. "This documentation is inherited from :func:`sqlalchemy%s`; "
  230. "this constructor, :func:`sqlalchemy%s`, "
  231. "creates a :class:`sqlalchemy%s` object. See that class for "
  232. "additional details describing this subclass."
  233. % (linked_to_location, location, class_location),
  234. 1,
  235. )
  236. decorated.__doc__ = linked_to_doc
  237. else:
  238. decorated.__doc__ = fn.__doc__
  239. decorated.__module__ = "sqlalchemy" + location.rsplit(".", 1)[0]
  240. if decorated.__module__ not in sys.modules:
  241. raise ImportError(
  242. "public_factory location %s is not in sys.modules"
  243. % (decorated.__module__,)
  244. )
  245. if compat.py2k or hasattr(fn, "__func__"):
  246. fn.__func__.__doc__ = doc
  247. if not hasattr(fn.__func__, "_linked_to"):
  248. fn.__func__._linked_to = (decorated, location)
  249. else:
  250. fn.__doc__ = doc
  251. if not hasattr(fn, "_linked_to"):
  252. fn._linked_to = (decorated, location)
  253. return decorated
  254. class PluginLoader(object):
  255. def __init__(self, group, auto_fn=None):
  256. self.group = group
  257. self.impls = {}
  258. self.auto_fn = auto_fn
  259. def clear(self):
  260. self.impls.clear()
  261. def load(self, name):
  262. if name in self.impls:
  263. return self.impls[name]()
  264. if self.auto_fn:
  265. loader = self.auto_fn(name)
  266. if loader:
  267. self.impls[name] = loader
  268. return loader()
  269. for impl in compat.importlib_metadata_get(self.group):
  270. if impl.name == name:
  271. self.impls[name] = impl.load
  272. return impl.load()
  273. raise exc.NoSuchModuleError(
  274. "Can't load plugin: %s:%s" % (self.group, name)
  275. )
  276. def register(self, name, modulepath, objname):
  277. def load():
  278. mod = compat.import_(modulepath)
  279. for token in modulepath.split(".")[1:]:
  280. mod = getattr(mod, token)
  281. return getattr(mod, objname)
  282. self.impls[name] = load
  283. def _inspect_func_args(fn):
  284. try:
  285. co_varkeywords = inspect.CO_VARKEYWORDS
  286. except AttributeError:
  287. # https://docs.python.org/3/library/inspect.html
  288. # The flags are specific to CPython, and may not be defined in other
  289. # Python implementations. Furthermore, the flags are an implementation
  290. # detail, and can be removed or deprecated in future Python releases.
  291. spec = compat.inspect_getfullargspec(fn)
  292. return spec[0], bool(spec[2])
  293. else:
  294. # use fn.__code__ plus flags to reduce method call overhead
  295. co = fn.__code__
  296. nargs = co.co_argcount
  297. return (
  298. list(co.co_varnames[:nargs]),
  299. bool(co.co_flags & co_varkeywords),
  300. )
  301. def get_cls_kwargs(cls, _set=None):
  302. r"""Return the full set of inherited kwargs for the given `cls`.
  303. Probes a class's __init__ method, collecting all named arguments. If the
  304. __init__ defines a \**kwargs catch-all, then the constructor is presumed
  305. to pass along unrecognized keywords to its base classes, and the
  306. collection process is repeated recursively on each of the bases.
  307. Uses a subset of inspect.getfullargspec() to cut down on method overhead,
  308. as this is used within the Core typing system to create copies of type
  309. objects which is a performance-sensitive operation.
  310. No anonymous tuple arguments please !
  311. """
  312. toplevel = _set is None
  313. if toplevel:
  314. _set = set()
  315. ctr = cls.__dict__.get("__init__", False)
  316. has_init = (
  317. ctr
  318. and isinstance(ctr, types.FunctionType)
  319. and isinstance(ctr.__code__, types.CodeType)
  320. )
  321. if has_init:
  322. names, has_kw = _inspect_func_args(ctr)
  323. _set.update(names)
  324. if not has_kw and not toplevel:
  325. return None
  326. if not has_init or has_kw:
  327. for c in cls.__bases__:
  328. if get_cls_kwargs(c, _set) is None:
  329. break
  330. _set.discard("self")
  331. return _set
  332. def get_func_kwargs(func):
  333. """Return the set of legal kwargs for the given `func`.
  334. Uses getargspec so is safe to call for methods, functions,
  335. etc.
  336. """
  337. return compat.inspect_getfullargspec(func)[0]
  338. def get_callable_argspec(fn, no_self=False, _is_init=False):
  339. """Return the argument signature for any callable.
  340. All pure-Python callables are accepted, including
  341. functions, methods, classes, objects with __call__;
  342. builtins and other edge cases like functools.partial() objects
  343. raise a TypeError.
  344. """
  345. if inspect.isbuiltin(fn):
  346. raise TypeError("Can't inspect builtin: %s" % fn)
  347. elif inspect.isfunction(fn):
  348. if _is_init and no_self:
  349. spec = compat.inspect_getfullargspec(fn)
  350. return compat.FullArgSpec(
  351. spec.args[1:],
  352. spec.varargs,
  353. spec.varkw,
  354. spec.defaults,
  355. spec.kwonlyargs,
  356. spec.kwonlydefaults,
  357. spec.annotations,
  358. )
  359. else:
  360. return compat.inspect_getfullargspec(fn)
  361. elif inspect.ismethod(fn):
  362. if no_self and (_is_init or fn.__self__):
  363. spec = compat.inspect_getfullargspec(fn.__func__)
  364. return compat.FullArgSpec(
  365. spec.args[1:],
  366. spec.varargs,
  367. spec.varkw,
  368. spec.defaults,
  369. spec.kwonlyargs,
  370. spec.kwonlydefaults,
  371. spec.annotations,
  372. )
  373. else:
  374. return compat.inspect_getfullargspec(fn.__func__)
  375. elif inspect.isclass(fn):
  376. return get_callable_argspec(
  377. fn.__init__, no_self=no_self, _is_init=True
  378. )
  379. elif hasattr(fn, "__func__"):
  380. return compat.inspect_getfullargspec(fn.__func__)
  381. elif hasattr(fn, "__call__"):
  382. if inspect.ismethod(fn.__call__):
  383. return get_callable_argspec(fn.__call__, no_self=no_self)
  384. else:
  385. raise TypeError("Can't inspect callable: %s" % fn)
  386. else:
  387. raise TypeError("Can't inspect callable: %s" % fn)
  388. def format_argspec_plus(fn, grouped=True):
  389. """Returns a dictionary of formatted, introspected function arguments.
  390. A enhanced variant of inspect.formatargspec to support code generation.
  391. fn
  392. An inspectable callable or tuple of inspect getargspec() results.
  393. grouped
  394. Defaults to True; include (parens, around, argument) lists
  395. Returns:
  396. args
  397. Full inspect.formatargspec for fn
  398. self_arg
  399. The name of the first positional argument, varargs[0], or None
  400. if the function defines no positional arguments.
  401. apply_pos
  402. args, re-written in calling rather than receiving syntax. Arguments are
  403. passed positionally.
  404. apply_kw
  405. Like apply_pos, except keyword-ish args are passed as keywords.
  406. apply_pos_proxied
  407. Like apply_pos but omits the self/cls argument
  408. Example::
  409. >>> format_argspec_plus(lambda self, a, b, c=3, **d: 123)
  410. {'args': '(self, a, b, c=3, **d)',
  411. 'self_arg': 'self',
  412. 'apply_kw': '(self, a, b, c=c, **d)',
  413. 'apply_pos': '(self, a, b, c, **d)'}
  414. """
  415. if compat.callable(fn):
  416. spec = compat.inspect_getfullargspec(fn)
  417. else:
  418. spec = fn
  419. args = compat.inspect_formatargspec(*spec)
  420. apply_pos = compat.inspect_formatargspec(
  421. spec[0], spec[1], spec[2], None, spec[4]
  422. )
  423. if spec[0]:
  424. self_arg = spec[0][0]
  425. apply_pos_proxied = compat.inspect_formatargspec(
  426. spec[0][1:], spec[1], spec[2], None, spec[4]
  427. )
  428. elif spec[1]:
  429. # I'm not sure what this is
  430. self_arg = "%s[0]" % spec[1]
  431. apply_pos_proxied = apply_pos
  432. else:
  433. self_arg = None
  434. apply_pos_proxied = apply_pos
  435. num_defaults = 0
  436. if spec[3]:
  437. num_defaults += len(spec[3])
  438. if spec[4]:
  439. num_defaults += len(spec[4])
  440. name_args = spec[0] + spec[4]
  441. if num_defaults:
  442. defaulted_vals = name_args[0 - num_defaults :]
  443. else:
  444. defaulted_vals = ()
  445. apply_kw = compat.inspect_formatargspec(
  446. name_args,
  447. spec[1],
  448. spec[2],
  449. defaulted_vals,
  450. formatvalue=lambda x: "=" + x,
  451. )
  452. if spec[0]:
  453. apply_kw_proxied = compat.inspect_formatargspec(
  454. name_args[1:],
  455. spec[1],
  456. spec[2],
  457. defaulted_vals,
  458. formatvalue=lambda x: "=" + x,
  459. )
  460. else:
  461. apply_kw_proxied = apply_kw
  462. if grouped:
  463. return dict(
  464. args=args,
  465. self_arg=self_arg,
  466. apply_pos=apply_pos,
  467. apply_kw=apply_kw,
  468. apply_pos_proxied=apply_pos_proxied,
  469. apply_kw_proxied=apply_kw_proxied,
  470. )
  471. else:
  472. return dict(
  473. args=args[1:-1],
  474. self_arg=self_arg,
  475. apply_pos=apply_pos[1:-1],
  476. apply_kw=apply_kw[1:-1],
  477. apply_pos_proxied=apply_pos_proxied[1:-1],
  478. apply_kw_proxied=apply_kw_proxied[1:-1],
  479. )
  480. def format_argspec_init(method, grouped=True):
  481. """format_argspec_plus with considerations for typical __init__ methods
  482. Wraps format_argspec_plus with error handling strategies for typical
  483. __init__ cases::
  484. object.__init__ -> (self)
  485. other unreflectable (usually C) -> (self, *args, **kwargs)
  486. """
  487. if method is object.__init__:
  488. args = "(self)" if grouped else "self"
  489. proxied = "()" if grouped else ""
  490. else:
  491. try:
  492. return format_argspec_plus(method, grouped=grouped)
  493. except TypeError:
  494. args = (
  495. "(self, *args, **kwargs)"
  496. if grouped
  497. else "self, *args, **kwargs"
  498. )
  499. proxied = "(*args, **kwargs)" if grouped else "*args, **kwargs"
  500. return dict(
  501. self_arg="self",
  502. args=args,
  503. apply_pos=args,
  504. apply_kw=args,
  505. apply_pos_proxied=proxied,
  506. apply_kw_proxied=proxied,
  507. )
  508. def create_proxy_methods(
  509. target_cls,
  510. target_cls_sphinx_name,
  511. proxy_cls_sphinx_name,
  512. classmethods=(),
  513. methods=(),
  514. attributes=(),
  515. ):
  516. """A class decorator that will copy attributes to a proxy class.
  517. The class to be instrumented must define a single accessor "_proxied".
  518. """
  519. def decorate(cls):
  520. def instrument(name, clslevel=False):
  521. fn = getattr(target_cls, name)
  522. spec = compat.inspect_getfullargspec(fn)
  523. env = {"__name__": fn.__module__}
  524. spec = _update_argspec_defaults_into_env(spec, env)
  525. caller_argspec = format_argspec_plus(spec, grouped=False)
  526. metadata = {
  527. "name": fn.__name__,
  528. "apply_pos_proxied": caller_argspec["apply_pos_proxied"],
  529. "apply_kw_proxied": caller_argspec["apply_kw_proxied"],
  530. "args": caller_argspec["args"],
  531. "self_arg": caller_argspec["self_arg"],
  532. }
  533. if clslevel:
  534. code = (
  535. "def %(name)s(%(args)s):\n"
  536. " return target_cls.%(name)s(%(apply_kw_proxied)s)"
  537. % metadata
  538. )
  539. env["target_cls"] = target_cls
  540. else:
  541. code = (
  542. "def %(name)s(%(args)s):\n"
  543. " return %(self_arg)s._proxied.%(name)s(%(apply_kw_proxied)s)" # noqa E501
  544. % metadata
  545. )
  546. proxy_fn = _exec_code_in_env(code, env, fn.__name__)
  547. proxy_fn.__defaults__ = getattr(fn, "__func__", fn).__defaults__
  548. proxy_fn.__doc__ = inject_docstring_text(
  549. fn.__doc__,
  550. ".. container:: class_bases\n\n "
  551. "Proxied for the %s class on behalf of the %s class."
  552. % (target_cls_sphinx_name, proxy_cls_sphinx_name),
  553. 1,
  554. )
  555. if clslevel:
  556. proxy_fn = classmethod(proxy_fn)
  557. return proxy_fn
  558. def makeprop(name):
  559. attr = target_cls.__dict__.get(name, None)
  560. if attr is not None:
  561. doc = inject_docstring_text(
  562. attr.__doc__,
  563. ".. container:: class_bases\n\n "
  564. "Proxied for the %s class on behalf of the %s class."
  565. % (
  566. target_cls_sphinx_name,
  567. proxy_cls_sphinx_name,
  568. ),
  569. 1,
  570. )
  571. else:
  572. doc = None
  573. code = (
  574. "def set_(self, attr):\n"
  575. " self._proxied.%(name)s = attr\n"
  576. "def get(self):\n"
  577. " return self._proxied.%(name)s\n"
  578. "get.__doc__ = doc\n"
  579. "getset = property(get, set_)"
  580. ) % {"name": name}
  581. getset = _exec_code_in_env(code, {"doc": doc}, "getset")
  582. return getset
  583. for meth in methods:
  584. if hasattr(cls, meth):
  585. raise TypeError(
  586. "class %s already has a method %s" % (cls, meth)
  587. )
  588. setattr(cls, meth, instrument(meth))
  589. for prop in attributes:
  590. if hasattr(cls, prop):
  591. raise TypeError(
  592. "class %s already has a method %s" % (cls, prop)
  593. )
  594. setattr(cls, prop, makeprop(prop))
  595. for prop in classmethods:
  596. if hasattr(cls, prop):
  597. raise TypeError(
  598. "class %s already has a method %s" % (cls, prop)
  599. )
  600. setattr(cls, prop, instrument(prop, clslevel=True))
  601. return cls
  602. return decorate
  603. def getargspec_init(method):
  604. """inspect.getargspec with considerations for typical __init__ methods
  605. Wraps inspect.getargspec with error handling for typical __init__ cases::
  606. object.__init__ -> (self)
  607. other unreflectable (usually C) -> (self, *args, **kwargs)
  608. """
  609. try:
  610. return compat.inspect_getfullargspec(method)
  611. except TypeError:
  612. if method is object.__init__:
  613. return (["self"], None, None, None)
  614. else:
  615. return (["self"], "args", "kwargs", None)
  616. def unbound_method_to_callable(func_or_cls):
  617. """Adjust the incoming callable such that a 'self' argument is not
  618. required.
  619. """
  620. if isinstance(func_or_cls, types.MethodType) and not func_or_cls.__self__:
  621. return func_or_cls.__func__
  622. else:
  623. return func_or_cls
  624. def generic_repr(obj, additional_kw=(), to_inspect=None, omit_kwarg=()):
  625. """Produce a __repr__() based on direct association of the __init__()
  626. specification vs. same-named attributes present.
  627. """
  628. if to_inspect is None:
  629. to_inspect = [obj]
  630. else:
  631. to_inspect = _collections.to_list(to_inspect)
  632. missing = object()
  633. pos_args = []
  634. kw_args = _collections.OrderedDict()
  635. vargs = None
  636. for i, insp in enumerate(to_inspect):
  637. try:
  638. spec = compat.inspect_getfullargspec(insp.__init__)
  639. except TypeError:
  640. continue
  641. else:
  642. default_len = spec.defaults and len(spec.defaults) or 0
  643. if i == 0:
  644. if spec.varargs:
  645. vargs = spec.varargs
  646. if default_len:
  647. pos_args.extend(spec.args[1:-default_len])
  648. else:
  649. pos_args.extend(spec.args[1:])
  650. else:
  651. kw_args.update(
  652. [(arg, missing) for arg in spec.args[1:-default_len]]
  653. )
  654. if default_len:
  655. kw_args.update(
  656. [
  657. (arg, default)
  658. for arg, default in zip(
  659. spec.args[-default_len:], spec.defaults
  660. )
  661. ]
  662. )
  663. output = []
  664. output.extend(repr(getattr(obj, arg, None)) for arg in pos_args)
  665. if vargs is not None and hasattr(obj, vargs):
  666. output.extend([repr(val) for val in getattr(obj, vargs)])
  667. for arg, defval in kw_args.items():
  668. if arg in omit_kwarg:
  669. continue
  670. try:
  671. val = getattr(obj, arg, missing)
  672. if val is not missing and val != defval:
  673. output.append("%s=%r" % (arg, val))
  674. except Exception:
  675. pass
  676. if additional_kw:
  677. for arg, defval in additional_kw:
  678. try:
  679. val = getattr(obj, arg, missing)
  680. if val is not missing and val != defval:
  681. output.append("%s=%r" % (arg, val))
  682. except Exception:
  683. pass
  684. return "%s(%s)" % (obj.__class__.__name__, ", ".join(output))
  685. class portable_instancemethod(object):
  686. """Turn an instancemethod into a (parent, name) pair
  687. to produce a serializable callable.
  688. """
  689. __slots__ = "target", "name", "kwargs", "__weakref__"
  690. def __getstate__(self):
  691. return {
  692. "target": self.target,
  693. "name": self.name,
  694. "kwargs": self.kwargs,
  695. }
  696. def __setstate__(self, state):
  697. self.target = state["target"]
  698. self.name = state["name"]
  699. self.kwargs = state.get("kwargs", ())
  700. def __init__(self, meth, kwargs=()):
  701. self.target = meth.__self__
  702. self.name = meth.__name__
  703. self.kwargs = kwargs
  704. def __call__(self, *arg, **kw):
  705. kw.update(self.kwargs)
  706. return getattr(self.target, self.name)(*arg, **kw)
  707. def class_hierarchy(cls):
  708. """Return an unordered sequence of all classes related to cls.
  709. Traverses diamond hierarchies.
  710. Fibs slightly: subclasses of builtin types are not returned. Thus
  711. class_hierarchy(class A(object)) returns (A, object), not A plus every
  712. class systemwide that derives from object.
  713. Old-style classes are discarded and hierarchies rooted on them
  714. will not be descended.
  715. """
  716. if compat.py2k:
  717. if isinstance(cls, types.ClassType):
  718. return list()
  719. hier = {cls}
  720. process = list(cls.__mro__)
  721. while process:
  722. c = process.pop()
  723. if compat.py2k:
  724. if isinstance(c, types.ClassType):
  725. continue
  726. bases = (
  727. _
  728. for _ in c.__bases__
  729. if _ not in hier and not isinstance(_, types.ClassType)
  730. )
  731. else:
  732. bases = (_ for _ in c.__bases__ if _ not in hier)
  733. for b in bases:
  734. process.append(b)
  735. hier.add(b)
  736. if compat.py3k:
  737. if c.__module__ == "builtins" or not hasattr(c, "__subclasses__"):
  738. continue
  739. else:
  740. if c.__module__ == "__builtin__" or not hasattr(
  741. c, "__subclasses__"
  742. ):
  743. continue
  744. for s in [_ for _ in c.__subclasses__() if _ not in hier]:
  745. process.append(s)
  746. hier.add(s)
  747. return list(hier)
  748. def iterate_attributes(cls):
  749. """iterate all the keys and attributes associated
  750. with a class, without using getattr().
  751. Does not use getattr() so that class-sensitive
  752. descriptors (i.e. property.__get__()) are not called.
  753. """
  754. keys = dir(cls)
  755. for key in keys:
  756. for c in cls.__mro__:
  757. if key in c.__dict__:
  758. yield (key, c.__dict__[key])
  759. break
  760. def monkeypatch_proxied_specials(
  761. into_cls,
  762. from_cls,
  763. skip=None,
  764. only=None,
  765. name="self.proxy",
  766. from_instance=None,
  767. ):
  768. """Automates delegation of __specials__ for a proxying type."""
  769. if only:
  770. dunders = only
  771. else:
  772. if skip is None:
  773. skip = (
  774. "__slots__",
  775. "__del__",
  776. "__getattribute__",
  777. "__metaclass__",
  778. "__getstate__",
  779. "__setstate__",
  780. )
  781. dunders = [
  782. m
  783. for m in dir(from_cls)
  784. if (
  785. m.startswith("__")
  786. and m.endswith("__")
  787. and not hasattr(into_cls, m)
  788. and m not in skip
  789. )
  790. ]
  791. for method in dunders:
  792. try:
  793. fn = getattr(from_cls, method)
  794. if not hasattr(fn, "__call__"):
  795. continue
  796. fn = getattr(fn, "__func__", fn)
  797. except AttributeError:
  798. continue
  799. try:
  800. spec = compat.inspect_getfullargspec(fn)
  801. fn_args = compat.inspect_formatargspec(spec[0])
  802. d_args = compat.inspect_formatargspec(spec[0][1:])
  803. except TypeError:
  804. fn_args = "(self, *args, **kw)"
  805. d_args = "(*args, **kw)"
  806. py = (
  807. "def %(method)s%(fn_args)s: "
  808. "return %(name)s.%(method)s%(d_args)s" % locals()
  809. )
  810. env = from_instance is not None and {name: from_instance} or {}
  811. compat.exec_(py, env)
  812. try:
  813. env[method].__defaults__ = fn.__defaults__
  814. except AttributeError:
  815. pass
  816. setattr(into_cls, method, env[method])
  817. def methods_equivalent(meth1, meth2):
  818. """Return True if the two methods are the same implementation."""
  819. return getattr(meth1, "__func__", meth1) is getattr(
  820. meth2, "__func__", meth2
  821. )
  822. def as_interface(obj, cls=None, methods=None, required=None):
  823. """Ensure basic interface compliance for an instance or dict of callables.
  824. Checks that ``obj`` implements public methods of ``cls`` or has members
  825. listed in ``methods``. If ``required`` is not supplied, implementing at
  826. least one interface method is sufficient. Methods present on ``obj`` that
  827. are not in the interface are ignored.
  828. If ``obj`` is a dict and ``dict`` does not meet the interface
  829. requirements, the keys of the dictionary are inspected. Keys present in
  830. ``obj`` that are not in the interface will raise TypeErrors.
  831. Raises TypeError if ``obj`` does not meet the interface criteria.
  832. In all passing cases, an object with callable members is returned. In the
  833. simple case, ``obj`` is returned as-is; if dict processing kicks in then
  834. an anonymous class is returned.
  835. obj
  836. A type, instance, or dictionary of callables.
  837. cls
  838. Optional, a type. All public methods of cls are considered the
  839. interface. An ``obj`` instance of cls will always pass, ignoring
  840. ``required``..
  841. methods
  842. Optional, a sequence of method names to consider as the interface.
  843. required
  844. Optional, a sequence of mandatory implementations. If omitted, an
  845. ``obj`` that provides at least one interface method is considered
  846. sufficient. As a convenience, required may be a type, in which case
  847. all public methods of the type are required.
  848. """
  849. if not cls and not methods:
  850. raise TypeError("a class or collection of method names are required")
  851. if isinstance(cls, type) and isinstance(obj, cls):
  852. return obj
  853. interface = set(methods or [m for m in dir(cls) if not m.startswith("_")])
  854. implemented = set(dir(obj))
  855. complies = operator.ge
  856. if isinstance(required, type):
  857. required = interface
  858. elif not required:
  859. required = set()
  860. complies = operator.gt
  861. else:
  862. required = set(required)
  863. if complies(implemented.intersection(interface), required):
  864. return obj
  865. # No dict duck typing here.
  866. if not isinstance(obj, dict):
  867. qualifier = complies is operator.gt and "any of" or "all of"
  868. raise TypeError(
  869. "%r does not implement %s: %s"
  870. % (obj, qualifier, ", ".join(interface))
  871. )
  872. class AnonymousInterface(object):
  873. """A callable-holding shell."""
  874. if cls:
  875. AnonymousInterface.__name__ = "Anonymous" + cls.__name__
  876. found = set()
  877. for method, impl in dictlike_iteritems(obj):
  878. if method not in interface:
  879. raise TypeError("%r: unknown in this interface" % method)
  880. if not compat.callable(impl):
  881. raise TypeError("%r=%r is not callable" % (method, impl))
  882. setattr(AnonymousInterface, method, staticmethod(impl))
  883. found.add(method)
  884. if complies(found, required):
  885. return AnonymousInterface
  886. raise TypeError(
  887. "dictionary does not contain required keys %s"
  888. % ", ".join(required - found)
  889. )
  890. class memoized_property(object):
  891. """A read-only @property that is only evaluated once."""
  892. def __init__(self, fget, doc=None):
  893. self.fget = fget
  894. self.__doc__ = doc or fget.__doc__
  895. self.__name__ = fget.__name__
  896. def __get__(self, obj, cls):
  897. if obj is None:
  898. return self
  899. obj.__dict__[self.__name__] = result = self.fget(obj)
  900. return result
  901. def _reset(self, obj):
  902. memoized_property.reset(obj, self.__name__)
  903. @classmethod
  904. def reset(cls, obj, name):
  905. obj.__dict__.pop(name, None)
  906. def memoized_instancemethod(fn):
  907. """Decorate a method memoize its return value.
  908. Best applied to no-arg methods: memoization is not sensitive to
  909. argument values, and will always return the same value even when
  910. called with different arguments.
  911. """
  912. def oneshot(self, *args, **kw):
  913. result = fn(self, *args, **kw)
  914. def memo(*a, **kw):
  915. return result
  916. memo.__name__ = fn.__name__
  917. memo.__doc__ = fn.__doc__
  918. self.__dict__[fn.__name__] = memo
  919. return result
  920. return update_wrapper(oneshot, fn)
  921. class HasMemoized(object):
  922. """A class that maintains the names of memoized elements in a
  923. collection for easy cache clearing, generative, etc.
  924. """
  925. __slots__ = ()
  926. _memoized_keys = frozenset()
  927. def _reset_memoizations(self):
  928. for elem in self._memoized_keys:
  929. self.__dict__.pop(elem, None)
  930. def _assert_no_memoizations(self):
  931. for elem in self._memoized_keys:
  932. assert elem not in self.__dict__
  933. def _set_memoized_attribute(self, key, value):
  934. self.__dict__[key] = value
  935. self._memoized_keys |= {key}
  936. class memoized_attribute(object):
  937. """A read-only @property that is only evaluated once."""
  938. def __init__(self, fget, doc=None):
  939. self.fget = fget
  940. self.__doc__ = doc or fget.__doc__
  941. self.__name__ = fget.__name__
  942. def __get__(self, obj, cls):
  943. if obj is None:
  944. return self
  945. obj.__dict__[self.__name__] = result = self.fget(obj)
  946. obj._memoized_keys |= {self.__name__}
  947. return result
  948. @classmethod
  949. def memoized_instancemethod(cls, fn):
  950. """Decorate a method memoize its return value."""
  951. def oneshot(self, *args, **kw):
  952. result = fn(self, *args, **kw)
  953. def memo(*a, **kw):
  954. return result
  955. memo.__name__ = fn.__name__
  956. memo.__doc__ = fn.__doc__
  957. self.__dict__[fn.__name__] = memo
  958. self._memoized_keys |= {fn.__name__}
  959. return result
  960. return update_wrapper(oneshot, fn)
  961. class MemoizedSlots(object):
  962. """Apply memoized items to an object using a __getattr__ scheme.
  963. This allows the functionality of memoized_property and
  964. memoized_instancemethod to be available to a class using __slots__.
  965. """
  966. __slots__ = ()
  967. def _fallback_getattr(self, key):
  968. raise AttributeError(key)
  969. def __getattr__(self, key):
  970. if key.startswith("_memoized"):
  971. raise AttributeError(key)
  972. elif hasattr(self, "_memoized_attr_%s" % key):
  973. value = getattr(self, "_memoized_attr_%s" % key)()
  974. setattr(self, key, value)
  975. return value
  976. elif hasattr(self, "_memoized_method_%s" % key):
  977. fn = getattr(self, "_memoized_method_%s" % key)
  978. def oneshot(*args, **kw):
  979. result = fn(*args, **kw)
  980. def memo(*a, **kw):
  981. return result
  982. memo.__name__ = fn.__name__
  983. memo.__doc__ = fn.__doc__
  984. setattr(self, key, memo)
  985. return result
  986. oneshot.__doc__ = fn.__doc__
  987. return oneshot
  988. else:
  989. return self._fallback_getattr(key)
  990. # from paste.deploy.converters
  991. def asbool(obj):
  992. if isinstance(obj, compat.string_types):
  993. obj = obj.strip().lower()
  994. if obj in ["true", "yes", "on", "y", "t", "1"]:
  995. return True
  996. elif obj in ["false", "no", "off", "n", "f", "0"]:
  997. return False
  998. else:
  999. raise ValueError("String is not true/false: %r" % obj)
  1000. return bool(obj)
  1001. def bool_or_str(*text):
  1002. """Return a callable that will evaluate a string as
  1003. boolean, or one of a set of "alternate" string values.
  1004. """
  1005. def bool_or_value(obj):
  1006. if obj in text:
  1007. return obj
  1008. else:
  1009. return asbool(obj)
  1010. return bool_or_value
  1011. def asint(value):
  1012. """Coerce to integer."""
  1013. if value is None:
  1014. return value
  1015. return int(value)
  1016. def coerce_kw_type(kw, key, type_, flexi_bool=True, dest=None):
  1017. r"""If 'key' is present in dict 'kw', coerce its value to type 'type\_' if
  1018. necessary. If 'flexi_bool' is True, the string '0' is considered false
  1019. when coercing to boolean.
  1020. """
  1021. if dest is None:
  1022. dest = kw
  1023. if (
  1024. key in kw
  1025. and (not isinstance(type_, type) or not isinstance(kw[key], type_))
  1026. and kw[key] is not None
  1027. ):
  1028. if type_ is bool and flexi_bool:
  1029. dest[key] = asbool(kw[key])
  1030. else:
  1031. dest[key] = type_(kw[key])
  1032. def constructor_key(obj, cls):
  1033. """Produce a tuple structure that is cacheable using the __dict__ of
  1034. obj to retrieve values
  1035. """
  1036. names = get_cls_kwargs(cls)
  1037. return (cls,) + tuple(
  1038. (k, obj.__dict__[k]) for k in names if k in obj.__dict__
  1039. )
  1040. def constructor_copy(obj, cls, *args, **kw):
  1041. """Instantiate cls using the __dict__ of obj as constructor arguments.
  1042. Uses inspect to match the named arguments of ``cls``.
  1043. """
  1044. names = get_cls_kwargs(cls)
  1045. kw.update(
  1046. (k, obj.__dict__[k]) for k in names.difference(kw) if k in obj.__dict__
  1047. )
  1048. return cls(*args, **kw)
  1049. def counter():
  1050. """Return a threadsafe counter function."""
  1051. lock = compat.threading.Lock()
  1052. counter = itertools.count(1)
  1053. # avoid the 2to3 "next" transformation...
  1054. def _next():
  1055. with lock:
  1056. return next(counter)
  1057. return _next
  1058. def duck_type_collection(specimen, default=None):
  1059. """Given an instance or class, guess if it is or is acting as one of
  1060. the basic collection types: list, set and dict. If the __emulates__
  1061. property is present, return that preferentially.
  1062. """
  1063. if hasattr(specimen, "__emulates__"):
  1064. # canonicalize set vs sets.Set to a standard: the builtin set
  1065. if specimen.__emulates__ is not None and issubclass(
  1066. specimen.__emulates__, set
  1067. ):
  1068. return set
  1069. else:
  1070. return specimen.__emulates__
  1071. isa = isinstance(specimen, type) and issubclass or isinstance
  1072. if isa(specimen, list):
  1073. return list
  1074. elif isa(specimen, set):
  1075. return set
  1076. elif isa(specimen, dict):
  1077. return dict
  1078. if hasattr(specimen, "append"):
  1079. return list
  1080. elif hasattr(specimen, "add"):
  1081. return set
  1082. elif hasattr(specimen, "set"):
  1083. return dict
  1084. else:
  1085. return default
  1086. def assert_arg_type(arg, argtype, name):
  1087. if isinstance(arg, argtype):
  1088. return arg
  1089. else:
  1090. if isinstance(argtype, tuple):
  1091. raise exc.ArgumentError(
  1092. "Argument '%s' is expected to be one of type %s, got '%s'"
  1093. % (name, " or ".join("'%s'" % a for a in argtype), type(arg))
  1094. )
  1095. else:
  1096. raise exc.ArgumentError(
  1097. "Argument '%s' is expected to be of type '%s', got '%s'"
  1098. % (name, argtype, type(arg))
  1099. )
  1100. def dictlike_iteritems(dictlike):
  1101. """Return a (key, value) iterator for almost any dict-like object."""
  1102. if compat.py3k:
  1103. if hasattr(dictlike, "items"):
  1104. return list(dictlike.items())
  1105. else:
  1106. if hasattr(dictlike, "iteritems"):
  1107. return dictlike.iteritems()
  1108. elif hasattr(dictlike, "items"):
  1109. return iter(dictlike.items())
  1110. getter = getattr(dictlike, "__getitem__", getattr(dictlike, "get", None))
  1111. if getter is None:
  1112. raise TypeError("Object '%r' is not dict-like" % dictlike)
  1113. if hasattr(dictlike, "iterkeys"):
  1114. def iterator():
  1115. for key in dictlike.iterkeys():
  1116. yield key, getter(key)
  1117. return iterator()
  1118. elif hasattr(dictlike, "keys"):
  1119. return iter((key, getter(key)) for key in dictlike.keys())
  1120. else:
  1121. raise TypeError("Object '%r' is not dict-like" % dictlike)
  1122. class classproperty(property):
  1123. """A decorator that behaves like @property except that operates
  1124. on classes rather than instances.
  1125. The decorator is currently special when using the declarative
  1126. module, but note that the
  1127. :class:`~.sqlalchemy.ext.declarative.declared_attr`
  1128. decorator should be used for this purpose with declarative.
  1129. """
  1130. def __init__(self, fget, *arg, **kw):
  1131. super(classproperty, self).__init__(fget, *arg, **kw)
  1132. self.__doc__ = fget.__doc__
  1133. def __get__(desc, self, cls):
  1134. return desc.fget(cls)
  1135. class hybridproperty(object):
  1136. def __init__(self, func):
  1137. self.func = func
  1138. self.clslevel = func
  1139. def __get__(self, instance, owner):
  1140. if instance is None:
  1141. clsval = self.clslevel(owner)
  1142. return clsval
  1143. else:
  1144. return self.func(instance)
  1145. def classlevel(self, func):
  1146. self.clslevel = func
  1147. return self
  1148. class hybridmethod(object):
  1149. """Decorate a function as cls- or instance- level."""
  1150. def __init__(self, func):
  1151. self.func = func
  1152. self.clslevel = func
  1153. def __get__(self, instance, owner):
  1154. if instance is None:
  1155. return self.clslevel.__get__(owner, owner.__class__)
  1156. else:
  1157. return self.func.__get__(instance, owner)
  1158. def classlevel(self, func):
  1159. self.clslevel = func
  1160. return self
  1161. class _symbol(int):
  1162. def __new__(self, name, doc=None, canonical=None):
  1163. """Construct a new named symbol."""
  1164. assert isinstance(name, compat.string_types)
  1165. if canonical is None:
  1166. canonical = hash(name)
  1167. v = int.__new__(_symbol, canonical)
  1168. v.name = name
  1169. if doc:
  1170. v.__doc__ = doc
  1171. return v
  1172. def __reduce__(self):
  1173. return symbol, (self.name, "x", int(self))
  1174. def __str__(self):
  1175. return repr(self)
  1176. def __repr__(self):
  1177. return "symbol(%r)" % self.name
  1178. _symbol.__name__ = "symbol"
  1179. class symbol(object):
  1180. """A constant symbol.
  1181. >>> symbol('foo') is symbol('foo')
  1182. True
  1183. >>> symbol('foo')
  1184. <symbol 'foo>
  1185. A slight refinement of the MAGICCOOKIE=object() pattern. The primary
  1186. advantage of symbol() is its repr(). They are also singletons.
  1187. Repeated calls of symbol('name') will all return the same instance.
  1188. The optional ``doc`` argument assigns to ``__doc__``. This
  1189. is strictly so that Sphinx autoattr picks up the docstring we want
  1190. (it doesn't appear to pick up the in-module docstring if the datamember
  1191. is in a different module - autoattribute also blows up completely).
  1192. If Sphinx fixes/improves this then we would no longer need
  1193. ``doc`` here.
  1194. """
  1195. symbols = {}
  1196. _lock = compat.threading.Lock()
  1197. def __new__(cls, name, doc=None, canonical=None):
  1198. with cls._lock:
  1199. sym = cls.symbols.get(name)
  1200. if sym is None:
  1201. cls.symbols[name] = sym = _symbol(name, doc, canonical)
  1202. return sym
  1203. @classmethod
  1204. def parse_user_argument(
  1205. cls, arg, choices, name, resolve_symbol_names=False
  1206. ):
  1207. """Given a user parameter, parse the parameter into a chosen symbol.
  1208. The user argument can be a string name that matches the name of a
  1209. symbol, or the symbol object itself, or any number of alternate choices
  1210. such as True/False/ None etc.
  1211. :param arg: the user argument.
  1212. :param choices: dictionary of symbol object to list of possible
  1213. entries.
  1214. :param name: name of the argument. Used in an :class:`.ArgumentError`
  1215. that is raised if the parameter doesn't match any available argument.
  1216. :param resolve_symbol_names: include the name of each symbol as a valid
  1217. entry.
  1218. """
  1219. # note using hash lookup is tricky here because symbol's `__hash__`
  1220. # is its int value which we don't want included in the lookup
  1221. # explicitly, so we iterate and compare each.
  1222. for sym, choice in choices.items():
  1223. if arg is sym:
  1224. return sym
  1225. elif resolve_symbol_names and arg == sym.name:
  1226. return sym
  1227. elif arg in choice:
  1228. return sym
  1229. if arg is None:
  1230. return None
  1231. raise exc.ArgumentError("Invalid value for '%s': %r" % (name, arg))
  1232. _creation_order = 1
  1233. def set_creation_order(instance):
  1234. """Assign a '_creation_order' sequence to the given instance.
  1235. This allows multiple instances to be sorted in order of creation
  1236. (typically within a single thread; the counter is not particularly
  1237. threadsafe).
  1238. """
  1239. global _creation_order
  1240. instance._creation_order = _creation_order
  1241. _creation_order += 1
  1242. def warn_exception(func, *args, **kwargs):
  1243. """executes the given function, catches all exceptions and converts to
  1244. a warning.
  1245. """
  1246. try:
  1247. return func(*args, **kwargs)
  1248. except Exception:
  1249. warn("%s('%s') ignored" % sys.exc_info()[0:2])
  1250. def ellipses_string(value, len_=25):
  1251. try:
  1252. if len(value) > len_:
  1253. return "%s..." % value[0:len_]
  1254. else:
  1255. return value
  1256. except TypeError:
  1257. return value
  1258. class _hash_limit_string(compat.text_type):
  1259. """A string subclass that can only be hashed on a maximum amount
  1260. of unique values.
  1261. This is used for warnings so that we can send out parameterized warnings
  1262. without the __warningregistry__ of the module, or the non-overridable
  1263. "once" registry within warnings.py, overloading memory,
  1264. """
  1265. def __new__(cls, value, num, args):
  1266. interpolated = (value % args) + (
  1267. " (this warning may be suppressed after %d occurrences)" % num
  1268. )
  1269. self = super(_hash_limit_string, cls).__new__(cls, interpolated)
  1270. self._hash = hash("%s_%d" % (value, hash(interpolated) % num))
  1271. return self
  1272. def __hash__(self):
  1273. return self._hash
  1274. def __eq__(self, other):
  1275. return hash(self) == hash(other)
  1276. def warn(msg, code=None):
  1277. """Issue a warning.
  1278. If msg is a string, :class:`.exc.SAWarning` is used as
  1279. the category.
  1280. """
  1281. if code:
  1282. _warnings_warn(exc.SAWarning(msg, code=code))
  1283. else:
  1284. _warnings_warn(msg, exc.SAWarning)
  1285. def warn_limited(msg, args):
  1286. """Issue a warning with a parameterized string, limiting the number
  1287. of registrations.
  1288. """
  1289. if args:
  1290. msg = _hash_limit_string(msg, 10, args)
  1291. _warnings_warn(msg, exc.SAWarning)
  1292. def _warnings_warn(message, category=None, stacklevel=2):
  1293. # adjust the given stacklevel to be outside of SQLAlchemy
  1294. try:
  1295. frame = sys._getframe(stacklevel)
  1296. except ValueError:
  1297. # being called from less than 3 (or given) stacklevels, weird,
  1298. # but don't crash
  1299. stacklevel = 0
  1300. except:
  1301. # _getframe() doesn't work, weird interpreter issue, weird,
  1302. # ok, but don't crash
  1303. stacklevel = 0
  1304. else:
  1305. # using __name__ here requires that we have __name__ in the
  1306. # __globals__ of the decorated string functions we make also.
  1307. # we generate this using {"__name__": fn.__module__}
  1308. while frame is not None and re.match(
  1309. r"^(?:sqlalchemy\.|alembic\.)", frame.f_globals.get("__name__", "")
  1310. ):
  1311. frame = frame.f_back
  1312. stacklevel += 1
  1313. if category is not None:
  1314. warnings.warn(message, category, stacklevel=stacklevel + 1)
  1315. else:
  1316. warnings.warn(message, stacklevel=stacklevel + 1)
  1317. def only_once(fn, retry_on_exception):
  1318. """Decorate the given function to be a no-op after it is called exactly
  1319. once."""
  1320. once = [fn]
  1321. def go(*arg, **kw):
  1322. # strong reference fn so that it isn't garbage collected,
  1323. # which interferes with the event system's expectations
  1324. strong_fn = fn # noqa
  1325. if once:
  1326. once_fn = once.pop()
  1327. try:
  1328. return once_fn(*arg, **kw)
  1329. except:
  1330. if retry_on_exception:
  1331. once.insert(0, once_fn)
  1332. raise
  1333. return go
  1334. _SQLA_RE = re.compile(r"sqlalchemy/([a-z_]+/){0,2}[a-z_]+\.py")
  1335. _UNITTEST_RE = re.compile(r"unit(?:2|test2?/)")
  1336. def chop_traceback(tb, exclude_prefix=_UNITTEST_RE, exclude_suffix=_SQLA_RE):
  1337. """Chop extraneous lines off beginning and end of a traceback.
  1338. :param tb:
  1339. a list of traceback lines as returned by ``traceback.format_stack()``
  1340. :param exclude_prefix:
  1341. a regular expression object matching lines to skip at beginning of
  1342. ``tb``
  1343. :param exclude_suffix:
  1344. a regular expression object matching lines to skip at end of ``tb``
  1345. """
  1346. start = 0
  1347. end = len(tb) - 1
  1348. while start <= end and exclude_prefix.search(tb[start]):
  1349. start += 1
  1350. while start <= end and exclude_suffix.search(tb[end]):
  1351. end -= 1
  1352. return tb[start : end + 1]
  1353. NoneType = type(None)
  1354. def attrsetter(attrname):
  1355. code = "def set(obj, value):" " obj.%s = value" % attrname
  1356. env = locals().copy()
  1357. exec(code, env)
  1358. return env["set"]
  1359. class EnsureKWArgType(type):
  1360. r"""Apply translation of functions to accept \**kw arguments if they
  1361. don't already.
  1362. """
  1363. def __init__(cls, clsname, bases, clsdict):
  1364. fn_reg = cls.ensure_kwarg
  1365. if fn_reg:
  1366. for key in clsdict:
  1367. m = re.match(fn_reg, key)
  1368. if m:
  1369. fn = clsdict[key]
  1370. spec = compat.inspect_getfullargspec(fn)
  1371. if not spec.varkw:
  1372. clsdict[key] = wrapped = cls._wrap_w_kw(fn)
  1373. setattr(cls, key, wrapped)
  1374. super(EnsureKWArgType, cls).__init__(clsname, bases, clsdict)
  1375. def _wrap_w_kw(self, fn):
  1376. def wrap(*arg, **kw):
  1377. return fn(*arg)
  1378. return update_wrapper(wrap, fn)
  1379. def wrap_callable(wrapper, fn):
  1380. """Augment functools.update_wrapper() to work with objects with
  1381. a ``__call__()`` method.
  1382. :param fn:
  1383. object with __call__ method
  1384. """
  1385. if hasattr(fn, "__name__"):
  1386. return update_wrapper(wrapper, fn)
  1387. else:
  1388. _f = wrapper
  1389. _f.__name__ = fn.__class__.__name__
  1390. if hasattr(fn, "__module__"):
  1391. _f.__module__ = fn.__module__
  1392. if hasattr(fn.__call__, "__doc__") and fn.__call__.__doc__:
  1393. _f.__doc__ = fn.__call__.__doc__
  1394. elif fn.__doc__:
  1395. _f.__doc__ = fn.__doc__
  1396. return _f
  1397. def quoted_token_parser(value):
  1398. """Parse a dotted identifier with accommodation for quoted names.
  1399. Includes support for SQL-style double quotes as a literal character.
  1400. E.g.::
  1401. >>> quoted_token_parser("name")
  1402. ["name"]
  1403. >>> quoted_token_parser("schema.name")
  1404. ["schema", "name"]
  1405. >>> quoted_token_parser('"Schema"."Name"')
  1406. ['Schema', 'Name']
  1407. >>> quoted_token_parser('"Schema"."Name""Foo"')
  1408. ['Schema', 'Name""Foo']
  1409. """
  1410. if '"' not in value:
  1411. return value.split(".")
  1412. # 0 = outside of quotes
  1413. # 1 = inside of quotes
  1414. state = 0
  1415. result = [[]]
  1416. idx = 0
  1417. lv = len(value)
  1418. while idx < lv:
  1419. char = value[idx]
  1420. if char == '"':
  1421. if state == 1 and idx < lv - 1 and value[idx + 1] == '"':
  1422. result[-1].append('"')
  1423. idx += 1
  1424. else:
  1425. state ^= 1
  1426. elif char == "." and state == 0:
  1427. result.append([])
  1428. else:
  1429. result[-1].append(char)
  1430. idx += 1
  1431. return ["".join(token) for token in result]
  1432. def add_parameter_text(params, text):
  1433. params = _collections.to_list(params)
  1434. def decorate(fn):
  1435. doc = fn.__doc__ is not None and fn.__doc__ or ""
  1436. if doc:
  1437. doc = inject_param_text(doc, {param: text for param in params})
  1438. fn.__doc__ = doc
  1439. return fn
  1440. return decorate
  1441. def _dedent_docstring(text):
  1442. split_text = text.split("\n", 1)
  1443. if len(split_text) == 1:
  1444. return text
  1445. else:
  1446. firstline, remaining = split_text
  1447. if not firstline.startswith(" "):
  1448. return firstline + "\n" + textwrap.dedent(remaining)
  1449. else:
  1450. return textwrap.dedent(text)
  1451. def inject_docstring_text(doctext, injecttext, pos):
  1452. doctext = _dedent_docstring(doctext or "")
  1453. lines = doctext.split("\n")
  1454. if len(lines) == 1:
  1455. lines.append("")
  1456. injectlines = textwrap.dedent(injecttext).split("\n")
  1457. if injectlines[0]:
  1458. injectlines.insert(0, "")
  1459. blanks = [num for num, line in enumerate(lines) if not line.strip()]
  1460. blanks.insert(0, 0)
  1461. inject_pos = blanks[min(pos, len(blanks) - 1)]
  1462. lines = lines[0:inject_pos] + injectlines + lines[inject_pos:]
  1463. return "\n".join(lines)
  1464. _param_reg = re.compile(r"(\s+):param (.+?):")
  1465. def inject_param_text(doctext, inject_params):
  1466. doclines = collections.deque(doctext.splitlines())
  1467. lines = []
  1468. # TODO: this is not working for params like ":param case_sensitive=True:"
  1469. to_inject = None
  1470. while doclines:
  1471. line = doclines.popleft()
  1472. m = _param_reg.match(line)
  1473. if to_inject is None:
  1474. if m:
  1475. param = m.group(2).lstrip("*")
  1476. if param in inject_params:
  1477. # default indent to that of :param: plus one
  1478. indent = " " * len(m.group(1)) + " "
  1479. # but if the next line has text, use that line's
  1480. # indentation
  1481. if doclines:
  1482. m2 = re.match(r"(\s+)\S", doclines[0])
  1483. if m2:
  1484. indent = " " * len(m2.group(1))
  1485. to_inject = indent + inject_params[param]
  1486. elif m:
  1487. lines.extend(["\n", to_inject, "\n"])
  1488. to_inject = None
  1489. elif not line.rstrip():
  1490. lines.extend([line, to_inject, "\n"])
  1491. to_inject = None
  1492. elif line.endswith("::"):
  1493. # TODO: this still wont cover if the code example itself has blank
  1494. # lines in it, need to detect those via indentation.
  1495. lines.extend([line, doclines.popleft()])
  1496. continue
  1497. lines.append(line)
  1498. return "\n".join(lines)
  1499. def repr_tuple_names(names):
  1500. """Trims a list of strings from the middle and return a string of up to
  1501. four elements. Strings greater than 11 characters will be truncated"""
  1502. if len(names) == 0:
  1503. return None
  1504. flag = len(names) <= 4
  1505. names = names[0:4] if flag else names[0:3] + names[-1:]
  1506. res = ["%s.." % name[:11] if len(name) > 11 else name for name in names]
  1507. if flag:
  1508. return ", ".join(res)
  1509. else:
  1510. return "%s, ..., %s" % (", ".join(res[0:3]), res[-1])
  1511. def has_compiled_ext():
  1512. try:
  1513. from sqlalchemy import cimmutabledict # noqa F401
  1514. from sqlalchemy import cprocessors # noqa F401
  1515. from sqlalchemy import cresultproxy # noqa F401
  1516. return True
  1517. except ImportError:
  1518. return False