[project]
name = "remedapy"
version = "1.0.1"
description = "Data-first and data-last utility library for python. A port of Remeda.js."
readme = "README.md"
license = { file = "LICENSE" }
classifiers = [
    "License :: OSI Approved :: MIT License",
]
authors = [
    { name = "Artur Mostowski", email = "artur.mostowski@protonmail.com" }
]
requires-python = ">=3.11"
dependencies = [
    "typing-extensions>=4.15.0",
]

[dependency-groups]
dev = [
    "basedpyright>=1.37.2",
    "chevron>=0.14.0",
    "numpydoc>=1.10.0",
    "pytest>=9.0.2",
    "pytest-cov>=7.0.0",
    "pytest-xdist>=3.8.0",
    "ruff>=0.14.14",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = [
    "src/remedapy"
]

[[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
publish-url = "https://test.pypi.org/legacy/"
explicit = true

[project.urls]
Repository = "https://codeberg.org/Vulwsztyn/remedapy"
Homepage = "https://codeberg.org/Vulwsztyn/remedapy"
Issues = "https://codeberg.org/Vulwsztyn/remedapy/issues"

[tool.pyright]
typeCheckingMode = "strict"
reportImplicitOverride = true


[tool.coverage.report]
exclude_also = [
    "def __repr__",
]

[tool.ruff]
# https://docs.astral.sh/ruff/configuration/
exclude = [
    ".git",
    ".pytest_cache",
    ".ruff_cache",
    ".vscode",
]

line-length = 120
indent-width = 4

target-version = "py311"

[tool.ruff.lint]
select = [
    # https://pycodestyle.pycqa.org/en/latest/\
    "E",
    # pyflakes
    "F",
    # equivalent of flake-commas
    # "COM812", # ruff told me to disable it
    # equivalent of flake8-quotes
    # "Q003", # ruff told me to disable it
    # equivalent of flake8-docstrings
    "D",
    # equivalent of flake8-bugbear
    "B",
    # pystylecode warnings
    "W",
    # McCabe complexity
    # "C901",
    # pyupgrade
    "UP",
    # https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf
    # "RUF005", # Consider {expression} instead of concatenation
    "RUF007", # Prefer itertools.pairwise() over zip() when iterating over successive pairs
    "RUF008", # Do not use mutable default values for dataclass attributes
    "RUF009", # Do not perform function call {name} in dataclass defaults
    # "RUF010", # Use explicit conversion flag
    # "RUF011", # Dictionary comprehension uses static key: {key} remapped to `B035`
    # "RUF012", # Mutable class attributes should be annotated with typing.ClassVar
    "RUF013", # PEP 484 prohibits implicit Optional
    "RUF015", # Prefer next({iterable}) over single element slice
    "RUF016", # Slice in indexed access to type {value_type} uses type {index_type} instead of an integer
    "RUF017", # Avoid quadratic list summation
    "RUF018", # Avoid assignment expressions in assert statements
    "RUF019", # Unnecessary key check before dictionary access
    "RUF020", # {never_like} | T is equivalent to T
    "RUF021", # Parenthesize a and b expressions when chaining and and or together, to make the precedence clear
    "RUF024", # Do not pass mutable objects as values to dict.fromkeys
    # "RUF025", # Unnecessary dict comprehension for iterable; use dict.fromkeys instead
    "RUF026", # default_factory is a positional-only argument to defaultdict
    "RUF100", # unused noqa
    "RUF101", # redirected noqa
    "C4", # flake8-comprehensions
    "PGH" # blanket noqa, blanket type ignore, and invalid mock access
]
ignore = [
    # "B904", # Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling
    # "B905", # `zip()` without an explicit `strict=` parameter
    "D100", # Missing docstring in public module
    "D101", # Missing docstring in public class
    "D102", # Missing docstring in public method
    "D103", # Missing docstring in public function
    "D104", # Missing docstring in public package
    "D105", # Missing docstring in magic method
    "D107", # Missing docstring in public __init__
    "E741", # Avoid using variable names that are single characters
    # "D200", # One-line docstring should fit on one line
    "D203", # 1 blank line required before class docstring
    # "D205", # 1 blank line required between summary line and description
    "D212", # Multi-line docstring summary should start at the first line i.e. """Comment.\nBla bla bla"""
    "D401", # First line of docstring should be in imperative mood: "Customer ns in list display."
    # "D404", # First word of the docstring should not be "This"
    # # The next 3 would change part of docstring
    # # See also:
    # #     bla
    # # into
    # # See Also
    # # ________
    # #     bla
    # "D405", # see comment above D405
    # "D406", # see comment above D405
    # "D407", # see comment above D405
    # "D412", # No blank lines allowed between a section header and its content
    # "D413", # Missing blank line after last section. Wants "sections" in docstrings to have a blank line after.
    # "E226", # Missing whitespace around arithmetic operator
    # "E251", # Unexpected-spaces-around-keyword-parameter-equals. Rule is unstable and in preview.
    # "E721", # Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
    # "E302", # Checks for missing blank lines between top level functions and classes.
    # "E303", # Two blank lines are expected between functions and classes blank line is expected between class methods.
    # "W391", # There should be one, and only one, blank line at the end of each file.
    # "C400", # Unnecessary `dict\list\set` call (rewrite as a literal) - forces [a for a in x if a] instead of list(a for a in x if a) etc
    # "C401", # Unnecessary generator (rewrite as a `set` comprehension) - forces {x['a'] for x in y} instead of set(x['a'] for x in y)
    # "C408", # Unnecessary collection call (rewrite as a literal) - forces {"a": x['a']} instead of dict(a=x['a'])
    # "C416", # Unnecessary `list\dict\set` comprehension (rewrite using `list\dict\set()`)
    # "C420", # Unnecessary dict comprehension for iterable; use `dict.fromkeys` instead - forces dict.fromkeys(x, 1) instead of {a: 1 for a in x}
    # "UP006",
    # "UP007",
    # "UP028", # Replace `yield` over `for` loop with `yield from`. I want `for` loops for debugging.
    # "UP045",
]

# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []

# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"


[tool.ruff.format]
quote-style = "single"
indent-style = "space"

# Respect magic trailing commas.
skip-magic-trailing-comma = false

line-ending = "auto"

[tool.ruff.lint.per-file-ignores]
"src/remedapy/clamp.py" = ["PGH003"]
"src/remedapy/negate.py" = ["PGH003"]
"src/remedapy/get.py" = ["D417"]

