8000 Centralize METADATA.toml parsing in the test suite by AlexWaygood · Pull Request #9534 · python/typeshed · GitHub
[go: up one dir, main page]

Skip to content

Centralize METADATA.toml parsing in the test suite #9534

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

Merged
merged 10 commits into from
Jan 28, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
cache: pip
cache-dependency-path: requirements-tests.txt
- run: pip install -r requirements-tests.txt
- run: ./tests/check_consistent.py
- run: python ./tests/check_consistent.py

new-syntax:
name: Ensure new syntax usage
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ extra_standard_library = [
"opcode",
"pyexpat",
]
known_first_party = ["utils"]
known_first_party = ["utils", "parse_metadata"]

[tool.pycln]
all = true
Expand Down
82 changes: 6 additions & 76 deletions tests/check_consistent.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,14 @@
import sys
from pathlib import Path

import tomli
import yaml
from packaging.requirements import Requirement
from packaging.specifiers import SpecifierSet
from packaging.version import Version

from utils import (
METADATA_MAPPING,
VERSIONS_RE,
get_all_testcase_directories,
get_gitignore_spec,
spec_matches_path,
strip_comments,
)

metadata_keys = {
"version",
"requires",
"extra_description",
"stub_distribution",
"obsolete_since",
"no_longer_updated",
"upload",
"tool",
}
tool_keys = {
"stubtest": {
"skip",
"apt_dependencies",
"brew_dependencies",
"choco_dependencies",
"extras",
"ignore_missing_stub",
"platforms",
}
}
extension_descriptions = {".pyi": "stub", ".py": ".py"}
supported_stubtest_platforms = {"win32", "darwin", "linux"}

dist_name_re = re.compile(r"^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$", re.IGNORECASE)
from parse_metadata import read_metadata
from utils import VERSIONS_RE, get_all_testcase_directories, get_gitignore_spec, spec_matches_path, strip_comments

extension_descriptions = {".pyi": "stub", ".py": ".py"}


def assert_consistent_filetypes(
Expand Down Expand Up @@ -162,46 +130,8 @@ def _find_stdlib_modules() -> set[str]:

def check_metadata() -> None:
Copy link
Collaborator
@Avasam Avasam Jan 14, 2023

Choose a reason for hiding this comment

The reason will be displayed t 8000 o describe this comment to others. Learn more.

At this point, this feels redundant since other tests will fail anyway. 😅
Unless you wanna use it as a smoke test.

Copy link
Member Author
@AlexWaygood AlexWaygood Jan 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get what you mean, but the other tests will assert the correctness of the METADATA.toml files "by accident". I feel like it's useful to have a test that asserts the correctness of the METADATA.toml files "on purpose"? That way we still have this guaranteed to be tested in CI, even if some other tests no longer need to get stuff from METADATA.toml files in the future, for whatever reason.

Copy link
Collaborator
@Avasam Avasam Jan 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's what I meant by a smoke test (an easy test that says, if this fails, everything else will fail anyway, so it's easy to find the source of the error). Just wanted to know if it was on purpose :)

for distribution in os.listdir("stubs"):
with open(os.path.join("stubs", distribution, "METADATA.toml"), encoding="UTF-8") as f:
data = tomli.loads(f.read())
assert "version" in data, f"Missing version for {distribution}"
version = data["version"]
msg = f"Unsupported version {repr(version)}"
assert isinstance(version, str), msg
# Check that the version parses
Version(version.removesuffix(".*"))
for key in data:
assert key in metadata_keys, f"Unexpected key {key} for {distribution}"
assert isinstance(data.get("requires", []), list), f"Invalid requires value for {distribution}"
for dep in data.get("requires", []):
assert isinstance(dep, str), f"Invalid requirement {repr(dep)} for {distribution}"
for space in " \t\n":
assert space not in dep, f"For consistency, requirement should not have whitespace: {dep}"
# Check that the requirement parses
Requirement(dep)

if "stub_distribution" in data:
assert dist_name_re.fullmatch(data["stub_distribution"]), f"Invalid 'stub_distribution' value for {distribution!r}"

assert isinstance(data.get("upload", True), bool), f"Invalid 'upload' value for {distribution!r}"

assert set(data.get("tool", [])).issubset(tool_keys.keys()), f"Unrecognised tool for {distribution}"
for tool, tk in tool_keys.items():
for key in data.get("tool", {}).get(tool, {}):
assert key in tk, f"Unrecognised {tool} key {key} for {distribution}"

tool_stubtest = data.get("tool", {}).get("stubtest", {})
specified_stubtest_platforms = set(tool_stubtest.get("platforms", ["linux"]))
assert (
specified_stubtest_platforms <= supported_stubtest_platforms
), f"Unrecognised platforms specified: {supported_stubtest_platforms - specified_stubtest_platforms} for {distribution}"

# Check that only specified platforms install packages:
for supported_plat in supported_stubtest_platforms:
if supported_plat not in specified_stubtest_platforms:
assert (
METADATA_MAPPING[supported_plat] not in tool_stubtest
), f"Installing system deps for unspecified platform {supported_plat} for {distribution}"
# This function does various sanity checks for METADATA.toml files
read_metadata(distribution)


def get_txt_requirements() -> dict[str, SpecifierSet]:
Expand Down
6D40
2 changes: 1 addition & 1 deletion tests/get_external_stub_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
import sys

from utils import read_dependencies
from parse_metadata import read_dependencies

distributions = sys.argv[1:]
if not distributions:
Expand Down
13 changes: 5 additions & 8 deletions tests/get_stubtest_system_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@
import os
import sys

import tomli

from utils import METADATA_MAPPING
from parse_metadata import read_stubtest_settings

platform = sys.platform
distributions = sys.argv[1:]
if not distributions:
distributions = os.listdir("stubs")

if platform in METADATA_MAPPING:
for distribution in distributions:
with open(f"stubs/{distribution}/METADATA.toml", "rb") as file:
for package in tomli.load(file).get("tool", {}).get("stubtest", {}).get(METADATA_MAPPING[platform], []):
print(package)
for distribution in distributions:
stubtest_settings = read_stubtest_settings(distribution)
for package in stubtest_settings.system_requirements_for_platform(platform):
print(package)
3 changes: 1 addition & 2 deletions tests/mypy_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,13 @@

import tomli

from parse_metadata import PackageDependencies, get_recursive_requirements
from utils import (
VERSIONS_RE as VERSION_LINE_RE,
PackageDependencies,
VenvInfo,
colored,
get_gitignore_spec,
get_mypy_req,
get_recursive_requirements,
make_venv,
print_error,
print_success_msg,
Expand Down
Loading
0