Skip to content

Commit

Permalink
Refactor poetry export
Browse files Browse the repository at this point in the history
Introduce a new root_package section in poetry.lock, and miscellaneous
fixes
  • Loading branch information
dimbleby committed Feb 6, 2022
1 parent 31657e7 commit e7d38ee
Show file tree
Hide file tree
Showing 37 changed files with 808 additions and 216 deletions.
350 changes: 171 additions & 179 deletions src/poetry/packages/locker.py

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/poetry/repositories/base_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
class BaseRepository:
def __init__(self) -> None:
self._packages: List["Package"] = []
self.root_package: Optional["Package"] = None

@property
def packages(self) -> List["Package"]:
Expand Down
44 changes: 30 additions & 14 deletions src/poetry/utils/exporter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import itertools
import urllib.parse

from copy import deepcopy
from typing import TYPE_CHECKING
from typing import Optional
from typing import Sequence
Expand Down Expand Up @@ -70,21 +70,37 @@ def _export_requirements_txt(
content = ""
dependency_lines = set()

for package, groups in itertools.groupby(
self._poetry.locker.get_project_dependency_packages(
project_requires=self._poetry.package.all_requires,
dev=dev,
extras=extras,
),
lambda dependency_package: dependency_package.package,
# If we have a root package then use that to tell us what the top-level
# dependencies are. If we don't (older version of poetry.lock) then try to
# cover all dependencies.
repository = self._poetry.locker.locked_repository(with_dev_reqs=dev)
root_package = repository.root_package
project_requires = (
self._poetry.package.all_requires
if root_package is None
else root_package.requires
)

# If we have a root package then we can also update the marker on each
# dependency to take account of the project-level python version.
if root_package is not None:
restricted_project_requires = []
for project_require in project_requires:
project_require = deepcopy(project_require)
project_require.marker = project_require.marker.intersect(
root_package.python_marker
)
restricted_project_requires.append(project_require)
project_requires = restricted_project_requires

for dependency_package in self._poetry.locker.get_project_dependency_packages(
project_requires=project_requires,
dev=dev,
extras=extras,
):
line = ""
dependency_packages = list(groups)
dependency = dependency_packages[0].dependency
marker = dependency.marker
for dep_package in dependency_packages[1:]:
marker = marker.union(dep_package.dependency.marker)
dependency.marker = marker
dependency = dependency_package.dependency
package = dependency_package.package

if package.develop:
line += "-e "
Expand Down
20 changes: 7 additions & 13 deletions tests/console/commands/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@ def _export_requirements(tester: "CommandTester", poetry: "Poetry") -> None:

assert poetry.locker.lock.exists()

expected = """\
foo==1.0.0
"""
expected = 'foo==1.0.0 ; python_version >= "2.7" and python_version < "2.8" or python_version >= "3.4" and python_version < "4.0"\n' # noqa: E501

assert content == expected

Expand All @@ -110,28 +108,24 @@ def test_export_fails_on_invalid_format(tester: "CommandTester", do_lock: None):

def test_export_prints_to_stdout_by_default(tester: "CommandTester", do_lock: None):
tester.execute("--format requirements.txt")
expected = """\
foo==1.0.0
"""
expected = 'foo==1.0.0 ; python_version >= "2.7" and python_version < "2.8" or python_version >= "3.4" and python_version < "4.0"\n' # noqa: E501
assert tester.io.fetch_output() == expected


def test_export_uses_requirements_txt_format_by_default(
tester: "CommandTester", do_lock: None
):
tester.execute()
expected = """\
foo==1.0.0
"""
expected = 'foo==1.0.0 ; python_version >= "2.7" and python_version < "2.8" or python_version >= "3.4" and python_version < "4.0"\n' # noqa: E501
assert tester.io.fetch_output() == expected


def test_export_includes_extras_by_flag(tester: "CommandTester", do_lock: None):
tester.execute("--format requirements.txt --extras feature_bar")
expected = """\
bar==1.1.0
foo==1.0.0
"""
expected = (
'bar==1.1.0 ; python_version >= "2.7" and python_version < "2.8" or python_version >= "3.4" and python_version < "4.0"\n' # noqa: E501
'foo==1.0.0 ; python_version >= "2.7" and python_version < "2.8" or python_version >= "3.4" and python_version < "4.0"\n' # noqa: E501
)
assert tester.io.fetch_output() == expected


Expand Down
15 changes: 15 additions & 0 deletions tests/installation/fixtures/extras-with-dependencies.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []
extras = { foo = ['c'] }

[root_package.dependencies]
A = "^1.0"
B = "^1.0"
C = { optional = true, version = "^1.0" }

[[package]]
name = "A"
version = "1.0"
Expand Down
16 changes: 16 additions & 0 deletions tests/installation/fixtures/extras.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
extras = { foo = ['d'] }
files = []

[root_package.dependencies]
A = "^1.0"
B = "^1.0"
C = "^1.0"
D = { version = "^1.0", optional = true }

[[package]]
name = "A"
version = "1.0"
Expand Down
9 changes: 9 additions & 0 deletions tests/installation/fixtures/install-no-dev.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[[package]]
name = "A"
version = "1.0"
Expand Down
9 changes: 9 additions & 0 deletions tests/installation/fixtures/no-dependencies.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package = []

[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[metadata]
python-versions = "*"
lock-version = "1.1"
Expand Down
9 changes: 9 additions & 0 deletions tests/installation/fixtures/old-lock.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[[package]]
name = "attrs"
version = "17.4.0"
Expand Down
12 changes: 12 additions & 0 deletions tests/installation/fixtures/remove.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
A = "~1.0"

[[package]]
name = "A"
version = "1.0"
Expand Down
12 changes: 12 additions & 0 deletions tests/installation/fixtures/update-with-lock.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
A = "*"

[[package]]
name = "A"
version = "1.1"
Expand Down
13 changes: 13 additions & 0 deletions tests/installation/fixtures/update-with-locked-extras.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
A = { version = "^1.0", extras = ['foo'] }
D = "^1.0"

[[package]]
name = "A"
version = "1.0"
Expand Down
12 changes: 12 additions & 0 deletions tests/installation/fixtures/with-category-change.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
B = "^1.1"

[[package]]
name = "A"
version = "1.0"
Expand Down
9 changes: 9 additions & 0 deletions tests/installation/fixtures/with-conditional-dependency.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[[package]]
name = "A"
version = "1.0.0"
Expand Down
13 changes: 13 additions & 0 deletions tests/installation/fixtures/with-dependencies-extras.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
A = "^1.0"
B = { version = "^1.0", extras = ['foo'] }

[[package]]
name = "A"
version = "1.0"
Expand Down
12 changes: 12 additions & 0 deletions tests/installation/fixtures/with-dependencies-nested-extras.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
A = { version = "^1.0", extras = ['B'] }

[[package]]
name = "A"
version = "1.0"
Expand Down
13 changes: 13 additions & 0 deletions tests/installation/fixtures/with-dependencies.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
A = "~1.0"
B = "^1.0"

[[package]]
name = "A"
version = "1.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
project-with-transitive-directory-dependencies = { path = "project_with_transitive_directory_dependencies" }

[[package]]
category = "main"
description = ""
Expand Down
12 changes: 12 additions & 0 deletions tests/installation/fixtures/with-directory-dependency-poetry.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
project-with-extras = { extras = ['extras_a'], path = "tests/fixtures/project_with_extras" }

[[package]]
description = ""
category = "main"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
project-with-setup = { path = "tests/fixtures/project_with_setup" }

[[package]]
name = "cachy"
version = "0.2.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[root_package]
name = "root"
version = "1.0"
description = ""
category = "dev"
optional = true
python-versions = "*"
files = []

[root_package.dependencies]
A = "*"

[[package]]
name = "A"
version = "1.1"
Expand Down
Loading

0 comments on commit e7d38ee

Please sign in to comment.