diff --git a/poetry/utils/exporter.py b/poetry/utils/exporter.py index 4200abd146d..35ef1681842 100644 --- a/poetry/utils/exporter.py +++ b/poetry/utils/exporter.py @@ -2,6 +2,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 @@ -87,23 +88,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 e26f448f6de..e14210c95ec 100644 --- a/tests/utils/test_exporter.py +++ b/tests/utils/test_exporter.py @@ -584,7 +584,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 @@ -629,7 +701,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