From 9bb70f5c7391215f96db92e8b437ff0e39fbf116 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 2 Nov 2022 10:04:23 +0200 Subject: [PATCH 1/6] refactor _generic_api to use EXT_SUFFIX, add more tests --- src/packaging/tags.py | 35 ++++++++++++++++++++++++++------ tests/test_tags.py | 46 ++++++++++++++++++++++++++++++------------- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/packaging/tags.py b/src/packaging/tags.py index a0e1ea23..6b404b43 100644 --- a/src/packaging/tags.py +++ b/src/packaging/tags.py @@ -225,10 +225,32 @@ def cpython_tags( yield Tag(interpreter, "abi3", platform_) -def _generic_abi() -> Iterator[str]: - abi = sysconfig.get_config_var("SOABI") - if abi: - yield _normalize_string(abi) +def _generic_abi() -> List[str]: + """Return the ABI tag based on EXT_SUFFIX""" + # ext_suffix is something like this. We want to keep the parts which are + # related to the ABI and remove the parts which are related to the + # platform: + # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 + # - mac: '.cpython-310-darwin.so' => cp310 + # - win: '.cp310-win_amd64.pyd' => cp310 + # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38-pp73 + # - graalpy: '.graalpy-38-native-x86_64-darwin.dylib' + # => graalpy-38-native + + ext_suffix = _get_config_var("EXT_SUFFIX", warn=True) + assert ext_suffix[0] == "." + _, soabi, ext = ext_suffix.split(".") + if soabi.startswith("cpython"): + abi = "cp" + soabi.split("-")[1] + elif soabi.startswith("pypy"): + abi = "-".join(soabi.split("-")[:2]) + elif soabi.startswith("graalpy"): + abi = "-".join(soabi.split("-")[:3]) + elif soabi: + abi = soabi + else: + return [] + return [_normalize_string(abi)] def generic_tags( @@ -252,8 +274,9 @@ def generic_tags( interpreter = "".join([interp_name, interp_version]) if abis is None: abis = _generic_abi() + else: + abis = list(abis) platforms = list(platforms or platform_tags()) - abis = list(abis) if "none" not in abis: abis.append("none") for abi in abis: @@ -462,7 +485,7 @@ def platform_tags() -> Iterator[str]: def interpreter_name() -> str: """ - Returns the name of the running interpreter. + Returns the name of the running interpreter, usually as two characters. """ name = sys.implementation.name return INTERPRETER_SHORT_NAMES.get(name) or name diff --git a/tests/test_tags.py b/tests/test_tags.py index 39515e8d..873cf9be 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -823,22 +823,40 @@ def test_no_abi3_python27(self): class TestGenericTags: - @pytest.mark.skipif( - not sysconfig.get_config_var("SOABI"), reason="SOABI not defined" - ) - def test__generic_abi_soabi_provided(self): - abi = sysconfig.get_config_var("SOABI").replace(".", "_").replace("-", "_") - assert [abi] == list(tags._generic_abi()) - - def test__generic_abi(self, monkeypatch): + def test__generic_abi_macos(self, monkeypatch): monkeypatch.setattr( - sysconfig, "get_config_var", lambda key: "cpython-37m-darwin" + sysconfig, "get_config_var", lambda key: ".cpython-37m-darwin.so" ) - assert list(tags._generic_abi()) == ["cpython_37m_darwin"] + monkeypatch.setattr(tags, "interpreter_name", lambda: "cp") + assert tags._generic_abi() == ["cp37m"] - def test__generic_abi_no_soabi(self, monkeypatch): - monkeypatch.setattr(sysconfig, "get_config_var", lambda key: None) - assert not list(tags._generic_abi()) + def test__generic_abi_linux_cpython(self, monkeypatch): + config = { + "Py_DEBUG": False, + "WITH_PYMALLOC": True, + "EXT_SUFFIX": ".cpython-37m-x86_64-linux-gnu.so", + } + monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) + monkeypatch.setattr(tags, "interpreter_name", lambda: "cp") + # They are identical + assert tags._cpython_abis((3, 7)) == ["cp37m"] + assert tags._generic_abi() == ["cp37m"] + + def test__generic_abi_jp(self, monkeypatch): + config = {"EXT_SUFFIX": ".return exactly this.so"} + monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) + monkeypatch.setattr(tags, "interpreter_name", lambda: "other") + assert tags._generic_abi() == ["return exactly this"] + + def test__generic_abi_linux_pypy(self, monkeypatch): + # issue gh-606 + config = { + "Py_DEBUG": False, + "EXT_SUFFIX": ".pypy39-pp73-x86_64-linux-gnu.so", + } + monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) + monkeypatch.setattr(tags, "interpreter_name", lambda: "pp") + assert tags._generic_abi() == ["pypy39_pp73"] def test_generic_platforms(self): platform = sysconfig.get_platform().replace("-", "_") @@ -874,7 +892,7 @@ def test_interpreter_default(self, monkeypatch): assert result == [tags.Tag("sillywalkNN", "none", "any")] def test_abis_default(self, monkeypatch): - monkeypatch.setattr(tags, "_generic_abi", lambda: iter(["abi"])) + monkeypatch.setattr(tags, "_generic_abi", lambda: ["abi"]) result = list(tags.generic_tags(interpreter="sillywalk", platforms=["any"])) assert result == [ tags.Tag("sillywalk", "abi", "any"), From 16687e530b70e1687ce1ed4be953cd0731f4eeec Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 10 Nov 2022 15:29:33 +0200 Subject: [PATCH 2/6] lint, coverage --- src/packaging/tags.py | 7 ++++--- tests/test_tags.py | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/packaging/tags.py b/src/packaging/tags.py index 6b404b43..034c16bb 100644 --- a/src/packaging/tags.py +++ b/src/packaging/tags.py @@ -233,12 +233,13 @@ def _generic_abi() -> List[str]: # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 # - mac: '.cpython-310-darwin.so' => cp310 # - win: '.cp310-win_amd64.pyd' => cp310 - # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38-pp73 + # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38_pp73 # - graalpy: '.graalpy-38-native-x86_64-darwin.dylib' - # => graalpy-38-native + # => graalpy_38_native ext_suffix = _get_config_var("EXT_SUFFIX", warn=True) - assert ext_suffix[0] == "." + if not isinstance(ext_suffix, str) or ext_suffix[0] != ".": + raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')") _, soabi, ext = ext_suffix.split(".") if soabi.startswith("cpython"): abi = "cp" + soabi.split("-")[1] diff --git a/tests/test_tags.py b/tests/test_tags.py index 873cf9be..dd2a2d14 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -845,9 +845,26 @@ def test__generic_abi_linux_cpython(self, monkeypatch): def test__generic_abi_jp(self, monkeypatch): config = {"EXT_SUFFIX": ".return exactly this.so"} monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) - monkeypatch.setattr(tags, "interpreter_name", lambda: "other") assert tags._generic_abi() == ["return exactly this"] + def test__generic_abi_graal(self, monkeypatch): + config = {"EXT_SUFFIX": ".graalpy-38-native-x86_64-darwin.so"} + monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) + assert tags._generic_abi() == ["graalpy_38_native"] + + def test__generic_abi_none(self, monkeypatch): + config = {"EXT_SUFFIX": "..so"} + monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) + assert tags._generic_abi() == [] + + @pytest.mark.parametrize("ext_suffix", ["invalid", None]) + def test__generic_abi_error(self, ext_suffix, monkeypatch): + config = {"EXT_SUFFIX": ext_suffix} + monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) + with pytest.raises(SystemError) as e: + tags._generic_abi() + assert "EXT_SUFFIX" in str(e.value) + def test__generic_abi_linux_pypy(self, monkeypatch): # issue gh-606 config = { From 682d5000a188a5989e85faaf0c179bec349bfb16 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 10 Nov 2022 16:37:50 +0200 Subject: [PATCH 3/6] fix for 'cpython<=3.7' on windows --- src/packaging/tags.py | 6 +++++- tests/test_tags.py | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/packaging/tags.py b/src/packaging/tags.py index 034c16bb..ae0b4e48 100644 --- a/src/packaging/tags.py +++ b/src/packaging/tags.py @@ -240,7 +240,11 @@ def _generic_abi() -> List[str]: ext_suffix = _get_config_var("EXT_SUFFIX", warn=True) if not isinstance(ext_suffix, str) or ext_suffix[0] != ".": raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')") - _, soabi, ext = ext_suffix.split(".") + parts = ext_suffix.split(".") + if len(parts) < 3: + # CPython3.7 and earlier uses ".pyd" on windows + return _cpython_abis(sys.version_info[:2]) + soabi = parts[1] if soabi.startswith("cpython"): abi = "cp" + soabi.split("-")[1] elif soabi.startswith("pypy"): diff --git a/tests/test_tags.py b/tests/test_tags.py index dd2a2d14..6f3281c2 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -875,6 +875,15 @@ def test__generic_abi_linux_pypy(self, monkeypatch): monkeypatch.setattr(tags, "interpreter_name", lambda: "pp") assert tags._generic_abi() == ["pypy39_pp73"] + def test__generic_abi_old_windows(self, monkeypatch): + config = { + "EXT_SUFFIX": ".pyd", + "Py_DEBUG": 0, + "WITH_PYMALLOC": 0, + } + monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) + assert tags._generic_abi() == tags._cpython_abis(sys.version_info[:2]) + def test_generic_platforms(self): platform = sysconfig.get_platform().replace("-", "_") platform = platform.replace(".", "_") From 6a37a6e918d1164c4758b627dad27ee8c39b28f9 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 16 Nov 2022 01:51:40 +0200 Subject: [PATCH 4/6] fix _generic_tag for CPython+windows, add comment about pyston --- src/packaging/tags.py | 6 ++++++ tests/test_tags.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/packaging/tags.py b/src/packaging/tags.py index ae0b4e48..af756273 100644 --- a/src/packaging/tags.py +++ b/src/packaging/tags.py @@ -233,6 +233,7 @@ def _generic_abi() -> List[str]: # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 # - mac: '.cpython-310-darwin.so' => cp310 # - win: '.cp310-win_amd64.pyd' => cp310 + # - win: '.pyd' => cp37 (uses _cpython_abis()) # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38_pp73 # - graalpy: '.graalpy-38-native-x86_64-darwin.dylib' # => graalpy_38_native @@ -246,12 +247,17 @@ def _generic_abi() -> List[str]: return _cpython_abis(sys.version_info[:2]) soabi = parts[1] if soabi.startswith("cpython"): + # non-windows abi = "cp" + soabi.split("-")[1] + elif soabi.startswith("cp"): + # windows + abi = soabi.split("-")[0] elif soabi.startswith("pypy"): abi = "-".join(soabi.split("-")[:2]) elif soabi.startswith("graalpy"): abi = "-".join(soabi.split("-")[:3]) elif soabi: + # pyston, ironpython, others? abi = soabi else: return [] diff --git a/tests/test_tags.py b/tests/test_tags.py index 6f3281c2..244e11df 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -884,6 +884,12 @@ def test__generic_abi_old_windows(self, monkeypatch): monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) assert tags._generic_abi() == tags._cpython_abis(sys.version_info[:2]) + @pytest.mark.skipif(sys.implementation.name != "cpython", reason="CPython-only") + def test__generic_abi_windows(self): + """Test that the two methods of finding the abi tag agree + """ + assert tags._generic_abi() == tags._cpython_abis(sys.version_info[:2]) + def test_generic_platforms(self): platform = sysconfig.get_platform().replace("-", "_") platform = platform.replace(".", "_") From 1fbadfe8155388bee4b7d9eb08169221143481ff Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 16 Nov 2022 02:52:43 +0200 Subject: [PATCH 5/6] add a test to improve coverage on non-windows, fix linting --- tests/test_tags.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/test_tags.py b/tests/test_tags.py index 244e11df..34a0f146 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -884,10 +884,16 @@ def test__generic_abi_old_windows(self, monkeypatch): monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) assert tags._generic_abi() == tags._cpython_abis(sys.version_info[:2]) + def test__generic_abi_windows(self, monkeypatch): + config = { + "EXT_SUFFIX": ".cp310-win_amd64.pyd", + } + monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__) + assert tags._generic_abi() == ["cp310"] + @pytest.mark.skipif(sys.implementation.name != "cpython", reason="CPython-only") - def test__generic_abi_windows(self): - """Test that the two methods of finding the abi tag agree - """ + def test__generic_abi_agree(self): + """Test that the two methods of finding the abi tag agree""" assert tags._generic_abi() == tags._cpython_abis(sys.version_info[:2]) def test_generic_platforms(self): From b9d2b48b1fdcedd8673c7f7be2148fcf72417ffc Mon Sep 17 00:00:00 2001 From: Matti Picus Date: Fri, 9 Dec 2022 21:41:51 -0500 Subject: [PATCH 6/6] changes from review Co-authored-by: Brett Cannon --- src/packaging/tags.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/packaging/tags.py b/src/packaging/tags.py index af756273..19ccbde3 100644 --- a/src/packaging/tags.py +++ b/src/packaging/tags.py @@ -226,10 +226,12 @@ def cpython_tags( def _generic_abi() -> List[str]: - """Return the ABI tag based on EXT_SUFFIX""" - # ext_suffix is something like this. We want to keep the parts which are - # related to the ABI and remove the parts which are related to the - # platform: + """ + Return the ABI tag based on EXT_SUFFIX. + """ + # The following are examples of `EXT_SUFFIX`. + # We want to keep the parts which are related to the ABI and remove the + # parts which are related to the platform: # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 # - mac: '.cpython-310-darwin.so' => cp310 # - win: '.cp310-win_amd64.pyd' => cp310 @@ -243,7 +245,7 @@ def _generic_abi() -> List[str]: raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')") parts = ext_suffix.split(".") if len(parts) < 3: - # CPython3.7 and earlier uses ".pyd" on windows + # CPython3.7 and earlier uses ".pyd" on Windows. return _cpython_abis(sys.version_info[:2]) soabi = parts[1] if soabi.startswith("cpython"): @@ -496,7 +498,10 @@ def platform_tags() -> Iterator[str]: def interpreter_name() -> str: """ - Returns the name of the running interpreter, usually as two characters. + Returns the name of the running interpreter. + + Some implementations have a reserved, two-letter abbreviation which will + be returned when appropriate. """ name = sys.implementation.name return INTERPRETER_SHORT_NAMES.get(name) or name