Skip to content
Merged
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,14 @@ reportUnannotatedClassAttribute = false
reportUnknownArgumentType = false
reportUnknownLambdaType = false
reportUnknownMemberType = false
reportUnknownParameterType = false
reportUnknownVariableType = false
reportUnnecessaryIsInstance = false
reportUnusedCallResult = false
reportUnusedParameter = false

[[tool.basedpyright.executionEnvironments]]
root = "tests"
reportUnknownParameterType = false
reportUnreachable = false
reportUnusedFunction = false

Expand Down
6 changes: 4 additions & 2 deletions src/usethis/_file/yaml/update.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from difflib import SequenceMatcher
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, TypeVar

from ruamel.yaml.comments import (
CommentedMap,
Expand All @@ -12,6 +12,8 @@

from usethis._file.yaml.typing_ import YAMLLiteral

_T = TypeVar("_T")


def update_ruamel_yaml_map(
cmap: YAMLLiteral | dict[str, Any],
Expand Down Expand Up @@ -64,7 +66,7 @@ def update_ruamel_yaml_map(
cmap[key] = cmap_copy[key]


def lcs_list_update(original: list, new: list) -> None:
def lcs_list_update(original: list[_T], new: list[_T]) -> None:
"""Update in-place using a longest common subsequence solver.

This makes `original` identical to `new`, but respects subtypes of list such as
Expand Down
2 changes: 1 addition & 1 deletion src/usethis/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def unlock(self) -> None:
self._content_by_path.pop(self.path, None)


Key: TypeAlias = str | re.Pattern
Key: TypeAlias = str | re.Pattern[str]


class KeyValueFileManager(UsethisFileManager, Generic[DocumentT]):
Expand Down
4 changes: 2 additions & 2 deletions src/usethis/_pipeweld/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ class Series(RootModel[list["Series | Parallel | DepGroup | str"]]):
def __hash__(self):
return hash((_HASH_SALT, tuple(self.root)))

def __getitem__(self, item):
def __getitem__(self, item: int) -> Series | Parallel | DepGroup | str:
return self.root[item]

def __setitem__(self, item, value):
def __setitem__(self, item: int, value: Series | Parallel | DepGroup | str) -> None:
self.root[item] = value

def __eq__(self, other: Any):
Expand Down
9 changes: 5 additions & 4 deletions src/usethis/_pipeweld/func.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,11 @@ def _insert_before_postrequisites(
idx=-1,
predecessor=predecessor,
)
if len(container) == 1 and container[0] == _union(
successor_component, self.step
):
component[idx + 1] = _union(successor_component, self.step)
union = _union(successor_component, self.step)
if len(container) == 1 and container[0] == union:
if union is None:
raise NotImplementedError
component[idx + 1] = union

return instructions
elif isinstance(successor_component, Parallel | DepGroup | str):
Expand Down
15 changes: 9 additions & 6 deletions src/usethis/_tool/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ def migrate_config_from_pre_commit(self) -> None:
if pre_commit_config.inform_how_to_use_on_migrate:
self.print_how_to_use()

def get_active_config_file_managers(self) -> set[KeyValueFileManager]:
def get_active_config_file_managers(self) -> set[KeyValueFileManager[object]]:
"""Get file managers for all active configuration files.

Active configuration files are just those that we expect to use based on our
Expand All @@ -257,8 +257,8 @@ def _get_active_config_file_managers_from_resolution(
self,
resolution: ResolutionT,
*,
file_manager_by_relative_path: dict[Path, KeyValueFileManager],
) -> set[KeyValueFileManager]:
file_manager_by_relative_path: dict[Path, KeyValueFileManager[object]],
) -> set[KeyValueFileManager[object]]:
if resolution == "first":
# N.B. keep this roughly in sync with the bespoke logic for pytest
# since that logic is based on this logic.
Expand Down Expand Up @@ -334,7 +334,10 @@ def add_configs(self) -> None:
already_added = True

def _add_config_item(
self, config_item: ConfigItem, *, file_managers: set[KeyValueFileManager]
self,
config_item: ConfigItem,
*,
file_managers: set[KeyValueFileManager[object]],
) -> bool:
"""Add a specific configuration item using specified file managers.

Expand Down Expand Up @@ -603,7 +606,7 @@ def _unconditional_update_bitbucket_steps(
):
remove_bitbucket_step_from_default(step)

def _get_select_keys(self, file_manager: KeyValueFileManager) -> list[str]:
def _get_select_keys(self, file_manager: KeyValueFileManager[object]) -> list[str]:
"""Get the configuration keys for selected rules.

This is optional - tools that don't support rule selection can leave this
Expand Down Expand Up @@ -655,7 +658,7 @@ def select_rules(self, rules: list[Rule]) -> bool:

return True

def _get_ignore_keys(self, file_manager: KeyValueFileManager) -> list[str]:
def _get_ignore_keys(self, file_manager: KeyValueFileManager[object]) -> list[str]:
"""Get the configuration keys for ignored rules.

Args:
Expand Down
4 changes: 2 additions & 2 deletions src/usethis/_tool/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class ConfigSpec(BaseModel):
@classmethod
def from_flat(
cls,
file_managers: list[KeyValueFileManager],
file_managers: list[KeyValueFileManager[object]],
resolution: ResolutionT,
config_items: list[ConfigItem],
) -> Self:
Expand Down Expand Up @@ -146,7 +146,7 @@ def paths(self) -> set[Path]:
return {(usethis_config.cpd() / path).resolve() for path in self.root}


def ensure_managed_file_exists(file_manager: UsethisFileManager) -> None:
def ensure_managed_file_exists(file_manager: UsethisFileManager[object]) -> None:
"""Ensure a file manager's managed file exists."""
if isinstance(file_manager, PyprojectTOMLManager):
ensure_pyproject_toml()
Expand Down
2 changes: 1 addition & 1 deletion src/usethis/_tool/impl/base/deptry.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def ignored_rules(self) -> list[Rule]:

return rules

def _get_ignore_keys(self, file_manager: KeyValueFileManager) -> list[str]:
def _get_ignore_keys(self, file_manager: KeyValueFileManager[object]) -> list[str]:
"""Get the keys for the ignored rules in the given file manager."""
if isinstance(file_manager, PyprojectTOMLManager):
return ["tool", "deptry", "ignore"]
Expand Down
2 changes: 1 addition & 1 deletion src/usethis/_tool/impl/base/pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def print_how_to_use(self) -> None:
how_print("Add test functions with the format 'test_*()'.")
how_print(f"Run '{self.how_to_use_cmd()}' to run the tests.")

def get_active_config_file_managers(self) -> set[KeyValueFileManager]:
def get_active_config_file_managers(self) -> set[KeyValueFileManager[object]]:
# This is a variant of the "first" method
config_spec = self.config_spec()
if config_spec.resolution != "bespoke":
Expand Down
10 changes: 6 additions & 4 deletions src/usethis/_tool/impl/base/ruff.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ def _are_pydocstyle_rules_selected(self) -> bool:
def _is_pydocstyle_rule(rule: Rule) -> bool:
return [d for d in rule if d.isalpha()] == ["D"]

def _get_select_keys(self, file_manager: KeyValueFileManager) -> list[str]:
def _get_select_keys(self, file_manager: KeyValueFileManager[object]) -> list[str]:
"""Get the keys for the selected rules in the given file manager."""
if isinstance(file_manager, PyprojectTOMLManager):
return ["tool", "ruff", "lint", "select"]
Expand All @@ -454,7 +454,7 @@ def _get_select_keys(self, file_manager: KeyValueFileManager) -> list[str]:
else:
return super()._get_select_keys(file_manager)

def _get_ignore_keys(self, file_manager: KeyValueFileManager) -> list[str]:
def _get_ignore_keys(self, file_manager: KeyValueFileManager[object]) -> list[str]:
"""Get the keys for the ignored rules in the given file manager."""
if isinstance(file_manager, PyprojectTOMLManager):
return ["tool", "ruff", "lint", "ignore"]
Expand All @@ -464,7 +464,7 @@ def _get_ignore_keys(self, file_manager: KeyValueFileManager) -> list[str]:
return super()._get_ignore_keys(file_manager)

def _get_per_file_ignore_keys(
self, file_manager: KeyValueFileManager, *, glob: str
self, file_manager: KeyValueFileManager[object], *, glob: str
) -> list[str]:
"""Get the keys for the per-file ignored rules in the given file manager."""
if isinstance(file_manager, PyprojectTOMLManager):
Expand All @@ -478,7 +478,9 @@ def _get_per_file_ignore_keys(
)
raise NotImplementedError(msg)

def _get_docstyle_keys(self, file_manager: KeyValueFileManager) -> list[str]:
def _get_docstyle_keys(
self, file_manager: KeyValueFileManager[object]
) -> list[str]:
"""Get the keys for the docstyle rules in the given file manager."""
if isinstance(file_manager, PyprojectTOMLManager):
return ["tool", "ruff", "lint", "pydocstyle", "convention"]
Expand Down
2 changes: 1 addition & 1 deletion src/usethis/_tool/impl/spec/codespell.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def meta(self) -> ToolMeta:
managed_files=[Path(".codespellrc")],
)

def preferred_file_manager(self) -> KeyValueFileManager:
def preferred_file_manager(self) -> KeyValueFileManager[object]:
if (usethis_config.cpd() / "pyproject.toml").exists():
return PyprojectTOMLManager()
return DotCodespellRCManager()
Expand Down
2 changes: 1 addition & 1 deletion src/usethis/_tool/impl/spec/coverage_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def meta(self) -> ToolMeta:
managed_files=[Path(".coveragerc"), Path(".coveragerc.toml")],
)

def preferred_file_manager(self) -> KeyValueFileManager:
def preferred_file_manager(self) -> KeyValueFileManager[object]:
if (usethis_config.cpd() / "pyproject.toml").exists():
return PyprojectTOMLManager()
return DotCoverageRCManager()
6 changes: 4 additions & 2 deletions src/usethis/_tool/impl/spec/import_linter.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def raw_cmd(self) -> str:
def dev_deps(self, *, unconditional: bool = False) -> list[Dependency]:
return [Dependency(name="import-linter")]

def preferred_file_manager(self) -> KeyValueFileManager:
def preferred_file_manager(self) -> KeyValueFileManager[object]:
if (usethis_config.cpd() / "pyproject.toml").exists():
return PyprojectTOMLManager()
return DotImportLinterManager()
Expand Down Expand Up @@ -94,7 +94,9 @@ def _get_layered_architecture_by_module_by_root_package(
def _get_resolution(self) -> ResolutionT:
return "first"

def _get_file_manager_by_relative_path(self) -> dict[Path, KeyValueFileManager]:
def _get_file_manager_by_relative_path(
self,
) -> dict[Path, KeyValueFileManager[object]]:
return {
Path("setup.cfg"): SetupCFGManager(),
Path(".importlinter"): DotImportLinterManager(),
Expand Down
2 changes: 1 addition & 1 deletion src/usethis/_tool/impl/spec/mkdocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def doc_deps(self, *, unconditional: bool = False) -> list[Dependency]:

return deps

def preferred_file_manager(self) -> KeyValueFileManager:
def preferred_file_manager(self) -> KeyValueFileManager[object]:
"""If there is no currently active config file, this is the preferred one."""
# Should set the mkdocs.yml file manager as the preferred one
return MkDocsYMLManager()
2 changes: 1 addition & 1 deletion src/usethis/_tool/impl/spec/pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def meta(self) -> ToolMeta:
def raw_cmd(self) -> str:
return "pytest"

def preferred_file_manager(self) -> KeyValueFileManager:
def preferred_file_manager(self) -> KeyValueFileManager[object]:
if (usethis_config.cpd() / "pyproject.toml").exists():
return PyprojectTOMLManager()
return PytestINIManager()
2 changes: 1 addition & 1 deletion src/usethis/_tool/impl/spec/ruff.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def meta(self) -> ToolMeta:
def dev_deps(self, *, unconditional: bool = False) -> list[Dependency]:
return [Dependency(name="ruff")]

def preferred_file_manager(self) -> KeyValueFileManager:
def preferred_file_manager(self) -> KeyValueFileManager[object]:
if (usethis_config.cpd() / "pyproject.toml").exists():
return PyprojectTOMLManager()
return RuffTOMLManager()
2 changes: 1 addition & 1 deletion src/usethis/_tool/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def rule_config(self) -> RuleConfig:
"""
return self.meta.rule_config

def preferred_file_manager(self) -> KeyValueFileManager:
def preferred_file_manager(self) -> KeyValueFileManager[object]:
"""If there is no currently active config file, this is the preferred one.

This can vary dynamically, since often we will prefer to respect an existing
Expand Down
Loading