Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
26d4fcd
redo PR and force push
aixtools Nov 29, 2019
730016e
modify import to work better with monkeypatch in tests
aixtools Nov 29, 2019
ce9e721
Add extra monkeypatch setting
aixtools Nov 29, 2019
89a7b23
More changes to get past Windows CI tests...
aixtools Nov 29, 2019
e3ce54e
CI module `black` says double quotes `"` needed
aixtools Nov 29, 2019
b46efe0
Changes made in accordance of peer review of CPyhton PR #17303
aixtools Dec 8, 2019
ac25b81
Specify `#pragma no cover` for Windows - that does not have os.uname()
aixtools Dec 8, 2019
9c999bb
Remove "too many spaces" in pragma (comment)
aixtools Dec 8, 2019
f06f81a
Non-posix systems (i.e., no `os.uname()`) fail coverage tests, use co…
aixtools Dec 8, 2019
c8d5d79
Sync code with CPython 3.9: `Lib/_aix_support.py`
aixtools Dec 17, 2019
8677561
typo corrections to pass lint
aixtools Dec 17, 2019
1dc7248
Merge branch 'master' into AIX-platform-tag
di Jan 2, 2020
5c9166b
Merge branch 'master' into AIX-platform-tag
aixtools Feb 3, 2020
2f9fc76
Merge branch 'master' into AIX-platform-tag
aixtools Mar 17, 2020
f9019b2
rename _AIX_platform to _aix_support - same as in CPython
aixtools Apr 3, 2020
5572136
Merge branch 'master' into AIX-platform-tag
aixtools Apr 3, 2020
91412e8
Sync _aix_support.py with CPython `Lib/_aix_support.py`
aixtools Apr 3, 2020
81ebe3c
Fix file to pass flake8 tests
aixtools Apr 3, 2020
27ebbb1
import subprocess no longer needed to support monkeypatch
aixtools Apr 3, 2020
cf52688
Shorten variable names to pass flake8 line-length tests
aixtools Apr 20, 2020
68e9c80
Add a NewType for normalized names (#292)
pradyunsg Apr 8, 2020
880edc3
Merge branch 'master' into AIX-platform-tag
aixtools Apr 20, 2020
48dab36
typo
aixtools Apr 20, 2020
5088c8c
Merge branch 'master' into AIX-platform-tag by removing the conflicts
aixtools Nov 1, 2020
ae6ee5f
Restored the lines removed - in order to restart work.
aixtools Nov 1, 2020
56aee30
Fix paste error; add a new-line
aixtools Nov 3, 2020
c9544b6
Fix blank line with spaces
aixtools Nov 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions packaging/_aix_support.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""Shared AIX support functions."""

import sys
from sysconfig import get_config_var

try:
from subprocess import check_output

_have_subprocess = True
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

from ._typing import TYPE_CHECKING

if TYPE_CHECKING: # pragma: no cover
from typing import List, Tuple


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
# 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
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 _have_subprocess:
# We expect all AIX systems to have lslpp installed in this location
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 was for CPython bootstrap phase (see Lib/_aix_aupport.py)
# To pass `pypa/packaging` Windows CI tests mock constants are used
release, version = 2, 7
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]
if _have_subprocess:
bgt = get_config_var("BUILD_GNU_TYPE")
else:
bgt = "powerpc-ibm-aix6.1.7.0"
return _aix_vrtl(vrmf=str(bgt))


def aix_buildtag():
# type: () -> str
"""
Return the platform_tag of the system Python was built on.
"""
# 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 = get_config_var("AIX_BUILDDATE") if _have_subprocess else "9898"
try:
bd = str(bd)
except (TypeError, ValueError):
bd = "9898"

return _aix_tag(_aix_bgt(), int(bd))
13 changes: 13 additions & 0 deletions packaging/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import sysconfig
import warnings

from ._aix_support import aix_platform
from ._typing import TYPE_CHECKING, cast

if TYPE_CHECKING: # pragma: no cover
Expand Down Expand Up @@ -748,6 +749,16 @@ def _linux_platforms(is_32bit=_32_BIT_INTERPRETER):
yield linux


def _aix_platforms():
# type: () -> Iterator[str]
# 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.count("-") == 1:
platform = aix_platform()
yield platform


def _generic_platforms():
# type: () -> Iterator[str]
yield _normalize_string(distutils.util.get_platform())
Expand All @@ -762,6 +773,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()

Expand Down
189 changes: 94 additions & 95 deletions tests/test_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import pretend
import pytest

from packaging import tags
from packaging import tags, _aix_support


@pytest.fixture
Expand Down Expand Up @@ -1213,102 +1213,101 @@ def test_generic(self, monkeypatch):
)
assert result[-1] == expected

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))
def test_aix_platform_notpep425_ready(monkeypatch):
if platform.system() != "AIX":
monkeypatch.setattr(
manylinux_module, "manylinux2014_compatible", False, raising=False
_aix_support,
"check_output",
lambda *a: b"bos.mp64:bos.mp64:5.3.7.0:::C::BOS 64-bit:::::::1:0:/:0747\n",
)
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")],
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",
)
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)]
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]
)
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
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"