From e746f41e00f24fb6cf29eb35c13fa541fcc3c231 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Wed, 31 Aug 2022 20:38:29 +0100 Subject: [PATCH] tolerate a non-existent extra --- src/poetry_plugin_export/walker.py | 2 +- tests/test_exporter.py | 56 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/poetry_plugin_export/walker.py b/src/poetry_plugin_export/walker.py index 53c3fe6..f2ab977 100644 --- a/src/poetry_plugin_export/walker.py +++ b/src/poetry_plugin_export/walker.py @@ -160,7 +160,7 @@ def walk_dependencies( for require in locked_package.requires: if require.is_optional() and not any( - require in locked_package.extras[feature] + require in locked_package.extras.get(feature, ()) for feature in locked_package.features ): continue diff --git a/tests/test_exporter.py b/tests/test_exporter.py index 6b83d82..68fb733 100644 --- a/tests/test_exporter.py +++ b/tests/test_exporter.py @@ -2398,3 +2398,59 @@ def test_exporter_respects_package_sources(tmp_dir: str, poetry: Poetry) -> None """ assert io.fetch_output() == expected + + +def test_exporter_tolerates_non_existent_extra(tmp_dir: str, poetry: Poetry) -> None: + # foo actually has a 'bar' extra, but pyproject.toml mistakenly references a 'baz' + # extra. + poetry.locker.mock_lock_data( # type: ignore[attr-defined] + { + "package": [ + { + "name": "foo", + "version": "1.2.3", + "category": "main", + "optional": False, + "python-versions": "*", + "dependencies": { + "bar": { + "version": ">=0.1.0", + "optional": True, + "markers": "extra == 'bar'", + } + }, + "extras": {"bar": ["bar (>=0.1.0)"]}, + }, + { + "name": "bar", + "version": "4.5.6", + "category": "main", + "optional": False, + "python-versions": "*", + }, + ], + "metadata": { + "python-versions": "*", + "content-hash": "123456789", + "hashes": {"foo": [], "bar": []}, + }, + } + ) + root = poetry.package.with_dependency_groups([], only=True) + root.add_dependency( + Factory.create_dependency( + name="foo", constraint={"version": "^1.2", "extras": ["baz"]} + ) + ) + poetry._package = root + + 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 = f"""\ +foo[baz]==1.2.3 ; {MARKER_PY27} or {MARKER_PY36} +""" + assert content == expected