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

Disallow blanket and unused suppressions #4526

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
1 change: 0 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations


extensions = [
'sphinx.ext.autodoc',
'jaraco.packaging.sphinx',
Expand Down
20 changes: 15 additions & 5 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
[mypy]
# CI should test for all versions, local development gets hints for oldest supported
# But our testing setup doesn't allow passing CLI arguments, so local devs have to set this manually.
# python_version = 3.8
## upstream

# Is the project well-typed?
strict = False

# Early opt-in even when strict = False
warn_unused_ignores = True
warn_redundant_casts = True
# required to support namespace packages: https://github.com/python/mypy/issues/14057
enable_error_code = ignore-without-code

# Support namespace packages per https://github.com/python/mypy/issues/14057
explicit_package_bases = True

disable_error_code =
# Disable due to many false positives
overload-overlap,

## local

# CI should test for all versions, local development gets hints for oldest supported
# But our testing setup doesn't allow passing CLI arguments, so local devs have to set this manually.
# python_version = 3.8

exclude = (?x)(
# Avoid scanning Python files in generated folders
^build/
Expand Down Expand Up @@ -54,6 +64,6 @@ ignore_missing_imports = True

# Even when excluding a module, import issues can show up due to following import
# https://github.com/python/mypy/issues/11936#issuecomment-1466764006
[mypy-setuptools.config._validate_pyproject.*,setuptools._distutils.*]
[mypy-setuptools.config._validate_pyproject.*,setuptools._vendor.*,setuptools._distutils.*]
follow_imports = silent
# silent => ignore errors when following imports
2 changes: 1 addition & 1 deletion pkg_resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2777,7 +2777,7 @@ def load(
if require:
# We could pass `env` and `installer` directly,
# but keeping `*args` and `**kwargs` for backwards compatibility
self.require(*args, **kwargs) # type: ignore
self.require(*args, **kwargs) # type: ignore[arg-type]
return self.resolve()

def resolve(self) -> _ResolvedEntryPoint:
Expand Down
4 changes: 0 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,3 @@ formats = "zip"


[tool.setuptools_scm]


[tool.pytest-enabler.mypy]
# Disabled due to jaraco/skeleton#143
6 changes: 4 additions & 2 deletions ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ extend-select = [

# local
"ANN2", # missing-return-type-*
"FA", # flake8-future-annotations
"F404", # late-future-import
"FA", # flake8-future-annotations
"I", # isort
"PGH", # pygrep-hooks (blanket-* rules)
"PYI", # flake8-pyi
"RUF10", # unused-noqa & redirected-noqa
"TRY", # tryceratops
"UP", # pyupgrade
"TRY",
"YTT", # flake8-2020
]
ignore = [
Expand Down
2 changes: 1 addition & 1 deletion setuptools/_distutils/compat/py38.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def removeprefix(self, prefix):

def aix_platform(osname, version, release):
try:
import _aix_support # type: ignore
import _aix_support

return _aix_support.aix_platform()
except ImportError:
Expand Down
16 changes: 10 additions & 6 deletions setuptools/config/expand.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
from ..discovery import find_package_path
from ..warnings import SetuptoolsWarning

from distutils.errors import DistutilsOptionError

Check warning on line 40 in setuptools/config/expand.py

View workflow job for this annotation

GitHub Actions / pyright (3.12, ubuntu-latest)

Import "distutils.errors" could not be resolved from source (reportMissingModuleSource)

if TYPE_CHECKING:
from typing_extensions import Self
Expand All @@ -54,7 +54,7 @@
def __init__(self, name: str, spec: ModuleSpec):
module = ast.parse(pathlib.Path(spec.origin).read_bytes()) # type: ignore[arg-type] # Let it raise an error on None
vars(self).update(locals())
del self.self

Check warning on line 57 in setuptools/config/expand.py

View workflow job for this annotation

GitHub Actions / pyright (3.8, ubuntu-latest)

Cannot delete attribute "self" for class "StaticModule*"   Attribute "self" is unknown (reportAttributeAccessIssue)

Check warning on line 57 in setuptools/config/expand.py

View workflow job for this annotation

GitHub Actions / pyright (3.12, ubuntu-latest)

Cannot delete attribute "self" for class "StaticModule*"   Attribute "self" is unknown (reportAttributeAccessIssue)

def _find_assignments(self) -> Iterator[tuple[ast.AST, ast.AST]]:
for statement in self.module.body:
Expand Down Expand Up @@ -188,7 +188,7 @@


def _find_spec(module_name: str, module_path: StrPath | None) -> ModuleSpec:
spec = importlib.util.spec_from_file_location(module_name, module_path)

Check warning on line 191 in setuptools/config/expand.py

View workflow job for this annotation

GitHub Actions / pyright (3.12, ubuntu-latest)

"util" is not a known attribute of module "importlib" (reportAttributeAccessIssue)
spec = spec or importlib.util.find_spec(module_name)

if spec is None:
Expand All @@ -203,7 +203,8 @@
return sys.modules[name]
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module # cache (it also ensures `==` works on loaded items)
spec.loader.exec_module(module) # type: ignore
assert spec.loader is not None
spec.loader.exec_module(module)
return module


Expand Down Expand Up @@ -285,10 +286,10 @@

from setuptools.discovery import construct_package_dir

if namespaces:
from setuptools.discovery import PEP420PackageFinder as PackageFinder
if not namespaces:
from setuptools.discovery import PackageFinder
else:
from setuptools.discovery import PackageFinder # type: ignore
from setuptools.discovery import PEP420PackageFinder as PackageFinder
Comment on lines +289 to +292
Copy link
Contributor Author

Choose a reason for hiding this comment

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


root_dir = root_dir or os.curdir
where = kwargs.pop('where', ['.'])
Expand Down Expand Up @@ -352,14 +353,17 @@
]


def entry_points(text: str, text_source="entry-points") -> dict[str, dict]:
def entry_points(
text: str, text_source: str = "entry-points"
) -> dict[str, dict[str, str]]:
"""Given the contents of entry-points file,
process it into a 2-level dictionary (``dict[str, dict[str, str]]``).
The first level keys are entry-point groups, the second level keys are
entry-point names, and the second level values are references to objects
(that correspond to the entry-point value).
"""
parser = ConfigParser(default_section=None, delimiters=("=",)) # type: ignore
# TODO: Explain why passing None is fine here when ConfigParser.default_section expects to be str
parser = ConfigParser(default_section=None, delimiters=("=",)) # type: ignore[call-overload]
parser.optionxform = str # case sensitive
parser.read_string(text, text_source)
groups = {k: dict(v.items()) for k, v in parser.items()}
Expand Down
9 changes: 5 additions & 4 deletions setuptools/config/pyprojecttoml.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ def validate(config: dict, filepath: StrPath) -> bool:

trove_classifier = validator.FORMAT_FUNCTIONS.get("trove-classifier")
if hasattr(trove_classifier, "_disable_download"):
# Improve reproducibility by default. See issue 31 for validate-pyproject.
trove_classifier._disable_download() # type: ignore
# Improve reproducibility by default. See https://github.com/abravalheri/validate-pyproject/issues/31
trove_classifier._disable_download() # type: ignore[union-attr]

try:
return validator.validate(config)
Expand Down Expand Up @@ -327,7 +327,7 @@ def _obtain_readme(self, dist: Distribution) -> dict[str, str] | None:

def _obtain_entry_points(
self, dist: Distribution, package_dir: Mapping[str, str]
) -> dict[str, dict] | None:
) -> dict[str, dict[str, Any]] | None:
fields = ("entry-points", "scripts", "gui-scripts")
if not any(field in self.dynamic for field in fields):
return None
Expand All @@ -337,7 +337,8 @@ def _obtain_entry_points(
return None

groups = _expand.entry_points(text)
expanded = {"entry-points": groups}
# Any is str | dict[str, str], but causes variance issues
expanded: dict[str, dict[str, Any]] = {"entry-points": groups}

def _set_scripts(field: str, group: str):
if group in groups:
Expand Down
17 changes: 10 additions & 7 deletions setuptools/config/setupcfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
List,
Tuple,
TypeVar,
Union,
cast,
)

Expand All @@ -53,7 +52,7 @@
while the second element of the tuple is the option value itself
"""
AllCommandOptions = Dict["str", SingleCommandOptions] # cmd name => its options
Target = TypeVar("Target", bound=Union["Distribution", "DistributionMetadata"])
Target = TypeVar("Target", "Distribution", "DistributionMetadata")


def read_configuration(
Expand Down Expand Up @@ -96,7 +95,7 @@ def _apply(
filepath: StrPath,
other_files: Iterable[StrPath] = (),
ignore_option_errors: bool = False,
) -> tuple[ConfigHandler, ...]:
) -> tuple[ConfigMetadataHandler, ConfigOptionsHandler]:
"""Read configuration from ``filepath`` and applies to the ``dist`` object."""
from setuptools.dist import _Distribution

Expand All @@ -122,7 +121,7 @@ def _apply(
return handlers


def _get_option(target_obj: Target, key: str):
def _get_option(target_obj: Distribution | DistributionMetadata, key: str):
"""
Given a target object and option key, get that option from
the target object, either through a get_{key} method or
Expand All @@ -134,10 +133,14 @@ def _get_option(target_obj: Target, key: str):
return getter()


def configuration_to_dict(handlers: tuple[ConfigHandler, ...]) -> dict:
def configuration_to_dict(
handlers: Iterable[
ConfigHandler[Distribution] | ConfigHandler[DistributionMetadata]
],
) -> dict:
"""Returns configuration data gathered by given handlers as a dict.

:param list[ConfigHandler] handlers: Handlers list,
:param Iterable[ConfigHandler] handlers: Handlers list,
usually from parse_configuration()

:rtype: dict
Expand Down Expand Up @@ -254,7 +257,7 @@ def __init__(
ensure_discovered: expand.EnsurePackagesDiscovered,
):
self.ignore_option_errors = ignore_option_errors
self.target_obj = target_obj
self.target_obj: Target = target_obj
self.sections = dict(self._section_options(options))
self.set_options: list[str] = []
self.ensure_discovered = ensure_discovered
Expand Down
2 changes: 1 addition & 1 deletion setuptools/tests/config/test_apply_pyprojecttoml.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from ini2toml.api import LiteTranslator
from packaging.metadata import Metadata

import setuptools # noqa ensure monkey patch to metadata
import setuptools # noqa: F401 # ensure monkey patch to metadata
from setuptools.command.egg_info import write_requirements
from setuptools.config import expand, pyprojecttoml, setupcfg
from setuptools.config._apply_pyprojecttoml import _MissingDynamic, _some_attrgetter
Expand Down
4 changes: 2 additions & 2 deletions setuptools/tests/config/test_setupcfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import pytest
from packaging.requirements import InvalidRequirement

from setuptools.config.setupcfg import ConfigHandler, read_configuration
from setuptools.config.setupcfg import ConfigHandler, Target, read_configuration
from setuptools.dist import Distribution, _Distribution
from setuptools.warnings import SetuptoolsDeprecationWarning

Expand All @@ -16,7 +16,7 @@
from distutils.errors import DistutilsFileError, DistutilsOptionError


class ErrConfigHandler(ConfigHandler):
class ErrConfigHandler(ConfigHandler[Target]):
"""Erroneous handler. Fails to implement required methods."""

section_prefix = "**err**"
Expand Down
2 changes: 1 addition & 1 deletion setuptools/tests/test_build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def get_build_ext_cmd(self, optional: bool, **opts):
"eggs.c": "#include missingheader.h\n",
".build": {"lib": {}, "tmp": {}},
}
path.build(files) # type: ignore[arg-type] # jaraco/path#232
path.build(files) # jaraco/path#232
extension = Extension('spam.eggs', ['eggs.c'], optional=optional)
dist = Distribution(dict(ext_modules=[extension]))
dist.script_name = 'setup.py'
Expand Down
8 changes: 4 additions & 4 deletions setuptools/tests/test_editable_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -878,18 +878,18 @@ class TestOverallBehaviour:
"otherfile.py": "",
"mypkg": {
"__init__.py": "",
"mod1.py": FLAT_LAYOUT["mypkg"]["mod1.py"], # type: ignore
"mod1.py": FLAT_LAYOUT["mypkg"]["mod1.py"], # type: ignore[index]
},
"other": FLAT_LAYOUT["mypkg"]["subpackage"], # type: ignore
"other": FLAT_LAYOUT["mypkg"]["subpackage"], # type: ignore[index]
},
"namespace": {
"pyproject.toml": dedent(PYPROJECT),
"MANIFEST.in": EXAMPLE["MANIFEST.in"],
"otherfile.py": "",
"src": {
"mypkg": {
"mod1.py": FLAT_LAYOUT["mypkg"]["mod1.py"], # type: ignore
"subpackage": FLAT_LAYOUT["mypkg"]["subpackage"], # type: ignore
"mod1.py": FLAT_LAYOUT["mypkg"]["mod1.py"], # type: ignore[index]
"subpackage": FLAT_LAYOUT["mypkg"]["subpackage"], # type: ignore[index]
},
},
},
Expand Down
Loading