Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor _generic_api to use EXT_SUFFIX #607

Merged
merged 7 commits into from Dec 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 44 additions & 5 deletions src/packaging/tags.py
Expand Up @@ -225,10 +225,45 @@ 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.
"""
# 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
# - 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

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')")
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"):
# 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 []
return [_normalize_string(abi)]


def generic_tags(
Expand All @@ -252,8 +287,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:
Expand Down Expand Up @@ -463,6 +499,9 @@ def platform_tags() -> Iterator[str]:
def interpreter_name() -> str:
"""
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
Expand Down
84 changes: 70 additions & 14 deletions tests/test_tags.py
Expand Up @@ -823,22 +823,78 @@ 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_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__)
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 = {
"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_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_abi_windows(self, monkeypatch):
config = {
"EXT_SUFFIX": ".cp310-win_amd64.pyd",
}
monkeypatch.setattr(sysconfig, "get_config_var", config.__getitem__)
assert tags._generic_abi() == ["cp310"]

def test__generic_abi_no_soabi(self, monkeypatch):
monkeypatch.setattr(sysconfig, "get_config_var", lambda key: None)
assert not list(tags._generic_abi())
@pytest.mark.skipif(sys.implementation.name != "cpython", reason="CPython-only")
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):
platform = sysconfig.get_platform().replace("-", "_")
Expand Down Expand Up @@ -874,7 +930,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"),
Expand Down