datastructures.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # -*- coding: utf-8 -*-
  2. #!/usr/bin/env python
  3. import types
  4. class Node:
  5. pass
  6. from redis import Redis
  7. class NodeVisitor:
  8. def visit(self, node):
  9. stack = [ node ]
  10. last_result = None
  11. while stack:
  12. try:
  13. last = stack[-1]
  14. if isinstance(last, types.GeneratorType):
  15. stack.append(last.send(last_result))
  16. last_result = None
  17. elif isinstance(last, Node):
  18. stack.append(self._visit(stack.pop()))
  19. else:
  20. last_result = stack.pop()
  21. except StopIteration:
  22. stack.pop()
  23. return last_result
  24. def _visit(self, node):
  25. methname = 'visit_' + type(node).__name__
  26. meth = getattr(self, methname, None)
  27. if meth is None:
  28. meth = self.generic_visit
  29. return meth(node)
  30. def generic_visit(self, node):
  31. raise RuntimeError('No {} method'.format('visit_' + type(node).__name__))
  32. # Base class. Uses a descriptor to set a value
  33. class Descriptor(object):
  34. def __init__(self, name=None, **options):
  35. self.name = name
  36. for key, value in options.items():
  37. setattr(self, key, value)
  38. def __set__(self, instance, value):
  39. instance.__dict__[self.name] = value
  40. # Descriptor for enforcing types
  41. class Typed(Descriptor):
  42. expected_type = type(None)
  43. def __set__(self, instance, value):
  44. if not isinstance(value, self.expected_type):
  45. raise TypeError('expected ' + str(self.expected_type))
  46. super(Typed, self).__set__(instance, value)
  47. # Descriptor for enforcing values
  48. class Unsigned(Descriptor):
  49. def __set__(self, instance, value):
  50. if value < 0:
  51. raise ValueError('Expected >= 0')
  52. super(Unsigned, self).__set__(instance, value)
  53. class MaxSized(Descriptor):
  54. def __init__(self, name=None, **options):
  55. if 'size' not in options:
  56. raise TypeError('missing size option')
  57. super(MaxSized, self).__init__(name, **options)
  58. # noinspection PyUnresolvedReferences
  59. def __set__(self, instance, value):
  60. if len(value) >= self.size:
  61. raise ValueError('size must be < ' + str(self.size))
  62. super(MaxSized, self).__set__(instance, value)
  63. # Class decorator to apply constraints
  64. def check_attributes(**kwargs):
  65. def decorate(cls):
  66. for key, value in kwargs.items():
  67. if isinstance(value, Descriptor):
  68. value.name = key
  69. setattr(cls, key, value)
  70. else:
  71. setattr(cls, key, value(key))
  72. return cls
  73. return decorate
  74. class LazyRedisConnection:
  75. builder = Redis
  76. def __init__(self, host, port, db=0):
  77. self.host = host
  78. self.port = port
  79. self.db = db
  80. self.client = None
  81. def __enter__(self):
  82. self.client = self.builder(host=self.host, port=self.port, db=self.db)
  83. return self.client
  84. def __exit__(self, exc_ty, exc_val, tb):
  85. self.client.close()
  86. class BaseVisitor(object):
  87. def entry(self, node):
  88. return type(node).__name__
  89. def visit(self, node):
  90. methname = 'visit_' + self.entry(node)
  91. meth = getattr(self, methname, None)
  92. if meth is None:
  93. meth = self.generic_visit
  94. return meth(node)
  95. def generic_visit(self, node):
  96. raise RuntimeError('No {} method'.format('visit_' + type(node).__name__))