Skip to content

Split tool.stubtest.platforms metadata key #13746

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/daily.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
PYTHON_EXECUTABLE="python"
fi

$PYTHON_EXECUTABLE tests/stubtest_third_party.py --specified-platforms-only --num-shards 4 --shard-index ${{ matrix.shard-index }}
$PYTHON_EXECUTABLE tests/stubtest_third_party.py --ci-platforms-only --num-shards 4 --shard-index ${{ matrix.shard-index }}

stub-uploader:
name: stub_uploader tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/stubtest_third_party.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
PYTHON_EXECUTABLE="python"
fi

$PYTHON_EXECUTABLE tests/stubtest_third_party.py --specified-platforms-only $STUBS
$PYTHON_EXECUTABLE tests/stubtest_third_party.py --ci-platforms-only $STUBS
else
echo "Nothing to test"
fi
15 changes: 10 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,16 @@ This has the following keys:
that need to be installed for stubtest to run successfully
* `choco_dependencies` (default: `[]`): A list of Windows Chocolatey packages
that need to be installed for stubtest to run successfully
* `platforms` (default: `["linux"]`): A list of OSes on which to run stubtest.
Can contain `win32`, `linux`, and `darwin` values.
If not specified, stubtest is run only on `linux`.
Only add extra OSes to the test
if there are platform-specific branches in a stubs package.
* `supported_platforms` (default: all platforms): A list of OSes on which
stubtest can be run. When a package is not platform-specific, this should
not be set. If the package is platform-specific, this should usually be set
to the supported platforms, unless stubtest is known to fail on a
specific platform.
* `ci_platforms` (default: `["linux"]`): A list of OSes on which to run
stubtest as part of our continuous integration (CI) tests. Can contain
`win32`, `linux`, and `darwin` values. If not specified, stubtest is run
only on `linux`. Only add extra OSes to the test if there are
platform-specific branches in a stubs package.

`*_dependencies` are usually packages needed to `pip install` the implementation
distribution.
Expand Down
27 changes: 19 additions & 8 deletions lib/ts_utils/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"read_stubtest_settings",
]

DEFAULT_STUBTEST_PLATFORMS = ["linux"]

_STUBTEST_PLATFORM_MAPPING: Final = {"linux": "apt_dependencies", "darwin": "brew_dependencies", "win32": "choco_dependencies"}
# Some older websites have a bad pattern of using query params for navigation.
Expand Down Expand Up @@ -69,7 +70,8 @@ class StubtestSettings:
choco_dependencies: list[str]
extras: list[str]
ignore_missing_stub: bool
platforms: list[str]
supported_platforms: list[str] | None # None means all platforms
ci_platforms: list[str]
stubtest_requirements: list[str]

def system_requirements_for_platform(self, platform: str) -> list[str]:
Expand All @@ -91,25 +93,32 @@ def read_stubtest_settings(distribution: str) -> StubtestSettings:
choco_dependencies: object = data.get("choco_dependencies", [])
extras: object = data.get("extras", [])
ignore_missing_stub: object = data.get("ignore_missing_stub", False)
specified_platforms: object = data.get("platforms", ["linux"])
supported_platforms: object = data.get("supported_platforms")
ci_platforms: object = data.get("ci_platforms", DEFAULT_STUBTEST_PLATFORMS)
stubtest_requirements: object = data.get("stubtest_requirements", [])

assert type(skip) is bool
assert type(ignore_missing_stub) is bool

# It doesn't work for type-narrowing if we use a for loop here...
assert _is_list_of_strings(specified_platforms)
assert supported_platforms is None or _is_list_of_strings(supported_platforms)
assert _is_list_of_strings(ci_platforms)
assert _is_list_of_strings(apt_dependencies)
assert _is_list_of_strings(brew_dependencies)
assert _is_list_of_strings(choco_dependencies)
assert _is_list_of_strings(extras)
assert _is_list_of_strings(stubtest_requirements)

unrecognised_platforms = set(specified_platforms) - _STUBTEST_PLATFORM_MAPPING.keys()
assert not unrecognised_platforms, f"Unrecognised platforms specified for {distribution!r}: {unrecognised_platforms}"
unrecognised_platforms = set(ci_platforms) - _STUBTEST_PLATFORM_MAPPING.keys()
assert not unrecognised_platforms, f"Unrecognised ci_platforms specified for {distribution!r}: {unrecognised_platforms}"

if supported_platforms is not None:
assert set(ci_platforms).issubset(
supported_platforms
), f"ci_platforms must be a subset of supported_platforms for {distribution!r}"

for platform, dep_key in _STUBTEST_PLATFORM_MAPPING.items():
if platform not in specified_platforms:
if platform not in ci_platforms:
assert dep_key not in data, (
f"Stubtest is not run on {platform} in CI for {distribution!r}, "
f"but {dep_key!r} are specified in METADATA.toml"
Expand All @@ -122,7 +131,8 @@ def read_stubtest_settings(distribution: str) -> StubtestSettings:
choco_dependencies=choco_dependencies,
extras=extras,
ignore_missing_stub=ignore_missing_stub,
platforms=specified_platforms,
supported_platforms=supported_platforms,
ci_platforms=ci_platforms,
stubtest_requirements=stubtest_requirements,
)

Expand Down Expand Up @@ -176,7 +186,8 @@ def is_obsolete(self) -> bool:
"choco_dependencies",
"extras",
"ignore_missing_stub",
"platforms",
"supported_platforms",
"ci_platforms",
"stubtest_requirements",
}
}
Expand Down
4 changes: 4 additions & 0 deletions lib/ts_utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ def print_info(message: str) -> None:
print(colored(message, "blue"))


def print_warning(message: str) -> None:
print(colored(message), "yellow")


def print_error(error: str, end: str = "\n", fix_path: tuple[str, str] = ("", "")) -> None:
error_split = error.split("\n")
old, new = fix_path
Expand Down
2 changes: 1 addition & 1 deletion stubs/JACK-Client/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ requires = ["numpy>=1.20", "types-cffi"]

[tool.stubtest]
# darwin and win32 are equivalent
platforms = ["darwin", "linux"]
ci_platforms = ["darwin", "linux"]
apt_dependencies = ["libjack-dev"]
brew_dependencies = ["jack"]
# No need to install on the CI. Leaving here as information for Windows contributors.
Expand Down
2 changes: 1 addition & 1 deletion stubs/PyScreeze/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ requires = ["Pillow>=10.3.0"]

[tool.stubtest]
# Linux has extra constants, win32 has different definitions
platforms = ["linux", "win32"]
ci_platforms = ["linux", "win32"]
# PyScreeze has an odd setup.py file
# that doesn't list Pillow as a dependency for py312+ yet:
# https://github.com/asweigart/pyscreeze/blob/eeca245a135cf171c163b3691300138518efa64e/setup.py#L38-L46
Expand Down
8 changes: 5 additions & 3 deletions stubs/RPi.GPIO/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ version = "0.7.*"
upstream_repository = "https://sourceforge.net/p/raspberry-gpio-python/code/"

[tool.stubtest]
# When stubtest tries to import this module:
# error: RPi.GPIO failed to import. RuntimeError: This module can only be run on a Raspberry Pi!
# This package is only supported on Raspberry Pi hardware, which identifies
# itself as 'linux'. When run on other hardware, it raises a RuntimeError:
# RPi.GPIO failed to import. RuntimeError: This module can only be run on a Raspberry Pi!
# https://sourceforge.net/p/raspberry-gpio-python/code/ci/08048dd1894a6b09a104557b6eaa6bb68b6baac5/tree/source/py_gpio.c#l1008
skip = true
supported_platforms = []
ci_platforms = []
2 changes: 1 addition & 1 deletion stubs/aiofiles/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ upstream_repository = "https://github.com/Tinche/aiofiles"

[tool.stubtest]
# linux and darwin are equivalent
platforms = ["linux", "win32"]
ci_platforms = ["linux", "win32"]
2 changes: 1 addition & 1 deletion stubs/antlr4-python3-runtime/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ upstream_repository = "https://github.com/antlr/antlr4"

[tool.stubtest]
ignore_missing_stub = true
platforms = ["linux", "win32"]
ci_platforms = ["linux", "win32"]
2 changes: 1 addition & 1 deletion stubs/cffi/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ requires = ["types-setuptools"]

[tool.stubtest]
# linux and darwin are mostly equivalent, except for a single `RTLD_DEEPBIND` variable
platforms = ["linux", "win32"]
ci_platforms = ["linux", "win32"]
2 changes: 1 addition & 1 deletion stubs/colorama/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ version = "0.4.*"
upstream_repository = "https://github.com/tartley/colorama"

[tool.stubtest]
platforms = ["linux", "win32"]
ci_platforms = ["linux", "win32"]
2 changes: 1 addition & 1 deletion stubs/gdb/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ extra_description = """\
"""

[tool.stubtest]
platforms = ["linux"]
ci_platforms = ["linux"]
apt_dependencies = ["gdb"]
2 changes: 1 addition & 1 deletion stubs/gevent/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ requires = ["types-greenlet", "types-psutil"]
[tool.stubtest]
# Run stubtest on all platforms, since there is some platform specific stuff
# especially in the stdlib module replacement
platforms = ["linux", "darwin", "win32"]
ci_platforms = ["linux", "darwin", "win32"]
# for testing the ffi loop implementations on all platforms
stubtest_requirements = ["cffi", "dnspython"]
apt_dependencies = ["libev4", "libev-dev", "libuv1", "libuv1-dev"]
Expand Down
2 changes: 1 addition & 1 deletion stubs/keyboard/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ upstream_repository = "https://github.com/boppreh/keyboard"
# It's only by possible mouse buttons and event literal types.
# As well as returning a tuple of int/long from keyboard.mouse.get_position
# The "mouse" module is obsoleted by the "mouse" package.
# platforms =
# ci_platforms = ["linux"]
2 changes: 1 addition & 1 deletion stubs/paramiko/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ partial_stub = true
[tool.stubtest]
ignore_missing_stub = true
# linux and darwin are equivalent
platforms = ["linux", "win32"]
ci_platforms = ["linux", "win32"]
2 changes: 1 addition & 1 deletion stubs/psutil/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ version = "7.0.*"
upstream_repository = "https://github.com/giampaolo/psutil"

[tool.stubtest]
platforms = ["darwin", "linux", "win32"]
ci_platforms = ["darwin", "linux", "win32"]
2 changes: 1 addition & 1 deletion stubs/pyaudio/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ version = "0.2.*"

[tool.stubtest]
# linux and win32 are equivalent
platforms = ["darwin", "linux"]
ci_platforms = ["darwin", "linux"]
apt_dependencies = ["portaudio19-dev"]
brew_dependencies = ["portaudio"]
2 changes: 1 addition & 1 deletion stubs/pycurl/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ version = "7.45.6"
upstream_repository = "https://github.com/pycurl/pycurl"

[tool.stubtest]
platforms = ["darwin", "linux", "win32"]
ci_platforms = ["darwin", "linux", "win32"]
2 changes: 1 addition & 1 deletion stubs/pygit2/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ requires = ["types-cffi"]
obsolete_since = "1.16.0" # Released on 2024-10-11

[tool.stubtest]
platforms = ["darwin", "linux", "win32"]
ci_platforms = ["darwin", "linux", "win32"]
# Does not build on any platform on Python 3.13 as of 2025-03-17.
skip = true
2 changes: 1 addition & 1 deletion stubs/pynput/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ version = "~=1.8.1"
upstream_repository = "https://github.com/moses-palmer/pynput"

[tool.stubtest]
platforms = ["darwin", "linux", "win32"]
ci_platforms = ["darwin", "linux", "win32"]
2 changes: 1 addition & 1 deletion stubs/pyperclip/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ version = "1.9.*"
upstream_repository = "https://github.com/asweigart/pyperclip"

[tool.stubtest]
platforms = ["win32", "linux", "darwin"]
ci_platforms = ["win32", "linux", "darwin"]
apt_dependencies = ["xclip"]
2 changes: 1 addition & 1 deletion stubs/pyserial/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ version = "3.5.*"
upstream_repository = "https://github.com/pyserial/pyserial"

[tool.stubtest]
platforms = ["darwin", "linux", "win32"]
ci_platforms = ["darwin", "linux", "win32"]
extras = ["cp2110"]
3 changes: 2 additions & 1 deletion stubs/pywin32/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ version = "310.*"
upstream_repository = "https://github.com/mhammond/pywin32"

[tool.stubtest]
platforms = ["win32"]
supported_platforms = ["win32"]
ci_platforms = ["win32"]
2 changes: 1 addition & 1 deletion stubs/setuptools/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ requires = ["setuptools"] # For pkg_resources

[tool.stubtest]
# darwin is equivalent to linux for OS-specific methods
platforms = ["linux", "win32"]
ci_platforms = ["linux", "win32"]
stubtest_requirements = ["tomli"]
2 changes: 1 addition & 1 deletion stubs/uWSGI/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ extra_description = """\
# Run stubtest on MacOS as well, to check that the
# uWSGI-specific parts of stubtest_third_party.py
# also work there
platforms = ["linux", "darwin"]
ci_platforms = ["linux", "darwin"]
2 changes: 1 addition & 1 deletion stubs/waitress/METADATA.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ upstream_repository = "https://github.com/Pylons/waitress"

[tool.stubtest]
# linux and darwin are equivalent
platforms = ["linux", "win32"]
ci_platforms = ["linux", "win32"]
29 changes: 17 additions & 12 deletions tests/stubtest_third_party.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,11 @@
print_info,
print_success_msg,
print_time,
print_warning,
)


def run_stubtest(
dist: Path, *, verbose: bool = False, specified_platforms_only: bool = False, keep_tmp_dir: bool = False
) -> bool:
def run_stubtest(dist: Path, *, verbose: bool = False, ci_platforms_only: bool = False, keep_tmp_dir: bool = False) -> bool:
"""Run stubtest for a single distribution."""

dist_name = dist.name
Expand All @@ -43,14 +42,16 @@ def run_stubtest(

stubtest_settings = metadata.stubtest_settings
if stubtest_settings.skip:
print(colored("skipping", "yellow"))
print(colored("skipping (skip = true)", "yellow"))
return True

if sys.platform not in stubtest_settings.platforms:
if specified_platforms_only:
print(colored("skipping (platform not specified in METADATA.toml)", "yellow"))
return True
print(colored(f"Note: {dist_name} is not currently tested on {sys.platform} in typeshed's CI.", "yellow"))
if stubtest_settings.supported_platforms is not None and sys.platform not in stubtest_settings.supported_platforms:
print(colored("skipping (platform not supported)", "yellow"))
return True

if ci_platforms_only and sys.platform not in stubtest_settings.ci_platforms:
print(colored("skipping (platform skipped in CI)", "yellow"))
return True

if not metadata.requires_python.contains(PYTHON_VERSION):
print(colored(f"skipping (requires Python {metadata.requires_python})", "yellow"))
Expand Down Expand Up @@ -176,6 +177,10 @@ def run_stubtest(
else:
print_time(time() - t)
print_success_msg()

if sys.platform not in stubtest_settings.ci_platforms:
print_warning(f"Note: {dist_name} is not currently tested on {sys.platform} in typeshed's CI")

if keep_tmp_dir:
print_info(f"Virtual environment kept at: {venv_dir}")
finally:
Expand Down Expand Up @@ -385,9 +390,9 @@ def main() -> NoReturn:
parser.add_argument("--num-shards", type=int, default=1)
parser.add_argument("--shard-index", type=int, default=0)
parser.add_argument(
"--specified-platforms-only",
"--ci-platforms-only",
action="store_true",
help="skip the test if the current platform is not specified in METADATA.toml/tool.stubtest.platforms",
help="skip the test if the current platform is not specified in METADATA.toml/tool.stubtest.ci-platforms",
)
parser.add_argument("--keep-tmp-dir", action="store_true", help="keep the temporary virtualenv")
parser.add_argument("dists", metavar="DISTRIBUTION", type=str, nargs=argparse.ZERO_OR_MORE)
Expand All @@ -404,7 +409,7 @@ def main() -> NoReturn:
continue
try:
if not run_stubtest(
dist, verbose=args.verbose, specified_platforms_only=args.specified_platforms_only, keep_tmp_dir=args.keep_tmp_dir
dist, verbose=args.verbose, ci_platforms_only=args.ci_platforms_only, keep_tmp_dir=args.keep_tmp_dir
):
result = 1
except NoSuchStubError as e:
Expand Down