Skip to content

Commit

Permalink
chore: extended ruff linting
Browse files Browse the repository at this point in the history
Extend and apply several ruff rules and fixes.
  • Loading branch information
nijel committed Nov 13, 2024
1 parent bff54ca commit 047a618
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 230 deletions.
76 changes: 36 additions & 40 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ Homepage = "https://weblate.org/"
"Source Code" = "https://github.com/WeblateOrg/translation-finder"
Twitter = "https://twitter.com/WeblateOrg"

[tool.black]
target-version = ['py39']

[tool.check-manifest]
ignore = [
"LICENSES/*",
Expand All @@ -100,59 +97,58 @@ ignore = [
"W002" # Duplicate test files
]

[tool.isort]
profile = "black"

[tool.pytest.ini_options]
doctest_optionflags = "NORMALIZE_WHITESPACE ALLOW_UNICODE"

[tool.ruff.lint]
extend-safe-fixes = [
"D",
"TCH",
"FLY",
"SIM",
"ANN",
"FA102",
"UP"
]
ignore = [
"CPY001", # TODO: copyright notices
"COM", # CONFIG: No trailing commas
"PT", # CONFIG: Not using pytest
"D10", # TODO: we are missing many docstrings
"D203", # CONFIG: incompatible with D211
"D212", # CONFIG: incompatible with D213
"D401", # TODO: many strings need rephrasing
'ISC001', # CONFIG: formatter
"FURB101", # TODO
"FBT001", # TODO
"FBT002", # TODO
"PLW1641", # TODO
"ARG004", # TODO
"PTH", # TODO: Not using pathlib
"ARG002", # TODO: Unused method argument (mostly for API compatibility)
"ANN001", # TODO: Missing type annotation for function argument
"ANN002", # TODO: Missing type annotation for `*args`
"ANN003", # TODO: Missing type annotation for `**kwargs`
"ANN201", # TODO: Missing return type annotation for public function
"ANN202", # TODO: Missing return type annotation for private function
"ANN204", # TODO: Missing return type annotation for special method
"ANN205", # TODO: Missing return type annotation for staticmethod
"ANN206", # TODO: Missing return type annotation for classmethod
"DOC", # TODO: Ignore all pydoclint rules for now
"PLR6301", # TODO: Method could be a function, class method, or static method
"RUF012", # TODO: Mutable class attributes should be annotated with `typing.ClassVar`
"E501", # WONTFIX: we accept long strings (rest is formatted by black)
"PLW2901" # TODO: overwriting variables inside loop
]
select = [
"E",
"F",
"B",
"T10",
"A",
"C4",
"C90",
"YTT",
"DJ",
"UP",
"D",
"PD",
"PGH",
"PL",
"TRY",
"RUF",
"ERA",
"ICN",
"ISC",
"EXE",
"INP",
"PIE",
"G",
"PYI",
"Q",
"SIM",
"TID",
"RSE",
"T20",
"RET",
"SLF",
"N"
]
preview = true
select = ["ALL"]

[tool.ruff.lint.mccabe]
max-complexity = 16

[tool.ruff.lint.per-file-ignores]
"translation_finder/test_*.py" = ["S301", "S403", "ANN"]

[tool.setuptools]
include-package-data = true
license-files = [
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@

from setuptools import setup


setup()
2 changes: 1 addition & 1 deletion translation_finder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .discovery.result import DiscoveryResult
from .finder import Finder

__all__ = ("Finder", "discover", "DiscoveryResult")
__all__ = ("DiscoveryResult", "Finder", "discover")

# Make sure all discovery modules are imported
import_module("translation_finder.discovery.transifex")
Expand Down
17 changes: 10 additions & 7 deletions translation_finder/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

"""Highlevel API for translation-finder."""

from __future__ import annotations

import sys
from argparse import ArgumentParser
from typing import Optional

from .finder import Finder

Expand All @@ -24,7 +25,7 @@ def discover(
mock=None,
source_language: str = "en",
eager: bool = False,
hint: Optional[str] = None,
hint: str | None = None,
):
"""
High level discovery interface.
Expand All @@ -45,14 +46,14 @@ def discover(
return results


def cli(stdout=None, args=None):
def cli(stdout=None, args=None) -> int:
"""Execution entry point."""
stdout = stdout if stdout is not None else sys.stdout

parser = ArgumentParser(
description="Weblate translation discovery utility.",
epilog="This utility is developed at <{}>.".format(
"https://github.com/WeblateOrg/translation-finder"
"https://github.com/WeblateOrg/translation-finder",
),
)
parser.add_argument("--source-language", help="Source language code", default="en")
Expand All @@ -68,12 +69,14 @@ def cli(stdout=None, args=None):

for pos, match in enumerate(
discover(
params.directory, source_language=params.source_language, eager=params.eager
)
params.directory,
source_language=params.source_language,
eager=params.eager,
),
):
origin = " ({})".format(match.meta["origin"]) if match.meta["origin"] else ""
print(f"== Match {pos + 1}{origin} ==", file=stdout)
for key, value in sorted(match.items()):
print(f"{key:15}: {value}", file=stdout)
print("", file=stdout)
print(file=stdout)
return 0
45 changes: 26 additions & 19 deletions translation_finder/discovery/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

"""Base discovery code."""

from __future__ import annotations

import fnmatch
import re
from itertools import chain
from typing import Optional

from charset_normalizer import detect
from weblate_language_data.country_codes import COUNTRIES
Expand Down Expand Up @@ -65,7 +66,7 @@ class BaseDiscovery:
priority = 1000
uses_template = False

def __init__(self, finder, source_language="en"):
def __init__(self, finder, source_language="en") -> None:
self.finder = finder
self.source_language = source_language

Expand All @@ -75,7 +76,7 @@ def is_country_code(code):
return code in COUNTRIES or code in LOCALES

@classmethod
def is_language_code(cls, code: str):
def is_language_code(cls, code: str) -> bool:
"""Analysis whether passed parameter looks like language code."""
code = code.lower().replace("-", "_")
if code in LANGUAGES and code not in LANGUAGES_BLACKLIST:
Expand Down Expand Up @@ -121,23 +122,25 @@ def get_wildcard(self, part: str):
# Handle prefix-<language>.extension or prefix_<language>.extension
tokens = TOKEN_SPLIT.split(base)
for pos, token in enumerate(tokens):
if token in ("-", "_", "."):
if token in {"-", "_", "."}:
continue
if self.is_language_code(token):
end = pos + 1
if pos + 3 <= len(tokens) and self.is_language_code(
"".join(tokens[pos : pos + 3])
"".join(tokens[pos : pos + 3]),
):
end = pos + 3
# Skip possible language codes in middle of string
if pos != 0 and end != len(tokens) and tokens[end] != ".":
continue
return "{}*{}.{}".format(
"".join(tokens[:pos]), "".join(tokens[end:]), ext
"".join(tokens[:pos]),
"".join(tokens[end:]),
ext,
)
return None

def fill_in_new_base(self, result: dict[str, str]):
def fill_in_new_base(self, result: dict[str, str]) -> None:
if not self.new_base_mask:
return
path = result["filemask"]
Expand All @@ -155,7 +158,8 @@ def fill_in_new_base(self, result: dict[str, str]):
path = path.rsplit("/", 1)[0]
path_wild = path.replace("*", "")
for match in self.finder.filter_files(
new_regex, f"{re.escape(path)}|{re.escape(path_wild)}"
new_regex,
f"{re.escape(path)}|{re.escape(path_wild)}",
):
if new_name == match.parts[-1].lower():
result["new_base"] = "/".join(match.parts)
Expand Down Expand Up @@ -184,27 +188,30 @@ def possible_templates(self, language: str, mask: str):
yield mask.replace(match, replacement)

def fill_in_template(
self, result: dict[str, str], source_language: Optional[str] = None
):
self,
result: dict[str, str],
source_language: str | None = None,
) -> None:
if "template" not in result:
if source_language is None:
source_language = self.source_language
for template in self.possible_templates(
source_language, result["filemask"]
source_language,
result["filemask"],
):
if self.has_storage(template):
result["template"] = template
break

def fill_in_file_format(self, result: dict[str, str]):
def fill_in_file_format(self, result: dict[str, str]) -> None:
if "file_format" not in result:
result["file_format"] = self.file_format

@staticmethod
def adjust_format(result: dict[str, str]):
def adjust_format(result: dict[str, str]) -> None:
return

def discover(self, eager: bool = False, hint: Optional[str] = None):
def discover(self, eager: bool = False, hint: str | None = None):
"""Retun list of translation configurations matching this discovery."""
discovered = set()
for result in self.get_masks(eager=eager, hint=hint):
Expand All @@ -230,10 +237,10 @@ def masks_list(self):
def filter_files(self):
"""Filters possible file matches."""
return self.finder.filter_files(
"|".join(fnmatch.translate(mask) for mask in self.masks_list)
"|".join(fnmatch.translate(mask) for mask in self.masks_list),
)

def get_masks(self, eager: bool = False, hint: Optional[str] = None):
def get_masks(self, eager: bool = False, hint: str | None = None):
"""
Return all file masks found in the directory.
Expand All @@ -258,7 +265,7 @@ def get_masks(self, eager: bool = False, hint: Optional[str] = None):
continue
wildcard = self.get_wildcard(part)
if wildcard:
mask = parts[:]
mask = parts.copy()
match = re.compile(f"(^|[._-]){re.escape(part)}($|[._-])")
for i, current in enumerate(mask):
if match.findall(current):
Expand All @@ -273,7 +280,7 @@ class MonoTemplateDiscovery(BaseDiscovery):

uses_template = True

def fill_in_new_base(self, result: dict[str, str]):
def fill_in_new_base(self, result: dict[str, str]) -> None:
if "new_base" not in result and "template" in result:
result["new_base"] = result["template"]

Expand All @@ -283,7 +290,7 @@ class EncodingDiscovery(BaseDiscovery):

encoding_map = {}

def adjust_format(self, result: dict[str, str]):
def adjust_format(self, result: dict[str, str]) -> None:
encoding = None
matches = [self.finder.mask_matches(result["filemask"])]
if "template" in result:
Expand Down
Loading

0 comments on commit 047a618

Please sign in to comment.