_util.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. # -*- coding: utf-8 -*-
  2. """
  3. internal gevent utilities, not for external use.
  4. """
  5. from __future__ import print_function, absolute_import, division
  6. from gevent._compat import iteritems
  7. class _NONE(object):
  8. """
  9. A special object you must never pass to any gevent API.
  10. Used as a marker object for keyword arguments that cannot have the
  11. builtin None (because that might be a valid value).
  12. """
  13. __slots__ = ()
  14. def __repr__(self):
  15. return '<default value>'
  16. _NONE = _NONE()
  17. def copy_globals(source,
  18. globs,
  19. only_names=None,
  20. ignore_missing_names=False,
  21. names_to_ignore=(),
  22. dunder_names_to_keep=('__implements__', '__all__', '__imports__'),
  23. cleanup_globs=True):
  24. """
  25. Copy attributes defined in `source.__dict__` to the dictionary in globs
  26. (which should be the caller's globals()).
  27. Names that start with `__` are ignored (unless they are in
  28. *dunder_names_to_keep*). Anything found in *names_to_ignore* is
  29. also ignored.
  30. If *only_names* is given, only those attributes will be considered.
  31. In this case, *ignore_missing_names* says whether or not to raise an AttributeError
  32. if one of those names can't be found.
  33. If cleanup_globs has a true value, then common things imported but not used
  34. at runtime are removed, including this function.
  35. Returns a list of the names copied
  36. """
  37. if only_names:
  38. if ignore_missing_names:
  39. items = ((k, getattr(source, k, _NONE)) for k in only_names)
  40. else:
  41. items = ((k, getattr(source, k)) for k in only_names)
  42. else:
  43. items = iteritems(source.__dict__)
  44. copied = []
  45. for key, value in items:
  46. if value is _NONE:
  47. continue
  48. if key in names_to_ignore:
  49. continue
  50. if key.startswith("__") and key not in dunder_names_to_keep:
  51. continue
  52. globs[key] = value
  53. copied.append(key)
  54. if cleanup_globs:
  55. if 'copy_globals' in globs:
  56. del globs['copy_globals']
  57. return copied
  58. class Lazy(object):
  59. """
  60. A non-data descriptor used just like @property. The
  61. difference is the function value is assigned to the instance
  62. dict the first time it is accessed and then the function is never
  63. called agoin.
  64. """
  65. def __init__(self, func):
  66. self.data = (func, func.__name__)
  67. def __get__(self, inst, class_):
  68. if inst is None:
  69. return self
  70. func, name = self.data
  71. value = func(inst)
  72. inst.__dict__[name] = value
  73. return value
  74. class readproperty(object):
  75. """
  76. A non-data descriptor like @property. The difference is that
  77. when the property is assigned to, it is cached in the instance
  78. and the function is not called on that instance again.
  79. """
  80. def __init__(self, func):
  81. self.func = func
  82. def __get__(self, inst, class_):
  83. if inst is None:
  84. return self
  85. return self.func(inst)