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.
 
 
 
 

158 lines
5.1 KiB

  1. import contextlib
  2. import os
  3. import subprocess
  4. import sys
  5. from pathlib import Path
  6. import path
  7. import pytest
  8. from . import contexts, environment
  9. @pytest.fixture
  10. def user_override(monkeypatch):
  11. """
  12. Override site.USER_BASE and site.USER_SITE with temporary directories in
  13. a context.
  14. """
  15. with contexts.tempdir() as user_base:
  16. monkeypatch.setattr('site.USER_BASE', user_base)
  17. with contexts.tempdir() as user_site:
  18. monkeypatch.setattr('site.USER_SITE', user_site)
  19. with contexts.save_user_site_setting():
  20. yield
  21. @pytest.fixture
  22. def tmpdir_cwd(tmpdir):
  23. with tmpdir.as_cwd() as orig:
  24. yield orig
  25. @pytest.fixture(autouse=True, scope="session")
  26. def workaround_xdist_376(request):
  27. """
  28. Workaround pytest-dev/pytest-xdist#376
  29. ``pytest-xdist`` tends to inject '' into ``sys.path``,
  30. which may break certain isolation expectations.
  31. Remove the entry so the import
  32. machinery behaves the same irrespective of xdist.
  33. """
  34. if not request.config.pluginmanager.has_plugin('xdist'):
  35. return
  36. with contextlib.suppress(ValueError):
  37. sys.path.remove('')
  38. @pytest.fixture
  39. def sample_project(tmp_path):
  40. """
  41. Clone the 'sampleproject' and return a path to it.
  42. """
  43. cmd = ['git', 'clone', 'https://github.com/pypa/sampleproject']
  44. try:
  45. subprocess.check_call(cmd, cwd=str(tmp_path))
  46. except Exception:
  47. pytest.skip("Unable to clone sampleproject")
  48. return tmp_path / 'sampleproject'
  49. # sdist and wheel artifacts should be stable across a round of tests
  50. # so we can build them once per session and use the files as "readonly"
  51. # In the case of setuptools, building the wheel without sdist may cause
  52. # it to contain the `build` directory, and therefore create situations with
  53. # `setuptools/build/lib/build/lib/...`. To avoid that, build both artifacts at once.
  54. def _build_distributions(tmp_path_factory, request):
  55. with contexts.session_locked_tmp_dir(
  56. request, tmp_path_factory, "dist_build"
  57. ) as tmp: # pragma: no cover
  58. sdist = next(tmp.glob("*.tar.gz"), None)
  59. wheel = next(tmp.glob("*.whl"), None)
  60. if sdist and wheel:
  61. return (sdist, wheel)
  62. # Sanity check: should not create recursive setuptools/build/lib/build/lib/...
  63. assert not Path(request.config.rootdir, "build/lib/build").exists()
  64. subprocess.check_output([
  65. sys.executable,
  66. "-m",
  67. "build",
  68. "--outdir",
  69. str(tmp),
  70. str(request.config.rootdir),
  71. ])
  72. # Sanity check: should not create recursive setuptools/build/lib/build/lib/...
  73. assert not Path(request.config.rootdir, "build/lib/build").exists()
  74. return next(tmp.glob("*.tar.gz")), next(tmp.glob("*.whl"))
  75. @pytest.fixture(scope="session")
  76. def setuptools_sdist(tmp_path_factory, request):
  77. prebuilt = os.getenv("PRE_BUILT_SETUPTOOLS_SDIST")
  78. if prebuilt and os.path.exists(prebuilt): # pragma: no cover
  79. return Path(prebuilt).resolve()
  80. sdist, _ = _build_distributions(tmp_path_factory, request)
  81. return sdist
  82. @pytest.fixture(scope="session")
  83. def setuptools_wheel(tmp_path_factory, request):
  84. prebuilt = os.getenv("PRE_BUILT_SETUPTOOLS_WHEEL")
  85. if prebuilt and os.path.exists(prebuilt): # pragma: no cover
  86. return Path(prebuilt).resolve()
  87. _, wheel = _build_distributions(tmp_path_factory, request)
  88. return wheel
  89. @pytest.fixture
  90. def venv(tmp_path, setuptools_wheel):
  91. """Virtual env with the version of setuptools under test installed"""
  92. env = environment.VirtualEnv()
  93. env.root = path.Path(tmp_path / 'venv')
  94. env.create_opts = ['--no-setuptools', '--wheel=bundle']
  95. # TODO: Use `--no-wheel` when setuptools implements its own bdist_wheel
  96. env.req = str(setuptools_wheel)
  97. # In some environments (eg. downstream distro packaging),
  98. # where tox isn't used to run tests and PYTHONPATH is set to point to
  99. # a specific setuptools codebase, PYTHONPATH will leak into the spawned
  100. # processes.
  101. # env.create() should install the just created setuptools
  102. # wheel, but it doesn't if it finds another existing matching setuptools
  103. # installation present on PYTHONPATH:
  104. # `setuptools is already installed with the same version as the provided
  105. # wheel. Use --force-reinstall to force an installation of the wheel.`
  106. # This prevents leaking PYTHONPATH to the created environment.
  107. with contexts.environment(PYTHONPATH=None):
  108. return env.create()
  109. @pytest.fixture
  110. def venv_without_setuptools(tmp_path):
  111. """Virtual env without any version of setuptools installed"""
  112. env = environment.VirtualEnv()
  113. env.root = path.Path(tmp_path / 'venv_without_setuptools')
  114. env.create_opts = ['--no-setuptools', '--no-wheel']
  115. env.ensure_env()
  116. return env
  117. @pytest.fixture
  118. def bare_venv(tmp_path):
  119. """Virtual env without any common packages installed"""
  120. env = environment.VirtualEnv()
  121. env.root = path.Path(tmp_path / 'bare_venv')
  122. env.create_opts = ['--no-setuptools', '--no-pip', '--no-wheel', '--no-seed']
  123. env.ensure_env()
  124. return env