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.

deprecation.py 5.1KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import asyncio
  2. import inspect
  3. import warnings
  4. from asgiref.sync import sync_to_async
  5. class RemovedInNextVersionWarning(DeprecationWarning):
  6. pass
  7. class RemovedInDjango50Warning(PendingDeprecationWarning):
  8. pass
  9. RemovedAfterNextVersionWarning = RemovedInDjango50Warning
  10. class warn_about_renamed_method:
  11. def __init__(
  12. self, class_name, old_method_name, new_method_name, deprecation_warning
  13. ):
  14. self.class_name = class_name
  15. self.old_method_name = old_method_name
  16. self.new_method_name = new_method_name
  17. self.deprecation_warning = deprecation_warning
  18. def __call__(self, f):
  19. def wrapped(*args, **kwargs):
  20. warnings.warn(
  21. "`%s.%s` is deprecated, use `%s` instead."
  22. % (self.class_name, self.old_method_name, self.new_method_name),
  23. self.deprecation_warning,
  24. 2,
  25. )
  26. return f(*args, **kwargs)
  27. return wrapped
  28. class RenameMethodsBase(type):
  29. """
  30. Handles the deprecation paths when renaming a method.
  31. It does the following:
  32. 1) Define the new method if missing and complain about it.
  33. 2) Define the old method if missing.
  34. 3) Complain whenever an old method is called.
  35. See #15363 for more details.
  36. """
  37. renamed_methods = ()
  38. def __new__(cls, name, bases, attrs):
  39. new_class = super().__new__(cls, name, bases, attrs)
  40. for base in inspect.getmro(new_class):
  41. class_name = base.__name__
  42. for renamed_method in cls.renamed_methods:
  43. old_method_name = renamed_method[0]
  44. old_method = base.__dict__.get(old_method_name)
  45. new_method_name = renamed_method[1]
  46. new_method = base.__dict__.get(new_method_name)
  47. deprecation_warning = renamed_method[2]
  48. wrapper = warn_about_renamed_method(class_name, *renamed_method)
  49. # Define the new method if missing and complain about it
  50. if not new_method and old_method:
  51. warnings.warn(
  52. "`%s.%s` method should be renamed `%s`."
  53. % (class_name, old_method_name, new_method_name),
  54. deprecation_warning,
  55. 2,
  56. )
  57. setattr(base, new_method_name, old_method)
  58. setattr(base, old_method_name, wrapper(old_method))
  59. # Define the old method as a wrapped call to the new method.
  60. if not old_method and new_method:
  61. setattr(base, old_method_name, wrapper(new_method))
  62. return new_class
  63. class DeprecationInstanceCheck(type):
  64. def __instancecheck__(self, instance):
  65. warnings.warn(
  66. "`%s` is deprecated, use `%s` instead." % (self.__name__, self.alternative),
  67. self.deprecation_warning,
  68. 2,
  69. )
  70. return super().__instancecheck__(instance)
  71. class MiddlewareMixin:
  72. sync_capable = True
  73. async_capable = True
  74. def __init__(self, get_response):
  75. if get_response is None:
  76. raise ValueError("get_response must be provided.")
  77. self.get_response = get_response
  78. self._async_check()
  79. super().__init__()
  80. def __repr__(self):
  81. return "<%s get_response=%s>" % (
  82. self.__class__.__qualname__,
  83. getattr(
  84. self.get_response,
  85. "__qualname__",
  86. self.get_response.__class__.__name__,
  87. ),
  88. )
  89. def _async_check(self):
  90. """
  91. If get_response is a coroutine function, turns us into async mode so
  92. a thread is not consumed during a whole request.
  93. """
  94. if asyncio.iscoroutinefunction(self.get_response):
  95. # Mark the class as async-capable, but do the actual switch
  96. # inside __call__ to avoid swapping out dunder methods
  97. self._is_coroutine = asyncio.coroutines._is_coroutine
  98. else:
  99. self._is_coroutine = None
  100. def __call__(self, request):
  101. # Exit out to async mode, if needed
  102. if self._is_coroutine:
  103. return self.__acall__(request)
  104. response = None
  105. if hasattr(self, "process_request"):
  106. response = self.process_request(request)
  107. response = response or self.get_response(request)
  108. if hasattr(self, "process_response"):
  109. response = self.process_response(request, response)
  110. return response
  111. async def __acall__(self, request):
  112. """
  113. Async version of __call__ that is swapped in when an async request
  114. is running.
  115. """
  116. response = None
  117. if hasattr(self, "process_request"):
  118. response = await sync_to_async(
  119. self.process_request,
  120. thread_sensitive=True,
  121. )(request)
  122. response = response or await self.get_response(request)
  123. if hasattr(self, "process_response"):
  124. response = await sync_to_async(
  125. self.process_response,
  126. thread_sensitive=True,
  127. )(request, response)
  128. return response