-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Add optional requires_python to third party stubs metadata #10724
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
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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/requests
python tests/mypy_test.py stubs/requests*
# multiple packages togetherpython tests/mypy_test.py stubs/requests -p 3.8 3.9 3.10 3.11
python 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.11
python 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():
continue to check against runtime Python version or if metadata.skip_test(version):
continue to 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_python
field in the third party stubsstub-uploader still needs to learn about this field and include it in the
setup.py
file of the corresponding package with a fallback to the minimal version supported by typeshed.