_compat.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import sys
  2. import platform
  3. __all__ = ['install', 'NullFinder', 'Protocol']
  4. try:
  5. from typing import Protocol
  6. except ImportError: # pragma: no cover
  7. """
  8. pytest-mypy complains here because:
  9. error: Incompatible import of "Protocol" (imported name has type
  10. "typing_extensions._SpecialForm", local name has type "typing._SpecialForm")
  11. """
  12. from typing_extensions import Protocol # type: ignore
  13. def install(cls):
  14. """
  15. Class decorator for installation on sys.meta_path.
  16. Adds the backport DistributionFinder to sys.meta_path and
  17. attempts to disable the finder functionality of the stdlib
  18. DistributionFinder.
  19. """
  20. sys.meta_path.append(cls())
  21. disable_stdlib_finder()
  22. return cls
  23. def disable_stdlib_finder():
  24. """
  25. Give the backport primacy for discovering path-based distributions
  26. by monkey-patching the stdlib O_O.
  27. See #91 for more background for rationale on this sketchy
  28. behavior.
  29. """
  30. def matches(finder):
  31. return getattr(
  32. finder, '__module__', None
  33. ) == '_frozen_importlib_external' and hasattr(finder, 'find_distributions')
  34. for finder in filter(matches, sys.meta_path): # pragma: nocover
  35. del finder.find_distributions
  36. class NullFinder:
  37. """
  38. A "Finder" (aka "MetaClassFinder") that never finds any modules,
  39. but may find distributions.
  40. """
  41. @staticmethod
  42. def find_spec(*args, **kwargs):
  43. return None
  44. # In Python 2, the import system requires finders
  45. # to have a find_module() method, but this usage
  46. # is deprecated in Python 3 in favor of find_spec().
  47. # For the purposes of this finder (i.e. being present
  48. # on sys.meta_path but having no other import
  49. # system functionality), the two methods are identical.
  50. find_module = find_spec
  51. def pypy_partial(val):
  52. """
  53. Adjust for variable stacklevel on partial under PyPy.
  54. Workaround for #327.
  55. """
  56. is_pypy = platform.python_implementation() == 'PyPy'
  57. return val + is_pypy