Commit 48171301 by David Hotham Committed by GitHub

enable strictness flags for mypy (#5531)

* enable strict mypy checking
* treat poetry.core as untyped
* python 3.7 typechecking
parent c0771f13
......@@ -5,9 +5,6 @@ ban-relative-imports = true
# flake8-use-fstring: https://github.com/MichaelKim0407/flake8-use-fstring#--percent-greedy-and---format-greedy
format-greedy = 1
inline-quotes = double
# Allow omission of a return type hint for __init__ if at least one argument is annotated
# used by flake8-annotations
mypy-init-return = true
enable-extensions = TC, TC1
type-checking-exempt-modules = typing, typing-extensions
eradicate-whitelist-extend = ^-.*;
......
......@@ -103,13 +103,9 @@ force-exclude = '''
[tool.mypy]
check_untyped_defs = true
ignore_missing_imports = true
show_error_codes = true
warn_redundant_casts = true
warn_unused_configs = true
warn_unused_ignores = true
files = "src"
show_error_codes = true
strict = true
# The following whitelist is used to allow for incremental adoption
# of Mypy. Modules should be removed from this whitelist as and when
......@@ -131,6 +127,21 @@ module = [
]
ignore_errors = true
[[tool.mypy.overrides]]
module = [
'cachecontrol.*',
'cachy.*',
'cleo.*',
'crashtest.*',
'entrypoints.*',
'html5lib.*',
'jsonschema.*',
'pexpect.*',
'poetry.core.*',
'requests_toolbelt.*',
'shellingham.*',
]
ignore_missing_imports = true
[tool.coverage.report]
exclude_lines = [
......
from __future__ import annotations
from typing import Callable
from poetry.utils._compat import metadata
__version__ = metadata.version("poetry")
# The metadata.version that we import for Python 3.7 is untyped, work around
# that.
version: Callable[[str], str] = metadata.version
__version__ = version("poetry")
......@@ -63,7 +63,7 @@ class Config:
self._auth_config_source: ConfigSource = DictConfigSource()
@property
def config(self) -> dict:
def config(self) -> dict[str, Any]:
return self._config
@property
......@@ -90,7 +90,7 @@ class Config:
merge_dicts(self._config, config)
def all(self) -> dict[str, Any]:
def _all(config: dict, parent_key: str = "") -> dict:
def _all(config: dict[str, Any], parent_key: str = "") -> dict[str, Any]:
all_ = {}
for key in config:
......@@ -159,10 +159,14 @@ class Config:
if not isinstance(value, str):
return value
return re.sub(r"{(.+?)}", lambda m: self.get(m.group(1)), value)
return re.sub(
r"{(.+?)}",
lambda m: self.get(m.group(1)), # type: ignore[no-any-return]
value,
)
@staticmethod
def _get_normalizer(name: str) -> Callable:
def _get_normalizer(name: str) -> Callable[[str], Any]:
if name in {
"virtualenvs.create",
"virtualenvs.in-project",
......
......@@ -37,12 +37,13 @@ if TYPE_CHECKING:
from poetry.poetry import Poetry
def load_command(name: str) -> Callable:
def load_command(name: str) -> Callable[[], type[Command]]:
def _load() -> type[Command]:
words = name.split(" ")
module = import_module("poetry.console.commands." + ".".join(words))
command_class = getattr(module, "".join(c.title() for c in words) + "Command")
return command_class()
command_type: type[Command] = command_class()
return command_type
return _load
......@@ -89,7 +90,7 @@ COMMANDS = [
]
class Application(BaseApplication):
class Application(BaseApplication): # type: ignore[misc]
def __init__(self) -> None:
super().__init__("poetry", __version__)
......@@ -128,7 +129,8 @@ class Application(BaseApplication):
@property
def command_loader(self) -> CommandLoader:
return self._command_loader
command_loader: CommandLoader = self._command_loader
return command_loader
def reset_poetry(self) -> None:
self._poetry = None
......@@ -176,7 +178,8 @@ class Application(BaseApplication):
self._load_plugins(io)
return super()._run(io)
exit_code: int = super()._run(io)
return exit_code
def _configure_io(self, io: IO) -> None:
# We need to check if the command being run
......@@ -212,7 +215,7 @@ class Application(BaseApplication):
io.set_input(run_input)
return super()._configure_io(io)
super()._configure_io(io)
def register_command_loggers(
self, event: ConsoleCommandEvent, event_name: str, _: Any
......@@ -376,7 +379,8 @@ class Application(BaseApplication):
def main() -> int:
return Application().run()
exit_code: int = Application().run()
return exit_code
if __name__ == "__main__":
......
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import Callable
from cleo.exceptions import LogicException
from cleo.loaders.factory_command_loader import FactoryCommandLoader
class CommandLoader(FactoryCommandLoader):
def register_factory(self, command_name: str, factory: Callable) -> None:
if TYPE_CHECKING:
from poetry.console.commands.command import Command
class CommandLoader(FactoryCommandLoader): # type: ignore[misc]
def register_factory(
self, command_name: str, factory: Callable[[], Command]
) -> None:
if command_name in self._factories:
raise LogicException(f'The command "{command_name}" already exists.')
......
from __future__ import annotations
from typing import Callable
from poetry.console.commands.command import Command
......@@ -12,12 +14,16 @@ class AboutCommand(Command):
def handle(self) -> None:
from poetry.utils._compat import metadata
# The metadata.version that we import for Python 3.7 is untyped, work around
# that.
version: Callable[[str], str] = metadata.version
self.line(
f"""\
<info>Poetry - Package Management for Python
Version: {metadata.version('poetry')}
Poetry-Core Version: {metadata.version('poetry-core')}</info>
Version: {version('poetry')}
Poetry-Core Version: {version('poetry-core')}</info>
<comment>Poetry is a dependency manager tracking local dependencies of your projects\
and libraries.
......
......@@ -262,7 +262,7 @@ You can specify a package in the following forms:
return status
def get_existing_packages_from_input(
self, packages: list[str], section: dict
self, packages: list[str], section: dict[str, Any]
) -> list[str]:
existing_packages = []
......
......@@ -12,7 +12,7 @@ if TYPE_CHECKING:
from poetry.poetry import Poetry
class Command(BaseCommand):
class Command(BaseCommand): # type: ignore[misc]
loggers: list[str] = []
_poetry: Poetry | None = None
......@@ -28,7 +28,8 @@ class Command(BaseCommand):
self._poetry = poetry
def get_application(self) -> Application:
return self.application
application: Application = self.application
return application
def reset_poetry(self) -> None:
self.get_application().reset_poetry()
......
......@@ -318,7 +318,8 @@ To remove a repository (repo is a short alias for repositories):
if isinstance(value, dict):
k += f"{key}."
self._list_configuration(value, cast(dict, raw_val), k=k)
raw_val = cast("dict[str, Any]", raw_val)
self._list_configuration(value, raw_val, k=k)
k = orig_k
continue
......@@ -338,50 +339,3 @@ To remove a repository (repo is a short alias for repositories):
message = f"<c1>{k + key}</c1> = <c2>{json.dumps(value)}</c2>"
self.line(message)
def _get_setting(
self,
contents: dict,
setting: str | None = None,
k: str | None = None,
default: Any | None = None,
) -> list[tuple[str, str]]:
orig_k = k
if setting and setting.split(".")[0] not in contents:
value = json.dumps(default)
return [((k or "") + setting, value)]
else:
values = []
for key, value in contents.items():
if setting and key != setting.split(".")[0]:
continue
if isinstance(value, dict) or key == "repositories" and k is None:
if k is None:
k = ""
k += re.sub(r"^config\.", "", key + ".")
if setting and len(setting) > 1:
setting = ".".join(setting.split(".")[1:])
values += self._get_setting(
cast(dict, value), k=k, setting=setting, default=default
)
k = orig_k
continue
if isinstance(value, list):
value = ", ".join(
json.dumps(val) if isinstance(val, list) else val
for val in value
)
value = f"[{value}]"
value = json.dumps(value)
values.append(((k or "") + key, value))
return values
......@@ -25,4 +25,5 @@ class DebugInfoCommand(Command):
)
command = self.application.get("env info")
return command.run(self._io)
exit_code: int = command.run(self._io)
return exit_code
......@@ -41,7 +41,7 @@ class DebugResolveCommand(InitCommand):
from poetry.core.packages.project_package import ProjectPackage
from poetry.factory import Factory
from poetry.puzzle import Solver
from poetry.puzzle.solver import Solver
from poetry.repositories.pool import Pool
from poetry.repositories.repository import Repository
from poetry.utils.env import EnvManager
......
......@@ -73,7 +73,7 @@ dependencies and not including the current project, run the command with the
def handle(self) -> int:
from poetry.core.masonry.utils.module import ModuleOrPackageNotFound
from poetry.masonry.builders import EditableBuilder
from poetry.masonry.builders.editable import EditableBuilder
self._installer.use_executor(
self.poetry.config.get("experimental.new-installer", False)
......
......@@ -170,16 +170,17 @@ You can specify a package in the following forms:
if self.option("dry-run"):
argv.append("--dry-run")
return update_command.run(
exit_code: int = update_command.run(
IO(
StringInput(" ".join(argv)),
self._io.output,
self._io.error_output,
)
)
return exit_code
def get_existing_packages_from_input(
self, packages: list[str], poetry_content: dict, target_section: str
self, packages: list[str], poetry_content: dict[str, Any], target_section: str
) -> list[str]:
existing_packages = []
......
......@@ -59,10 +59,11 @@ class PluginRemoveCommand(Command):
if self.option("dry-run"):
argv.append("--dry-run")
return remove_command.run(
exit_code: int = remove_command.run(
IO(
StringInput(" ".join(argv)),
self._io.output,
self._io.error_output,
)
)
return exit_code
......@@ -298,7 +298,10 @@ lists all packages available."""
io.write_line(f" <b>{package.pretty_version}</b>{description}")
dependencies = package.requires
dependencies = sorted(dependencies, key=lambda x: x.name)
dependencies = sorted(
dependencies,
key=lambda x: x.name, # type: ignore[no-any-return]
)
tree_bar = "├"
total = len(dependencies)
for i, dependency in enumerate(dependencies, 1):
......@@ -338,7 +341,10 @@ lists all packages available."""
break
dependencies = sorted(dependencies, key=lambda x: x.name)
dependencies = sorted(
dependencies,
key=lambda x: x.name, # type: ignore[no-any-return]
)
tree_bar = previous_tree_bar + " ├"
total = len(dependencies)
for i, dependency in enumerate(dependencies, 1):
......
......@@ -3,6 +3,6 @@ from __future__ import annotations
from cleo.exceptions import CleoSimpleException
class PoetrySimpleConsoleException(CleoSimpleException):
class PoetrySimpleConsoleException(CleoSimpleException): # type: ignore[misc]
pass
......@@ -9,7 +9,7 @@ if TYPE_CHECKING:
from cleo.io.inputs.definition import Definition
class RunArgvInput(ArgvInput):
class RunArgvInput(ArgvInput): # type: ignore[misc]
def __init__(
self,
argv: list[str] | None = None,
......
......@@ -43,7 +43,7 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
class Factory(BaseFactory):
class Factory(BaseFactory): # type: ignore[misc]
"""
Factory class to create various elements needed by Poetry.
"""
......
......@@ -71,7 +71,7 @@ class PackageInfo:
requires_python: str | None = None,
files: list[dict[str, str]] | None = None,
cache_version: str | None = None,
):
) -> None:
self.name = name
self.version = version
self.summary = summary
......
......@@ -41,7 +41,7 @@ class Installer:
config: Config,
installed: Repository | None = None,
executor: Executor | None = None,
):
) -> None:
self._io = io
self._env = env
self._package = package
......
......@@ -43,7 +43,8 @@ class Operation:
raise NotImplementedError()
def format_version(self, package: Package) -> str:
return package.full_pretty_version
version: str = package.full_pretty_version
return version
def skip(self: T, reason: str) -> T:
self._skipped = True
......
......@@ -3,6 +3,8 @@ from __future__ import annotations
import json
import os
from typing import Any
import jsonschema
......@@ -14,7 +16,7 @@ class ValidationError(ValueError):
pass
def validate_object(obj: dict, schema_name: str) -> list[str]:
def validate_object(obj: dict[str, Any], schema_name: str) -> list[str]:
schema = os.path.join(SCHEMA_DIR, f"{schema_name}.json")
if not os.path.exists(schema):
......@@ -24,7 +26,10 @@ def validate_object(obj: dict, schema_name: str) -> list[str]:
schema = json.loads(f.read())
validator = jsonschema.Draft7Validator(schema)
validation_errors = sorted(validator.iter_errors(obj), key=lambda e: e.path)
validation_errors = sorted(
validator.iter_errors(obj),
key=lambda e: e.path, # type: ignore[no-any-return]
)
errors = []
......
......@@ -52,7 +52,7 @@ class Layout:
python: str = "*",
dependencies: dict[str, str] | None = None,
dev_dependencies: dict[str, str] | None = None,
):
) -> None:
self._project = canonicalize_name(project).replace(".", "-")
self._package_path_relative = Path(
*(module_name(part) for part in canonicalize_name(project).split("."))
......@@ -91,10 +91,13 @@ class Layout:
package = inline_table()
include = self._package_path_relative.parts[0]
package.append("include", include)
package.append("include", include) # type: ignore[no-untyped-call]
if self.basedir != Path():
package.append("from", self.basedir.as_posix())
package.append( # type: ignore[no-untyped-call]
"from",
self.basedir.as_posix(),
)
else:
if include == self._project:
# package include and package name are the same,
......
......@@ -39,7 +39,7 @@ WINDOWS_CMD_TEMPLATE = """\
"""
class EditableBuilder(Builder):
class EditableBuilder(Builder): # type: ignore[misc]
def __init__(self, poetry: Poetry, env: Env, io: IO) -> None:
super().__init__(poetry)
......
......@@ -63,7 +63,7 @@ class _Writer:
buffer.append("")
if isinstance(self._root.cause, ConflictCause):
self._visit(self._root, {})
self._visit(self._root)
else:
self._write(self._root, f"Because {self._root}, version solving failed.")
......@@ -108,7 +108,6 @@ class _Writer:
def _visit(
self,
incompatibility: Incompatibility,
details_for_incompatibility: dict,
conclusion: bool = False,
) -> None:
numbered = conclusion or self._derivations[incompatibility] > 1
......@@ -117,7 +116,6 @@ class _Writer:
cause: ConflictCause = cast(ConflictCause, incompatibility.cause)
details_for_cause: dict = {}
if isinstance(cause.conflict.cause, ConflictCause) and isinstance(
cause.other.cause, ConflictCause
):
......@@ -126,7 +124,7 @@ class _Writer:
if conflict_line is not None and other_line is not None:
reason = cause.conflict.and_to_string(
cause.other, details_for_cause, conflict_line, other_line
cause.other, conflict_line, other_line
)
self._write(
incompatibility,
......@@ -143,7 +141,7 @@ class _Writer:
without_line = cause.conflict
line = other_line
self._visit(without_line, details_for_cause)
self._visit(without_line)
self._write(
incompatibility,
f"{conjunction} because {with_line!s} ({line}),"
......@@ -157,18 +155,18 @@ class _Writer:
if single_line_other or single_line_conflict:
first = cause.conflict if single_line_other else cause.other
second = cause.other if single_line_other else cause.conflict
self._visit(first, details_for_cause)
self._visit(second, details_for_cause)
self._visit(first)
self._visit(second)
self._write(
incompatibility,
f"Thus, {incompatibility_string}.",
numbered=numbered,
)
else:
self._visit(cause.conflict, {}, conclusion=True)
self._visit(cause.conflict, conclusion=True)
self._lines.append(("", None))
self._visit(cause.other, details_for_cause)
self._visit(cause.other)
self._write(
incompatibility,
......@@ -193,9 +191,7 @@ class _Writer:
derived_line = self._line_numbers.get(derived)
if derived_line is not None:
reason = ext.and_to_string(
derived, details_for_cause, None, derived_line
)
reason = ext.and_to_string(derived, None, derived_line)
self._write(
incompatibility,
f"Because {reason}, {incompatibility_string}.",
......@@ -211,26 +207,22 @@ class _Writer:
collapsed_ext = derived_cause.conflict
details_for_cause = {}
self._visit(collapsed_derived, details_for_cause)
reason = collapsed_ext.and_to_string(ext, details_for_cause, None, None)
self._visit(collapsed_derived)
reason = collapsed_ext.and_to_string(ext, None, None)
self._write(
incompatibility,
f"{conjunction} because {reason}, {incompatibility_string}.",
numbered=numbered,
)
else:
self._visit(derived, details_for_cause)
self._visit(derived)
self._write(
incompatibility,
f"{conjunction} because {ext!s}, {incompatibility_string}.",
numbered=numbered,
)
else:
reason = cause.conflict.and_to_string(
cause.other, details_for_cause, None, None
)
reason = cause.conflict.and_to_string(cause.other, None, None)
self._write(
incompatibility,
f"Because {reason}, {incompatibility_string}.",
......
......@@ -214,23 +214,18 @@ class Incompatibility:
def and_to_string(
self,
other: Incompatibility,
details: dict,
this_line: int | None,
other_line: int | None,
) -> str:
requires_both = self._try_requires_both(other, details, this_line, other_line)
requires_both = self._try_requires_both(other, this_line, other_line)
if requires_both is not None:
return requires_both
requires_through = self._try_requires_through(
other, details, this_line, other_line
)
requires_through = self._try_requires_through(other, this_line, other_line)
if requires_through is not None:
return requires_through
requires_forbidden = self._try_requires_forbidden(
other, details, this_line, other_line
)
requires_forbidden = self._try_requires_forbidden(other, this_line, other_line)
if requires_forbidden is not None:
return requires_forbidden
......@@ -248,7 +243,6 @@ class Incompatibility:
def _try_requires_both(
self,
other: Incompatibility,
details: dict,
this_line: int | None,
other_line: int | None,
) -> str | None:
......@@ -298,7 +292,6 @@ class Incompatibility:
def _try_requires_through(
self,
other: Incompatibility,
details: dict,
this_line: int | None,
other_line: int | None,
) -> str | None:
......@@ -380,7 +373,6 @@ class Incompatibility:
def _try_requires_forbidden(
self,
other: Incompatibility,
details: dict,
this_line: int | None,
other_line: int | None,
) -> str | None:
......@@ -442,7 +434,8 @@ class Incompatibility:
return f"every version of {term.dependency.complete_name}"
if term.dependency.is_root:
return term.dependency.pretty_name
pretty_name: str = term.dependency.pretty_name
return pretty_name
return f"{term.dependency.pretty_name} ({term.dependency.pretty_constraint})"
......
......@@ -13,7 +13,7 @@ if TYPE_CHECKING:
from poetry.puzzle.exceptions import SolverProblemError
class PythonRequirementSolutionProvider(HasSolutionsForException):
class PythonRequirementSolutionProvider(HasSolutionsForException): # type: ignore[misc]
def can_solve(self, exception: Exception) -> bool:
from poetry.puzzle.exceptions import SolverProblemError
......
......@@ -10,7 +10,7 @@ if TYPE_CHECKING:
from poetry.puzzle.exceptions import SolverProblemError
class PythonRequirementSolution(Solution):
class PythonRequirementSolution(Solution): # type: ignore[misc]
def __init__(self, exception: SolverProblemError) -> None:
from poetry.core.semver.helpers import parse_constraint
......
......@@ -152,11 +152,12 @@ class Term:
return self.intersect(other.inverse)
def _compatible_dependency(self, other: Dependency) -> bool:
return (
compatible: bool = (
self.dependency.is_root
or other.is_root
or other.is_same_package_as(self.dependency)
)
return compatible
def _non_empty_term(
self, constraint: VersionConstraint, is_positive: bool
......
......@@ -39,7 +39,7 @@ class DependencyCache:
again.
"""
def __init__(self, provider: Provider):
def __init__(self, provider: Provider) -> None:
self.provider = provider
self.cache: dict[str, list[DependencyPackage]] = {}
......@@ -75,7 +75,7 @@ class VersionSolver:
provider: Provider,
locked: dict[str, list[DependencyPackage]] | None = None,
use_latest: list[str] | None = None,
):
) -> None:
self._root = root
self._provider = provider
self._dependency_cache = DependencyCache(provider)
......@@ -212,7 +212,8 @@ class VersionSolver:
unsatisfied.dependency, not unsatisfied.is_positive(), incompatibility
)
return unsatisfied.dependency.complete_name
complete_name: str = unsatisfied.dependency.complete_name
return complete_name
def _resolve_conflict(self, incompatibility: Incompatibility) -> Incompatibility:
"""
......@@ -404,7 +405,8 @@ class VersionSolver:
self._add_incompatibility(
Incompatibility([Term(dependency, True)], PackageNotFoundCause(e))
)
return dependency.complete_name
complete_name: str = dependency.complete_name
return complete_name
package = None
if dependency.name not in self._use_latest:
......@@ -427,7 +429,8 @@ class VersionSolver:
Incompatibility([Term(dependency, True)], NoVersionsCause())
)
return dependency.complete_name
complete_name = dependency.complete_name
return complete_name
else:
package = locked
......@@ -454,7 +457,8 @@ class VersionSolver:
f"selecting {package.complete_name} ({package.full_pretty_version})"
)
return dependency.complete_name
complete_name = dependency.complete_name
return complete_name
def _result(self) -> SolverResult:
"""
......
......@@ -53,4 +53,5 @@ class DependencyPackage:
if isinstance(other, DependencyPackage):
other = other.package
return self._package == other
equal: bool = self._package == other
return equal
......@@ -31,9 +31,9 @@ from tomlkit import document
from tomlkit import inline_table
from tomlkit import item
from tomlkit import table
from tomlkit.container import Table
from tomlkit.exceptions import TOMLKitError
from tomlkit.items import Array
from tomlkit.items import Table
from poetry.packages import DependencyPackage
from poetry.utils.extras import get_extra_package_names
......@@ -55,7 +55,7 @@ class Locker:
_legacy_keys = ["dependencies", "source", "extras", "dev-dependencies"]
_relevant_keys = [*_legacy_keys, "group"]
def __init__(self, lock: str | Path, local_config: dict) -> None:
def __init__(self, lock: str | Path, local_config: dict[str, Any]) -> None:
self._lock = TOMLFile(lock)
self._local_config = local_config
self._lock_data: TOMLDocument | None = None
......@@ -89,7 +89,8 @@ class Locker:
metadata = lock.get("metadata", {})
if "content-hash" in metadata:
return self._content_hash == metadata["content-hash"]
fresh: bool = self._content_hash == metadata["content-hash"]
return fresh
return False
......@@ -306,7 +307,10 @@ class Locker:
# Put higher versions first so that we prefer them.
for packages in packages_by_name.values():
packages.sort(key=lambda package: package.version, reverse=True)
packages.sort(
key=lambda package: package.version, # type: ignore[no-any-return]
reverse=True,
)
nested_dependencies = cls.__walk_dependencies(
dependencies=project_requires,
......@@ -445,7 +449,7 @@ class Locker:
raise RuntimeError("No lockfile found. Unable to read locked packages")
try:
lock_data = self._lock.read()
lock_data: TOMLDocument = self._lock.read()
except TOMLKitError as e:
raise RuntimeError(f"Unable to read the lock file ({e}).")
......@@ -486,7 +490,10 @@ class Locker:
def _dump_package(self, package: Package) -> dict[str, Any]:
dependencies: dict[str, list[Any]] = {}
for dependency in sorted(package.requires, key=lambda d: d.name):
for dependency in sorted(
package.requires,
key=lambda d: d.name, # type: ignore[no-any-return]
):
if dependency.pretty_name not in dependencies:
dependencies[dependency.pretty_name] = []
......@@ -549,7 +556,10 @@ class Locker:
"category": package.category,
"optional": package.optional,
"python-versions": package.python_versions,
"files": sorted(package.files, key=lambda x: x["file"]),
"files": sorted(
package.files,
key=lambda x: x["file"], # type: ignore[no-any-return]
),
}
if dependencies:
......
......@@ -11,7 +11,7 @@ if TYPE_CHECKING:
from poetry.core.packages.package import Package
class PackageCollection(list):
class PackageCollection(list): # type: ignore[type-arg]
def __init__(
self,
dependency: Dependency,
......
......@@ -9,7 +9,7 @@ if TYPE_CHECKING:
from poetry.core.semver.version import Version
class ProjectPackage(_ProjectPackage):
class ProjectPackage(_ProjectPackage): # type: ignore[misc]
def set_version(
self, version: str | Version, pretty_version: str | None = None
) -> None:
......
......@@ -33,7 +33,11 @@ class PluginManager:
self._load_plugin_entrypoint(entrypoint)
def get_plugin_entry_points(self) -> list[entrypoints.EntryPoint]:
return entrypoints.get_group_all(self._group)
entry_points: list[entrypoints.EntryPoint] = entrypoints.get_group_all(
self._group
)
return entry_points
def add_plugin(self, plugin: Plugin) -> None:
if not isinstance(plugin, (Plugin, ApplicationPlugin)):
......
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import Any
from poetry.core.poetry import Poetry as BasePoetry
......@@ -19,18 +20,18 @@ if TYPE_CHECKING:
from poetry.repositories.pool import Pool
class Poetry(BasePoetry):
class Poetry(BasePoetry): # type: ignore[misc]
VERSION = __version__
def __init__(
self,
file: Path,
local_config: dict,
local_config: dict[str, Any],
package: ProjectPackage,
locker: Locker,
config: Config,
):
) -> None:
from poetry.repositories.pool import Pool
super().__init__(file, local_config, package)
......
......@@ -60,7 +60,8 @@ class Uploader:
@property
def user_agent(self) -> str:
return user_agent("poetry", __version__)
agent: str = user_agent("poetry", __version__)
return agent
@property
def adapter(self) -> adapters.HTTPAdapter:
......
......@@ -54,7 +54,7 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
class Indicator(ProgressIndicator):
class Indicator(ProgressIndicator): # type: ignore[misc]
def _formatter_elapsed(self) -> str:
elapsed = time.time() - self._start_time
......@@ -104,7 +104,7 @@ class Provider:
self._io = io
self._env = env
self._python_constraint = package.python_constraint
self._is_debugging = self._io.is_debug() or self._io.is_very_verbose()
self._is_debugging: bool = self._io.is_debug() or self._io.is_very_verbose()
self._in_progress = False
self._overrides: dict[DependencyPackage, dict[str, Dependency]] = {}
self._deferred_cache: dict[Dependency, Package] = {}
......
......@@ -49,7 +49,7 @@ class Solver:
locked: Repository,
io: IO,
provider: Provider | None = None,
):
) -> None:
self._package = package
self._pool = pool
self._installed = installed
......@@ -140,7 +140,8 @@ class Solver:
)
for dependency_packages in locked.values():
dependency_packages.sort(
key=lambda package: package.package.version, reverse=True
key=lambda p: p.package.version, # type: ignore[no-any-return]
reverse=True,
)
try:
......
......@@ -3,6 +3,7 @@ from __future__ import annotations
from abc import ABC
from abc import abstractmethod
from typing import TYPE_CHECKING
from typing import Any
from cachy import CacheManager
from poetry.core.semver.helpers import parse_constraint
......@@ -20,7 +21,7 @@ if TYPE_CHECKING:
class CachedRepository(Repository, ABC):
CACHE_VERSION = parse_constraint("1.0.0")
def __init__(self, name: str, disable_cache: bool = False):
def __init__(self, name: str, disable_cache: bool = False) -> None:
super().__init__(name)
self._disable_cache = disable_cache
self._cache_dir = REPOSITORY_CACHE_DIR / name
......@@ -37,7 +38,7 @@ class CachedRepository(Repository, ABC):
)
@abstractmethod
def _get_release_info(self, name: str, version: str) -> dict:
def _get_release_info(self, name: str, version: str) -> dict[str, Any]:
raise NotImplementedError()
def get_release_info(self, name: str, version: str) -> PackageInfo:
......@@ -73,6 +74,6 @@ class CachedRepository(Repository, ABC):
self,
name: str,
version: str,
extras: (list | None) = None,
extras: list[str] | None = None,
) -> Package:
return self.get_release_info(name, version).to_package(name=name, extras=extras)
......@@ -200,7 +200,7 @@ class HTTPRepository(CachedRepository, ABC):
return self._get_info_from_sdist(urls["sdist"][0])
def _links_to_data(self, links: list[Link], data: PackageInfo) -> dict:
def _links_to_data(self, links: list[Link], data: PackageInfo) -> dict[str, Any]:
if not links:
raise PackageNotFound(
f'No valid distribution links found for package: "{data.name}" version:'
......@@ -260,7 +260,7 @@ class HTTPRepository(CachedRepository, ABC):
def _get_response(self, endpoint: str) -> requests.Response | None:
url = self._url + endpoint
try:
response = self.session.get(url, raise_for_status=False)
response: requests.Response = self.session.get(url, raise_for_status=False)
if response.status_code in (401, 403):
self._log(
f"Authorization error accessing {url}",
......
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import Any
from poetry.core.packages.package import Package
from poetry.core.semver.version import Version
......@@ -120,7 +121,7 @@ class LegacyRepository(HTTPRepository):
return list(page.links_for_version(package.name, package.version))
def _get_release_info(self, name: str, version: str) -> dict:
def _get_release_info(self, name: str, version: str) -> dict[str, Any]:
page = self._get_page(f"/{canonicalize_name(name).replace('.', '-')}/")
if page is None:
raise PackageNotFound(f'No package named "{name}"')
......
......@@ -122,7 +122,11 @@ class Pool(Repository):
raise NotImplementedError()
def package(
self, name: str, version: str, extras: list[str] = None, repository: str = None
self,
name: str,
version: str,
extras: list[str] | None = None,
repository: str | None = None,
) -> Package:
if repository is not None:
repository = repository.lower()
......
......@@ -4,6 +4,7 @@ import logging
from collections import defaultdict
from typing import TYPE_CHECKING
from typing import Any
import requests
......@@ -128,7 +129,7 @@ class PyPiRepository(HTTPRepository):
return results
def get_package_info(self, name: str) -> dict:
def get_package_info(self, name: str) -> dict[str, Any]:
"""
Return the package information given its name.
......@@ -138,11 +139,12 @@ class PyPiRepository(HTTPRepository):
if self._disable_cache:
return self._get_package_info(name)
return self._cache.store("packages").remember_forever(
package_info: dict[str, Any] = self._cache.store("packages").remember_forever(
name, lambda: self._get_package_info(name)
)
return package_info
def _get_package_info(self, name: str) -> dict:
def _get_package_info(self, name: str) -> dict[str, Any]:
data = self._get(f"pypi/{name}/json")
if data is None:
raise PackageNotFound(f"Package [{name}] not found.")
......@@ -226,7 +228,7 @@ class PyPiRepository(HTTPRepository):
return data.asdict()
def _get(self, endpoint: str) -> dict | None:
def _get(self, endpoint: str) -> dict[str, Any] | None:
try:
json_response = self.session.get(self._base_url + endpoint)
except requests.exceptions.TooManyRedirects:
......@@ -238,4 +240,5 @@ class PyPiRepository(HTTPRepository):
if json_response.status_code == 404:
return None
return json_response.json()
json: dict[str, Any] = json_response.json()
return json
......@@ -5,7 +5,7 @@ from poetry.repositories.link_sources.html import SimpleRepositoryPage
class SinglePageRepository(LegacyRepository):
def _get_page(self, endpoint: str = None) -> SimpleRepositoryPage | None:
def _get_page(self, endpoint: str | None = None) -> SimpleRepositoryPage | None:
"""
Single page repositories only have one page irrespective of endpoint.
"""
......
......@@ -9,7 +9,7 @@ if sys.version_info < (3, 8):
# compatibility for python <3.8
import importlib_metadata as metadata
else:
from importlib import metadata # noqa: F401, TC002
from importlib import metadata
WINDOWS = sys.platform == "win32"
......@@ -49,3 +49,6 @@ def list_to_shell_command(cmd: list[str]) -> str:
f'"{token}"' if " " in token and token[0] not in {"'", '"'} else token
for token in cmd
)
__all__ = ["WINDOWS", "decode", "encode", "list_to_shell_command", "metadata", "to_str"]
......@@ -119,7 +119,8 @@ class Authenticator:
if not self.is_cached:
return session
return CacheControl(sess=session, cache=self._cache_control)
session = CacheControl(sess=session, cache=self._cache_control)
return session
def get_session(self, url: str | None = None) -> requests.Session:
if not url:
......@@ -188,7 +189,7 @@ class Authenticator:
if verify is not None:
verify = str(verify)
settings = session.merge_environment_settings(
settings = session.merge_environment_settings( # type: ignore[no-untyped-call]
prepared_request.url, proxies, stream, verify, cert
)
......
......@@ -1852,7 +1852,7 @@ class MockEnv(NullEnv):
marker_env: dict[str, Any] = None,
supported_tags: list[Tag] = None,
**kwargs: Any,
):
) -> None:
super().__init__(**kwargs)
self._version_info = version_info
......
......@@ -59,7 +59,7 @@ def get_client_cert(config: Config, repository_name: str) -> Path | None:
return None
def _on_rm_error(func: Callable, path: str, exc_info: Exception) -> None:
def _on_rm_error(func: Callable[[str], None], path: str, exc_info: Exception) -> None:
if not os.path.exists(path):
return
......@@ -84,7 +84,7 @@ def remove_directory(
shutil.rmtree(path, *args, **kwargs)
def merge_dicts(d1: dict, d2: dict) -> None:
def merge_dicts(d1: dict[str, Any], d2: dict[str, Any]) -> None:
for k in d2.keys():
if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], Mapping):
merge_dicts(d1[k], d2[k])
......@@ -119,7 +119,8 @@ def get_package_version_display_string(
path = Path(os.path.relpath(package.source_url, root.as_posix())).as_posix()
return f"{package.version} {path}"
return package.full_pretty_version
pretty_version: str = package.full_pretty_version
return pretty_version
def paths_csv(paths: list[Path]) -> str:
......
......@@ -168,7 +168,8 @@ class PasswordManager:
def get_pypi_token(self, name: str) -> str | None:
if not self.keyring.is_available():
return self._config.get(f"pypi-token.{name}")
token: str | None = self._config.get(f"pypi-token.{name}")
return token
return self.keyring.get_password(name, "__token__")
......
......@@ -25,7 +25,7 @@ class SetupReader:
FILES = ["setup.py", "setup.cfg"]
@classmethod
def read_from_directory(cls, directory: str | Path) -> dict[str, list | dict]:
def read_from_directory(cls, directory: str | Path) -> dict[str, Any]:
if isinstance(directory, str):
directory = Path(directory)
......@@ -44,7 +44,7 @@ class SetupReader:
return result
def read_setup_py(self, filepath: str | Path) -> dict[str, list | dict]:
def read_setup_py(self, filepath: str | Path) -> dict[str, Any]:
if isinstance(filepath, str):
filepath = Path(filepath)
......
......@@ -3,4 +3,4 @@ from __future__ import annotations
from poetry.vcs.git.backend import Git
__all__ = [Git.__name__]
__all__ = ["Git"]
......@@ -149,18 +149,21 @@ class GitRepoLocalInfo:
class Git:
@staticmethod
def as_repo(repo: Path | str) -> Repo:
return Repo(repo)
return Repo(str(repo)) # type: ignore[no-untyped-call]
@staticmethod
def get_remote_url(repo: Repo, remote: str = "origin") -> str:
with repo:
config = repo.get_config()
section = (b"remote", remote.encode("utf-8"))
return (
config.get(section, b"url").decode("utf-8")
if config.has_section(section)
else ""
)
url = ""
if config.has_section(section): # type: ignore[no-untyped-call]
value = config.get(section, b"url") # type: ignore[no-untyped-call]
assert value is not None
url = value.decode("utf-8")
return url
@staticmethod
def get_revision(repo: Repo) -> str:
......@@ -184,16 +187,17 @@ class Git:
path: str
credentials = get_default_authenticator().get_credentials_for_url(url=url)
client, path = get_transport_and_path(
client, path = get_transport_and_path( # type: ignore[no-untyped-call]
url, username=credentials.username, password=credentials.password
)
with local:
return client.fetch(
result: FetchPackResult = client.fetch( # type: ignore[no-untyped-call]
path,
local,
determine_wants=local.object_store.determine_wants_all,
)
return result
@staticmethod
def _clone_legacy(url: str, refspec: GitRefSpec, target: Path) -> Repo:
......@@ -229,7 +233,8 @@ class Git:
f"Failed to checkout {url} at '{revision}'"
)
return Repo(target)
repo = Repo(str(target)) # type: ignore[no-untyped-call]
return repo
@classmethod
def _clone(cls, url: str, refspec: GitRefSpec, target: Path) -> Repo:
......@@ -237,11 +242,12 @@ class Git:
Helper method to clone a remove repository at the given `url` at the specified
ref spec.
"""
local: Repo
if not target.exists():
local = Repo.init(target, mkdir=True)
porcelain.remote_add(local, "origin", url)
local = Repo.init(str(target), mkdir=True) # type: ignore[no-untyped-call]
porcelain.remote_add(local, "origin", url) # type: ignore[no-untyped-call]
else:
local = Repo(target)
local = Repo(str(target)) # type: ignore[no-untyped-call]
remote_refs = cls._fetch_remote_refs(url=url, local=local)
......@@ -268,7 +274,7 @@ class Git:
(b"refs/remotes/origin", b"refs/heads/"),
(b"refs/tags", b"refs/tags"),
}:
local.refs.import_refs(
local.refs.import_refs( # type: ignore[no-untyped-call]
base=base,
other={
n[len(prefix) :]: v
......@@ -279,7 +285,7 @@ class Git:
try:
with local:
local.reset_index()
local.reset_index() # type: ignore[no-untyped-call]
except (AssertionError, KeyError) as e:
# this implies the ref we need does not exist or is invalid
if isinstance(e, KeyError):
......@@ -321,7 +327,8 @@ class Git:
url: bytes
path: bytes
for path, url, _ in parse_submodules(config):
submodules = parse_submodules(config) # type: ignore[no-untyped-call]
for path, url, _ in submodules:
path_relative = Path(path.decode("utf-8"))
path_absolute = repo_root.joinpath(path_relative)
......@@ -344,11 +351,12 @@ class Git:
def is_using_legacy_client() -> bool:
from poetry.factory import Factory
return (
legacy_client: bool = (
Factory.create_config()
.get("experimental", {})
.get("system-git-client", False)
)
return legacy_client
@staticmethod
def get_default_source_root() -> Path:
......@@ -381,7 +389,7 @@ class Git:
else:
# check if the current local copy matches the requested ref spec
try:
current_repo = Repo(target)
current_repo = Repo(str(target)) # type: ignore[no-untyped-call]
with current_repo:
current_sha = current_repo.head().decode("utf-8")
......
......@@ -48,10 +48,9 @@ class SystemGit:
folder.as_posix(),
) + args
git_command = find_git_command() # type: ignore[no-untyped-call]
return (
subprocess.check_output(
find_git_command() + list(args), stderr=subprocess.STDOUT
)
subprocess.check_output(git_command + list(args), stderr=subprocess.STDOUT)
.decode()
.strip()
)
......
......@@ -103,7 +103,8 @@ def test_group_options_are_passed_to_the_installer(
"""
mocker.patch.object(tester.command.installer, "run", return_value=0)
editable_builder_mock = mocker.patch(
"poetry.masonry.builders.EditableBuilder", side_effect=ModuleOrPackageNotFound()
"poetry.masonry.builders.editable.EditableBuilder",
side_effect=ModuleOrPackageNotFound(),
)
if not with_root:
......
......@@ -126,7 +126,7 @@ def mock_download(url: str, dest: str, **__: Any) -> None:
class TestExecutor(Executor):
def __init__(self, *args: Any, **kwargs: Any):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self._installs = []
......@@ -162,7 +162,7 @@ class TestExecutor(Executor):
class PoetryTestApplication(Application):
def __init__(self, poetry: Poetry):
def __init__(self, poetry: Poetry) -> None:
super().__init__()
self._poetry = poetry
......@@ -177,7 +177,7 @@ class PoetryTestApplication(Application):
class TestLocker(Locker):
def __init__(self, lock: str | Path, local_config: dict):
def __init__(self, lock: str | Path, local_config: dict) -> None:
self._lock = TOMLFile(lock)
self._local_config = local_config
self._lock_data = None
......
......@@ -62,7 +62,7 @@ class Installer(BaseInstaller):
class Executor(BaseExecutor):
def __init__(self, *args: Any, **kwargs: Any):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self._installs: list[DependencyPackage] = []
......@@ -106,7 +106,7 @@ class CustomInstalledRepository(InstalledRepository):
class Locker(BaseLocker):
def __init__(self, lock_path: str | Path):
def __init__(self, lock_path: str | Path) -> None:
self._lock = TOMLFile(Path(lock_path).joinpath("poetry.lock"))
self._written_data = None
self._locked = False
......
......@@ -54,7 +54,7 @@ class CustomInstalledRepository(InstalledRepository):
class Locker(BaseLocker):
def __init__(self, lock_path: str | Path):
def __init__(self, lock_path: str | Path) -> None:
self._lock = TOMLFile(Path(lock_path).joinpath("poetry.lock"))
self._written_data = None
self._locked = False
......
......@@ -379,7 +379,9 @@ def test_get_package_retrieves_packages_with_no_hashes():
class MockHttpRepository(LegacyRepository):
def __init__(self, endpoint_responses: dict, http: type[httpretty.httpretty]):
def __init__(
self, endpoint_responses: dict, http: type[httpretty.httpretty]
) -> None:
base_url = "http://legacy.foo.bar"
super().__init__("legacy", url=base_url, disable_cache=True)
......
......@@ -32,7 +32,7 @@ class MockRepository(PyPiRepository):
JSON_FIXTURES = Path(__file__).parent / "fixtures" / "pypi.org" / "json"
DIST_FIXTURES = Path(__file__).parent / "fixtures" / "pypi.org" / "dists"
def __init__(self, fallback: bool = False):
def __init__(self, fallback: bool = False) -> None:
super().__init__(url="http://foo.bar", disable_cache=True, fallback=fallback)
def _get(self, url: str) -> dict | None:
......
......@@ -56,7 +56,7 @@ class MockVirtualEnv(VirtualEnv):
path: Path,
base: Path | None = None,
sys_path: list[str] | None = None,
):
) -> None:
super().__init__(path, base=base)
self._sys_path = sys_path
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment