Skip to content

Commit 9cd9f6f

Browse files
sobolevnAlexWaygoodJelleZijlstra
authored
Add the ability to run third-party stubtest on Windows or MacOS when needed (#8923)
Co-authored-by: Alex Waygood <[email protected]> Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent 0f33721 commit 9cd9f6f

15 files changed

+129
-61
lines changed

.github/workflows/daily.yml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ jobs:
4444
stubtest-third-party:
4545
name: Check third party stubs with stubtest
4646
if: ${{ github.repository == 'python/typeshed' || github.event_name == 'workflow_dispatch' }}
47-
runs-on: ubuntu-20.04
47+
runs-on: ${{ matrix.os }}
4848
strategy:
4949
matrix:
50+
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
5051
shard-index: [0, 1, 2, 3]
5152
fail-fast: false
5253
steps:
@@ -56,12 +57,17 @@ jobs:
5657
python-version: "3.9"
5758
- name: Install dependencies
5859
run: pip install -r requirements-tests.txt
59-
- name: Install apt packages
60-
run: |
61-
sudo apt update
62-
sudo apt install -y $(python tests/get_apt_packages.py)
6360
- name: Run stubtest
64-
run: xvfb-run python tests/stubtest_third_party.py --num-shards 4 --shard-index ${{ matrix.shard-index }}
61+
shell: bash
62+
run: |
63+
if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then
64+
sudo apt update
65+
sudo apt install -y $(python tests/get_packages.py)
66+
67+
xvfb-run python tests/stubtest_third_party.py --num-shards 4 --shard-index ${{ matrix.shard-index }}
68+
else
69+
python tests/stubtest_third_party.py --num-shards 4 --shard-index ${{ matrix.shard-index }}
70+
fi
6571
6672
stub-uploader:
6773
name: Run the stub_uploader tests

.github/workflows/stubtest_stdlib.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Run stubtest
1+
name: Stdlib stubtest
22

33
on:
44
workflow_dispatch:
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Third-party stubtest
2+
3+
on:
4+
pull_request:
5+
paths-ignore:
6+
- '**/*.md'
7+
- 'scripts/**'
8+
9+
permissions:
10+
contents: read
11+
12+
env:
13+
PIP_DISABLE_PIP_VERSION_CHECK: 1
14+
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
stubtest-third-party:
21+
name: Check third party stubs with stubtest
22+
23+
runs-on: ${{ matrix.os }}
24+
strategy:
25+
matrix:
26+
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
27+
fail-fast: false
28+
29+
steps:
30+
- uses: actions/checkout@v3
31+
with:
32+
fetch-depth: 0
33+
- uses: actions/setup-python@v4
34+
with:
35+
python-version: "3.9"
36+
- name: Install dependencies
37+
run: pip install -r requirements-tests.txt
38+
- name: Run stubtest
39+
shell: bash
40+
run: |
41+
STUBS=$(
42+
git diff --name-only origin/${{ github.base_ref }} HEAD |
43+
# Use the daily.yml workflow to run stubtest on all third party stubs
44+
egrep ^stubs/ | cut -d "/" -f 2 | sort -u | (while read stub; do [ -d stubs/$stub ] && echo $stub || true; done)
45+
)
46+
47+
if [ -n "$STUBS" ]; then
48+
echo "Testing $STUBS..."
49+
PACKAGES=$(python tests/get_packages.py $STUBS)
50+
51+
if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then
52+
if [ -n "$PACKAGES" ]; then
53+
echo "Installing apt packages: $PACKAGES"
54+
sudo apt update && sudo apt install -y $PACKAGES
55+
fi
56+
xvfb-run python tests/stubtest_third_party.py $STUBS
57+
fi
58+
59+
if [ "${{ matrix.os }}" = "macos-latest" ]; then
60+
# Could install brew packages here if we run into stubs that need it
61+
python tests/stubtest_third_party.py $STUBS
62+
fi
63+
64+
if [ "${{ matrix.os }}" = "windows-latest" ]; then
65+
# Could install choco packages here if we run into stubs that need it
66+
python tests/stubtest_third_party.py $STUBS
67+
fi
68+
else
69+
echo "Nothing to test"
70+
fi

.github/workflows/tests.yml

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -146,36 +146,3 @@ jobs:
146146
cd stub_uploader
147147
pip install -r requirements.txt
148148
python -m pytest tests
149-
150-
stubtest-third-party:
151-
name: Check third party stubs with stubtest
152-
runs-on: ubuntu-20.04
153-
if: github.event_name == 'pull_request'
154-
steps:
155-
- uses: actions/checkout@v3
156-
with:
157-
fetch-depth: 0
158-
- uses: actions/setup-python@v4
159-
with:
160-
python-version: "3.9"
161-
- name: Install dependencies
162-
run: pip install -r requirements-tests.txt
163-
- name: Run stubtest
164-
run: |
165-
STUBS=$(
166-
git diff --name-only origin/${{ github.base_ref }} HEAD |
167-
# Uncomment the following to (very slowly) run on all third party stubs:
168-
# git ls-files |
169-
egrep ^stubs/ | cut -d "/" -f 2 | sort -u | (while read stub; do [ -d stubs/$stub ] && echo $stub || true; done)
170-
)
171-
if test -n "$STUBS"; then
172-
echo "Testing $STUBS..."
173-
APT_PACKAGES=$(python tests/get_apt_packages.py $STUBS)
174-
if test -n "$APT_PACKAGES"; then
175-
echo "Installing apt packages: $APT_PACKAGES"
176-
sudo apt update && sudo apt install -y $APT_PACKAGES
177-
fi
178-
xvfb-run python tests/stubtest_third_party.py $STUBS
179-
else
180-
echo "Nothing to test"
181-
fi

CONTRIBUTING.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ This has the following keys:
192192
* `apt_dependencies` (default: `[]`): A list of Ubuntu APT packages
193193
that need to be installed for stubtest to run successfully. These are
194194
usually packages needed to pip install the implementation distribution.
195+
* `platforms` (default: `["linux"]`): A list of OSes on which to run stubtest.
196+
Can contain `win32`, `linux`, and `darwin` values.
197+
If not specified, stubtest is run only on `linux`.
198+
Only add extra OSes to the test
199+
if there are platform-specific branches in a stubs package.
195200

196201
The format of all `METADATA.toml` files can be checked by running
197202
`python3 ./tests/check_consistent.py`.

stubs/D3DShot/METADATA.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ version = "0.1.*"
22
requires = ["types-Pillow"]
33

44
[tool.stubtest]
5-
# The library only works on Windows; we currently only run stubtest on Ubuntu for third-party stubs in CI.
6-
# See #8660
5+
# TODO: figure out how to run stubtest for this package
6+
# (the package pins Pillow in a problematic way)
77
skip = true
8+
platforms = ["win32"]

stubs/JACK-Client/METADATA.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
version = "0.5.*"
22

33
[tool.stubtest]
4+
platforms = ["linux"]
45
apt_dependencies = ["libjack-dev"]

stubs/pyaudio/METADATA.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
version = "0.2.*"
22

33
[tool.stubtest]
4+
platforms = ["linux"]
45
apt_dependencies = ["portaudio19-dev"]

stubs/pycurl/METADATA.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
version = "7.45.*"
22

33
[tool.stubtest]
4+
platforms = ["linux"]
45
apt_dependencies = ["libcurl4-openssl-dev"]

stubs/pywin32/METADATA.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
version = "305.*"
2+
23
[tool.stubtest]
4+
platforms = ["win32"]
35
ignore_missing_stub = false
4-
# The library only works on Windows; we currently only run stubtest on Ubuntu for third-party stubs in CI.
5-
# See #8660
6-
skip = true

tests/check_consistent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from utils import VERSIONS_RE, get_all_testcase_directories, get_gitignore_spec, spec_matches_path, strip_comments
1919

2020
metadata_keys = {"version", "requires", "extra_description", "obsolete_since", "no_longer_updated", "tool"}
21-
tool_keys = {"stubtest": {"skip", "apt_dependencies", "extras", "ignore_missing_stub"}}
21+
tool_keys = {"stubtest": {"skip", "apt_dependencies", "extras", "ignore_missing_stub", "platforms"}}
2222
extension_descriptions = {".pyi": "stub", ".py": ".py"}
2323

2424

tests/get_apt_packages.py

Lines changed: 0 additions & 14 deletions
This file was deleted.

tests/get_packages.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env python3
2+
import os
3+
import sys
4+
5+
import tomli
6+
7+
platform = sys.platform
8+
distributions = sys.argv[1:]
9+
if not distributions:
10+
distributions = os.listdir("stubs")
11+
12+
metadata_mapping = {
13+
"linux": "apt_dependencies",
14+
# We could add others here if we run into stubs that need it:
15+
# "darwin": "brew_dependencies",
16+
# "win32": "choco_dependencies",
17+
}
18+
19+
if platform in metadata_mapping:
20+
for distribution in distributions:
21+
with open(f"stubs/{distribution}/METADATA.toml", "rb") as file:
22+
for package in tomli.load(file).get("tool", {}).get("stubtest", {}).get(metadata_mapping[platform], []):
23+
print(package)

tests/stubtest_third_party.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ def run_stubtest(dist: Path, *, verbose: bool = False) -> bool:
3434
print(colored("skipping", "yellow"))
3535
return True
3636

37+
platforms_to_test = stubtest_meta.get("platforms", ["linux"])
38+
if sys.platform not in platforms_to_test:
39+
print(colored(f"skipping, unsupported platform: {sys.platform}, supported: {platforms_to_test}", "yellow"))
40+
return True
41+
3742
with tempfile.TemporaryDirectory() as tmp:
3843
venv_dir = Path(tmp)
3944
venv.create(venv_dir, with_pip=True, clear=True)
@@ -57,8 +62,8 @@ def run_stubtest(dist: Path, *, verbose: bool = False) -> bool:
5762
# If @tests/requirements-stubtest.txt exists, run "pip install" on it.
5863
req_path = dist / "@tests" / "requirements-stubtest.txt"
5964
if req_path.exists():
65+
pip_cmd = [pip_exe, "install", "-r", str(req_path)]
6066
try:
61-
pip_cmd = [pip_exe, "install", "-r", str(req_path)]
6267
subprocess.run(pip_cmd, check=True, capture_output=True)
6368
except subprocess.CalledProcessError as e:
6469
print_command_failure("Failed to install requirements", e)
@@ -102,6 +107,9 @@ def run_stubtest(dist: Path, *, verbose: bool = False) -> bool:
102107
allowlist_path = dist / "@tests/stubtest_allowlist.txt"
103108
if allowlist_path.exists():
104109
stubtest_cmd.extend(["--allowlist", str(allowlist_path)])
110+
platform_allowlist = dist / f"@tests/stubtest_allowlist_{sys.platform}.txt"
111+
if platform_allowlist.exists():
112+
stubtest_cmd.extend(["--allowlist", str(platform_allowlist)])
105113

106114
try:
107115
subprocess.run(stubtest_cmd, env=stubtest_env, check=True, capture_output=True)

0 commit comments

Comments
 (0)