base.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. # -*- coding: utf-8 -*-
  2. '''stuf base.'''
  3. import sys
  4. from functools import partial
  5. from keyword import iskeyword
  6. from operator import itemgetter
  7. from unicodedata import normalize
  8. from importlib import import_module
  9. from collections import Sequence, Mapping
  10. # one frame
  11. one = lambda a, b: a(b)
  12. # two frame
  13. two = lambda a, b, *args: a(b(*args))
  14. # factory for "is" checkers
  15. isfactory = lambda x: partial(lambda x, y, z: x(z, y), isinstance, x)
  16. # next frame up
  17. getframe = partial(sys._getframe, 1)
  18. identity = lambda x: x
  19. dualidentity = lambda x, y: (x, y)
  20. isnone = lambda x, y: x if y is None else y
  21. first = itemgetter(0)
  22. second = itemgetter(1)
  23. last = itemgetter(-1)
  24. maporseq = isfactory((Mapping, Sequence))
  25. ismapping = isfactory(Mapping)
  26. issequence = isfactory(Sequence)
  27. norm = partial(normalize, 'NFKD')
  28. # illegal characters for Python names
  29. ic = frozenset('()[]{}@,:`=;+*/%&|^><\'"#\\$?!~'.split())
  30. def backport(*paths):
  31. '''Go through import `paths` until one imports or everything fails.'''
  32. load = None
  33. for path in paths:
  34. try:
  35. load = importer(path)
  36. break
  37. except ImportError:
  38. continue
  39. if load is None:
  40. raise ImportError('no path')
  41. return load
  42. def checkname(name, ic=ic):
  43. '''Ensures `name` is legal for Python.'''
  44. # Remove characters that are illegal in a Python name
  45. name = name.strip().lower().replace('-', '_').replace(
  46. '.', '_'
  47. ).replace(' ', '_')
  48. name = ''.join(i for i in name if i not in ic)
  49. # add _ if value is Python keyword
  50. return name + '_' if iskeyword(name) else name
  51. def coroutine(func):
  52. '''The Dave Beazley co-routine decorator.'''
  53. def start(*args, **kw):
  54. cr = func(*args, **kw)
  55. cr.next()
  56. return cr
  57. return start
  58. def docit(call, doc):
  59. '''Add documentation to a callable.'''
  60. call.__doc__ = doc
  61. return call
  62. def importer(path, attribute=None, i=import_module, g=getattr):
  63. '''Import module `path`, optionally with `attribute`.'''
  64. try:
  65. dot = path.rindex('.')
  66. # import module
  67. path = g(i(path[:dot]), path[dot + 1:])
  68. # If nothing but module name, import the module
  69. except (AttributeError, ValueError):
  70. path = i(path)
  71. if attribute:
  72. path = g(path, attribute)
  73. return path