_core.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. # -*- coding: utf-8 -*-
  2. '''some core stuf.'''
  3. from itertools import chain
  4. from collections import MutableMapping
  5. from operator import methodcaller, attrgetter
  6. from .desc import lazy_class, lazy
  7. from .collects import recursive_repr
  8. from .deep import clsname, getcls, clsdict
  9. from .six import getvalues, getitems, getkeys
  10. from .iterable import exhaustcall, exhaustmap
  11. wraps = attrgetter('_wrapped')
  12. delitem = attrgetter('_wrapped.__delitem__')
  13. getitem = attrgetter('_wrapped.__getitem__')
  14. setitem = attrgetter('_wrapped.__setitem__')
  15. length = attrgetter('_wrapped.__len__')
  16. _iter = attrgetter('_wrapped.__iter__')
  17. asdict = attrgetter('_wrapped._asdict')
  18. _reserved = 'allowed _wrapped _map'.split()
  19. class baseread(object):
  20. def __getattr__(self, key, _getter=object.__getattribute__):
  21. if key == 'iteritems':
  22. return getitems(self)
  23. elif key == 'iterkeys':
  24. return getkeys(self)
  25. elif key == 'itervalues':
  26. return getvalues(self)
  27. try:
  28. return self[key]
  29. except KeyError:
  30. return _getter(self, key)
  31. @recursive_repr()
  32. def __repr__(self):
  33. items = methodcaller('items')(self)
  34. kwstr = ', '.join('{0!s}={1!r}'.format(*item) for item in items)
  35. return '{0}({1})'.format(clsname(self), kwstr)
  36. @lazy_class
  37. def _classkeys(self):
  38. # protected keywords
  39. return frozenset(chain(
  40. iter(vars(self)), iter(vars(getcls(self))), _reserved,
  41. ))
  42. class basewrite(baseread):
  43. def __setattr__(self, key, value):
  44. # handle normal object attributes
  45. if key == '_classkeys' or key in self._classkeys:
  46. clsdict(self)[key] = value
  47. # handle special attributes
  48. else:
  49. try:
  50. self[key] = value
  51. except KeyError:
  52. raise AttributeError(key)
  53. def __delattr__(self, key):
  54. # allow deletion of key-value pairs only
  55. if not key == '_classkeys' or key in self._classkeys:
  56. try:
  57. del self[key]
  58. except KeyError:
  59. raise AttributeError(key)
  60. class corestuf(baseread):
  61. _map = dict
  62. def _build(self, iterable):
  63. # add class to handle potential nested objects of the same class
  64. try:
  65. kw = self._map()
  66. # extract appropriate key-values from sequence
  67. exhaustcall(kw.update, iterable)
  68. except ValueError:
  69. kw.update(iterable)
  70. return kw
  71. def _mapping(self, iterable):
  72. return self._map(iterable)
  73. def _new(self, iterable):
  74. return getcls(self)(self._build(iterable))
  75. def _prepop(self, *args, **kw):
  76. kw.update(self._build(args))
  77. return kw
  78. def _pop(self, past, future):
  79. def closure(key, value, new=self._new):
  80. try:
  81. if not hasattr(value, 'capitalize'):
  82. # see if stuf can be converted to nested stuf
  83. trial = new(value)
  84. value = trial if trial else value
  85. except (TypeError, IOError):
  86. pass
  87. future[key] = value
  88. exhaustmap(closure, past)
  89. return self._postpop(future)
  90. def _postpop(self, future):
  91. return future
  92. def copy(self):
  93. return self._new(dict(self))
  94. class writestuf(corestuf, basewrite):
  95. def update(self, *args, **kw):
  96. self._pop(self._prepop(*args, **kw), self)
  97. class wrapstuf(corestuf):
  98. def __init__(self, *args, **kw):
  99. super(wrapstuf, self).__init__()
  100. self._wrapped = self._pop(self._prepop(*args, **kw), self._map())
  101. def _postpop(self, future):
  102. return self._mapping(future)
  103. class writewrapstuf(wrapstuf, writestuf, MutableMapping):
  104. @lazy
  105. def __getitem__(self):
  106. return getitem(self)
  107. @lazy
  108. def __setitem__(self):
  109. return setitem(self)
  110. @lazy
  111. def __delitem__(self):
  112. return delitem(self)
  113. @lazy
  114. def __iter__(self):
  115. return _iter(self)
  116. @lazy
  117. def __len__(self):
  118. return length(self)
  119. def __reduce__(self):
  120. return (getcls(self), (wraps(self).copy(),))