From 175af5f755e5c649788d3fab2e8b8b68a132822f Mon Sep 17 00:00:00 2001 From: Maximilian <39695405+maxispeicher@users.noreply.github.com> Date: Sun, 21 Mar 2021 00:04:40 +0100 Subject: [PATCH] exporter: ensure local references use uri This change ensures that when exporting `requirements.txt`, local direct reference dependencies are exported as uri and not paths. Resolves: #3189 --- poetry/utils/exporter.py | 22 +++++++---- tests/utils/test_exporter.py | 76 +++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/poetry/utils/exporter.py b/poetry/utils/exporter.py index f7c40f6975f..b8cced2067e 100644 --- a/poetry/utils/exporter.py +++ b/poetry/utils/exporter.py @@ -4,6 +4,7 @@ from clikit.api.io import IO +from poetry.core.packages.utils.utils import path_to_url from poetry.poetry import Poetry from poetry.utils._compat import Path from poetry.utils._compat import decode @@ -70,23 +71,30 @@ def _export_requirements_txt( line += "-e " requirement = dependency.to_pep_508(with_extras=False) - is_direct_reference = ( - dependency.is_vcs() - or dependency.is_url() - or dependency.is_file() - or dependency.is_directory() + is_direct_local_reference = ( + dependency.is_file() or dependency.is_directory() ) + is_direct_remote_reference = dependency.is_vcs() or dependency.is_url() - if is_direct_reference: + if is_direct_remote_reference: line = requirement + elif is_direct_local_reference: + dependency_uri = path_to_url(dependency.source_url) + line = "{} @ {}".format(dependency.name, dependency_uri) else: line = "{}=={}".format(package.name, package.version) + + if not is_direct_remote_reference: if ";" in requirement: markers = requirement.split(";", 1)[1].strip() if markers: line += "; {}".format(markers) - if not is_direct_reference and package.source_url: + if ( + not is_direct_remote_reference + and not is_direct_local_reference + and package.source_url + ): indexes.add(package.source_url) if package.files and with_hashes: diff --git a/tests/utils/test_exporter.py b/tests/utils/test_exporter.py index 1e660ce69cd..2082bd23181 100644 --- a/tests/utils/test_exporter.py +++ b/tests/utils/test_exporter.py @@ -833,7 +833,79 @@ def test_exporter_can_export_requirements_txt_with_directory_packages( expected = """\ foo @ {}/tests/fixtures/sample_project """.format( - working_directory.as_posix() + working_directory.as_uri() + ) + + assert expected == content + + +def test_exporter_can_export_requirements_txt_with_nested_directory_packages( + tmp_dir, poetry, working_directory +): + poetry.locker.mock_lock_data( + { + "package": [ + { + "name": "foo", + "version": "1.2.3", + "category": "main", + "optional": False, + "python-versions": "*", + "source": { + "type": "directory", + "url": "tests/fixtures/sample_project", + "reference": "", + }, + }, + { + "name": "bar", + "version": "4.5.6", + "category": "main", + "optional": False, + "python-versions": "*", + "source": { + "type": "directory", + "url": "tests/fixtures/sample_project/../project_with_nested_local/bar", + "reference": "", + }, + }, + { + "name": "baz", + "version": "7.8.9", + "category": "main", + "optional": False, + "python-versions": "*", + "source": { + "type": "directory", + "url": "tests/fixtures/sample_project/../project_with_nested_local/bar/..", + "reference": "", + }, + }, + ], + "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") + + with (Path(tmp_dir) / "requirements.txt").open(encoding="utf-8") as f: + content = f.read() + + expected = """\ +bar @ {}/tests/fixtures/project_with_nested_local/bar +baz @ {}/tests/fixtures/project_with_nested_local +foo @ {}/tests/fixtures/sample_project +""".format( + working_directory.as_uri(), + working_directory.as_uri(), + working_directory.as_uri(), ) assert expected == content @@ -878,7 +950,7 @@ def test_exporter_can_export_requirements_txt_with_directory_packages_and_marker expected = """\ foo @ {}/tests/fixtures/sample_project; python_version < "3.7" """.format( - working_directory.as_posix() + working_directory.as_uri() ) assert expected == content