Skip to content
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

Re-enable ANN2 for setuptools #4709

Merged
merged 1 commit into from
Oct 31, 2024
Merged

Re-enable ANN2 for setuptools #4709

merged 1 commit into from
Oct 31, 2024

Conversation

Avasam
Copy link
Contributor

@Avasam Avasam commented Oct 28, 2024

Summary of changes

Follow-up to #4504, works towards #2345
I didn't include long/complex overloads in this PR, that may come later

This has some overlap with #4711, but they can be merged in either order.

Pull Request Checklist

  • Changes have tests (existing type-checking and runtime tests)
  • News fragment added in newsfragments/. (no public facing changes)
    (See documentation for details)

@@ -226,7 +226,7 @@ def reinitialize_command(
) -> _Command:
cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
vars(cmd).update(kw)
return cmd
return cmd # pyright: ignore[reportReturnType] # pypa/distutils#307
Copy link
Contributor Author

Choose a reason for hiding this comment

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

outfile = str(Path(outfile).resolve())
return super().copy_file(
outfile = str(Path(outfile).resolve()) # type: ignore[assignment] # Re-assigning a str when outfile is StrPath is ok
return super().copy_file( # pyright: ignore[reportReturnType] # pypa/distutils#309
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines -141 to +166
def has_magic(s):
def has_magic(s: str | bytes) -> bool:
if isinstance(s, bytes):
match = magic_check_bytes.search(s)
return magic_check_bytes.search(s) is not None
else:
match = magic_check.search(s)
return match is not None
return magic_check.search(s) is not None
Copy link
Contributor Author

Choose a reason for hiding this comment

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

mypy will declare the first match as typed Math[bytes] | None, so the second assignement doesn't respect that typing, this is the same issue as python/mypy#10736 AFAICT

Either the variable needs to be explicitely typed as Match[bytes] | Match[str] | None, or we simply don't assign.

Comment on lines 54 to 57
def get_version(self, paths=None, default: str = "unknown"):
def get_version(
self, paths=None, default: str | int = "unknown"
) -> str | int | None:
Copy link
Contributor Author

@Avasam Avasam Oct 28, 2024

Choose a reason for hiding this comment

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

get_version, get_module_constant, and extract_constant can return Any (because of getattr on _imp.get_module and code.co_consts is typed as tuple[Any, ...]), but I'm not sure that's within intended usage ? Should that maybe be runtime validated ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this module is a bit annoying...

It looks very "vestigial", not very used in the setuptools code-base itself. But is exported as part of the API.

get_module_constant and extract_constant seem to be very likely returning something compatible with the return values of ast.parse_literal and possibly other objects that can be disassembled directly from Python bytecode. But I guess Any is the best thing we can do about that.

get_version is returning None | Literal["default"] | T if self.format is defined as Callable[..., T] or Any otherwise. But I don't think it is worth to add any form of validation here, we want to avoid breaking this API (potentially it is a good candidate for deprecation or moving to a different 3rd-party package).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok so essentially Any, but I changed it to at least give some hints.

@@ -455,7 +455,7 @@ def make_zipfile(
"""
import zipfile

mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
mkpath(os.path.dirname(zip_filename), dry_run=dry_run) # type: ignore[arg-type] # python/mypy#18075
Copy link
Contributor Author

Choose a reason for hiding this comment

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

# Overwrite base class to allow using links
if link:
infile = str(Path(infile).resolve())
outfile = str(Path(outfile).resolve())
return super().copy_file(
outfile = str(Path(outfile).resolve()) # type: ignore[assignment] # Re-assigning a str when outfile is StrPath is ok
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This may or may not also be related to python/mypy#18075

setuptools/_path.py Outdated Show resolved Hide resolved
Comment on lines 54 to 57
def get_version(self, paths=None, default: str = "unknown"):
def get_version(
self, paths=None, default: str | int = "unknown"
) -> str | int | None:
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this module is a bit annoying...

It looks very "vestigial", not very used in the setuptools code-base itself. But is exported as part of the API.

get_module_constant and extract_constant seem to be very likely returning something compatible with the return values of ast.parse_literal and possibly other objects that can be disassembled directly from Python bytecode. But I guess Any is the best thing we can do about that.

get_version is returning None | Literal["default"] | T if self.format is defined as Callable[..., T] or Any otherwise. But I don't think it is worth to add any form of validation here, we want to avoid breaking this API (potentially it is a good candidate for deprecation or moving to a different 3rd-party package).

@@ -52,6 +51,9 @@
if TYPE_CHECKING:
from typing_extensions import TypeAlias

from pkg_resources import Distribution as _pkg_resources_Distribution
Copy link
Contributor

Choose a reason for hiding this comment

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

It is good this is inside a if TYPE_CHECKING block. Thank you!

Ideally we want to avoid importing pkg_resources in runtime because of the performance hit.

It is only acceptable to "lazily" import pkg_resources on deprecated code paths (but never eagerly).

@abravalheri abravalheri merged commit 39179c1 into pypa:main Oct 31, 2024
24 checks passed
@abravalheri
Copy link
Contributor

I don't know if it was a false negative but apparently after merging this in top of the previous merges we have a mypy error:

image
https://github.com/pypa/setuptools/actions/runs/11617414532/job/32352587471#step:9:71

Maybe there is a new version of mypy?

@Avasam, do you have any info?

@Avasam
Copy link
Contributor Author

Avasam commented Oct 31, 2024

I don't know if it was a false negative but apparently after merging this in top of the previous merges we have a mypy error:

[…]

@Avasam, do you have any info?

I can take a look at it tomorrow. I'm omw to a Halloween party 🎃

If needed for other PRs you can suppress the error temporarily (or suppress for entire file if it only happens on one side of the 3.12 distutils boundary)

It's possible that two PRs individually didn't trigger new errors, but together do. And it wouldn't be caught by CI if the branches weren't updated (and there was no conflict forcing an update)

@Avasam Avasam deleted the ANN2-autofixes branch October 31, 2024 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants