|
6 | 6 | import typing
|
7 | 7 |
|
8 | 8 | import poetry.core.factory
|
| 9 | +import tomlkit |
9 | 10 | import tox
|
10 | 11 |
|
11 | 12 | if typing.TYPE_CHECKING:
|
|
17 | 18 | PIP_DEFAULT_INDEX_SERVER_URL = 'https://pypi.org/simple'
|
18 | 19 | PIP_DEFAULT_INDEX_SERVER_NAME = 'pypi'
|
19 | 20 |
|
| 21 | +POETRY_LOCKFILE_FILE_NAME = 'poetry.lock' |
| 22 | + |
20 | 23 |
|
21 | 24 | class _Exception(Exception):
|
22 | 25 | """Base exception."""
|
@@ -47,15 +50,24 @@ def tox_addoption(parser: tox.config.Parser) -> None:
|
47 | 50 | 'poetry_use_source_repos',
|
48 | 51 | 'string',
|
49 | 52 | (
|
50 |
| - "Use Poetry's source repositories. Set 'pip_env_vars' to set as " |
51 |
| - "Pip environment variables ('PIP_INDEX_URL', and " |
52 |
| - "'PIP_EXTRA_INDEX_URL')." |
| 53 | + "Use Poetry's source repositories. Set 'pip_env_vars' to set as" |
| 54 | + " Pip environment variables ('PIP_INDEX_URL' and" |
| 55 | + " 'PIP_EXTRA_INDEX_URL')." |
53 | 56 | ),
|
54 | 57 | )
|
55 | 58 | parser.add_testenv_attribute(
|
56 | 59 | 'poetry_experimental_no_virtual_env',
|
57 | 60 | 'bool',
|
58 |
| - "Do not create a virtual environment.", |
| 61 | + "(EXPERIMENTAL) Do not create a virtual environment.", |
| 62 | + default=False, |
| 63 | + ) |
| 64 | + parser.add_testenv_attribute( |
| 65 | + 'poetry_experimental_add_locked_dependencies', |
| 66 | + 'bool', |
| 67 | + ( |
| 68 | + "(EXPERIMENTAL) Add Poetry's locked dependencies from the lockfile" |
| 69 | + " to 'deps' in the test environment." |
| 70 | + ), |
59 | 71 | default=False,
|
60 | 72 | )
|
61 | 73 |
|
@@ -99,11 +111,18 @@ def _is_test_env(env_config: tox.config.TestenvConfig) -> bool:
|
99 | 111 | @tox.hookimpl # type: ignore[misc]
|
100 | 112 | def tox_configure(config: tox.config.Config) -> None:
|
101 | 113 | """Set hook."""
|
| 114 | + # |
| 115 | + project_dir_path = pathlib.Path(config.setupdir) |
| 116 | + # |
102 | 117 | try:
|
103 |
| - poetry_ = _get_poetry(config.setupdir) |
| 118 | + poetry_ = _get_poetry(project_dir_path) |
104 | 119 | except (NoPoetryFound, NoPyprojectTomlFound):
|
105 | 120 | pass
|
106 | 121 | else:
|
| 122 | + # |
| 123 | + locked_deps = _get_locked_deps(project_dir_path) |
| 124 | + _add_locked_dependencies(config, locked_deps) |
| 125 | + # |
107 | 126 | dev_deps = _get_dev_requirements(poetry_)
|
108 | 127 | _add_dev_dependencies(config, dev_deps)
|
109 | 128 | #
|
@@ -144,10 +163,11 @@ def _add_dev_dependencies(
|
144 | 163 | ) -> None:
|
145 | 164 | #
|
146 | 165 | for env_config in tox_config.envconfigs.values():
|
147 |
| - if _is_test_env(env_config): |
148 |
| - if env_config.add_poetry_dev_dependencies is True: |
149 |
| - for dep_config in dev_dep_configs: |
150 |
| - env_config.deps.append(dep_config) |
| 166 | + if env_config.poetry_experimental_add_locked_dependencies is not True: |
| 167 | + if _is_test_env(env_config): |
| 168 | + if env_config.add_poetry_dev_dependencies is True: |
| 169 | + for dep_config in dev_dep_configs: |
| 170 | + env_config.deps.append(dep_config) |
151 | 171 |
|
152 | 172 |
|
153 | 173 | def _add_index_servers(
|
@@ -179,6 +199,21 @@ def _add_index_servers_as_pip_env_vars(
|
179 | 199 | )
|
180 | 200 |
|
181 | 201 |
|
| 202 | +def _add_locked_dependencies( |
| 203 | + tox_config: tox.config.Config, |
| 204 | + locked_deps: typing.Mapping[str, typing.List[tox.config.DepConfig]], |
| 205 | +) -> None: |
| 206 | + # |
| 207 | + for env_config in tox_config.envconfigs.values(): |
| 208 | + if _is_test_env(env_config): |
| 209 | + if env_config.poetry_experimental_add_locked_dependencies is True: |
| 210 | + for dep_config in locked_deps['main']: |
| 211 | + env_config.deps.append(dep_config) |
| 212 | + if env_config.add_poetry_dev_dependencies is True: |
| 213 | + for dep_config in locked_deps['dev']: |
| 214 | + env_config.deps.append(dep_config) |
| 215 | + |
| 216 | + |
182 | 217 | def _get_poetry(project_root_path: pathlib.Path) -> poetry.core.poetry.Poetry:
|
183 | 218 | poetry_factory = poetry.core.factory.Factory()
|
184 | 219 | try:
|
@@ -257,4 +292,30 @@ def _get_index_servers(
|
257 | 292 | return index_servers
|
258 | 293 |
|
259 | 294 |
|
| 295 | +def _get_locked_deps( |
| 296 | + project_root_path: pathlib.Path, |
| 297 | +) -> typing.Dict[str, typing.List[tox.config.DepConfig]]: |
| 298 | + # |
| 299 | + locked_deps: typing.Dict[str, typing.List[tox.config.DepConfig]] = {} |
| 300 | + # |
| 301 | + lock_file_path = project_root_path.joinpath(POETRY_LOCKFILE_FILE_NAME) |
| 302 | + if lock_file_path.is_file(): |
| 303 | + # |
| 304 | + lock_str = lock_file_path.read_text() |
| 305 | + lock_document = tomlkit.parse(lock_str) |
| 306 | + # |
| 307 | + for dependency in lock_document['package']: |
| 308 | + # |
| 309 | + dep_name = dependency['name'] |
| 310 | + dep_version = dependency['version'] |
| 311 | + # |
| 312 | + dep_pep_508 = f'{dep_name}=={dep_version}' |
| 313 | + # |
| 314 | + dep_category = dependency['category'] |
| 315 | + dep_config = tox.config.DepConfig(dep_pep_508) |
| 316 | + locked_deps.setdefault(dep_category, []).append(dep_config) |
| 317 | + # |
| 318 | + return locked_deps |
| 319 | + |
| 320 | + |
260 | 321 | # EOF
|
0 commit comments