Skip to content

Commit

Permalink
exporter: handle dev extras correctly
Browse files Browse the repository at this point in the history
Resolves: #3018
  • Loading branch information
abn committed Oct 2, 2020
1 parent 9408eff commit 8e3f3c2
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 7 deletions.
10 changes: 7 additions & 3 deletions poetry/packages/locker.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ def locked_repository(
return packages

def get_project_dependencies(
self, project_requires, pinned_versions=False, with_nested=False
): # type: (List[Dependency], bool, bool) -> Any
packages = self.locked_repository().packages
self, project_requires, pinned_versions=False, with_nested=False, with_dev=False
): # type: (List[Dependency], bool, bool, bool) -> Any
packages = self.locked_repository(with_dev).packages

# group packages entries by name, this is required because requirement might use
# different constraints
Expand Down Expand Up @@ -230,6 +230,10 @@ def __get_locked_package(
# project level dependencies take precedence
continue

# we make a copy to avoid any side-effects
requirement = deepcopy(requirement)
requirement._category = pkg.category

if pinned_versions:
requirement.set_constraint(
__get_locked_package(requirement).to_dependency().constraint
Expand Down
10 changes: 6 additions & 4 deletions poetry/utils/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,14 @@ def _export_requirements_txt(
dependency_lines = set()

for dependency in self._poetry.locker.get_project_dependencies(
project_requires=self._poetry.package.requires
if not dev
else self._poetry.package.all_requires,
project_requires=self._poetry.package.all_requires,
with_nested=True,
with_dev=dev,
):
package = repository.find_packages(dependency=dependency)[0]
try:
package = repository.find_packages(dependency=dependency)[0]
except IndexError:
continue

# If a package is optional and we haven't opted in to it, continue
if package.optional and package.name not in extra_package_names:
Expand Down
62 changes: 62 additions & 0 deletions tests/utils/test_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,68 @@ def test_exporter_exports_requirements_txt_with_legacy_packages(tmp_dir, poetry)
assert expected == content


@pytest.mark.parametrize(
("dev", "expected"),
[
(True, ["bar==1.2.2", "baz==1.2.3", "foo==1.2.1"]),
(False, ["bar==1.2.2", "foo==1.2.1"]),
],
)
def test_exporter_exports_requirements_txt_with_dev_extras(
tmp_dir, poetry, dev, expected
):
poetry.locker.mock_lock_data(
{
"package": [
{
"name": "foo",
"version": "1.2.1",
"category": "main",
"optional": False,
"python-versions": "*",
},
{
"name": "bar",
"version": "1.2.2",
"category": "main",
"optional": False,
"python-versions": "*",
"dependencies": {
"baz": {
"version": ">=0.1.0",
"optional": True,
"markers": "extra == 'baz'",
}
},
"extras": {"baz": ["baz (>=0.1.0)"]},
},
{
"name": "baz",
"version": "1.2.3",
"category": "dev",
"optional": False,
"python-versions": "*",
},
],
"metadata": {
"python-versions": "*",
"content-hash": "123456789",
"hashes": {"foo": [], "bar": [], "baz": []},
},
}
)
set_package_requires(poetry)

exporter = Exporter(poetry)

exporter.export("requirements.txt", Path(tmp_dir), "requirements.txt", dev=dev)

with (Path(tmp_dir) / "requirements.txt").open(encoding="utf-8") as f:
content = f.read()

assert content == "{}\n".format("\n".join(expected))


def test_exporter_exports_requirements_txt_with_legacy_packages_and_duplicate_sources(
tmp_dir, poetry
):
Expand Down

0 comments on commit 8e3f3c2

Please sign in to comment.