From 26d4fcd526c33eda99303cfeae3f00463382f74a Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Fri, 29 Nov 2019 14:32:53 +0000 Subject: [PATCH 01/21] redo PR and force push --- packaging/_AIX_platform.py | 96 ++++++++++++++++++++++++++++++++++++++ packaging/tags.py | 12 +++++ tests/test_tags.py | 91 +++++++++++++++++++++++++++++++++++- 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 packaging/_AIX_platform.py diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py new file mode 100644 index 000000000..f8822d0dc --- /dev/null +++ b/packaging/_AIX_platform.py @@ -0,0 +1,96 @@ +"""Shared AIX support functions.""" + +import sys +from sysconfig import get_config_var + +# subprocess is not available early in the build process, test this +try: + from subprocess import check_output + + _subprocess_rdy = True +except ImportError: # pragma: no cover + _subprocess_rdy = False + +from ._typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: # pragma: no cover + from typing import List, Tuple + + +# if var("AIX_BUILDDATE") is unknown, provide a substitute, +# impossible builddate to specify 'unknown' +_tmp = str(get_config_var("AIX_BUILDDATE")) +_bd = 9898 if (_tmp == "None") else int(_tmp) +_bgt = get_config_var("BUILD_GNU_TYPE") +_sz = 32 if sys.maxsize == 2147483647 else 64 + + +def _aix_tag(v, bd): + # type: (List[int], int) -> str + # v is used as variable name so line below passes pep8 length test + # v[version, release, technology_level] + return "AIX-{:1x}{:1d}{:02d}-{:04d}-{}".format(v[0], v[1], v[2], bd, _sz) + + +# extract version, release and technology level from a VRMF string +def _aix_vrtl(vrmf): + # type: (str) -> List[int] + v, r, tl = vrmf.split(".")[:3] + return [int(v[-1]), int(r), int(tl)] + + +def _aix_bosmp64(): + # type: () -> Tuple[str, int] + """ + Return a Tuple[str, int] e.g., ['7.1.4.34', 1806] + The fileset bos.mp64 is the AIX kernel. It's VRMF and builddate + reflect the current ABI levels of the runtime environment. + """ + if _subprocess_rdy: + out = check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) + out = out.decode("utf-8").strip().split(":") # type: ignore + # Use str() and int() to help mypy see types + return str(out[2]), int(out[-1]) + else: + from os import uname + + osname, host, release, version, machine = uname() + return "{}.{}.0.0".format(version, release), 9898 + + +def aix_platform(): + # type: () -> str + """ + AIX filesets are identified by four decimal values: V.R.M.F. + V (version) and R (release) can be retreived using ``uname`` + Since 2007, starting with AIX 5.3 TL7, the M value has been + included with the fileset bos.mp64 and represents the Technology + Level (TL) of AIX. The F (Fix) value also increases, but is not + relevant for comparing releases and binary compatibility. + For binary compatibility the so-called builddate is needed. + Again, the builddate of an AIX release is associated with bos.mp64. + AIX ABI compatibility is described as guaranteed at: https://www.ibm.com/\ + support/knowledgecenter/en/ssw_aix_72/install/binary_compatability.html + + For pep425 purposes the AIX platform tag becomes: + "AIX-{:1x}{:1d}{:02d}-{:04d}-{}".format(v, r, tl, builddate, bitsize) + e.g., "AIX-6107-1415-32" for AIX 6.1 TL7 bd 1415, 32-bit + and, "AIX-6107-1415-64" for AIX 6.1 TL7 bd 1415, 64-bit + """ + vrmf, bd = _aix_bosmp64() + return _aix_tag(_aix_vrtl(vrmf), bd) + + +# extract vrtl from the BUILD_GNU_TYPE as an int +def _aix_bgt(): + # type: () -> List[int] + assert _bgt + return _aix_vrtl(vrmf=_bgt) + + +def aix_buildtag(): + # type: () -> str + """ + Return the platform_tag of the system Python was built on. + """ + return _aix_tag(_aix_bgt(), _bd) diff --git a/packaging/tags.py b/packaging/tags.py index a719d4e73..f89bd8dd8 100644 --- a/packaging/tags.py +++ b/packaging/tags.py @@ -22,6 +22,7 @@ import warnings from ._typing import MYPY_CHECK_RUNNING, cast +from ._AIX_platform import aix_platform if MYPY_CHECK_RUNNING: # pragma: no cover from typing import ( @@ -526,6 +527,15 @@ def _linux_platforms(is_32bit=_32_BIT_INTERPRETER): yield linux +def _aix_platforms(): + # type: () -> Iterator[str] + # Call support module if CPython returns old tag + platform = distutils.util.get_platform() + if platform[:3] == "aix": + platform = aix_platform() + yield platform + + def _generic_platforms(): # type: () -> Iterator[str] yield _normalize_string(distutils.util.get_platform()) @@ -540,6 +550,8 @@ def _platform_tags(): return mac_platforms() elif platform.system() == "Linux": return _linux_platforms() + elif platform.system() == "AIX": + return _aix_platforms() else: return _generic_platforms() diff --git a/tests/test_tags.py b/tests/test_tags.py index 0a89991e1..90f9dc176 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -16,6 +16,7 @@ import os import platform import re +import subprocess import sys import sysconfig import types @@ -24,7 +25,7 @@ import pretend import pytest -from packaging import tags +from packaging import tags, _AIX_platform @pytest.fixture @@ -839,3 +840,91 @@ def test_generic(self, monkeypatch): result = list(tags.sys_tags()) expected = tags.Tag("py{}0".format(sys.version_info[0]), "none", "any") assert result[-1] == expected + + +def test_aix_platform_notpep425_ready(monkeypatch): + if platform.system() != "AIX": + monkeypatch.setattr( + subprocess, + "check_output", + lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", + ) + monkeypatch.setattr(distutils.util, "get_platform", lambda: "aix_5_3") + monkeypatch.setattr(_AIX_platform, "_sz", 64) + result0 = list(tags._aix_platforms()) + result1 = [_AIX_platform.aix_platform()] + assert result0 == result1 + assert result0[0].startswith("AIX") + assert result0[0].endswith("64") + + +def test_aix_platform_no_subprocess(monkeypatch): + monkeypatch.setattr(_AIX_platform, "_subprocess_rdy", False) + vrmf, bd = _AIX_platform._aix_bosmp64() + assert vrmf + assert bd == 9898 + + +def test_aix_platform_pep425_ready(monkeypatch): + monkeypatch.setattr( + subprocess, + "check_output", + lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", + ) + monkeypatch.setattr(distutils.util, "get_platform", lambda: "AIX-5307-0747-32") + monkeypatch.setattr(_AIX_platform, "_sz", 32) + result0 = list(tags._aix_platforms()) + result1 = [_AIX_platform.aix_platform()] + assert result0[0][:4] == result1[0][:4] + assert result0[0].startswith("AIX") + assert result0[0].endswith("32") + + +def test_sys_tags_aix64_cpython(mock_interpreter_name, monkeypatch): + if mock_interpreter_name("CPython"): + monkeypatch.setattr(tags, "_cpython_abis", lambda *a: ["cp36m"]) + if platform.system() != "xAIX": + monkeypatch.setattr(platform, "system", lambda: "AIX") + monkeypatch.setattr(tags, "_aix_platforms", lambda: ["AIX_5307_0747_64"]) + abis = tags._cpython_abis(sys.version_info[:2]) + platforms = tags._aix_platforms() + result = list(tags.sys_tags()) + expected_interpreter = "cp{major}{minor}".format( + major=sys.version_info[0], minor=sys.version_info[1] + ) + assert len(abis) == 1 + assert result[0] == tags.Tag(expected_interpreter, abis[0], platforms[0]) + expected = tags.Tag("py{}0".format(sys.version_info[0]), "none", "any") + assert result[-1] == expected + + +def test_sys_tags_aix32_cpython(mock_interpreter_name, monkeypatch): + if mock_interpreter_name("CPython"): + monkeypatch.setattr(tags, "_cpython_abis", lambda *a: ["cp36m"]) + if platform.system() != "AIX": + monkeypatch.setattr(platform, "system", lambda: "AIX") + monkeypatch.setattr(tags, "_aix_platforms", lambda: ["AIX_5307_0747_32"]) + abis = tags._cpython_abis(sys.version_info[:2]) + platforms = tags._aix_platforms() + result = list(tags.sys_tags()) + expected_interpreter = "cp{major}{minor}".format( + major=sys.version_info[0], minor=sys.version_info[1] + ) + assert len(abis) == 1 + assert result[0] == tags.Tag(expected_interpreter, abis[0], platforms[0]) + expected = tags.Tag("py{}0".format(sys.version_info[0]), "none", "any") + assert result[-1] == expected + + +def test_aix_buildtag(monkeypatch): + monkeypatch.setattr(_AIX_platform, "_bgt", "powerpc-ibm-aix5.3.7.0") + assert _AIX_platform._bd == 9898 + monkeypatch.setattr(_AIX_platform, "_bd", 9797) + monkeypatch.setattr(_AIX_platform, "_sz", 64) + assert _AIX_platform._bd == 9797 + result = _AIX_platform.aix_buildtag() + assert result == "AIX-5307-9797-64" + monkeypatch.setattr(_AIX_platform, "_bd", 747) + monkeypatch.setattr(_AIX_platform, "_sz", 32) + result = _AIX_platform.aix_buildtag() + assert result == "AIX-5307-0747-32" From 730016e9e0b2df12ef477eda77b0298d60c40440 Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Fri, 29 Nov 2019 14:52:13 +0000 Subject: [PATCH 02/21] modify import to work better with monkeypatch in tests --- packaging/_AIX_platform.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index f8822d0dc..156b18c23 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -5,7 +5,7 @@ # subprocess is not available early in the build process, test this try: - from subprocess import check_output + import subprocess _subprocess_rdy = True except ImportError: # pragma: no cover @@ -47,7 +47,7 @@ def _aix_bosmp64(): reflect the current ABI levels of the runtime environment. """ if _subprocess_rdy: - out = check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) + out = subprocess.check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) out = out.decode("utf-8").strip().split(":") # type: ignore # Use str() and int() to help mypy see types return str(out[2]), int(out[-1]) From ce9e721090a304c35d377950a42da7c373298924 Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Fri, 29 Nov 2019 17:09:10 +0000 Subject: [PATCH 03/21] Add extra monkeypatch setting --- packaging/_AIX_platform.py | 6 +++--- tests/test_tags.py | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index 156b18c23..380b5f948 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -46,15 +46,15 @@ def _aix_bosmp64(): The fileset bos.mp64 is the AIX kernel. It's VRMF and builddate reflect the current ABI levels of the runtime environment. """ + import os if _subprocess_rdy: out = subprocess.check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) out = out.decode("utf-8").strip().split(":") # type: ignore # Use str() and int() to help mypy see types return str(out[2]), int(out[-1]) + # need additional test to pass monkeypatch tests on Windows else: - from os import uname - - osname, host, release, version, machine = uname() + osname, host, release, version, machine = os.uname() return "{}.{}.0.0".format(version, release), 9898 diff --git a/tests/test_tags.py b/tests/test_tags.py index 90f9dc176..54e38674b 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -859,6 +859,8 @@ def test_aix_platform_notpep425_ready(monkeypatch): def test_aix_platform_no_subprocess(monkeypatch): + if (os.name != 'posix'): + monkeypatch.setattr(os, "uname", lambda: ('AIX', 'localhost', '2', '5', '00C286454C00')) monkeypatch.setattr(_AIX_platform, "_subprocess_rdy", False) vrmf, bd = _AIX_platform._aix_bosmp64() assert vrmf From 89a7b23c5281b835834cd6ec37f70276fa3fc6ae Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Fri, 29 Nov 2019 18:09:57 +0000 Subject: [PATCH 04/21] More changes to get past Windows CI tests... --- packaging/_AIX_platform.py | 7 +++---- tests/test_tags.py | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index 380b5f948..4be5578a5 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -46,16 +46,15 @@ def _aix_bosmp64(): The fileset bos.mp64 is the AIX kernel. It's VRMF and builddate reflect the current ABI levels of the runtime environment. """ - import os if _subprocess_rdy: out = subprocess.check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) out = out.decode("utf-8").strip().split(":") # type: ignore # Use str() and int() to help mypy see types return str(out[2]), int(out[-1]) - # need additional test to pass monkeypatch tests on Windows else: - osname, host, release, version, machine = os.uname() - return "{}.{}.0.0".format(version, release), 9898 + # pretend os.uname() => ('AIX', 'localhost', '2', '5', '00C286454C00') + # osname, host, release, version, machine = os.uname() + return "{}.{}.0.0".format('5', '2'), 9898 def aix_platform(): diff --git a/tests/test_tags.py b/tests/test_tags.py index 54e38674b..90f9dc176 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -859,8 +859,6 @@ def test_aix_platform_notpep425_ready(monkeypatch): def test_aix_platform_no_subprocess(monkeypatch): - if (os.name != 'posix'): - monkeypatch.setattr(os, "uname", lambda: ('AIX', 'localhost', '2', '5', '00C286454C00')) monkeypatch.setattr(_AIX_platform, "_subprocess_rdy", False) vrmf, bd = _AIX_platform._aix_bosmp64() assert vrmf From e3ce54e8f19e3ae5fc2d41419d3103b228e3eb80 Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Fri, 29 Nov 2019 18:37:55 +0000 Subject: [PATCH 05/21] CI module `black` says double quotes `"` needed --- packaging/_AIX_platform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index 4be5578a5..1a2b256ab 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -54,7 +54,7 @@ def _aix_bosmp64(): else: # pretend os.uname() => ('AIX', 'localhost', '2', '5', '00C286454C00') # osname, host, release, version, machine = os.uname() - return "{}.{}.0.0".format('5', '2'), 9898 + return "{}.{}.0.0".format("5", "2"), 9898 def aix_platform(): From b46efe006f16223a8e33ffad3cab8cdd7e35dd89 Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Sun, 8 Dec 2019 21:42:01 +0000 Subject: [PATCH 06/21] Changes made in accordance of peer review of CPyhton PR #17303 See https://github.com/python/cpython/pull/17303#pullrequestreview-328606611 --- packaging/_AIX_platform.py | 32 ++++++++++++++++++-------------- packaging/tags.py | 5 +++-- tests/test_tags.py | 18 +++++++++--------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index 1a2b256ab..a00c2606d 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -3,13 +3,19 @@ import sys from sysconfig import get_config_var -# subprocess is not available early in the build process, test this +# subprocess is not available early in the build process +# if not available, the config_vars are also not available +# supply substitutes to bootstrap the build try: import subprocess _subprocess_rdy = True + _tmp = str(get_config_var("AIX_BUILDDATE")) + _bgt = get_config_var("BUILD_GNU_TYPE") except ImportError: # pragma: no cover _subprocess_rdy = False + _tmp = "None" + _bgt = "powerpc-ibm-aix6.1.7.0" from ._typing import MYPY_CHECK_RUNNING @@ -17,19 +23,16 @@ from typing import List, Tuple -# if var("AIX_BUILDDATE") is unknown, provide a substitute, +# if get_config_var("AIX_BUILDDATE") was unknown, provide a substitute, # impossible builddate to specify 'unknown' -_tmp = str(get_config_var("AIX_BUILDDATE")) _bd = 9898 if (_tmp == "None") else int(_tmp) -_bgt = get_config_var("BUILD_GNU_TYPE") _sz = 32 if sys.maxsize == 2147483647 else 64 -def _aix_tag(v, bd): +def _aix_tag(vrtl, bd): # type: (List[int], int) -> str - # v is used as variable name so line below passes pep8 length test - # v[version, release, technology_level] - return "AIX-{:1x}{:1d}{:02d}-{:04d}-{}".format(v[0], v[1], v[2], bd, _sz) + # vrtl[version, release, technology_level] + return "aix-{:1x}{:1d}{:02d}-{:04d}-{}".format(vrtl[0], vrtl[1], vrtl[2], bd, _sz) # extract version, release and technology level from a VRMF string @@ -52,9 +55,10 @@ def _aix_bosmp64(): # Use str() and int() to help mypy see types return str(out[2]), int(out[-1]) else: - # pretend os.uname() => ('AIX', 'localhost', '2', '5', '00C286454C00') - # osname, host, release, version, machine = os.uname() - return "{}.{}.0.0".format("5", "2"), 9898 + from os import uname + + osname, host, release, version, machine = uname() + return "{}.{}.0.0".format(version, release), 9898 def aix_platform(): @@ -72,9 +76,9 @@ def aix_platform(): support/knowledgecenter/en/ssw_aix_72/install/binary_compatability.html For pep425 purposes the AIX platform tag becomes: - "AIX-{:1x}{:1d}{:02d}-{:04d}-{}".format(v, r, tl, builddate, bitsize) - e.g., "AIX-6107-1415-32" for AIX 6.1 TL7 bd 1415, 32-bit - and, "AIX-6107-1415-64" for AIX 6.1 TL7 bd 1415, 64-bit + "aix-{:1x}{:1d}{:02d}-{:04d}-{}".format(v, r, tl, builddate, bitsize) + e.g., "aix-6107-1415-32" for AIX 6.1 TL7 bd 1415, 32-bit + and, "aix-6107-1415-64" for AIX 6.1 TL7 bd 1415, 64-bit """ vrmf, bd = _aix_bosmp64() return _aix_tag(_aix_vrtl(vrmf), bd) diff --git a/packaging/tags.py b/packaging/tags.py index f89bd8dd8..3ae76f9ec 100644 --- a/packaging/tags.py +++ b/packaging/tags.py @@ -529,9 +529,10 @@ def _linux_platforms(is_32bit=_32_BIT_INTERPRETER): def _aix_platforms(): # type: () -> Iterator[str] - # Call support module if CPython returns old tag + # Starting with Python3 3.9 the platform tag for AIX has additional hyphens ("-") + # Call support module if distutils returns old tag, e.g., "aix-7.2" platform = distutils.util.get_platform() - if platform[:3] == "aix": + if platform.count("-") == 1: platform = aix_platform() yield platform diff --git a/tests/test_tags.py b/tests/test_tags.py index 90f9dc176..7c95de228 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -849,12 +849,12 @@ def test_aix_platform_notpep425_ready(monkeypatch): "check_output", lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", ) - monkeypatch.setattr(distutils.util, "get_platform", lambda: "aix_5_3") + monkeypatch.setattr(distutils.util, "get_platform", lambda: "aix-7.2") monkeypatch.setattr(_AIX_platform, "_sz", 64) result0 = list(tags._aix_platforms()) result1 = [_AIX_platform.aix_platform()] assert result0 == result1 - assert result0[0].startswith("AIX") + assert result0[0].startswith("aix") assert result0[0].endswith("64") @@ -871,21 +871,21 @@ def test_aix_platform_pep425_ready(monkeypatch): "check_output", lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", ) - monkeypatch.setattr(distutils.util, "get_platform", lambda: "AIX-5307-0747-32") + monkeypatch.setattr(distutils.util, "get_platform", lambda: "aix-5307-0747-32") monkeypatch.setattr(_AIX_platform, "_sz", 32) result0 = list(tags._aix_platforms()) result1 = [_AIX_platform.aix_platform()] assert result0[0][:4] == result1[0][:4] - assert result0[0].startswith("AIX") + assert result0[0].startswith("aix") assert result0[0].endswith("32") def test_sys_tags_aix64_cpython(mock_interpreter_name, monkeypatch): if mock_interpreter_name("CPython"): monkeypatch.setattr(tags, "_cpython_abis", lambda *a: ["cp36m"]) - if platform.system() != "xAIX": + if platform.system() != "AIX": monkeypatch.setattr(platform, "system", lambda: "AIX") - monkeypatch.setattr(tags, "_aix_platforms", lambda: ["AIX_5307_0747_64"]) + monkeypatch.setattr(tags, "_aix_platforms", lambda: ["aix_5307_0747_64"]) abis = tags._cpython_abis(sys.version_info[:2]) platforms = tags._aix_platforms() result = list(tags.sys_tags()) @@ -903,7 +903,7 @@ def test_sys_tags_aix32_cpython(mock_interpreter_name, monkeypatch): monkeypatch.setattr(tags, "_cpython_abis", lambda *a: ["cp36m"]) if platform.system() != "AIX": monkeypatch.setattr(platform, "system", lambda: "AIX") - monkeypatch.setattr(tags, "_aix_platforms", lambda: ["AIX_5307_0747_32"]) + monkeypatch.setattr(tags, "_aix_platforms", lambda: ["aix_5307_0747_32"]) abis = tags._cpython_abis(sys.version_info[:2]) platforms = tags._aix_platforms() result = list(tags.sys_tags()) @@ -923,8 +923,8 @@ def test_aix_buildtag(monkeypatch): monkeypatch.setattr(_AIX_platform, "_sz", 64) assert _AIX_platform._bd == 9797 result = _AIX_platform.aix_buildtag() - assert result == "AIX-5307-9797-64" + assert result == "aix-5307-9797-64" monkeypatch.setattr(_AIX_platform, "_bd", 747) monkeypatch.setattr(_AIX_platform, "_sz", 32) result = _AIX_platform.aix_buildtag() - assert result == "AIX-5307-0747-32" + assert result == "aix-5307-0747-32" From ac25b8170c848f62e43808a61701e59e750f7d09 Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Sun, 8 Dec 2019 22:13:37 +0000 Subject: [PATCH 07/21] Specify `#pragma no cover` for Windows - that does not have os.uname() --- packaging/_AIX_platform.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index a00c2606d..e1ca63d84 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -54,7 +54,8 @@ def _aix_bosmp64(): out = out.decode("utf-8").strip().split(":") # type: ignore # Use str() and int() to help mypy see types return str(out[2]), int(out[-1]) - else: + else: # pragma: no cover + # no cover during Windows coverage test from os import uname osname, host, release, version, machine = uname() From 9c999bb83aec2b710028f58e2e87305629a0d8a3 Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Sun, 8 Dec 2019 22:18:33 +0000 Subject: [PATCH 08/21] Remove "too many spaces" in pragma (comment) --- packaging/_AIX_platform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index e1ca63d84..405f73c35 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -54,7 +54,7 @@ def _aix_bosmp64(): out = out.decode("utf-8").strip().split(":") # type: ignore # Use str() and int() to help mypy see types return str(out[2]), int(out[-1]) - else: # pragma: no cover + else: # pragma: no cover # no cover during Windows coverage test from os import uname From f06f81ae435e82ee504d30cffad99d8e381ee296 Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Sun, 8 Dec 2019 22:29:11 +0000 Subject: [PATCH 09/21] Non-posix systems (i.e., no `os.uname()`) fail coverage tests, use constants instead --- packaging/_AIX_platform.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index 405f73c35..b3a86e0cd 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -56,9 +56,13 @@ def _aix_bosmp64(): return str(out[2]), int(out[-1]) else: # pragma: no cover # no cover during Windows coverage test - from os import uname + # This code is only for during the bootstrap phase + # Under normal use this will never be reached, so constants are provided + # rather than actually calling os.uname() + # from os import uname - osname, host, release, version, machine = uname() + # osname, host, release, version, machine = uname() + release, version = 2, 7 return "{}.{}.0.0".format(version, release), 9898 From c8d5d79dc0c80f022a5f8497b6185676db8be86e Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Tue, 17 Dec 2019 07:42:16 +0000 Subject: [PATCH 10/21] Sync code with CPython 3.9: `Lib/_aix_support.py` --- packaging/_AIX_platform.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index b3a86e0cd..5f938f10b 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -4,17 +4,16 @@ from sysconfig import get_config_var # subprocess is not available early in the build process -# if not available, the config_vars are also not available -# supply substitutes to bootstrap the build +# when not available, the get_config_var() values are not available +# and substitures are necessary for bootstrap and CI coverage tests try: import subprocess - - _subprocess_rdy = True - _tmp = str(get_config_var("AIX_BUILDDATE")) + _have_subprocess = True + _tmp_bd = get_config_var("AIX_BUILDDATE") _bgt = get_config_var("BUILD_GNU_TYPE") except ImportError: # pragma: no cover - _subprocess_rdy = False - _tmp = "None" + _have_subprocess = False + _tmp_bd = None _bgt = "powerpc-ibm-aix6.1.7.0" from ._typing import MYPY_CHECK_RUNNING @@ -25,8 +24,14 @@ # if get_config_var("AIX_BUILDDATE") was unknown, provide a substitute, # impossible builddate to specify 'unknown' -_bd = 9898 if (_tmp == "None") else int(_tmp) -_sz = 32 if sys.maxsize == 2147483647 else 64 +_MISSING_BD = 9898 +try: + _bd = int(_tmp_bd) +except TypeError: + _bd = _MISSING_BD + +# Infer the ABI bitwidth from maxsize (assuming 64 bit as the default) +_sz = 32 if sys.maxsize == (2**31-1) else 64 def _aix_tag(vrtl, bd): @@ -49,21 +54,20 @@ def _aix_bosmp64(): The fileset bos.mp64 is the AIX kernel. It's VRMF and builddate reflect the current ABI levels of the runtime environment. """ - if _subprocess_rdy: + if _have_subprocess: + # We expect all AIX systems to have lslpp installed in this location out = subprocess.check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) out = out.decode("utf-8").strip().split(":") # type: ignore # Use str() and int() to help mypy see types return str(out[2]), int(out[-1]) - else: # pragma: no cover - # no cover during Windows coverage test - # This code is only for during the bootstrap phase - # Under normal use this will never be reached, so constants are provided + else: + # This code is for CPython bootstrap phase (see Lib/_aix_aupport.py) + # To pass `pypa/packaging` Windows CI tests mock constants are used # rather than actually calling os.uname() # from os import uname - # osname, host, release, version, machine = uname() release, version = 2, 7 - return "{}.{}.0.0".format(version, release), 9898 + return "{}.{}.0.0".format(version, release), _MISSING_BD def aix_platform(): From 8677561a236f52cf875d0539fc074d222f4004d9 Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Tue, 17 Dec 2019 08:23:55 +0000 Subject: [PATCH 11/21] typo corrections to pass lint --- packaging/_AIX_platform.py | 7 ++++--- tests/test_tags.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packaging/_AIX_platform.py b/packaging/_AIX_platform.py index 5f938f10b..b39c65f5f 100644 --- a/packaging/_AIX_platform.py +++ b/packaging/_AIX_platform.py @@ -8,6 +8,7 @@ # and substitures are necessary for bootstrap and CI coverage tests try: import subprocess + _have_subprocess = True _tmp_bd = get_config_var("AIX_BUILDDATE") _bgt = get_config_var("BUILD_GNU_TYPE") @@ -26,12 +27,12 @@ # impossible builddate to specify 'unknown' _MISSING_BD = 9898 try: - _bd = int(_tmp_bd) -except TypeError: + _bd = int(str(_tmp_bd)) +except (TypeError, ValueError): _bd = _MISSING_BD # Infer the ABI bitwidth from maxsize (assuming 64 bit as the default) -_sz = 32 if sys.maxsize == (2**31-1) else 64 +_sz = 32 if sys.maxsize == (2 ** 31 - 1) else 64 def _aix_tag(vrtl, bd): diff --git a/tests/test_tags.py b/tests/test_tags.py index 7c95de228..bf2162e7e 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -859,7 +859,7 @@ def test_aix_platform_notpep425_ready(monkeypatch): def test_aix_platform_no_subprocess(monkeypatch): - monkeypatch.setattr(_AIX_platform, "_subprocess_rdy", False) + monkeypatch.setattr(_AIX_platform, "_have_subprocess", False) vrmf, bd = _AIX_platform._aix_bosmp64() assert vrmf assert bd == 9898 From f9019b2734d4a0c570ab932adde7539bc549ae38 Mon Sep 17 00:00:00 2001 From: M Felt aka aixtools Date: Fri, 3 Apr 2020 06:46:09 +0000 Subject: [PATCH 12/21] rename _AIX_platform to _aix_support - same as in CPython --- packaging/{_AIX_platform.py => _aix_support.py} | 0 packaging/tags.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename packaging/{_AIX_platform.py => _aix_support.py} (100%) diff --git a/packaging/_AIX_platform.py b/packaging/_aix_support.py similarity index 100% rename from packaging/_AIX_platform.py rename to packaging/_aix_support.py diff --git a/packaging/tags.py b/packaging/tags.py index acc5de6eb..ed024d48e 100644 --- a/packaging/tags.py +++ b/packaging/tags.py @@ -23,7 +23,7 @@ import warnings from ._typing import MYPY_CHECK_RUNNING, cast -from ._AIX_platform import aix_platform +from ._aix_support import aix_platform if MYPY_CHECK_RUNNING: # pragma: no cover from typing import ( From 91412e8fddb51a9117c805fe51186a4070327e16 Mon Sep 17 00:00:00 2001 From: M Felt aka aixtools Date: Fri, 3 Apr 2020 13:07:59 +0000 Subject: [PATCH 13/21] Sync _aix_support.py with CPython `Lib/_aix_support.py` Remove all references to old name _AIX_platform.py --- packaging/_aix_support.py | 56 +++++++++++++++++---------------------- tests/test_tags.py | 50 +++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 50 deletions(-) diff --git a/packaging/_aix_support.py b/packaging/_aix_support.py index b39c65f5f..e3b5c474c 100644 --- a/packaging/_aix_support.py +++ b/packaging/_aix_support.py @@ -1,21 +1,16 @@ """Shared AIX support functions.""" import sys -from sysconfig import get_config_var +import sysconfig -# subprocess is not available early in the build process -# when not available, the get_config_var() values are not available -# and substitures are necessary for bootstrap and CI coverage tests try: - import subprocess + from subprocess import check_output _have_subprocess = True - _tmp_bd = get_config_var("AIX_BUILDDATE") - _bgt = get_config_var("BUILD_GNU_TYPE") except ImportError: # pragma: no cover + # subprocess is not available early in the build process + # substitures are necessary for bootstrap and CI coverage tests _have_subprocess = False - _tmp_bd = None - _bgt = "powerpc-ibm-aix6.1.7.0" from ._typing import MYPY_CHECK_RUNNING @@ -23,22 +18,12 @@ from typing import List, Tuple -# if get_config_var("AIX_BUILDDATE") was unknown, provide a substitute, -# impossible builddate to specify 'unknown' -_MISSING_BD = 9898 -try: - _bd = int(str(_tmp_bd)) -except (TypeError, ValueError): - _bd = _MISSING_BD - -# Infer the ABI bitwidth from maxsize (assuming 64 bit as the default) -_sz = 32 if sys.maxsize == (2 ** 31 - 1) else 64 - - def _aix_tag(vrtl, bd): # type: (List[int], int) -> str + # Infer the ABI bitwidth from maxsize (assuming 64 bit as the default) + sz = 32 if sys.maxsize == (2 ** 31 - 1) else 64 # vrtl[version, release, technology_level] - return "aix-{:1x}{:1d}{:02d}-{:04d}-{}".format(vrtl[0], vrtl[1], vrtl[2], bd, _sz) + return "aix-{:1x}{:1d}{:02d}-{:04d}-{}".format(vrtl[0], vrtl[1], vrtl[2], bd, sz) # extract version, release and technology level from a VRMF string @@ -57,18 +42,15 @@ def _aix_bosmp64(): """ if _have_subprocess: # We expect all AIX systems to have lslpp installed in this location - out = subprocess.check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) + out = check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) out = out.decode("utf-8").strip().split(":") # type: ignore # Use str() and int() to help mypy see types return str(out[2]), int(out[-1]) else: - # This code is for CPython bootstrap phase (see Lib/_aix_aupport.py) + # This code was for CPython bootstrap phase (see Lib/_aix_aupport.py) # To pass `pypa/packaging` Windows CI tests mock constants are used - # rather than actually calling os.uname() - # from os import uname - # osname, host, release, version, machine = uname() release, version = 2, 7 - return "{}.{}.0.0".format(version, release), _MISSING_BD + return "{}.{}.0.0".format(version, release), 9898 def aix_platform(): @@ -97,8 +79,11 @@ def aix_platform(): # extract vrtl from the BUILD_GNU_TYPE as an int def _aix_bgt(): # type: () -> List[int] - assert _bgt - return _aix_vrtl(vrmf=_bgt) + if _have_subprocess: + bgt = sysconfig.get_config_var("BUILD_GNU_TYPE") + else: + bgt = "powerpc-ibm-aix6.1.7.0" + return _aix_vrtl(vrmf=bgt) def aix_buildtag(): @@ -106,4 +91,13 @@ def aix_buildtag(): """ Return the platform_tag of the system Python was built on. """ - return _aix_tag(_aix_bgt(), _bd) + # To permit packaging to be used when the variable "AIX_BUILDDATE" + # is not defined - return an impossible value rather than + # raise ValueError() as Cpython Lib/_aix_support does + bd = sysconfig.get_config_var("AIX_BUILDDATE") if _have_subprocess else "9898" + try: + bd = int(str(bd)) + except (TypeError, ValueError): + bd = 9898 + + return _aix_tag(_aix_bgt(), bd) diff --git a/tests/test_tags.py b/tests/test_tags.py index 4e9dc63f7..769d29ec7 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -25,7 +25,7 @@ import pretend import pytest -from packaging import tags, _AIX_platform +from packaging import tags, _aix_support @pytest.fixture @@ -1160,17 +1160,17 @@ def test_aix_platform_notpep425_ready(monkeypatch): lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", ) monkeypatch.setattr(distutils.util, "get_platform", lambda: "aix-7.2") - monkeypatch.setattr(_AIX_platform, "_sz", 64) + monkeypatch.setattr(sys, "maxsize", 2 ** 63 - 1) result0 = list(tags._aix_platforms()) - result1 = [_AIX_platform.aix_platform()] + result1 = [_aix_support.aix_platform()] assert result0 == result1 assert result0[0].startswith("aix") assert result0[0].endswith("64") def test_aix_platform_no_subprocess(monkeypatch): - monkeypatch.setattr(_AIX_platform, "_have_subprocess", False) - vrmf, bd = _AIX_platform._aix_bosmp64() + monkeypatch.setattr(_aix_support, "_have_subprocess", False) + vrmf, bd = _aix_support._aix_bosmp64() assert vrmf assert bd == 9898 @@ -1182,9 +1182,9 @@ def test_aix_platform_pep425_ready(monkeypatch): lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", ) monkeypatch.setattr(distutils.util, "get_platform", lambda: "aix-5307-0747-32") - monkeypatch.setattr(_AIX_platform, "_sz", 32) + monkeypatch.setattr(sys, "maxsize", 2 ** 31 - 1) result0 = list(tags._aix_platforms()) - result1 = [_AIX_platform.aix_platform()] + result1 = [_aix_support.aix_platform()] assert result0[0][:4] == result1[0][:4] assert result0[0].startswith("aix") assert result0[0].endswith("32") @@ -1226,15 +1226,27 @@ def test_sys_tags_aix32_cpython(mock_interpreter_name, monkeypatch): assert result[-1] == expected -def test_aix_buildtag(monkeypatch): - monkeypatch.setattr(_AIX_platform, "_bgt", "powerpc-ibm-aix5.3.7.0") - assert _AIX_platform._bd == 9898 - monkeypatch.setattr(_AIX_platform, "_bd", 9797) - monkeypatch.setattr(_AIX_platform, "_sz", 64) - assert _AIX_platform._bd == 9797 - result = _AIX_platform.aix_buildtag() - assert result == "aix-5307-9797-64" - monkeypatch.setattr(_AIX_platform, "_bd", 747) - monkeypatch.setattr(_AIX_platform, "_sz", 32) - result = _AIX_platform.aix_buildtag() - assert result == "aix-5307-0747-32" +def test_aix_bgt(monkeypatch): + monkeypatch.setattr(_aix_support, "_have_subprocess", False) + result = _aix_support._aix_bgt() + assert result == [6, 1, 7] + monkeypatch.setattr(_aix_support, "_have_subprocess", True) + monkeypatch.setattr(sysconfig, "get_config_var", lambda key: "powerpc-ibm-aix5.3.7.0") + result = _aix_support._aix_bgt() + assert result == [5, 3, 7] + + +# def test_aix_buildtag(monkeypatch): + monkeypatch.setattr(_aix_support, "_have_subprocess", False) + monkeypatch.setattr(sys, "maxsize", 2 ** 31 - 1) + result = _aix_support.aix_buildtag() + assert result == "aix-6107-9898-32" + monkeypatch.setattr(_aix_support, "_have_subprocess", True) + monkeypatch.setattr(_aix_support, "_aix_bgt", lambda: [5, 3, 7]) + monkeypatch.setattr(sysconfig, "get_config_var", lambda key: None) + result = _aix_support.aix_buildtag() + assert result == "aix-5307-9898-32" + monkeypatch.setattr(sys, "maxsize", 2 ** 63 - 1) + monkeypatch.setattr(sysconfig, "get_config_var", lambda key: "0747") + result = _aix_support.aix_buildtag() + assert result == "aix-5307-0747-64" From 81ebe3c203f6089877d9034ef087720f5810eb4f Mon Sep 17 00:00:00 2001 From: M Felt aka aixtools Date: Fri, 3 Apr 2020 15:32:51 +0000 Subject: [PATCH 14/21] Fix file to pass flake8 tests Rename module used for monkeypatch --- tests/test_tags.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_tags.py b/tests/test_tags.py index 769d29ec7..8eeba8d9b 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -1155,7 +1155,7 @@ def test_generic(self, monkeypatch): def test_aix_platform_notpep425_ready(monkeypatch): if platform.system() != "AIX": monkeypatch.setattr( - subprocess, + _aix_support, "check_output", lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", ) @@ -1177,7 +1177,7 @@ def test_aix_platform_no_subprocess(monkeypatch): def test_aix_platform_pep425_ready(monkeypatch): monkeypatch.setattr( - subprocess, + _aix_support, "check_output", lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", ) @@ -1231,7 +1231,7 @@ def test_aix_bgt(monkeypatch): result = _aix_support._aix_bgt() assert result == [6, 1, 7] monkeypatch.setattr(_aix_support, "_have_subprocess", True) - monkeypatch.setattr(sysconfig, "get_config_var", lambda key: "powerpc-ibm-aix5.3.7.0") + monkeypatch.setattr(sysconfig, "get_config_var", lambda k: "powerpc-ibm-aix5.3.7.0") result = _aix_support._aix_bgt() assert result == [5, 3, 7] From 27ebbb1116280b4d4fd312848fb08e333f0caaab Mon Sep 17 00:00:00 2001 From: M Felt aka aixtools Date: Fri, 3 Apr 2020 15:41:08 +0000 Subject: [PATCH 15/21] import subprocess no longer needed to support monkeypatch --- tests/test_tags.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_tags.py b/tests/test_tags.py index 8eeba8d9b..c2415bad6 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -16,7 +16,6 @@ import os import platform import re -import subprocess import sys import sysconfig import types From cf52688e3ca2466a425a8869d90f207dcc61063b Mon Sep 17 00:00:00 2001 From: M Felt aka aixtools Date: Mon, 20 Apr 2020 16:41:57 +0000 Subject: [PATCH 16/21] Shorten variable names to pass flake8 line-length tests --- packaging/_aix_support.py | 22 +++++++++++----------- tests/test_tags.py | 3 +-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packaging/_aix_support.py b/packaging/_aix_support.py index e3b5c474c..c0be89253 100644 --- a/packaging/_aix_support.py +++ b/packaging/_aix_support.py @@ -1,7 +1,7 @@ """Shared AIX support functions.""" import sys -import sysconfig +from sysconfig import get_config_var try: from subprocess import check_output @@ -12,18 +12,18 @@ # substitures are necessary for bootstrap and CI coverage tests _have_subprocess = False -from ._typing import MYPY_CHECK_RUNNING +from ._typing import TYPE_CHECKING if MYPY_CHECK_RUNNING: # pragma: no cover from typing import List, Tuple -def _aix_tag(vrtl, bd): +def _aix_tag(tl, bd): # type: (List[int], int) -> str # Infer the ABI bitwidth from maxsize (assuming 64 bit as the default) sz = 32 if sys.maxsize == (2 ** 31 - 1) else 64 - # vrtl[version, release, technology_level] - return "aix-{:1x}{:1d}{:02d}-{:04d}-{}".format(vrtl[0], vrtl[1], vrtl[2], bd, sz) + # tl[version, release, technology_level] + return "aix-{:1x}{:1d}{:02d}-{:04d}-{}".format(tl[0], tl[1], tl[2], bd, sz) # extract version, release and technology level from a VRMF string @@ -80,10 +80,10 @@ def aix_platform(): def _aix_bgt(): # type: () -> List[int] if _have_subprocess: - bgt = sysconfig.get_config_var("BUILD_GNU_TYPE") + bgt = get_config_var("BUILD_GNU_TYPE") else: bgt = "powerpc-ibm-aix6.1.7.0" - return _aix_vrtl(vrmf=bgt) + return _aix_vrtl(vrmf=str(bgt)) def aix_buildtag(): @@ -94,10 +94,10 @@ def aix_buildtag(): # To permit packaging to be used when the variable "AIX_BUILDDATE" # is not defined - return an impossible value rather than # raise ValueError() as Cpython Lib/_aix_support does - bd = sysconfig.get_config_var("AIX_BUILDDATE") if _have_subprocess else "9898" + bd = get_config_var("AIX_BUILDDATE") if _have_subprocess else "9898" try: - bd = int(str(bd)) + bd = str(bd) except (TypeError, ValueError): - bd = 9898 + bd = "9898" - return _aix_tag(_aix_bgt(), bd) + return _aix_tag(_aix_bgt(), int(bd)) diff --git a/tests/test_tags.py b/tests/test_tags.py index c2415bad6..4db96f3b5 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -1234,8 +1234,7 @@ def test_aix_bgt(monkeypatch): result = _aix_support._aix_bgt() assert result == [5, 3, 7] - -# def test_aix_buildtag(monkeypatch): + # def test_aix_buildtag(monkeypatch): monkeypatch.setattr(_aix_support, "_have_subprocess", False) monkeypatch.setattr(sys, "maxsize", 2 ** 31 - 1) result = _aix_support.aix_buildtag() From 68e9c8007cd1a97b10eb3cd2d6bba642a828b586 Mon Sep 17 00:00:00 2001 From: Pradyun Gedam Date: Wed, 8 Apr 2020 18:24:09 +0530 Subject: [PATCH 17/21] Add a NewType for normalized names (#292) * Make our mypy type-casting magic more robust Newer versions of mypy are better at following code flow, and assign Any types to our reimplemented cast function. This commit significantly restructures our typing.cast re-definition, to make it more robust. * Rename MYPY_CHECK_RUNNING -> TYPE_CHECKING This allows for some significant cleanups in our typing helpers, and makes it much easier to document our... workarounds. * Bump to newer mypy * Improve `canonicalize_name` safety with type hints --- .pre-commit-config.yaml | 2 +- CHANGELOG.rst | 4 ++++ packaging/_compat.py | 4 ++-- packaging/_typing.py | 29 +++++++++++++++++++---------- packaging/markers.py | 4 ++-- packaging/requirements.py | 4 ++-- packaging/specifiers.py | 4 ++-- packaging/tags.py | 4 ++-- packaging/utils.py | 13 ++++++++----- packaging/version.py | 4 ++-- 10 files changed, 44 insertions(+), 28 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 691246784..50d1f6c80 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.750 + rev: v0.770 hooks: - id: mypy exclude: '^(docs|tasks|tests)|setup\.py' diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b6af82a3..3ce556a37 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,10 @@ Changelog ~~~~~~~~~~~~ * Canonicalize version before comparing specifiers. (:issue:`282`) +* Change type hint for ``canonicalize_name`` to return + ``packaging.utils.NormalizedName``. + This enables the use of static typing tools (like mypy) to detect mixing of + normalized and un-normalized names. 20.3 - 2020-03-05 ~~~~~~~~~~~~~~~~~ diff --git a/packaging/_compat.py b/packaging/_compat.py index a145f7eeb..e54bd4ede 100644 --- a/packaging/_compat.py +++ b/packaging/_compat.py @@ -5,9 +5,9 @@ import sys -from ._typing import MYPY_CHECK_RUNNING +from ._typing import TYPE_CHECKING -if MYPY_CHECK_RUNNING: # pragma: no cover +if TYPE_CHECKING: # pragma: no cover from typing import Any, Dict, Tuple, Type diff --git a/packaging/_typing.py b/packaging/_typing.py index dc6dfce7a..77a8b9185 100644 --- a/packaging/_typing.py +++ b/packaging/_typing.py @@ -18,22 +18,31 @@ In packaging, all static-typing related imports should be guarded as follows: - from packaging._typing import MYPY_CHECK_RUNNING + from packaging._typing import TYPE_CHECKING - if MYPY_CHECK_RUNNING: + if TYPE_CHECKING: from typing import ... Ref: https://github.com/python/mypy/issues/3216 """ -MYPY_CHECK_RUNNING = False +__all__ = ["TYPE_CHECKING", "cast"] -if MYPY_CHECK_RUNNING: # pragma: no cover - import typing - - cast = typing.cast +# The TYPE_CHECKING constant defined by the typing module is False at runtime +# but True while type checking. +if False: # pragma: no cover + from typing import TYPE_CHECKING +else: + TYPE_CHECKING = False + +# typing's cast syntax requires calling typing.cast at runtime, but we don't +# want to import typing at runtime. Here, we inform the type checkers that +# we're importing `typing.cast` as `cast` and re-implement typing.cast's +# runtime behavior in a block that is ignored by type checkers. +if TYPE_CHECKING: # pragma: no cover + # not executed at runtime + from typing import cast else: - # typing's cast() is needed at runtime, but we don't want to import typing. - # Thus, we use a dummy no-op version, which we tell mypy to ignore. - def cast(type_, value): # type: ignore + # executed at runtime + def cast(type_, value): # noqa return value diff --git a/packaging/markers.py b/packaging/markers.py index f01747113..87cd3f958 100644 --- a/packaging/markers.py +++ b/packaging/markers.py @@ -13,10 +13,10 @@ from pyparsing import Literal as L # noqa from ._compat import string_types -from ._typing import MYPY_CHECK_RUNNING +from ._typing import TYPE_CHECKING from .specifiers import Specifier, InvalidSpecifier -if MYPY_CHECK_RUNNING: # pragma: no cover +if TYPE_CHECKING: # pragma: no cover from typing import Any, Callable, Dict, List, Optional, Tuple, Union Operator = Callable[[str, str], bool] diff --git a/packaging/requirements.py b/packaging/requirements.py index 1b547927d..91f81ede0 100644 --- a/packaging/requirements.py +++ b/packaging/requirements.py @@ -11,11 +11,11 @@ from pyparsing import Literal as L # noqa from six.moves.urllib import parse as urlparse -from ._typing import MYPY_CHECK_RUNNING +from ._typing import TYPE_CHECKING from .markers import MARKER_EXPR, Marker from .specifiers import LegacySpecifier, Specifier, SpecifierSet -if MYPY_CHECK_RUNNING: # pragma: no cover +if TYPE_CHECKING: # pragma: no cover from typing import List diff --git a/packaging/specifiers.py b/packaging/specifiers.py index 4eeef14f8..9f7dd2787 100644 --- a/packaging/specifiers.py +++ b/packaging/specifiers.py @@ -9,11 +9,11 @@ import re from ._compat import string_types, with_metaclass -from ._typing import MYPY_CHECK_RUNNING +from ._typing import TYPE_CHECKING from .utils import canonicalize_version from .version import Version, LegacyVersion, parse -if MYPY_CHECK_RUNNING: # pragma: no cover +if TYPE_CHECKING: # pragma: no cover from typing import ( List, Dict, diff --git a/packaging/tags.py b/packaging/tags.py index 87e1c3d4c..d963cfe61 100644 --- a/packaging/tags.py +++ b/packaging/tags.py @@ -22,10 +22,10 @@ import sysconfig import warnings -from ._typing import MYPY_CHECK_RUNNING, cast from ._aix_support import aix_platform +from ._typing import TYPE_CHECKING, cast -if MYPY_CHECK_RUNNING: # pragma: no cover +if TYPE_CHECKING: # pragma: no cover from typing import ( Dict, FrozenSet, diff --git a/packaging/utils.py b/packaging/utils.py index 44f1bf987..19579c1a0 100644 --- a/packaging/utils.py +++ b/packaging/utils.py @@ -5,19 +5,22 @@ import re -from ._typing import MYPY_CHECK_RUNNING +from ._typing import TYPE_CHECKING, cast from .version import InvalidVersion, Version -if MYPY_CHECK_RUNNING: # pragma: no cover - from typing import Union +if TYPE_CHECKING: # pragma: no cover + from typing import NewType, Union + + NormalizedName = NewType("NormalizedName", str) _canonicalize_regex = re.compile(r"[-_.]+") def canonicalize_name(name): - # type: (str) -> str + # type: (str) -> NormalizedName # This is taken from PEP 503. - return _canonicalize_regex.sub("-", name).lower() + value = _canonicalize_regex.sub("-", name).lower() + return cast("NormalizedName", value) def canonicalize_version(_version): diff --git a/packaging/version.py b/packaging/version.py index f39a2a12a..00371e86a 100644 --- a/packaging/version.py +++ b/packaging/version.py @@ -8,9 +8,9 @@ import re from ._structures import Infinity, NegativeInfinity -from ._typing import MYPY_CHECK_RUNNING +from ._typing import TYPE_CHECKING -if MYPY_CHECK_RUNNING: # pragma: no cover +if TYPE_CHECKING: # pragma: no cover from typing import Callable, Iterator, List, Optional, SupportsInt, Tuple, Union from ._structures import InfinityType, NegativeInfinityType From 48dab3670eeff9f08a7e94fa6b14394fa78f14c4 Mon Sep 17 00:00:00 2001 From: M Felt aka aixtools Date: Mon, 20 Apr 2020 17:31:40 +0000 Subject: [PATCH 18/21] typo --- packaging/_aix_support.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/_aix_support.py b/packaging/_aix_support.py index c0be89253..8033a5cbc 100644 --- a/packaging/_aix_support.py +++ b/packaging/_aix_support.py @@ -14,7 +14,7 @@ from ._typing import TYPE_CHECKING -if MYPY_CHECK_RUNNING: # pragma: no cover +if TYPE_CHECKING: # pragma: no cover from typing import List, Tuple From ae6ee5fa238166795b8695c5a33b5f6c5fab1ff8 Mon Sep 17 00:00:00 2001 From: M Felt aka aixtools Date: Sun, 1 Nov 2020 18:45:24 +0000 Subject: [PATCH 19/21] Restored the lines removed - in order to restart work. Additional conflicts in coding expected due to changes in `master`. --- tests/test_tags.py | 198 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/tests/test_tags.py b/tests/test_tags.py index 56107b43f..edd9d7052 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -1212,3 +1212,201 @@ def test_generic(self, monkeypatch): "py" + tags._version_nodot((sys.version_info[0], 0)), "none", "any" ) assert result[-1] == expected + +def test_aix_platform_notpep425_ready(monkeypatch): + if platform.system() != "AIX": + monkeypatch.setattr( + _aix_support, + "check_output", + lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", + ) + monkeypatch.setattr(distutils.util, "get_platform", lambda: "aix-7.2") + monkeypatch.setattr(sys, "maxsize", 2 ** 63 - 1) + result0 = list(tags._aix_platforms()) + result1 = [_aix_support.aix_platform()] + assert result0 == result1 + assert result0[0].startswith("aix") + assert result0[0].endswith("64") + + +def test_aix_platform_no_subprocess(monkeypatch): + monkeypatch.setattr(_aix_support, "_have_subprocess", False) + vrmf, bd = _aix_support._aix_bosmp64() + assert vrmf + assert bd == 9898 + + +def test_aix_platform_pep425_ready(monkeypatch): + monkeypatch.setattr( + _aix_support, + "check_output", + lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n", + ) + monkeypatch.setattr(distutils.util, "get_platform", lambda: "aix-5307-0747-32") + monkeypatch.setattr(sys, "maxsize", 2 ** 31 - 1) + result0 = list(tags._aix_platforms()) + result1 = [_aix_support.aix_platform()] + assert result0[0][:4] == result1[0][:4] + assert result0[0].startswith("aix") + assert result0[0].endswith("32") + + +def test_sys_tags_aix64_cpython(mock_interpreter_name, monkeypatch): + if mock_interpreter_name("CPython"): + monkeypatch.setattr(tags, "_cpython_abis", lambda *a: ["cp36m"]) + if platform.system() != "AIX": + monkeypatch.setattr(platform, "system", lambda: "AIX") + monkeypatch.setattr(tags, "_aix_platforms", lambda: ["aix_5307_0747_64"]) + abis = tags._cpython_abis(sys.version_info[:2]) + platforms = tags._aix_platforms() + result = list(tags.sys_tags()) + expected_interpreter = "cp{major}{minor}".format( + major=sys.version_info[0], minor=sys.version_info[1] + ) + assert len(abis) == 1 + assert result[0] == tags.Tag(expected_interpreter, abis[0], platforms[0]) + expected = tags.Tag("py{}0".format(sys.version_info[0]), "none", "any") + assert result[-1] == expected + + +def test_sys_tags_aix32_cpython(mock_interpreter_name, monkeypatch): + if mock_interpreter_name("CPython"): + monkeypatch.setattr(tags, "_cpython_abis", lambda *a: ["cp36m"]) + if platform.system() != "AIX": + monkeypatch.setattr(platform, "system", lambda: "AIX") + monkeypatch.setattr(tags, "_aix_platforms", lambda: ["aix_5307_0747_32"]) + abis = tags._cpython_abis(sys.version_info[:2]) + platforms = tags._aix_platforms() + result = list(tags.sys_tags()) + expected_interpreter = "cp{major}{minor}".format( + major=sys.version_info[0], minor=sys.version_info[1] + ) + assert len(abis) == 1 + assert result[0] == tags.Tag(expected_interpreter, abis[0], platforms[0]) + expected = tags.Tag("py{}0".format(sys.version_info[0]), "none", "any") + assert result[-1] == expected + + +def test_aix_bgt(monkeypatch): + monkeypatch.setattr(_aix_support, "_have_subprocess", False) + result = _aix_support._aix_bgt() + assert result == [6, 1, 7] + monkeypatch.setattr(_aix_support, "_have_subprocess", True) + monkeypatch.setattr(sysconfig, "get_config_var", lambda k: "powerpc-ibm-aix5.3.7.0") + result = _aix_support._aix_bgt() + assert result == [5, 3, 7] + + # def test_aix_buildtag(monkeypatch): + monkeypatch.setattr(_aix_support, "_have_subprocess", False) + monkeypatch.setattr(sys, "maxsize", 2 ** 31 - 1) + result = _aix_support.aix_buildtag() + assert result == "aix-6107-9898-32" + monkeypatch.setattr(_aix_support, "_have_subprocess", True) + monkeypatch.setattr(_aix_support, "_aix_bgt", lambda: [5, 3, 7]) + monkeypatch.setattr(sysconfig, "get_config_var", lambda key: None) + result = _aix_support.aix_buildtag() + assert result == "aix-5307-9898-32" + monkeypatch.setattr(sys, "maxsize", 2 ** 63 - 1) + monkeypatch.setattr(sysconfig, "get_config_var", lambda key: "0747") + result = _aix_support.aix_buildtag() + assert result == "aix-5307-0747-64" +======= + def test_linux_platforms_manylinux2014_armv6l(self, monkeypatch, manylinux_module): + monkeypatch.setattr(distutils.util, "get_platform", lambda: "linux_armv6l") + monkeypatch.setattr(os, "confstr", lambda x: "glibc 2.20", raising=False) + platforms = list(tags._linux_platforms(is_32bit=True)) + expected = ["linux_armv6l"] + assert platforms == expected + + def test_skip_manylinux_2014(self, monkeypatch, manylinux_module): + monkeypatch.setattr(distutils.util, "get_platform", lambda: "linux_ppc64") + monkeypatch.setattr(tags, "_get_glibc_version", lambda: (2, 20)) + monkeypatch.setattr( + manylinux_module, "manylinux2014_compatible", False, raising=False + ) + expected = [ + "manylinux_2_20_ppc64", + "manylinux_2_19_ppc64", + "manylinux_2_18_ppc64", + # "manylinux2014_ppc64", # this one is skipped + # "manylinux_2_17_ppc64", # this one is also skipped + "linux_ppc64", + ] + platforms = list(tags._linux_platforms()) + assert platforms == expected + + @pytest.mark.parametrize( + "machine, abi, alt_machine", + [("x86_64", "x32", "i686"), ("armv7l", "armel", "armv7l")], + ) + def test_linux_platforms_not_manylinux_abi( + self, monkeypatch, manylinux_module, machine, abi, alt_machine + ): + monkeypatch.setattr( + distutils.util, "get_platform", lambda: "linux_{}".format(machine) + ) + monkeypatch.setattr( + sys, + "executable", + os.path.join( + os.path.dirname(__file__), "hello-world-{}-{}".format(machine, abi) + ), + ) + platforms = list(tags._linux_platforms(is_32bit=True)) + expected = ["linux_{}".format(alt_machine)] + assert platforms == expected + + @pytest.mark.parametrize( + "machine, major, minor, tf", [("x86_64", 2, 20, False), ("s390x", 2, 22, True)] + ) + def test_linux_use_manylinux_compatible( + self, monkeypatch, manylinux_module, machine, major, minor, tf + ): + def manylinux_compatible(tag_major, tag_minor, tag_arch): + if tag_major == 2 and tag_minor == 22: + return tag_arch == "s390x" + return False + + monkeypatch.setattr(tags, "_get_glibc_version", lambda: (major, minor)) + monkeypatch.setattr( + distutils.util, "get_platform", lambda: "linux_{}".format(machine) + ) + monkeypatch.setattr( + manylinux_module, + "manylinux_compatible", + manylinux_compatible, + raising=False, + ) + platforms = list(tags._linux_platforms()) + if tf: + expected = ["manylinux_2_22_{}".format(machine)] + else: + expected = [] + expected.append("linux_{}".format(machine)) + assert platforms == expected + + def test_linux_use_manylinux_compatible_none(self, monkeypatch, manylinux_module): + def manylinux_compatible(tag_major, tag_minor, tag_arch): + if tag_major == 2 and tag_minor < 25: + return False + return None + + monkeypatch.setattr(tags, "_get_glibc_version", lambda: (2, 30)) + monkeypatch.setattr(distutils.util, "get_platform", lambda: "linux_x86_64") + monkeypatch.setattr( + manylinux_module, + "manylinux_compatible", + manylinux_compatible, + raising=False, + ) + platforms = list(tags._linux_platforms()) + expected = [ + "manylinux_2_30_x86_64", + "manylinux_2_29_x86_64", + "manylinux_2_28_x86_64", + "manylinux_2_27_x86_64", + "manylinux_2_26_x86_64", + "manylinux_2_25_x86_64", + "linux_x86_64", + ] + assert platforms == expected From 56aee303ee8b5d9e2e7d241edfecff51410b867d Mon Sep 17 00:00:00 2001 From: M Felt aka aixtools Date: Tue, 3 Nov 2020 14:15:09 +0000 Subject: [PATCH 20/21] Fix paste error; add a new-line --- tests/test_tags.py | 101 +-------------------------------------------- 1 file changed, 1 insertion(+), 100 deletions(-) diff --git a/tests/test_tags.py b/tests/test_tags.py index edd9d7052..e0bb4a492 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -1213,6 +1213,7 @@ def test_generic(self, monkeypatch): ) assert result[-1] == expected + def test_aix_platform_notpep425_ready(monkeypatch): if platform.system() != "AIX": monkeypatch.setattr( @@ -1310,103 +1311,3 @@ def test_aix_bgt(monkeypatch): monkeypatch.setattr(sysconfig, "get_config_var", lambda key: "0747") result = _aix_support.aix_buildtag() assert result == "aix-5307-0747-64" -======= - def test_linux_platforms_manylinux2014_armv6l(self, monkeypatch, manylinux_module): - monkeypatch.setattr(distutils.util, "get_platform", lambda: "linux_armv6l") - monkeypatch.setattr(os, "confstr", lambda x: "glibc 2.20", raising=False) - platforms = list(tags._linux_platforms(is_32bit=True)) - expected = ["linux_armv6l"] - assert platforms == expected - - def test_skip_manylinux_2014(self, monkeypatch, manylinux_module): - monkeypatch.setattr(distutils.util, "get_platform", lambda: "linux_ppc64") - monkeypatch.setattr(tags, "_get_glibc_version", lambda: (2, 20)) - monkeypatch.setattr( - manylinux_module, "manylinux2014_compatible", False, raising=False - ) - expected = [ - "manylinux_2_20_ppc64", - "manylinux_2_19_ppc64", - "manylinux_2_18_ppc64", - # "manylinux2014_ppc64", # this one is skipped - # "manylinux_2_17_ppc64", # this one is also skipped - "linux_ppc64", - ] - platforms = list(tags._linux_platforms()) - assert platforms == expected - - @pytest.mark.parametrize( - "machine, abi, alt_machine", - [("x86_64", "x32", "i686"), ("armv7l", "armel", "armv7l")], - ) - def test_linux_platforms_not_manylinux_abi( - self, monkeypatch, manylinux_module, machine, abi, alt_machine - ): - monkeypatch.setattr( - distutils.util, "get_platform", lambda: "linux_{}".format(machine) - ) - monkeypatch.setattr( - sys, - "executable", - os.path.join( - os.path.dirname(__file__), "hello-world-{}-{}".format(machine, abi) - ), - ) - platforms = list(tags._linux_platforms(is_32bit=True)) - expected = ["linux_{}".format(alt_machine)] - assert platforms == expected - - @pytest.mark.parametrize( - "machine, major, minor, tf", [("x86_64", 2, 20, False), ("s390x", 2, 22, True)] - ) - def test_linux_use_manylinux_compatible( - self, monkeypatch, manylinux_module, machine, major, minor, tf - ): - def manylinux_compatible(tag_major, tag_minor, tag_arch): - if tag_major == 2 and tag_minor == 22: - return tag_arch == "s390x" - return False - - monkeypatch.setattr(tags, "_get_glibc_version", lambda: (major, minor)) - monkeypatch.setattr( - distutils.util, "get_platform", lambda: "linux_{}".format(machine) - ) - monkeypatch.setattr( - manylinux_module, - "manylinux_compatible", - manylinux_compatible, - raising=False, - ) - platforms = list(tags._linux_platforms()) - if tf: - expected = ["manylinux_2_22_{}".format(machine)] - else: - expected = [] - expected.append("linux_{}".format(machine)) - assert platforms == expected - - def test_linux_use_manylinux_compatible_none(self, monkeypatch, manylinux_module): - def manylinux_compatible(tag_major, tag_minor, tag_arch): - if tag_major == 2 and tag_minor < 25: - return False - return None - - monkeypatch.setattr(tags, "_get_glibc_version", lambda: (2, 30)) - monkeypatch.setattr(distutils.util, "get_platform", lambda: "linux_x86_64") - monkeypatch.setattr( - manylinux_module, - "manylinux_compatible", - manylinux_compatible, - raising=False, - ) - platforms = list(tags._linux_platforms()) - expected = [ - "manylinux_2_30_x86_64", - "manylinux_2_29_x86_64", - "manylinux_2_28_x86_64", - "manylinux_2_27_x86_64", - "manylinux_2_26_x86_64", - "manylinux_2_25_x86_64", - "linux_x86_64", - ] - assert platforms == expected From c9544b6cd3cc0fba35e298e7da24d68cd3585737 Mon Sep 17 00:00:00 2001 From: M Felt aka aixtools Date: Tue, 3 Nov 2020 14:22:23 +0000 Subject: [PATCH 21/21] Fix blank line with spaces --- tests/test_tags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_tags.py b/tests/test_tags.py index e0bb4a492..f46b68784 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -1212,7 +1212,7 @@ def test_generic(self, monkeypatch): "py" + tags._version_nodot((sys.version_info[0], 0)), "none", "any" ) assert result[-1] == expected - + def test_aix_platform_notpep425_ready(monkeypatch): if platform.system() != "AIX":