diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 36f78cd..e800b88 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,5 +34,5 @@ repos: rev: "v0.1.5" hooks: - id: ruff - args: ["--fix", "--show-fixes"] + args: ["--fix", "--show-fixes", "--unsafe-fixes"] - id: ruff-format diff --git a/peppyproject/__main__.py b/peppyproject/__main__.py index f2ab839..809c0bc 100644 --- a/peppyproject/__main__.py +++ b/peppyproject/__main__.py @@ -9,17 +9,10 @@ @app.command() def main( - directory: Path = typer.Argument( - None, help="directory from which to read configuration" - ), - output_filename: Path = typer.Option( - None, "-o", "--output", help="path to which to write TOML" - ), + directory: Path = typer.Argument(None, help="directory from which to read configuration"), + output_filename: Path = typer.Option(None, "-o", "--output", help="path to which to write TOML"), ): - """ - read a Python project configuration and output a PEP621-compliant `pyproject.toml` - """ - + """Read a Python project configuration and output a PEP621-compliant `pyproject.toml`.""" if directory is None: directory = Path.cwd() diff --git a/peppyproject/base.py b/peppyproject/base.py index b32b1a9..b108296 100644 --- a/peppyproject/base.py +++ b/peppyproject/base.py @@ -1,9 +1,12 @@ +from __future__ import annotations + from abc import ABC +from collections.abc import Collection, Iterator, Mapping, MutableMapping from configparser import ConfigParser from datetime import datetime from pathlib import Path from tempfile import NamedTemporaryFile -from typing import Any, Collection, Iterator, Mapping, MutableMapping, Union +from typing import Any import tomli import tomli_w @@ -14,15 +17,13 @@ class ConfigurationTable(MutableMapping, ABC): - """ - abstraction of a TOML configuration table - """ + """abstraction of a TOML configuration table.""" name: str fields: dict[str, Any] start_with_placeholders: bool = True - def __init__(self, **kwargs): + def __init__(self, **kwargs) -> None: if self.start_with_placeholders: self.__configuration = {key: None for key in self.fields} else: @@ -31,7 +32,7 @@ def __init__(self, **kwargs): self.update(kwargs) @classmethod - def from_file(cls, filename: str) -> "ConfigurationTable": + def from_file(cls, filename: str) -> ConfigurationTable: if not isinstance(filename, Path): filename = Path(filename) @@ -43,10 +44,7 @@ def from_file(cls, filename: str) -> "ConfigurationTable": base_table = cls.name.split(".", 1)[0] if base_table in file_configuration: configuration.update(file_configuration[base_table]) - elif ( - filename.suffix.lower() in [".cfg", ".ini"] - or filename.name.lower() == "setup.py" - ): + elif filename.suffix.lower() in [".cfg", ".ini"] or filename.name.lower() == "setup.py": if filename.suffix.lower() in [".cfg", ".ini"]: with open(filename) as configuration_file: ini_string = configuration_file.read() @@ -65,25 +63,17 @@ def from_file(cls, filename: str) -> "ConfigurationTable": setup_cfg.add_section(section_name) setup_cfg.set(section_name, key, value) else: - value = inify_mapping( - mapping=value, name=f"{section_name}.{key}" - ) + value = inify_mapping(mapping=value, name=f"{section_name}.{key}") for ( value_section_name, value_section, ) in value.items(): if len(value_section) == 0: - if ( - value_section_name - == "options.packages.find" - ): + if value_section_name == "options.packages.find": value_section["namespaces"] = "False" else: continue - if ( - value_section_name - not in setup_cfg.sections() - ): + if value_section_name not in setup_cfg.sections(): setup_cfg.add_section(value_section_name) for ( entry_name, @@ -119,19 +109,14 @@ def from_file(cls, filename: str) -> "ConfigurationTable": setuptools_table = tool_table["setuptools"] if "packages" in setuptools_table: packages_table = setuptools_table["packages"] - if "find" in packages_table: - if "namespaces" in packages_table["find"]: - packages_table["find"]["namespaces"] = ( - packages_table["find"]["namespaces"] == "True" - ) + if "find" in packages_table and "namespaces" in packages_table["find"]: + packages_table["find"]["namespaces"] = packages_table["find"]["namespaces"] == "True" setuptools_table["packages"] = packages_table if setup_py is not None: if "extras-require" in setuptools_table: if "project" not in file_configuration: file_configuration["project"] = ConfigurationSubTable() - file_configuration["project"][ - "optional-dependencies" - ] = setup_py["extras_require"] + file_configuration["project"]["optional-dependencies"] = setup_py["extras_require"] del setuptools_table["extras-require"] if "package-data" in setuptools_table: if "project" not in file_configuration: @@ -146,7 +131,7 @@ def from_file(cls, filename: str) -> "ConfigurationTable": return configuration @classmethod - def from_directory(cls, directory: str) -> "ConfigurationTable": + def from_directory(cls, directory: str) -> ConfigurationTable: if not isinstance(directory, Path): directory = Path(directory) @@ -155,10 +140,7 @@ def from_directory(cls, directory: str) -> "ConfigurationTable": file_configurations = {} for filename in directory.iterdir(): - if filename.is_file() and ( - filename.name.lower() in known_filenames - or filename.suffix.lower() in known_suffixes - ): + if filename.is_file() and (filename.name.lower() in known_filenames or filename.suffix.lower() in known_suffixes): file_configuration = cls.from_file(filename) if len(file_configuration) > 0: file_configurations[filename.name] = file_configuration @@ -166,9 +148,7 @@ def from_directory(cls, directory: str) -> "ConfigurationTable": configuration = cls() configuration.__from_directory = directory file_configurations = [ - file_configurations[filename] - for filename in reversed(known_filenames) - if filename in file_configurations + file_configurations[filename] for filename in reversed(known_filenames) if filename in file_configurations ] for file_configuration in file_configurations: if file_configuration is not None and len(file_configuration) > 0: @@ -179,23 +159,15 @@ def from_directory(cls, directory: str) -> "ConfigurationTable": def __getitem__(self, key: str) -> Any: return self.__configuration[key] - def __setitem__(self, key: str, value: Any): + def __setitem__(self, key: str, value: Any) -> None: if key in self.fields: desired_type = self.fields[key] subtable_class = ( - desired_type - if desired_type is not None and not isinstance(desired_type, Mapping) - else ConfigurationSubTable + desired_type if desired_type is not None and not isinstance(desired_type, Mapping) else ConfigurationSubTable ) if hasattr(desired_type, "__origin__") and ( - ( - hasattr(desired_type.__origin__, "__name__") - and desired_type.__origin__.__name__ == "Union" - ) - or ( - hasattr(desired_type.__origin__, "_name") - and desired_type.__origin__._name == "Union" - ) + (hasattr(desired_type.__origin__, "__name__") and desired_type.__origin__.__name__ == "Union") + or (hasattr(desired_type.__origin__, "_name") and desired_type.__origin__._name == "Union") ): values = [] errors = [] @@ -207,24 +179,20 @@ def __setitem__(self, key: str, value: Any): if len(values) == 0: raise RuntimeError(";".join(errors)) self.__configuration[key] = values[0] - else: - if isinstance(desired_type, Mapping) and isinstance(value, Mapping): - if len(value) > 0: - for sub_key, sub_value in value.items(): - if sub_key in desired_type: - if ( - key not in self.__configuration - or self.__configuration[key] is None - ): - self.__configuration[key] = subtable_class() - self[key][sub_key] = typepigeon.to_type( - sub_value, - desired_type[sub_key], - ) - else: - self.__configuration[key] = subtable_class() + elif isinstance(desired_type, Mapping) and isinstance(value, Mapping): + if len(value) > 0: + for sub_key, sub_value in value.items(): + if sub_key in desired_type: + if key not in self.__configuration or self.__configuration[key] is None: + self.__configuration[key] = subtable_class() + self[key][sub_key] = typepigeon.to_type( + sub_value, + desired_type[sub_key], + ) else: - self.__configuration[key] = typepigeon.to_type(value, desired_type) + self.__configuration[key] = subtable_class() + else: + self.__configuration[key] = typepigeon.to_type(value, desired_type) else: self.__configuration[key] = value @@ -233,7 +201,7 @@ def update(self, items: Mapping): if value is not None and (not hasattr(value, "__len__") or len(value) > 0): self[key] = value - def __delitem__(self, key: str): + def __delitem__(self, key: str) -> None: message = "cannot delete configuration entry; set as `None` instead" raise RuntimeError(message) @@ -247,15 +215,11 @@ def __len__(self) -> int: if entry is not None } return len( - [ - length - for length in lengths.values() - if not self.start_with_placeholders or length > 0 - ], + [length for length in lengths.values() if not self.start_with_placeholders or length > 0], ) @property - def __toml(self) -> dict[str, Union[str, dict]]: + def __toml(self) -> dict[str, str | dict]: return { key: value.__toml if isinstance(value, ConfigurationTable) @@ -281,11 +245,7 @@ def __repr__(self) -> str: configuration_string = { key: value for key, value in self.__configuration.items() - if value is not None - and ( - not self.start_with_placeholders - or (not hasattr(value, "__len__") or len(value) > 0) - ) + if value is not None and (not self.start_with_placeholders or (not hasattr(value, "__len__") or len(value) > 0)) } return repr(configuration_string) @@ -301,10 +261,7 @@ def to_dict(value: Mapping) -> dict: if isinstance(value, Mapping): for entry_name, entry in value.items(): if isinstance(entry, Mapping): - entry = { - subentry_name: to_dict(subentry) - for subentry_name, subentry in entry.items() - } + entry = {subentry_name: to_dict(subentry) for subentry_name, subentry in entry.items()} output[entry_name] = entry else: output = value diff --git a/peppyproject/configuration.py b/peppyproject/configuration.py index d2e5014..14d5435 100644 --- a/peppyproject/configuration.py +++ b/peppyproject/configuration.py @@ -1,5 +1,5 @@ +from collections.abc import Iterator, Mapping from pathlib import Path -from typing import Iterator, Mapping from peppyproject.base import ConfigurationTable from peppyproject.tables import BuildConfiguration, ProjectMetadata, ToolsTable @@ -7,16 +7,14 @@ class PyProjectConfiguration(Mapping): - """ - abstraction of ``pyproject.toml`` configuration - """ + """abstraction of ``pyproject.toml`` configuration.""" def __init__( self, project: ProjectMetadata = None, build_system: BuildConfiguration = None, tool: ToolsTable = None, - ): + ) -> None: if project is None or len(project) == 0: project = ProjectMetadata() if tool is None or len(tool) == 0: @@ -24,10 +22,7 @@ def __init__( if build_system is None or len(build_system) == 0: build_system = BuildConfiguration.default_setuptools() if project["dynamic"] is not None and "version" in project["dynamic"]: - if not any( - "setuptools_scm" in requirement - for requirement in build_system["requires"] - ): + if not any("setuptools_scm" in requirement for requirement in build_system["requires"]): build_system["requires"].append("setuptools_scm[toml]>=3.4") if "setuptools_scm" not in tool: tool["setuptools_scm"] = SetuptoolsSCMTable() @@ -67,7 +62,7 @@ def __iter__(self) -> Iterator: def __repr__(self) -> str: tables_string = ", ".join( - f"{key}={repr(value)}" + f"{key}={value!r}" for key, value in self.__tables.items() if value is not None and (not hasattr(value, "__len__") or len(value) > 0) ) diff --git a/peppyproject/files.py b/peppyproject/files.py index 9fb773e..72577e6 100644 --- a/peppyproject/files.py +++ b/peppyproject/files.py @@ -1,10 +1,13 @@ # https://setuptools.pypa.io/en/latest/userguide/declarative_config.html#compatibility-with-other-tools +from __future__ import annotations + import ast import contextlib import re import warnings +from collections.abc import Collection, Mapping from pathlib import Path -from typing import Any, Collection, Mapping, Union +from typing import Any SETUP_CFG_INDENT = " " * 4 SETUP_CFG = { @@ -40,8 +43,8 @@ def python_statement( lines: list[str], index: int = 0, - current_statement: str = None, - statements: list[str] = None, + current_statement: str | None = None, + statements: list[str] | None = None, ) -> tuple[list[str], int]: if current_statement is None: current_statement = "" @@ -59,10 +62,7 @@ def python_statement( index += 1 # check if line continues - if any( - line.endswith(continuing_character) - for continuing_character in PYTHON_LINE["continuing"] - ): + if any(line.endswith(continuing_character) for continuing_character in PYTHON_LINE["continuing"]): statements, index = python_statement( lines=lines, index=index, @@ -78,11 +78,8 @@ def python_statement( else: current_statement += line - if any( - line.endswith(ending_character) for ending_character in PYTHON_LINE["ending"] - ) and any( - statements[-1].endswith(continuing_character) - for continuing_character in PYTHON_LINE["continuing"] + if any(line.endswith(ending_character) for ending_character in PYTHON_LINE["ending"]) and any( + statements[-1].endswith(continuing_character) for continuing_character in PYTHON_LINE["continuing"] ): statements[-1] += current_statement else: @@ -93,7 +90,7 @@ def python_statement( def parse_function_parameters( parameter_string: str, - variables: dict[str, Any] = None, + variables: dict[str, Any] | None = None, ) -> dict[str, Any]: if variables is None: variables = {} @@ -105,7 +102,7 @@ def parse_function_parameters( parameter_index = 0 while parameter_index < len(parameters): parameter = parameters[parameter_index].strip() - if parameter.startswith('"') or parameter.startswith("'"): + if parameter.startswith(('"', "'")): parameters[parameter_index - 1] += parameters.pop(parameter_index) else: parameter_index += 1 @@ -181,17 +178,11 @@ def read_python_file(filename: str) -> list[str]: indices = [] for index in reversed(range(len(statements))): statement = statements[index] - if any( - statement.strip().endswith(continuing_character) - for continuing_character in PYTHON_LINE["continuing"] - ): + if any(statement.strip().endswith(continuing_character) for continuing_character in PYTHON_LINE["continuing"]): if index < len(statements) - 1: statements[index] += statements[index + 1] indices.append(index + 1) - elif any( - statement.strip().startswith(ending_character) - for ending_character in PYTHON_LINE["ending"] - ): + elif any(statement.strip().startswith(ending_character) for ending_character in PYTHON_LINE["ending"]): statements[index - 1] += statement indices.append(index) @@ -205,11 +196,7 @@ def read_setup_py(filename: str) -> dict[str, Any]: statements = read_python_file(filename) setup_parameters = {} - setup_calls = { - index: statement - for index, statement in enumerate(statements) - if "setup(" in statement - } + setup_calls = {index: statement for index, statement in enumerate(statements) if "setup(" in statement} if len(setup_calls) > 0: if len(setup_calls) > 1: @@ -239,20 +226,17 @@ def read_setup_py(filename: str) -> dict[str, Any]: for parameter in list(setup_parameters): value = setup_parameters[parameter] if isinstance(value, Mapping) and any(key == "" for key in value): - setup_parameters[parameter] = { - key if key != "" else "*": entry for key, entry in value.items() - } + setup_parameters[parameter] = {key if key != "" else "*": entry for key, entry in value.items()} return setup_parameters -def inify(value: Any, indent: str = None) -> str: +def inify(value: Any, indent: str | None = None) -> str: if indent is None: indent = SETUP_CFG_INDENT if isinstance(value, Mapping): value = "\n" + "\n".join( - f'{key}{":" if "find" in value else " ="} {inify(value=entry, indent=indent)}' - for key, entry in value.items() + f'{key}{":" if "find" in value else " ="} {inify(value=entry, indent=indent)}' for key, entry in value.items() ) elif isinstance(value, Collection) and not isinstance(value, str): value = "\n" + "\n".join(f"{indent}{entry}" for entry in value) @@ -262,9 +246,7 @@ def inify(value: Any, indent: str = None) -> str: return value -def inify_mapping( - mapping: Mapping[str, Any], name: str, level: int = 0 -) -> dict[str, Union[str, dict[str, str]]]: +def inify_mapping(mapping: Mapping[str, Any], name: str, level: int = 0) -> dict[str, str | dict[str, str]]: output = {name: {}} for key, value in mapping.items(): if not isinstance(value, Mapping): diff --git a/peppyproject/tables.py b/peppyproject/tables.py index a6968b5..7d61b7b 100644 --- a/peppyproject/tables.py +++ b/peppyproject/tables.py @@ -1,22 +1,24 @@ import warnings +from collections.abc import Mapping from pathlib import Path -from typing import Any, Mapping, Union +from typing import TYPE_CHECKING, Any, Union import tomli_w import typepigeon from peppyproject.base import ConfigurationTable, to_dict from peppyproject.tools import CoverageTable, SetuptoolsTable -from peppyproject.tools.base import ToolTable from peppyproject.tools.flake8 import Flake8Table from peppyproject.tools.ruff import RuffTable from peppyproject.tools.setuptools_scm import SetuptoolsSCMTable +if TYPE_CHECKING: + from peppyproject.tools.base import ToolTable + class ProjectMetadata(ConfigurationTable): - """ - PEP621 project metadata configuration - https://peps.python.org/pep-0621/#table-name + """PEP621 project metadata configuration + https://peps.python.org/pep-0621/#table-name. """ name = "project" @@ -39,11 +41,9 @@ class ProjectMetadata(ConfigurationTable): "dynamic": list[str], } - def __setitem__(self, key: str, value: Any): + def __setitem__(self, key: str, value: Any) -> None: directory = Path( - self._ConfigurationTable__from_directory - if hasattr(self, "_ConfigurationTable__from_directory") - else ".", + self._ConfigurationTable__from_directory if hasattr(self, "_ConfigurationTable__from_directory") else ".", ) filenames = [filename.name for filename in directory.iterdir()] if value is not None: @@ -67,39 +67,23 @@ def __setitem__(self, key: str, value: Any): if isinstance(value, str) and value in filenames: license_filename = value else: - license_files = [ - filename - for filename in filenames - if "license" in filename.lower() - ] + license_files = [filename for filename in filenames if "license" in filename.lower()] if len(license_files) > 0: if len(license_files) > 1: warnings.warn( f"multiple license files found; {license_files}", ) license_filename = license_files[0] - value = ( - {"file": license_filename, "content-type": "text/plain"} - if license_filename is not None - else None - ) + value = {"file": license_filename, "content-type": "text/plain"} if license_filename is not None else None elif key == "readme": if isinstance(value, Mapping) and "text" in value: value = value["text"] if isinstance(value, str): if value in filenames: - content_type = ( - "text/markdown" - if Path(value).suffix.lower() == ".md" - else "text/x-rst" - ) + content_type = "text/markdown" if Path(value).suffix.lower() == ".md" else "text/x-rst" value = {"file": value, "content-type": content_type} else: - readme_files = [ - filename - for filename in filenames - if "readme" in filename.lower() - ] + readme_files = [filename for filename in filenames if "readme" in filename.lower()] if len(readme_files) > 0: if len(readme_files) > 1: warnings.warn( @@ -133,17 +117,14 @@ def __setitem__(self, key: str, value: Any): for entry_point in entry_points.splitlines() if len(entry_point) > 0 ] - value[entry_point_location] = { - key: value for key, value in entry_points - } + value[entry_point_location] = dict(entry_points) super().__setitem__(key, value) class BuildConfiguration(ConfigurationTable): - """ - PEP517 build system configuration - https://peps.python.org/pep-0517/#source-trees + """PEP517 build system configuration + https://peps.python.org/pep-0517/#source-trees. """ name = "build-system" @@ -160,18 +141,14 @@ def default_setuptools(cls): configuration["build-backend"] = "setuptools.build_meta" if configuration["requires"] is None or len(configuration["requires"]) == 0: configuration["requires"] = ["setuptools>=61.2", "wheel"] - elif not any( - "setuptools" in requirement for requirement in configuration["requires"] - ): + elif not any("setuptools" in requirement for requirement in configuration["requires"]): configuration["requires"].append("setuptools>=61.2") return configuration class ToolsTable(ConfigurationTable): - """ - abstraction of the top-level ``[tool]`` table in ``pyproject.toml`` - """ + """abstraction of the top-level ``[tool]`` table in ``pyproject.toml``.""" name = "tool" fields = { @@ -183,15 +160,11 @@ class ToolsTable(ConfigurationTable): } start_with_placeholders = False - def __init__(self, **kwargs): + def __init__(self, **kwargs) -> None: super().__init__(**kwargs) - def __setitem__(self, table_name: str, table: "ToolTable"): - if ( - table_name in self.fields - and self.fields[table_name] is not None - and table is not None - ): + def __setitem__(self, table_name: str, table: "ToolTable") -> None: + if table_name in self.fields and self.fields[table_name] is not None and table is not None: configuration = self.fields[table_name]() configuration.update(table) table = configuration @@ -200,11 +173,7 @@ def __setitem__(self, table_name: str, table: "ToolTable"): def update(self, items: Mapping): for key, value in items.items(): if value is not None: - if ( - key in self - and isinstance(self[key], Mapping) - and isinstance(value, Mapping) - ): + if key in self and isinstance(self[key], Mapping) and isinstance(value, Mapping): self[key].update(value) else: self[key] = value @@ -214,7 +183,5 @@ def configuration(self) -> str: tables = self._ConfigurationTable__toml for table_name, table in tables.items(): if isinstance(table, ConfigurationTable): - tables[table_name] = { - key: value for key, value in table.items() if value is not None - } + tables[table_name] = {key: value for key, value in table.items() if value is not None} return tomli_w.dumps(to_dict({"tool": tables})) diff --git a/peppyproject/tools/base.py b/peppyproject/tools/base.py index 90b1cbd..e066826 100644 --- a/peppyproject/tools/base.py +++ b/peppyproject/tools/base.py @@ -5,11 +5,9 @@ class ToolTable(ConfigurationTable, ABC): - """ - abstraction of an individual tool configuration - """ + """abstraction of an individual tool configuration.""" - def __init__(self, **kwargs: dict[str, Any]): + def __init__(self, **kwargs: dict[str, Any]) -> None: super().__init__(**kwargs) if self.name is not None and not self.name.startswith("tool."): message = f'"{self.name}" table name must start with `tool.`' diff --git a/peppyproject/tools/flake8.py b/peppyproject/tools/flake8.py index e5e0904..94a341f 100644 --- a/peppyproject/tools/flake8.py +++ b/peppyproject/tools/flake8.py @@ -2,9 +2,8 @@ class Flake8Table(ToolTable): - """ - ``flake8`` configuration - https://flake8.pycqa.org/en/latest/user/options.html#options-and-their-descriptions + """``flake8`` configuration + https://flake8.pycqa.org/en/latest/user/options.html#options-and-their-descriptions. """ name = "tool.flake8" diff --git a/peppyproject/tools/ruff.py b/peppyproject/tools/ruff.py index 106551c..9d7cb26 100644 --- a/peppyproject/tools/ruff.py +++ b/peppyproject/tools/ruff.py @@ -4,9 +4,8 @@ class RuffTable(ToolTable): - """ - ``ruff`` configuration - https://github.com/charliermarsh/ruff#reference + """``ruff`` configuration + https://github.com/charliermarsh/ruff#reference. """ name = "tool.ruff" diff --git a/peppyproject/tools/setuptools.py b/peppyproject/tools/setuptools.py index 4d02045..eba3e57 100644 --- a/peppyproject/tools/setuptools.py +++ b/peppyproject/tools/setuptools.py @@ -4,9 +4,8 @@ class SetuptoolsTable(ToolTable): - """ - ``setuptools`` configuration - https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#setuptools-specific-configuration + """``setuptools`` configuration + https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#setuptools-specific-configuration. """ name = "tool.setuptools" diff --git a/pyproject.toml b/pyproject.toml index 0a4855f..04f99f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,9 +65,9 @@ extend-select = [ 'D', # pydocstyle (docstring style guide) 'UP', # pyupgrade (upgrade code to modern python) 'YTT', # flake8-2020 (system version info) - 'ANN', # flake8-annotations (best practices for type annotations) + #'ANN', # flake8-annotations (best practices for type annotations) 'S', # flake8-bandit (security checks) - 'BLE', # flake8-blind-except (prevent blind except statements) + #'BLE', # flake8-blind-except (prevent blind except statements) 'B', # flake8-bugbear (prevent common gotcha bugs) 'A', # flake8-builtins (prevent shadowing of builtins) 'C4', # flake8-comprehensions (best practices for comprehensions) @@ -84,9 +84,9 @@ extend-select = [ 'Q', # flake8-quotes (best practices for quotes) 'RSE', # flake8-raise (best practices for raising exceptions) 'RET', # flake8-return (best practices for return statements) - 'SLF', # flake8-self (prevent private member access) + #'SLF', # flake8-self (prevent private member access) 'SLOT', # flake8-slots (require __slots__ for immutable classes) - 'SIM', # flake8-simplify (suggest simplifications to code where possible) + #'SIM', # flake8-simplify (suggest simplifications to code where possible) 'TID', # flake8-tidy-imports (prevent banned api and best import practices) 'TCH', # flake8-type-checking (move type checking imports into type checking blocks) 'INT', # flake8-gettext (when to use printf style strings) @@ -103,11 +103,21 @@ extend-select = [ 'RUF', # ruff specific checks ] ignore = [ + 'PERF203', # `try`-`except` within a loop incurs performance overhead + 'B008', + 'B028', + 'PLW2901', # `for` loop variable overwritten by assignment target + 'PTH123', # use `Path.open()` instead of `open()` 'ISC001', # interferes with formatter 'PLR0912', # Too many branches 'PLR0913', # Too many arguments 'PLR0915', # Too many statements 'PLR2004', # Magic value used in comparison + 'E722', # Do not use bare `except` + + 'S101', # use of `assert` detected + 'INP001', # part of an implicit namespace package. Add an `__init__.py`. + 'RUF012', # mutable class variable # Pydocstyle (to fix over time 'D100', # Undocumented public module @@ -115,6 +125,8 @@ ignore = [ 'D102', # Undocumented public method 'D103', # Undocumented public function 'D104', # Undocumented public package + 'D105', # Undocumented magic function + 'D107', # Missing docstring in `__init__` 'D205', # 1 blank line required between summary line and description 'D401', # First line of docstring should be in imperative mood 'D404', # First word of docstring should not be This diff --git a/tests/data/input/pyproject_toml/pytest.ini b/tests/data/input/pyproject_toml/pytest.ini index d155c51..00cdee0 100644 --- a/tests/data/input/pyproject_toml/pytest.ini +++ b/tests/data/input/pyproject_toml/pytest.ini @@ -1,4 +1,3 @@ [pytest] markers = soctests: run only the SOC tests in the suite. - \ No newline at end of file diff --git a/tests/data/input/pyproject_toml/tox.ini b/tests/data/input/pyproject_toml/tox.ini index 5f3d9f5..633775f 100644 --- a/tests/data/input/pyproject_toml/tox.ini +++ b/tests/data/input/pyproject_toml/tox.ini @@ -107,4 +107,4 @@ skip_install = true deps = build commands = - python -m build . \ No newline at end of file + python -m build . diff --git a/tests/data/input/setup_cfg/docs/conf.py b/tests/data/input/setup_cfg/docs/conf.py index d9b7378..dea48e0 100644 --- a/tests/data/input/setup_cfg/docs/conf.py +++ b/tests/data/input/setup_cfg/docs/conf.py @@ -439,7 +439,7 @@ def check_sphinx_version(expected_version): # The format is a list of tuples containing the path and title. # epub_pre_files = [] -# HTML files shat should be inserted after the pages created by sphinx. +# HTML files that should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. # epub_post_files = [] diff --git a/tests/data/input/setup_py/README.rst b/tests/data/input/setup_py/README.rst index 9ade8ff..01f478e 100644 --- a/tests/data/input/setup_py/README.rst +++ b/tests/data/input/setup_py/README.rst @@ -13,7 +13,7 @@ web sites corresponding to each project (http://hst-crds.stsci.edu or https://jwst-crds.stsci.edu/) which record information about reference files and provide related services. -CRDS development is occuring at: +CRDS development is occurring at: `Project's github page `_. CRDS is also available for installation as part of ``stenv``: @@ -49,7 +49,7 @@ File Submission Installation For performing the file submission role, CRDS includes additional dependencies and can be trickier to install. -Addding CRDS to an Existing Environment +Adding CRDS to an Existing Environment +++++++++++++++++++++++++++++++++++++++ You can install/upgrade CRDS and it's dependencies in your current environment diff --git a/tests/test_write.py b/tests/test_write.py index f016885..fc1eadc 100644 --- a/tests/test_write.py +++ b/tests/test_write.py @@ -17,8 +17,8 @@ def test_to_file(directory, tmp_path): configuration = PyProjectConfiguration.from_directory(input_path) configuration.to_file(test_path) - with open(reference_path, "rb") as reference_file: + with Path.open(reference_path, "rb") as reference_file: reference_tomli = tomli.load(reference_file) - with open(test_path, "rb") as test_file: + with Path.open(test_path, "rb") as test_file: assert tomli.load(test_file) == reference_tomli