[build-system]
build-backend = "setuptools.build_meta"

requires = [ "setuptools>=77" ]

[project]
name = "pylint"
description = "python code static checker"
readme = "README.rst"
keywords = [ "lint", "linter", "python", "static code analysis" ]
license = "GPL-2.0-or-later"
license-files = [ "LICENSE", "CONTRIBUTORS.txt" ]
authors = [
  { name = "Python Code Quality Authority", email = "code-quality@python.org" },
]
requires-python = ">=3.10.0"
classifiers = [
  "Development Status :: 6 - Mature",
  "Environment :: Console",
  "Intended Audience :: Developers",
  "Operating System :: OS Independent",
  "Programming Language :: Python",
  "Programming Language :: Python :: 3 :: Only",
  "Programming Language :: Python :: 3.10",
  "Programming Language :: Python :: 3.11",
  "Programming Language :: Python :: 3.12",
  "Programming Language :: Python :: 3.13",
  "Programming Language :: Python :: 3.14",
  "Programming Language :: Python :: Implementation :: CPython",
  "Programming Language :: Python :: Implementation :: PyPy",
  "Topic :: Software Development :: Debuggers",
  "Topic :: Software Development :: Quality Assurance",
  "Topic :: Software Development :: Testing",
  "Typing :: Typed",
]
dynamic = [ "version" ]
# All the dependencies of the project will be configured here, once pip fully supports PEP735
# TODO: Remove all requirements.txt files and use this section instead once pip supports PEP735
dependencies = [
  # Also upgrade requirements_test_min.txt.
  # Pinned to dev of second minor update to allow editable installs and fix primer issues,
  # see https://github.com/pylint-dev/astroid/issues/1341
  "astroid>=4.0.2,<=4.1.dev0",
  "colorama>=0.4.5; sys_platform=='win32'",
  "dill>=0.2; python_version<'3.11'",
  "dill>=0.3.6; python_version>='3.11'",
  "dill>=0.3.7; python_version>='3.12'",
  "isort>=5,!=5.13,<10",
  "mccabe>=0.6,<0.8",
  "platformdirs>=2.2",
  "tomli>=1.1; python_version<'3.11'",
  "tomlkit>=0.10.1",
  "typing-extensions>=3.10; python_version<'3.10'",
]

optional-dependencies.spelling = [ "pyenchant~=3.2" ]
optional-dependencies.testutils = [ "gitpython>3" ]

urls."Bug Tracker" = "https://github.com/pylint-dev/pylint/issues"
urls."Discord Server" = "https://discord.com/invite/Egy6P8AMB5"
urls."Docs: Contributor Guide" = "https://pylint.readthedocs.io/en/latest/development_guide/contributor_guide/index.html"
urls."Docs: User Guide" = "https://pylint.readthedocs.io/en/latest/"
urls."homepage" = "https://github.com/pylint-dev/pylint"
urls."Source Code" = "https://github.com/pylint-dev/pylint"
urls."What's New" = "https://pylint.readthedocs.io/en/latest/whatsnew/4/"
scripts.pylint = "pylint:run_pylint"
scripts.pylint-config = "pylint:_run_pylint_config"
scripts.pyreverse = "pylint:run_pyreverse"
scripts.symilar = "pylint:run_symilar"

[dependency-groups]
dev = [
  "contributors-txt>=1",
  "pre-commit",
  "tbump~=6.11.0",
]

test = [
  "coverage~=7.10",
  "pytest-cov>=6.2,<8",
  "pytest-xdist~=3.8",
  "six",
  "tox>=3",
  { include-group = "test-min" },
]

docs = [
  "furo==2025.9.25",
  "sphinx==8.2.3",
  "sphinx-reredirects<1",
  "towncrier>=24.8,<26",
]

# Configuration for the build system
test-min = [
  # Base test dependencies
  "astroid==4.0.2",                     # Pinned to a specific version for tests
  "py~=1.11.0",
  "pytest~=8.4",
  "pytest-benchmark~=5.1",
  "pytest-timeout~=2.4",
  "requests",
  "setuptools; python_version>='3.12'",
  "towncrier>=24.8,<26",
  "typing-extensions~=4.15",
]

[tool.setuptools.packages.find]
include = [ "pylint*" ]

[tool.setuptools.package-dir]
# Simulate editable_mode=compat, described at:
# https://github.com/pypa/setuptools/issues/3767
# TODO: remove after solving root cause described at:
# https://github.com/pylint-dev/astroid/pull/2267#issuecomment-1666642781
"" = "."

[tool.setuptools.package-data]
pylint = [ "testutils/testing_pylintrc", "py.typed" ]

[tool.setuptools.dynamic]
version = { attr = "pylint.__pkginfo__.__version__" }

[tool.ruff]

# ruff is less lenient than pylint and does not make any exceptions
# (for docstrings, strings and comments in particular).
line-length = 115

extend-exclude = [
  "tests/**/data/",
  "tests/**/functional/",
  "tests/input/",
  "tests/regrtest_data/",
]

lint.select = [
  "B",   # bugbear
  "D",   # pydocstyle
  "E",   # pycodestyle
  "F",   # pyflakes
  "I",   # isort
  "PIE", # flake8-pie
  "PTH", # flake8-pathlib
  "PYI", # flake8-pyi
  "RUF", # ruff
  "UP",  # pyupgrade
  "W",   # pycodestyle
]
lint.ignore = [
  "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
  "D106",   # Missing docstring in public nested class
  "D107",   # Missing docstring in `__init__`
  "D205",   # 1 blank line required between summary line and description
  "D400",   # First line should end with a period
  "D401",   # First line of docstring should be in imperative mood
  "PTH100", # `os.path.abspath()` should be replaced by `Path.resolve()`
  "PTH103", # `os.makedirs()` should be replaced by `Path.mkdir(parents=True)`
  "PTH107", # `os.remove()` should be replaced by `Path.unlink()`
  "PTH108", # `os.unlink()` should be replaced by `Path.unlink()`
  "PTH109", # `os.getcwd()` should be replaced by `Path.cwd()`
  "PTH110", # `os.path.exists()` should be replaced by `Path.exists()`
  "PTH111", # `os.path.expanduser()` should be replaced by `Path.expanduser()`
  "PTH112", # `os.path.isdir()` should be replaced by `Path.is_dir()`
  "PTH113", # `os.path.isfile()` should be replaced by `Path.is_file()`
  "PTH118", # `os.path.join()` should be replaced by `Path` with `/` operator
  "PTH119", # `os.path.basename()` should be replaced by `Path.name`
  "PTH120", # `os.path.dirname()` should be replaced by `Path.parent`
  "PTH122", # `os.path.splitext()` should be replaced by `Path.suffix`, `Path.stem`, and `Path.parent`
  "PTH123", # `open()` should be replaced by `Path.open()`
  "PTH207", # Replace `glob` with `Path.glob` or `Path.rglob`
  "PTH208", # Use `pathlib.Path.iterdir()` instead"
  "RUF012", # mutable default values in class attributes
]
lint.pydocstyle.convention = "pep257"

[tool.isort]
profile = "black"
known_third_party = [ "platformdirs", "astroid", "sphinx", "isort", "pytest", "mccabe", "six", "toml" ]
extra_standard_library = [ "_string" ]
skip_glob = [
  "tests/functional/**",
  "tests/input/**",
  "tests/extensions/data/**",
  "tests/regrtest_data/**",
  "tests/data/**",
  "astroid/**",
  "venv/**",
]
src_paths = [ "pylint" ]

[tool.codespell]
ignore-words = [ "custom_dict.txt" ]

# Disabled the spelling files for obvious reason, but also,
# the test file with typing extension imported as 'te' and:
# tests/functional/i/implicit/implicit_str_concat_latin1.py:
#   - bad encoding
# pylint/pyreverse/diagrams.py and tests/pyreverse/test_diagrams.py:
#   - An API from pyreverse use 'classe', and would need to be deprecated
# pylint/checkers/imports.py:
#   - 'THIRDPARTY' is a value from isort that would need to be handled even
#   if isort fix the typo in newer versions
# tests/functional/m/member/member_checks.py:
#   - typos are voluntary to create credible 'no-member'

skip = """
tests/checkers/unittest_spelling.py,\
CODE_OF_CONDUCT.md,\
CONTRIBUTORS.txt,\
pylint/checkers/imports.py,\
pylint/pyreverse/diagrams.py,\
tests/pyreverse/test_diagrams.py,\
tests/functional/i/implicit/implicit_str_concat_latin1.py,\
tests/functional/m/member/member_checks.py,\
tests/functional/t/type/typevar_naming_style_rgx.py,\
tests/functional/t/type/typevar_naming_style_default.py,\
tests/functional/m/member/member_checks_async.py,\
"""

[tool.pyproject-fmt]
max_supported_python = "3.14"

[tool.pytest.ini_options]
testpaths = [ "tests" ]
python_files = [ "*test_*.py" ]
addopts = "--strict-markers"
filterwarnings = [
  "error",
  # Added in Python 3.14
  "ignore:'break' in a 'finally' block:SyntaxWarning",
  "ignore:'return' in a 'finally' block:SyntaxWarning",
  "ignore:'continue' in a 'finally' block:SyntaxWarning",
]
markers = [
  "primer_stdlib: Checks for crashes and errors when running pylint on stdlib",
  "benchmark: Baseline of pylint performance, if this regress something serious happened",
  "timeout: Marks from pytest-timeout.",
  "needs_two_cores: Checks that need 2 or more cores to be meaningful",
]

[tool.mypy]
scripts_are_modules = true
warn_unused_ignores = true
show_error_codes = true
enable_error_code = "ignore-without-code"
strict = true
# TODO: Remove this once pytest has annotations
disallow_untyped_decorators = false

[[tool.mypy.overrides]]
ignore_missing_imports = true
module = [
  "_pytest.*",
  "_string",
  "astroid.*",
  # `colorama` ignore is needed for Windows environment
  "colorama",
  "contributors_txt",
  "coverage",
  "dill",
  "enchant.*",
  "git.*",
  "mccabe",
  "pytest_benchmark.*",
  "pytest",
  "sphinx.*",
]

# For local tests: Enable follow_untyped_imports overwrite for astroid
# [[tool.mypy.overrides]]
# module = ["astroid.*"]
# follow_untyped_imports = true

[tool.pyright]
include = [
  "pylint",
  # not checking the tests yet, but we could
]
pythonVersion = "3.10"
typeCheckingMode = "basic"
reportMissingImports = "none" # pytest / astroid are not detected
reportOptionalMemberAccess = "none" # 150 issues
reportArgumentType = "none" # 12 issues
reportAttributeAccessIssue = "none" # 11 issues
reportInvalidTypeForm = "none" # 6 issues
reportOptionalCall = "none" # 2 issues
reportGeneralTypeIssues = "none" # 1 issue
reportCallIssue = "none" # 1 issue
reportInvalidTypeVarUse = "none" # 2 warnings

[tool.aliases]
test = "pytest"
