You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

monkey.py 2.2KB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. # -*- test-case-name: twisted.test.test_monkey -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. from __future__ import division, absolute_import
  5. class MonkeyPatcher(object):
  6. """
  7. Cover up attributes with new objects. Neat for monkey-patching things for
  8. unit-testing purposes.
  9. """
  10. def __init__(self, *patches):
  11. # List of patches to apply in (obj, name, value).
  12. self._patchesToApply = []
  13. # List of the original values for things that have been patched.
  14. # (obj, name, value) format.
  15. self._originals = []
  16. for patch in patches:
  17. self.addPatch(*patch)
  18. def addPatch(self, obj, name, value):
  19. """
  20. Add a patch so that the attribute C{name} on C{obj} will be assigned to
  21. C{value} when C{patch} is called or during C{runWithPatches}.
  22. You can restore the original values with a call to restore().
  23. """
  24. self._patchesToApply.append((obj, name, value))
  25. def _alreadyPatched(self, obj, name):
  26. """
  27. Has the C{name} attribute of C{obj} already been patched by this
  28. patcher?
  29. """
  30. for o, n, v in self._originals:
  31. if (o, n) == (obj, name):
  32. return True
  33. return False
  34. def patch(self):
  35. """
  36. Apply all of the patches that have been specified with L{addPatch}.
  37. Reverse this operation using L{restore}.
  38. """
  39. for obj, name, value in self._patchesToApply:
  40. if not self._alreadyPatched(obj, name):
  41. self._originals.append((obj, name, getattr(obj, name)))
  42. setattr(obj, name, value)
  43. def restore(self):
  44. """
  45. Restore all original values to any patched objects.
  46. """
  47. while self._originals:
  48. obj, name, value = self._originals.pop()
  49. setattr(obj, name, value)
  50. def runWithPatches(self, f, *args, **kw):
  51. """
  52. Apply each patch already specified. Then run the function f with the
  53. given args and kwargs. Restore everything when done.
  54. """
  55. self.patch()
  56. try:
  57. return f(*args, **kw)
  58. finally:
  59. self.restore()