langhelpers.py 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945
  1. # util/langhelpers.py
  2. # Copyright (C) 2005-2024 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: https://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. :meta private:
  939. """
  940. def __init__(self, fget, doc=None):
  941. self.fget = fget
  942. self.__doc__ = doc or fget.__doc__
  943. self.__name__ = fget.__name__
  944. def __get__(self, obj, cls):
  945. if obj is None:
  946. return self
  947. obj.__dict__[self.__name__] = result = self.fget(obj)
  948. obj._memoized_keys |= {self.__name__}
  949. return result
  950. @classmethod
  951. def memoized_instancemethod(cls, fn):
  952. """Decorate a method memoize its return value."""
  953. def oneshot(self, *args, **kw):
  954. result = fn(self, *args, **kw)
  955. def memo(*a, **kw):
  956. return result
  957. memo.__name__ = fn.__name__
  958. memo.__doc__ = fn.__doc__
  959. self.__dict__[fn.__name__] = memo
  960. self._memoized_keys |= {fn.__name__}
  961. return result
  962. return update_wrapper(oneshot, fn)
  963. class MemoizedSlots(object):
  964. """Apply memoized items to an object using a __getattr__ scheme.
  965. This allows the functionality of memoized_property and
  966. memoized_instancemethod to be available to a class using __slots__.
  967. """
  968. __slots__ = ()
  969. def _fallback_getattr(self, key):
  970. raise AttributeError(key)
  971. def __getattr__(self, key):
  972. if key.startswith("_memoized"):
  973. raise AttributeError(key)
  974. elif hasattr(self, "_memoized_attr_%s" % key):
  975. value = getattr(self, "_memoized_attr_%s" % key)()
  976. setattr(self, key, value)
  977. return value
  978. elif hasattr(self, "_memoized_method_%s" % key):
  979. fn = getattr(self, "_memoized_method_%s" % key)
  980. def oneshot(*args, **kw):
  981. result = fn(*args, **kw)
  982. def memo(*a, **kw):
  983. return result
  984. memo.__name__ = fn.__name__
  985. memo.__doc__ = fn.__doc__
  986. setattr(self, key, memo)
  987. return result
  988. oneshot.__doc__ = fn.__doc__
  989. return oneshot
  990. else:
  991. return self._fallback_getattr(key)
  992. # from paste.deploy.converters
  993. def asbool(obj):
  994. if isinstance(obj, compat.string_types):
  995. obj = obj.strip().lower()
  996. if obj in ["true", "yes", "on", "y", "t", "1"]:
  997. return True
  998. elif obj in ["false", "no", "off", "n", "f", "0"]:
  999. return False
  1000. else:
  1001. raise ValueError("String is not true/false: %r" % obj)
  1002. return bool(obj)
  1003. def bool_or_str(*text):
  1004. """Return a callable that will evaluate a string as
  1005. boolean, or one of a set of "alternate" string values.
  1006. """
  1007. def bool_or_value(obj):
  1008. if obj in text:
  1009. return obj
  1010. else:
  1011. return asbool(obj)
  1012. return bool_or_value
  1013. def asint(value):
  1014. """Coerce to integer."""
  1015. if value is None:
  1016. return value
  1017. return int(value)
  1018. def coerce_kw_type(kw, key, type_, flexi_bool=True, dest=None):
  1019. r"""If 'key' is present in dict 'kw', coerce its value to type 'type\_' if
  1020. necessary. If 'flexi_bool' is True, the string '0' is considered false
  1021. when coercing to boolean.
  1022. """
  1023. if dest is None:
  1024. dest = kw
  1025. if (
  1026. key in kw
  1027. and (not isinstance(type_, type) or not isinstance(kw[key], type_))
  1028. and kw[key] is not None
  1029. ):
  1030. if type_ is bool and flexi_bool:
  1031. dest[key] = asbool(kw[key])
  1032. else:
  1033. dest[key] = type_(kw[key])
  1034. def constructor_key(obj, cls):
  1035. """Produce a tuple structure that is cacheable using the __dict__ of
  1036. obj to retrieve values
  1037. """
  1038. names = get_cls_kwargs(cls)
  1039. return (cls,) + tuple(
  1040. (k, obj.__dict__[k]) for k in names if k in obj.__dict__
  1041. )
  1042. def constructor_copy(obj, cls, *args, **kw):
  1043. """Instantiate cls using the __dict__ of obj as constructor arguments.
  1044. Uses inspect to match the named arguments of ``cls``.
  1045. """
  1046. names = get_cls_kwargs(cls)
  1047. kw.update(
  1048. (k, obj.__dict__[k]) for k in names.difference(kw) if k in obj.__dict__
  1049. )
  1050. return cls(*args, **kw)
  1051. def counter():
  1052. """Return a threadsafe counter function."""
  1053. lock = compat.threading.Lock()
  1054. counter = itertools.count(1)
  1055. # avoid the 2to3 "next" transformation...
  1056. def _next():
  1057. with lock:
  1058. return next(counter)
  1059. return _next
  1060. def duck_type_collection(specimen, default=None):
  1061. """Given an instance or class, guess if it is or is acting as one of
  1062. the basic collection types: list, set and dict. If the __emulates__
  1063. property is present, return that preferentially.
  1064. """
  1065. if hasattr(specimen, "__emulates__"):
  1066. # canonicalize set vs sets.Set to a standard: the builtin set
  1067. if specimen.__emulates__ is not None and issubclass(
  1068. specimen.__emulates__, set
  1069. ):
  1070. return set
  1071. else:
  1072. return specimen.__emulates__
  1073. isa = isinstance(specimen, type) and issubclass or isinstance
  1074. if isa(specimen, list):
  1075. return list
  1076. elif isa(specimen, set):
  1077. return set
  1078. elif isa(specimen, dict):
  1079. return dict
  1080. if hasattr(specimen, "append"):
  1081. return list
  1082. elif hasattr(specimen, "add"):
  1083. return set
  1084. elif hasattr(specimen, "set"):
  1085. return dict
  1086. else:
  1087. return default
  1088. def assert_arg_type(arg, argtype, name):
  1089. if isinstance(arg, argtype):
  1090. return arg
  1091. else:
  1092. if isinstance(argtype, tuple):
  1093. raise exc.ArgumentError(
  1094. "Argument '%s' is expected to be one of type %s, got '%s'"
  1095. % (name, " or ".join("'%s'" % a for a in argtype), type(arg))
  1096. )
  1097. else:
  1098. raise exc.ArgumentError(
  1099. "Argument '%s' is expected to be of type '%s', got '%s'"
  1100. % (name, argtype, type(arg))
  1101. )
  1102. def dictlike_iteritems(dictlike):
  1103. """Return a (key, value) iterator for almost any dict-like object."""
  1104. if compat.py3k:
  1105. if hasattr(dictlike, "items"):
  1106. return list(dictlike.items())
  1107. else:
  1108. if hasattr(dictlike, "iteritems"):
  1109. return dictlike.iteritems()
  1110. elif hasattr(dictlike, "items"):
  1111. return iter(dictlike.items())
  1112. getter = getattr(dictlike, "__getitem__", getattr(dictlike, "get", None))
  1113. if getter is None:
  1114. raise TypeError("Object '%r' is not dict-like" % dictlike)
  1115. if hasattr(dictlike, "iterkeys"):
  1116. def iterator():
  1117. for key in dictlike.iterkeys():
  1118. yield key, getter(key)
  1119. return iterator()
  1120. elif hasattr(dictlike, "keys"):
  1121. return iter((key, getter(key)) for key in dictlike.keys())
  1122. else:
  1123. raise TypeError("Object '%r' is not dict-like" % dictlike)
  1124. class classproperty(property):
  1125. """A decorator that behaves like @property except that operates
  1126. on classes rather than instances.
  1127. The decorator is currently special when using the declarative
  1128. module, but note that the
  1129. :class:`~.sqlalchemy.ext.declarative.declared_attr`
  1130. decorator should be used for this purpose with declarative.
  1131. """
  1132. def __init__(self, fget, *arg, **kw):
  1133. super(classproperty, self).__init__(fget, *arg, **kw)
  1134. self.__doc__ = fget.__doc__
  1135. def __get__(desc, self, cls):
  1136. return desc.fget(cls)
  1137. class hybridproperty(object):
  1138. def __init__(self, func):
  1139. self.func = func
  1140. self.clslevel = func
  1141. def __get__(self, instance, owner):
  1142. if instance is None:
  1143. clsval = self.clslevel(owner)
  1144. return clsval
  1145. else:
  1146. return self.func(instance)
  1147. def classlevel(self, func):
  1148. self.clslevel = func
  1149. return self
  1150. class hybridmethod(object):
  1151. """Decorate a function as cls- or instance- level."""
  1152. def __init__(self, func):
  1153. self.func = self.__func__ = func
  1154. self.clslevel = func
  1155. def __get__(self, instance, owner):
  1156. if instance is None:
  1157. return self.clslevel.__get__(owner, owner.__class__)
  1158. else:
  1159. return self.func.__get__(instance, owner)
  1160. def classlevel(self, func):
  1161. self.clslevel = func
  1162. return self
  1163. class _symbol(int):
  1164. def __new__(self, name, doc=None, canonical=None):
  1165. """Construct a new named symbol."""
  1166. assert isinstance(name, compat.string_types)
  1167. if canonical is None:
  1168. canonical = hash(name)
  1169. v = int.__new__(_symbol, canonical)
  1170. v.name = name
  1171. if doc:
  1172. v.__doc__ = doc
  1173. return v
  1174. def __reduce__(self):
  1175. return symbol, (self.name, "x", int(self))
  1176. def __str__(self):
  1177. return repr(self)
  1178. def __repr__(self):
  1179. return "symbol(%r)" % self.name
  1180. _symbol.__name__ = "symbol"
  1181. class symbol(object):
  1182. """A constant symbol.
  1183. >>> symbol('foo') is symbol('foo')
  1184. True
  1185. >>> symbol('foo')
  1186. <symbol 'foo>
  1187. A slight refinement of the MAGICCOOKIE=object() pattern. The primary
  1188. advantage of symbol() is its repr(). They are also singletons.
  1189. Repeated calls of symbol('name') will all return the same instance.
  1190. The optional ``doc`` argument assigns to ``__doc__``. This
  1191. is strictly so that Sphinx autoattr picks up the docstring we want
  1192. (it doesn't appear to pick up the in-module docstring if the datamember
  1193. is in a different module - autoattribute also blows up completely).
  1194. If Sphinx fixes/improves this then we would no longer need
  1195. ``doc`` here.
  1196. """
  1197. symbols = {}
  1198. _lock = compat.threading.Lock()
  1199. def __new__(cls, name, doc=None, canonical=None):
  1200. with cls._lock:
  1201. sym = cls.symbols.get(name)
  1202. if sym is None:
  1203. cls.symbols[name] = sym = _symbol(name, doc, canonical)
  1204. return sym
  1205. @classmethod
  1206. def parse_user_argument(
  1207. cls, arg, choices, name, resolve_symbol_names=False
  1208. ):
  1209. """Given a user parameter, parse the parameter into a chosen symbol.
  1210. The user argument can be a string name that matches the name of a
  1211. symbol, or the symbol object itself, or any number of alternate choices
  1212. such as True/False/ None etc.
  1213. :param arg: the user argument.
  1214. :param choices: dictionary of symbol object to list of possible
  1215. entries.
  1216. :param name: name of the argument. Used in an :class:`.ArgumentError`
  1217. that is raised if the parameter doesn't match any available argument.
  1218. :param resolve_symbol_names: include the name of each symbol as a valid
  1219. entry.
  1220. """
  1221. # note using hash lookup is tricky here because symbol's `__hash__`
  1222. # is its int value which we don't want included in the lookup
  1223. # explicitly, so we iterate and compare each.
  1224. for sym, choice in choices.items():
  1225. if arg is sym:
  1226. return sym
  1227. elif resolve_symbol_names and arg == sym.name:
  1228. return sym
  1229. elif arg in choice:
  1230. return sym
  1231. if arg is None:
  1232. return None
  1233. raise exc.ArgumentError("Invalid value for '%s': %r" % (name, arg))
  1234. _creation_order = 1
  1235. def set_creation_order(instance):
  1236. """Assign a '_creation_order' sequence to the given instance.
  1237. This allows multiple instances to be sorted in order of creation
  1238. (typically within a single thread; the counter is not particularly
  1239. threadsafe).
  1240. """
  1241. global _creation_order
  1242. instance._creation_order = _creation_order
  1243. _creation_order += 1
  1244. def warn_exception(func, *args, **kwargs):
  1245. """executes the given function, catches all exceptions and converts to
  1246. a warning.
  1247. """
  1248. try:
  1249. return func(*args, **kwargs)
  1250. except Exception:
  1251. warn("%s('%s') ignored" % sys.exc_info()[0:2])
  1252. def ellipses_string(value, len_=25):
  1253. try:
  1254. if len(value) > len_:
  1255. return "%s..." % value[0:len_]
  1256. else:
  1257. return value
  1258. except TypeError:
  1259. return value
  1260. class _hash_limit_string(compat.text_type):
  1261. """A string subclass that can only be hashed on a maximum amount
  1262. of unique values.
  1263. This is used for warnings so that we can send out parameterized warnings
  1264. without the __warningregistry__ of the module, or the non-overridable
  1265. "once" registry within warnings.py, overloading memory,
  1266. """
  1267. def __new__(cls, value, num, args):
  1268. interpolated = (value % args) + (
  1269. " (this warning may be suppressed after %d occurrences)" % num
  1270. )
  1271. self = super(_hash_limit_string, cls).__new__(cls, interpolated)
  1272. self._hash = hash("%s_%d" % (value, hash(interpolated) % num))
  1273. return self
  1274. def __hash__(self):
  1275. return self._hash
  1276. def __eq__(self, other):
  1277. return hash(self) == hash(other)
  1278. def warn(msg, code=None):
  1279. """Issue a warning.
  1280. If msg is a string, :class:`.exc.SAWarning` is used as
  1281. the category.
  1282. """
  1283. if code:
  1284. _warnings_warn(exc.SAWarning(msg, code=code))
  1285. else:
  1286. _warnings_warn(msg, exc.SAWarning)
  1287. def warn_limited(msg, args):
  1288. """Issue a warning with a parameterized string, limiting the number
  1289. of registrations.
  1290. """
  1291. if args:
  1292. msg = _hash_limit_string(msg, 10, args)
  1293. _warnings_warn(msg, exc.SAWarning)
  1294. def _warnings_warn(message, category=None, stacklevel=2):
  1295. # adjust the given stacklevel to be outside of SQLAlchemy
  1296. try:
  1297. frame = sys._getframe(stacklevel)
  1298. except ValueError:
  1299. # being called from less than 3 (or given) stacklevels, weird,
  1300. # but don't crash
  1301. stacklevel = 0
  1302. except:
  1303. # _getframe() doesn't work, weird interpreter issue, weird,
  1304. # ok, but don't crash
  1305. stacklevel = 0
  1306. else:
  1307. # using __name__ here requires that we have __name__ in the
  1308. # __globals__ of the decorated string functions we make also.
  1309. # we generate this using {"__name__": fn.__module__}
  1310. while frame is not None and re.match(
  1311. r"^(?:sqlalchemy\.|alembic\.)", frame.f_globals.get("__name__", "")
  1312. ):
  1313. frame = frame.f_back
  1314. stacklevel += 1
  1315. if category is not None:
  1316. warnings.warn(message, category, stacklevel=stacklevel + 1)
  1317. else:
  1318. warnings.warn(message, stacklevel=stacklevel + 1)
  1319. def only_once(fn, retry_on_exception):
  1320. """Decorate the given function to be a no-op after it is called exactly
  1321. once."""
  1322. once = [fn]
  1323. def go(*arg, **kw):
  1324. # strong reference fn so that it isn't garbage collected,
  1325. # which interferes with the event system's expectations
  1326. strong_fn = fn # noqa
  1327. if once:
  1328. once_fn = once.pop()
  1329. try:
  1330. return once_fn(*arg, **kw)
  1331. except:
  1332. if retry_on_exception:
  1333. once.insert(0, once_fn)
  1334. raise
  1335. return go
  1336. _SQLA_RE = re.compile(r"sqlalchemy/([a-z_]+/){0,2}[a-z_]+\.py")
  1337. _UNITTEST_RE = re.compile(r"unit(?:2|test2?/)")
  1338. def chop_traceback(tb, exclude_prefix=_UNITTEST_RE, exclude_suffix=_SQLA_RE):
  1339. """Chop extraneous lines off beginning and end of a traceback.
  1340. :param tb:
  1341. a list of traceback lines as returned by ``traceback.format_stack()``
  1342. :param exclude_prefix:
  1343. a regular expression object matching lines to skip at beginning of
  1344. ``tb``
  1345. :param exclude_suffix:
  1346. a regular expression object matching lines to skip at end of ``tb``
  1347. """
  1348. start = 0
  1349. end = len(tb) - 1
  1350. while start <= end and exclude_prefix.search(tb[start]):
  1351. start += 1
  1352. while start <= end and exclude_suffix.search(tb[end]):
  1353. end -= 1
  1354. return tb[start : end + 1]
  1355. NoneType = type(None)
  1356. def attrsetter(attrname):
  1357. code = "def set(obj, value):" " obj.%s = value" % attrname
  1358. env = locals().copy()
  1359. exec(code, env)
  1360. return env["set"]
  1361. class EnsureKWArgType(type):
  1362. r"""Apply translation of functions to accept \**kw arguments if they
  1363. don't already.
  1364. """
  1365. def __init__(cls, clsname, bases, clsdict):
  1366. fn_reg = cls.ensure_kwarg
  1367. if fn_reg:
  1368. for key in clsdict:
  1369. m = re.match(fn_reg, key)
  1370. if m:
  1371. fn = clsdict[key]
  1372. spec = compat.inspect_getfullargspec(fn)
  1373. if not spec.varkw:
  1374. clsdict[key] = wrapped = cls._wrap_w_kw(fn)
  1375. setattr(cls, key, wrapped)
  1376. super(EnsureKWArgType, cls).__init__(clsname, bases, clsdict)
  1377. def _wrap_w_kw(self, fn):
  1378. def wrap(*arg, **kw):
  1379. return fn(*arg)
  1380. return update_wrapper(wrap, fn)
  1381. def wrap_callable(wrapper, fn):
  1382. """Augment functools.update_wrapper() to work with objects with
  1383. a ``__call__()`` method.
  1384. :param fn:
  1385. object with __call__ method
  1386. """
  1387. if hasattr(fn, "__name__"):
  1388. return update_wrapper(wrapper, fn)
  1389. else:
  1390. _f = wrapper
  1391. _f.__name__ = fn.__class__.__name__
  1392. if hasattr(fn, "__module__"):
  1393. _f.__module__ = fn.__module__
  1394. if hasattr(fn.__call__, "__doc__") and fn.__call__.__doc__:
  1395. _f.__doc__ = fn.__call__.__doc__
  1396. elif fn.__doc__:
  1397. _f.__doc__ = fn.__doc__
  1398. return _f
  1399. def quoted_token_parser(value):
  1400. """Parse a dotted identifier with accommodation for quoted names.
  1401. Includes support for SQL-style double quotes as a literal character.
  1402. E.g.::
  1403. >>> quoted_token_parser("name")
  1404. ["name"]
  1405. >>> quoted_token_parser("schema.name")
  1406. ["schema", "name"]
  1407. >>> quoted_token_parser('"Schema"."Name"')
  1408. ['Schema', 'Name']
  1409. >>> quoted_token_parser('"Schema"."Name""Foo"')
  1410. ['Schema', 'Name""Foo']
  1411. """
  1412. if '"' not in value:
  1413. return value.split(".")
  1414. # 0 = outside of quotes
  1415. # 1 = inside of quotes
  1416. state = 0
  1417. result = [[]]
  1418. idx = 0
  1419. lv = len(value)
  1420. while idx < lv:
  1421. char = value[idx]
  1422. if char == '"':
  1423. if state == 1 and idx < lv - 1 and value[idx + 1] == '"':
  1424. result[-1].append('"')
  1425. idx += 1
  1426. else:
  1427. state ^= 1
  1428. elif char == "." and state == 0:
  1429. result.append([])
  1430. else:
  1431. result[-1].append(char)
  1432. idx += 1
  1433. return ["".join(token) for token in result]
  1434. def add_parameter_text(params, text):
  1435. params = _collections.to_list(params)
  1436. def decorate(fn):
  1437. doc = fn.__doc__ is not None and fn.__doc__ or ""
  1438. if doc:
  1439. doc = inject_param_text(doc, {param: text for param in params})
  1440. fn.__doc__ = doc
  1441. return fn
  1442. return decorate
  1443. def _dedent_docstring(text):
  1444. split_text = text.split("\n", 1)
  1445. if len(split_text) == 1:
  1446. return text
  1447. else:
  1448. firstline, remaining = split_text
  1449. if not firstline.startswith(" "):
  1450. return firstline + "\n" + textwrap.dedent(remaining)
  1451. else:
  1452. return textwrap.dedent(text)
  1453. def inject_docstring_text(doctext, injecttext, pos):
  1454. doctext = _dedent_docstring(doctext or "")
  1455. lines = doctext.split("\n")
  1456. if len(lines) == 1:
  1457. lines.append("")
  1458. injectlines = textwrap.dedent(injecttext).split("\n")
  1459. if injectlines[0]:
  1460. injectlines.insert(0, "")
  1461. blanks = [num for num, line in enumerate(lines) if not line.strip()]
  1462. blanks.insert(0, 0)
  1463. inject_pos = blanks[min(pos, len(blanks) - 1)]
  1464. lines = lines[0:inject_pos] + injectlines + lines[inject_pos:]
  1465. return "\n".join(lines)
  1466. _param_reg = re.compile(r"(\s+):param (.+?):")
  1467. def inject_param_text(doctext, inject_params):
  1468. doclines = collections.deque(doctext.splitlines())
  1469. lines = []
  1470. # TODO: this is not working for params like ":param case_sensitive=True:"
  1471. to_inject = None
  1472. while doclines:
  1473. line = doclines.popleft()
  1474. m = _param_reg.match(line)
  1475. if to_inject is None:
  1476. if m:
  1477. param = m.group(2).lstrip("*")
  1478. if param in inject_params:
  1479. # default indent to that of :param: plus one
  1480. indent = " " * len(m.group(1)) + " "
  1481. # but if the next line has text, use that line's
  1482. # indentation
  1483. if doclines:
  1484. m2 = re.match(r"(\s+)\S", doclines[0])
  1485. if m2:
  1486. indent = " " * len(m2.group(1))
  1487. to_inject = indent + inject_params[param]
  1488. elif m:
  1489. lines.extend(["\n", to_inject, "\n"])
  1490. to_inject = None
  1491. elif not line.rstrip():
  1492. lines.extend([line, to_inject, "\n"])
  1493. to_inject = None
  1494. elif line.endswith("::"):
  1495. # TODO: this still wont cover if the code example itself has blank
  1496. # lines in it, need to detect those via indentation.
  1497. lines.extend([line, doclines.popleft()])
  1498. continue
  1499. lines.append(line)
  1500. return "\n".join(lines)
  1501. def repr_tuple_names(names):
  1502. """Trims a list of strings from the middle and return a string of up to
  1503. four elements. Strings greater than 11 characters will be truncated"""
  1504. if len(names) == 0:
  1505. return None
  1506. flag = len(names) <= 4
  1507. names = names[0:4] if flag else names[0:3] + names[-1:]
  1508. res = ["%s.." % name[:11] if len(name) > 11 else name for name in names]
  1509. if flag:
  1510. return ", ".join(res)
  1511. else:
  1512. return "%s, ..., %s" % (", ".join(res[0:3]), res[-1])
  1513. def has_compiled_ext():
  1514. try:
  1515. from sqlalchemy import cimmutabledict # noqa: F401
  1516. from sqlalchemy import cprocessors # noqa: F401
  1517. from sqlalchemy import cresultproxy # noqa: F401
  1518. return True
  1519. except ImportError:
  1520. return False