Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
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.

context.py 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. # -*- test-case-name: twisted.test.test_context -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Dynamic pseudo-scoping for Python.
  6. Call functions with context.call({key: value}, func); func and
  7. functions that it calls will be able to use 'context.get(key)' to
  8. retrieve 'value'.
  9. This is thread-safe.
  10. """
  11. from threading import local
  12. from typing import Dict, Type
  13. defaultContextDict: Dict[Type[object], Dict[str, str]] = {}
  14. setDefault = defaultContextDict.__setitem__
  15. class ContextTracker:
  16. """
  17. A L{ContextTracker} provides a way to pass arbitrary key/value data up and
  18. down a call stack without passing them as parameters to the functions on
  19. that call stack.
  20. This can be useful when functions on the top and bottom of the call stack
  21. need to cooperate but the functions in between them do not allow passing the
  22. necessary state. For example::
  23. from twisted.python.context import call, get
  24. def handleRequest(request):
  25. call({'request-id': request.id}, renderRequest, request.url)
  26. def renderRequest(url):
  27. renderHeader(url)
  28. renderBody(url)
  29. def renderHeader(url):
  30. return "the header"
  31. def renderBody(url):
  32. return "the body (request id=%r)" % (get("request-id"),)
  33. This should be used sparingly, since the lack of a clear connection between
  34. the two halves can result in code which is difficult to understand and
  35. maintain.
  36. @ivar contexts: A C{list} of C{dict}s tracking the context state. Each new
  37. L{ContextTracker.callWithContext} pushes a new C{dict} onto this stack
  38. for the duration of the call, making the data available to the function
  39. called and restoring the previous data once it is complete..
  40. """
  41. def __init__(self):
  42. self.contexts = [defaultContextDict]
  43. def callWithContext(self, newContext, func, *args, **kw):
  44. """
  45. Call C{func(*args, **kw)} such that the contents of C{newContext} will
  46. be available for it to retrieve using L{getContext}.
  47. @param newContext: A C{dict} of data to push onto the context for the
  48. duration of the call to C{func}.
  49. @param func: A callable which will be called.
  50. @param args: Any additional positional arguments to pass to C{func}.
  51. @param kw: Any additional keyword arguments to pass to C{func}.
  52. @return: Whatever is returned by C{func}
  53. @raise Exception: Whatever is raised by C{func}.
  54. """
  55. self.contexts.append(newContext)
  56. try:
  57. return func(*args, **kw)
  58. finally:
  59. self.contexts.pop()
  60. def getContext(self, key, default=None):
  61. """
  62. Retrieve the value for a key from the context.
  63. @param key: The key to look up in the context.
  64. @param default: The value to return if C{key} is not found in the
  65. context.
  66. @return: The value most recently remembered in the context for C{key}.
  67. """
  68. for ctx in reversed(self.contexts):
  69. try:
  70. return ctx[key]
  71. except KeyError:
  72. pass
  73. return default
  74. class ThreadedContextTracker:
  75. def __init__(self):
  76. self.storage = local()
  77. def currentContext(self):
  78. try:
  79. return self.storage.ct
  80. except AttributeError:
  81. ct = self.storage.ct = ContextTracker()
  82. return ct
  83. def callWithContext(self, ctx, func, *args, **kw):
  84. return self.currentContext().callWithContext(ctx, func, *args, **kw)
  85. def getContext(self, key, default=None):
  86. return self.currentContext().getContext(key, default)
  87. theContextTracker = ThreadedContextTracker()
  88. call = theContextTracker.callWithContext
  89. get = theContextTracker.getContext
  90. def installContextTracker(ctr):
  91. global theContextTracker
  92. global call
  93. global get
  94. theContextTracker = ctr
  95. call = theContextTracker.callWithContext
  96. get = theContextTracker.getContext