Skip to content

Saner linters #58

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
7 changes: 2 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,8 @@ jobs:
pixi-version: v0.39.0
cache: true
environments: lint
- name: Run Pylint, Mypy & Pyright
run: |
pixi run -e lint pylint
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant and incompatible with ruff

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pylint is also included in ruff, so why would it be incompatible?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are many pylint rules that ruff hasn't implemented: astral-sh/ruff#970

Copy link
Contributor Author

@crusaderky crusaderky Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A simple example was

class at:

pylint complains that classes need to be capitalized;
but if you add a # noqa to silence pylint, then ruff fails with an "unnecessary noqa" error

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the way to silence pylint is # pylint: disable=invalid-name

pixi run -e lint mypy
pixi run -e lint pyright
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't have pyright AND mypy in the same project. They will eventually result conflicting with each other, and in fact they did so heavily in #53.
Chose mypy as I found pyright extremely obnoxious and factually wrong in too many cases.

Copy link

@jorenham jorenham Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't have pyright AND mypy in the same project. They will eventually result conflicting with each other, and in fact they did so heavily in #53.

This isn't true at all, and all of my typed projects are proof of this.
In my experience, there are indeed situations where mypy and pyright behave differently. In at least 99% of these cases, this is caused by one of the >1200 confirmed bugs in mypy that aren't present in pyright: https://github.com/erictraut/mypy_issues

Chose mypy as I found pyright extremely obnoxious and factually wrong in too many cases.

Do you have an example of this?

- name: Run Mypy
run: pixi run -e lint mypy

checks:
name: Check ${{ matrix.environment }}
Expand Down
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repos:
additional_dependencies: [black==24.*]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: "v4.6.0"
rev: "v5.0.0"
hooks:
- id: check-added-large-files
- id: check-case-conflict
Expand All @@ -35,14 +35,14 @@ repos:
- id: rst-inline-touching-normal

- repo: https://github.com/rbubley/mirrors-prettier
rev: "v3.3.3"
rev: "v3.4.2"
hooks:
- id: prettier
types_or: [yaml, markdown, html, css, scss, javascript, json]
args: [--prose-wrap=always]

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.6.1"
rev: "v0.8.2"
hooks:
- id: ruff
args: ["--fix", "--show-fixes"]
Expand All @@ -68,13 +68,13 @@ repos:
exclude: .pre-commit-config.yaml

- repo: https://github.com/abravalheri/validate-pyproject
rev: "v0.19"
rev: "v0.23"
hooks:
- id: validate-pyproject
additional_dependencies: ["validate-pyproject-schema-store[all]"]

- repo: https://github.com/python-jsonschema/check-jsonschema
rev: "0.29.1"
rev: "0.30.0"
hooks:
- id: check-dependabot
- id: check-github-workflows
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
</svg>
""",
""", # noqa: E501
"class": "",
},
],
Expand Down
2 changes: 0 additions & 2 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,7 @@ pixi run ipython

```
pixi run pre-commit
pixi run pylint
pixi run mypy
pixi run pyright
```

Alternative environments are available with a subset of the dependencies and
Expand Down
503 changes: 134 additions & 369 deletions pixi.lock

Large diffs are not rendered by default.

71 changes: 25 additions & 46 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ array-api-extra = { path = ".", editable = true }

[tool.pixi.feature.lint.dependencies]
pre-commit = "*"
pylint = "*"
basedmypy = "*"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaced basedmypy with mypy. I think it is an extremely bad idea to diverge from PEPs. Namely, IDE plugins will not support this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is untrue. All mypy IDE plugins and other CI tools also work with basedmypy.

In fact, mypy diverges more from the typing specification that basedmypy does. It also has significantly more bugs.

basedpyright = "*"
mypy = "*"
typing_extensions = ">=4.12.2,<4.13"
# import dependencies for mypy:
array-api-strict = "*"
Expand All @@ -81,11 +79,9 @@ pytest = "*"

[tool.pixi.feature.lint.tasks]
pre-commit-install = { cmd = "pre-commit install" }
pre-commit = { cmd = "pre-commit run -v --all-files --show-diff-on-failure" }
pre-commit = { cmd = "pre-commit run --all-files" }
mypy = { cmd = "mypy", cwd = "." }
pylint = { cmd = ["pylint", "array_api_extra"], cwd = "src" }
pyright = { cmd = "basedpyright", cwd = "." }
lint = { depends-on = ["pre-commit", "pylint", "mypy", "pyright"] }
lint = { depends-on = ["pre-commit", "mypy"] }

[tool.pixi.feature.tests.dependencies]
pytest = ">=6"
Expand Down Expand Up @@ -154,42 +150,34 @@ run.source = ["array_api_extra"]
report.exclude_also = [
'\.\.\.',
'if typing.TYPE_CHECKING:',
'if TYPE_CHECKING:',
]


# mypy

[tool.mypy]
files = ["src", "tests"]
files = ["src", "tests", "vendor_tests"]
python_version = "3.10"
warn_unused_configs = true
strict = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unreachable = true
disallow_untyped_defs = false
disallow_incomplete_defs = false
# data-apis/array-api#589
disallow_any_expr = false
disallow_incomplete_defs = false
disallow_untyped_defs = false
disallow_untyped_decorators = true
ignore_missing_imports = true
no_implicit_optional = true
show_error_codes = true
warn_redundant_casts = true
warn_unused_configs = true
warn_unused_ignores = true
warn_unreachable = true


[[tool.mypy.overrides]]
module = "array_api_extra.*"
disallow_untyped_defs = true
disallow_incomplete_defs = true


# pyright

[tool.basedpyright]
include = ["src", "tests"]
pythonVersion = "3.10"
pythonPlatform = "All"
typeCheckingMode = "all"

# data-apis/array-api#589
reportAny = false
reportExplicitAny = false
# data-apis/array-api-strict#6
reportUnknownMemberType = false
disallow_untyped_defs = true


# Ruff
Expand All @@ -200,11 +188,16 @@ target-version = "py310"
[tool.ruff.lint]
extend-select = [
"B", # flake8-bugbear
"F", # Pyflakes
"I", # isort
"E", # Pycodestyle
"W", # Pycodestyle
"N", # pep8-naming
"ARG", # flake8-unused-arguments
"C4", # flake8-comprehensions
"EM", # flake8-errmsg
"ICN", # flake8-import-conventions
"ISC", # flake8-implicit-str-concat
"G", # flake8-logging-format
"PGH", # pygrep-hooks
"PIE", # flake8-pie
Expand All @@ -220,29 +213,15 @@ extend-select = [
"EXE", # flake8-executable
"NPY", # NumPy specific rules
"PD", # pandas-vet
"UP", # Pyupgrade
]
ignore = [
"PLR09", # Too many <...>
"PLR2004", # Magic value used in comparison
"ISC001", # Conflicts with formatter
"N802", # Function name should be lowercase
"N806", # Variable in function should be lowercase
]

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["T20"]


# Pylint

[tool.pylint]
py-version = "3.10"
ignore-paths = [".*/_version.py"]
reports.output-format = "colorized"
similarities.ignore-imports = "yes"
messages_control.disable = [
"design",
"fixme",
"line-too-long",
"missing-module-docstring",
"missing-function-docstring",
"wrong-import-position",
]
3 changes: 1 addition & 2 deletions src/array_api_extra/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990
from __future__ import annotations

from ._funcs import atleast_nd, cov, create_diagonal, expand_dims, kron, setdiff1d, sinc

__version__ = "0.3.3.dev0"

# pylint: disable=duplicate-code
__all__ = [
"__version__",
"atleast_nd",
Expand Down
7 changes: 2 additions & 5 deletions src/array_api_extra/_funcs.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990
from __future__ import annotations

import typing
import warnings

if typing.TYPE_CHECKING:
from ._lib._typing import Array, ModuleType

from ._lib import _utils
from ._lib._compat import array_namespace
from ._lib._typing import Array, ModuleType

__all__ = [
"atleast_nd",
Expand Down
10 changes: 5 additions & 5 deletions src/array_api_extra/_lib/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
from __future__ import annotations

try:
from ..._array_api_compat_vendor import ( # pyright: ignore[reportMissingImports]
array_namespace, # pyright: ignore[reportUnknownVariableType]
device, # pyright: ignore[reportUnknownVariableType]
from ..._array_api_compat_vendor import (
array_namespace,
device,
)
except ImportError:
from array_api_compat import ( # pyright: ignore[reportMissingTypeStubs]
array_namespace, # pyright: ignore[reportUnknownVariableType]
from array_api_compat import (
array_namespace,
device,
)

Expand Down
22 changes: 5 additions & 17 deletions src/array_api_extra/_lib/_typing.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990
from __future__ import annotations

import typing
from types import ModuleType
from typing import Any

if typing.TYPE_CHECKING:
from typing_extensions import override
# To be changed to a Protocol later (see data-apis/array-api#589)
Array = Any
Device = Any

# To be changed to a Protocol later (see data-apis/array-api#589)
Array = Any # type: ignore[no-any-explicit]
Device = Any # type: ignore[no-any-explicit]
else:

def no_op_decorator(f): # pyright: ignore[reportUnreachable]
return f

override = no_op_decorator

__all__ = ["ModuleType", "override"]
if typing.TYPE_CHECKING:
__all__ += ["Array", "Device"]
__all__ = ["Array", "Device", "ModuleType"]
8 changes: 2 additions & 6 deletions src/array_api_extra/_lib/_utils.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990

import typing

if typing.TYPE_CHECKING:
from ._typing import Array, ModuleType
from __future__ import annotations

from . import _compat
from ._typing import Array, ModuleType

__all__ = ["in1d", "mean"]

Expand Down
9 changes: 3 additions & 6 deletions tests/test_funcs.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990
from __future__ import annotations

import contextlib
import typing
import warnings

# data-apis/array-api-strict#6
import array_api_strict as xp # type: ignore[import-untyped] # pyright: ignore[reportMissingTypeStubs]
import array_api_strict as xp
import numpy as np
import pytest
from numpy.testing import assert_allclose, assert_array_equal, assert_equal
Expand All @@ -19,9 +18,7 @@
setdiff1d,
sinc,
)

if typing.TYPE_CHECKING:
from array_api_extra._lib._typing import Array
from array_api_extra._lib._typing import Array


class TestAtLeastND:
Expand Down
10 changes: 3 additions & 7 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990

import typing
from __future__ import annotations

# data-apis/array-api-strict#6
import array_api_strict as xp # type: ignore[import-untyped] # pyright: ignore[reportMissingTypeStubs]
import array_api_strict as xp
import pytest
from numpy.testing import assert_array_equal

from array_api_extra._lib._typing import Array
from array_api_extra._lib._utils import in1d

if typing.TYPE_CHECKING:
from array_api_extra._lib._typing import Array


# some test coverage already provided by TestSetDiff1D
class TestIn1D:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from __future__ import annotations # https://github.com/pylint-dev/pylint/pull/9990
from __future__ import annotations

import importlib.metadata

Expand Down
2 changes: 1 addition & 1 deletion vendor_tests/test_vendor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def test_vendor_compat():
from ._array_api_compat_vendor import array_namespace

x = xp.asarray([1, 2, 3])
assert array_namespace(x) is xp
assert array_namespace(x) is xp # type: ignore[no-untyped-call]


def test_vendor_extra():
Expand Down
Loading