Add optional requires_python to third party stubs metadata#10724
Add optional requires_python to third party stubs metadata#10724AlexWaygood merged 19 commits intopython:mainfrom
Conversation
|
It wouldn't be as easy to adjust pyright/pytype, but I also don't think it'll be as important to "fix" those tests in a "principled" way; we can probably leave them as they are for now |
|
The changes to |
Okay. I'll leave them for later
Let me see if it is simple enough to do here, if not I'll leave it as well |
AlexWaygood
left a comment
There was a problem hiding this comment.
Lots of good stuff here, but needs a few changes -- see my comments below:
- move to pyproject.toml - add to __all__ - parens in message - mininum supported version is also not allowed - delete print - test against python runtime version and target versions (mypy and regr tests) - different messages for different reasons - default the specifier to >=oldest_supported
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
|
With this PR checked out, I tried applying this diff: diff --git a/stubs/requests/METADATA.toml b/stubs/requests/METADATA.toml
index 39371b90e..677799c7d 100644
--- a/stubs/requests/METADATA.toml
+++ b/stubs/requests/METADATA.toml
@@ -1,6 +1,7 @@
version = "2.31.*"
upstream_repository = "https://github.com/psf/requests"
requires = ["types-urllib3"]
+requires_python = ">=3.9"
[tool.stubtest]
extras = ["socks"]I then ran this command (using Python 3.11): Output: *** Testing Python 3.12 on win32
Testing third-party packages...
testing requests (17 files)... success
*** Testing Python 3.11 on win32
Testing third-party packages...
testing requests (17 files)... success
*** Testing Python 3.10 on win32
Testing third-party packages...
testing requests (17 files)... success
*** Testing Python 3.9 on win32
Testing third-party packages...
testing requests (17 files)... success
*** Testing Python 3.8 on win32
Testing third-party packages...
skipping 'requests' for target Python 3.8 (requires Python >=3.9)
Traceback (most recent call last):
File "C:\Users\alexw\coding\typeshed\tests\mypy_test.py", line 573, in <module>
main()
File "C:\Users\alexw\coding\typeshed\tests\mypy_test.py", line 556, in main
code, files_checked_this_version, packages_skipped_this_version = test_typeshed(code, args=config, tempdir=td_path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\typeshed\tests\mypy_test.py", line 535, in test_typeshed
code, third_party_files_checked, third_party_packages_skipped = test_third_party_stubs(code, args, tempdir)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\typeshed\tests\mypy_test.py", line 511, in test_third_party_stubs
assert _DISTRIBUTION_TO_VENV_MAPPING.keys() == distributions_to_check.keys()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError |
|
Running this: Results in this output being printed to the terminal: Could we have it print something like "All tests were skipped!" to the terminal, if all tests were skipped? If all tests were skipped, that doesn't feel like a "successful" test run to me. |
tests/mypy_test.py
Outdated
| # Some distributions may have been skipped earlier and therefore don't have a venv. | ||
| distributions_without_venv = { | ||
| distribution: requirements | ||
| for distribution, requirements in distributions_to_check.items() | ||
| if distribution not in _DISTRIBUTION_TO_VENV_MAPPING | ||
| } | ||
| if distributions_without_venv: | ||
| setup_virtual_environments(distributions_without_venv, args, tempdir) | ||
|
|
||
| # Check that there is a venv for every distribution we're testing. | ||
| # Some venvs may exist from previous runs but are skipped in this run. | ||
| assert _DISTRIBUTION_TO_VENV_MAPPING.keys() >= distributions_to_check.keys() | ||
|
|
||
| for distribution in distributions_to_check: | ||
| venv_info = _DISTRIBUTION_TO_VENV_MAPPING[distribution] |
There was a problem hiding this comment.
OK so this should work now in all cases (hopefully). I tested with your requests example and all these invocations work
python tests/mypy_test.py stubs/requestspython tests/mypy_test.py stubs/requests*# multiple packages togetherpython tests/mypy_test.py stubs/requests -p 3.8 3.9 3.10 3.11python tests/mypy_test.py stubs/requests -p 3.11 3.8 3.9 3.10# this also crashed before, order is importantpython tests/mypy_test.py stubs/requests* -p 3.8 3.9 3.10 3.11python tests/mypy_test.py stubs/requests* -p 3.11 3.8 3.9 3.10
Also the for loop now correctly skips distributions that should not run. It must loop over distributions_to_check, not venvs
This is part of the work towards python/typeshed#10722 Note that the field is called `python_requires` in `setup.py`. References: - typeshed issue: python/typeshed#10722 - typeshed PR: python/typeshed#10724 - setuptools docs: https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#python-requirement
|
Oh, shoot, I just caused you merge conflicts with #10714 -- sorry :( I was planning on merging this first and then fixing the conflicts in my PR, but I forgot :( |
No problem, I fixed them. I removed the |
|
@AlexWaygood WDYT about this patch? diff --git a/tests/parse_metadata.py b/tests/parse_metadata.py
index dfb266ad0..9977db339 100644
--- a/tests/parse_metadata.py
+++ b/tests/parse_metadata.py
@@ -7,7 +7,7 @@ from __future__ import annotations
import os
import re
import urllib.parse
-from collections.abc import Mapping
+from collections.abc import Callable, Mapping
from dataclasses import dataclass
from pathlib import Path
from typing import NamedTuple
@@ -18,7 +18,7 @@ from packaging.requirements import Requirement
from packaging.specifiers import Specifier
from packaging.version import Version
-from utils import cache
+from utils import PYTHON_VERSION, cache, colored
__all__ = [
"NoSuchStubError",
@@ -129,6 +129,7 @@ class StubMetadata:
Don't construct instances directly; use the `read_metadata` function.
"""
+ name: str
version: str
requires: Annotated[list[str], "The raw requirements as listed in METADATA.toml"]
extra_description: str | None
@@ -141,6 +142,21 @@ class StubMetadata:
stubtest_settings: StubtestSettings
requires_python: Annotated[Specifier, "Versions of Python supported by the stub package"]
+ def skip_test(self, version: str | None = None, printer: Callable[[str], object] = print) -> bool:
+ """Return True if the stub should be skipped.
+
+ If version is None, the runtime Python version is used.
+ """
+ if self.requires_python.contains(version if version is not None else PYTHON_VERSION):
+ return False
+ msg = f"skipping {self.name!r} "
+ if version is not None:
+ msg += f"for target Python {version} (requires Python {self.requires_python})"
+ else:
+ msg += f"(requires Python {self.requires_python}; test is being run using Python {PYTHON_VERSION})"
+ printer(colored(msg, "yellow"))
+ return True
+
_KNOWN_METADATA_FIELDS: Final = frozenset(
{
@@ -277,6 +293,7 @@ def read_metadata(distribution: str) -> StubMetadata:
assert key in tk, f"Unrecognised {tool} key {key!r} for {distribution!r}"
return StubMetadata(
+ name=distribution,
version=version,
requires=requires,
extra_description=extra_description,since we are doing this check in a lot of places. Then we can simply do: if metadata.skip_test():
continueto check against runtime Python version or if metadata.skip_test(version):
continueto check against target version from the command line |
Hmm, not sure -- I think I prefer it as you currently have it. That patch leads to more shared code, it's true, but it feels strange to me to be printing stuff to the terminal from I wouldn't be opposed to adding a little helper method, though, e.g. class StubMetadata:
def should_skip_tests(py_version: str) -> bool:
return self.requires_python.contains(version) |
|
It is strange hence my question :D |
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
There was a problem hiding this comment.
Other than #10724 (comment), this now looks great. Thanks for persevering with this, there was a lot to think through here!
|
@srittau, did you want to take a quick look, or are you okay with me merging this? |
|
I haven't had time to look at it, but I don't need to. Please merge if you are confident. |
|
Thanks again @hamdanal! :D |
|
Thank you Alex, as always, you've been very helpful :) |
|
Thanks! My only issue, is that it's not documented in https://github.com/python/typeshed/blob/main/CONTRIBUTING.md#the-metadatatoml-file ! |
A very good point, that I completely missed! |
Added it to the to-do list in #10722 (comment) |
The typeshed part of #10722
This PR implements the following:
requires_pythonfield in the third party stubsstub-uploader still needs to learn about this field and include it in the
setup.pyfile of the corresponding package with a fallback to the minimal version supported by typeshed.