|
| 1 | +[project] |
| 2 | +# This section is needed to avoid writing --no-project everytime when using "uv run" |
| 3 | +# https://github.com/astral-sh/uv/issues/8666 |
| 4 | +name = "typeshed" |
| 5 | +version = "0" |
| 6 | +requires-python = ">=3.9" # Minimum version to run tests, used by uv run |
| 7 | + |
| 8 | +[tool.black] |
| 9 | +line-length = 130 |
| 10 | +target-version = ["py310"] |
| 11 | +skip-magic-trailing-comma = true |
| 12 | + |
| 13 | +[tool.ruff] |
| 14 | +line-length = 130 |
| 15 | +# Oldest supported Python version |
| 16 | +target-version = "py39" |
| 17 | +fix = true |
| 18 | +exclude = [ |
| 19 | + # virtual environment |
| 20 | + ".env", |
| 21 | + ".venv", |
| 22 | + "env", |
| 23 | + # cache directories, etc.: |
| 24 | + ".git", |
| 25 | + ".mypy_cache", |
| 26 | +] |
| 27 | + |
| 28 | +[tool.ruff.lint] |
| 29 | +future-annotations = true |
| 30 | +# Disable all rules on test cases by default: |
| 31 | +# test cases often deliberately contain code |
| 32 | +# that might not be considered idiomatic or modern. |
| 33 | +# |
| 34 | +# Note: some rules that are specifically useful to the test cases |
| 35 | +# are invoked via separate runs of ruff in pre-commit: |
| 36 | +# see our .pre-commit-config.yaml file for details |
| 37 | +exclude = ["**/test_cases/**/*.py"] |
| 38 | +# We still use flake8-pyi to check these (see .flake8 config file); |
| 39 | +# tell ruff not to flag these as e.g. "unused noqa comments" |
| 40 | +external = ["F821", "Y"] |
| 41 | +select = [ |
| 42 | + "A", # flake8-builtins |
| 43 | + "ARG", # flake8-unused-arguments |
| 44 | + "B", # flake8-bugbear |
| 45 | + "C4", # flake8-comprehensions |
| 46 | + "D", # pydocstyle |
| 47 | + "DTZ", # flake8-datetimez |
| 48 | + "EXE", # flake8-executable |
| 49 | + "FA", # flake8-future-annotations |
| 50 | + "FBT", # flake8-boolean-trap |
| 51 | + "FLY", # flynt |
| 52 | + "I", # isort |
| 53 | + "N", # pep8-naming |
| 54 | + "PGH", # pygrep-hooks |
| 55 | + "PIE", # flake8-pie |
| 56 | + "PL", # Pylint |
| 57 | + "PTH", # flake8-use-pathlib |
| 58 | + "RSE", # flake8-raise |
| 59 | + "RUF", # Ruff-specific and unused-noqa |
| 60 | + "SLOT", # flake8-slots |
| 61 | + "T10", # flake8-debugger |
| 62 | + "TD", # flake8-todos |
| 63 | + "TRY", # tryceratops |
| 64 | + "UP", # pyupgrade |
| 65 | + "YTT", # flake8-2020 |
| 66 | + # Flake8 base rules |
| 67 | + "E", # pycodestyle Error |
| 68 | + "F", # Pyflakes |
| 69 | + "W", # pycodestyle Warning |
| 70 | + # Only include flake8-annotations rules that are autofixable. Otherwise leave this to mypy+pyright |
| 71 | + "ANN2", |
| 72 | + # Most refurb rules are in preview and can be opinionated, |
| 73 | + # consider them individually as they come out of preview (last check: 0.13.1) |
| 74 | + "FURB105", # Unnecessary empty string passed to `print` |
| 75 | + "FURB116", # Replace `{function_name}` call with `{display}` |
| 76 | + "FURB122", # Use of `{}.write` in a for loop |
| 77 | + "FURB129", # Instead of calling `readlines()`, iterate over file object directly |
| 78 | + "FURB132", # Use `{suggestion}` instead of `check` and `remove` |
| 79 | + "FURB136", # Replace `if` expression with `{min_max}` call |
| 80 | + "FURB157", # Verbose expression in `Decimal` constructor |
| 81 | + "FURB162", # Unnecessary timezone replacement with zero offset |
| 82 | + "FURB166", # Use of `int` with explicit `base={base}` after removing prefix |
| 83 | + "FURB167", # Use of regular expression alias `re.{}` |
| 84 | + "FURB168", # Prefer `is` operator over `isinstance` to check if an object is `None` |
| 85 | + "FURB169", # Compare the identities of `{object}` and None instead of their respective types |
| 86 | + "FURB177", # Prefer `Path.cwd()` over `Path().resolve()` for current-directory lookups |
| 87 | + "FURB187", # Use of assignment of `reversed` on list `{name}` |
| 88 | + "FURB188", # Prefer `str.removeprefix()` over conditionally replacing with slice. |
| 89 | + # Used for lint.flake8-import-conventions.aliases |
| 90 | + "ICN001", # `{name}` should be imported as `{asname}` |
| 91 | + # PYI: only enable rules that have autofixes and that we always want to fix (even manually), |
| 92 | + # avoids duplicate # noqa with flake8-pyi |
| 93 | + "PYI009", # Empty body should contain `...`, not pass |
| 94 | + "PYI010", # Function body must contain only `...` |
| 95 | + "PYI012", # Class bodies must not contain `pass` |
| 96 | + "PYI013", # Non-empty class bodies must not contain `...` |
| 97 | + "PYI014", # Only simple default values allowed for arguments |
| 98 | + "PYI015", # Only simple default values allowed for assignments |
| 99 | + "PYI016", # Duplicate union member `{}` |
| 100 | + "PYI018", # Private `{type_var_like_kind}` `{type_var_like_name}` is never used |
| 101 | + "PYI019", # Methods like `{method_name}` should return `Self` instead of a custom `TypeVar` |
| 102 | + "PYI020", # Quoted annotations should not be included in stubs |
| 103 | + "PYI025", # Use `from collections.abc import Set as AbstractSet` to avoid confusion with the `set` builtin |
| 104 | + # "PYI026", Waiting for this mypy bug to be fixed: https://github.com/python/mypy/issues/16581 |
| 105 | + "PYI030", # Multiple literal members in a union. Use a single literal, e.g. `Literal[{}]` |
| 106 | + "PYI032", # Prefer `object` to `Any` for the second parameter to `{method_name}` |
| 107 | + "PYI036", # Star-args in `{method_name}` should be annotated with `object` |
| 108 | + "PYI044", # `from __future__ import annotations` has no effect in stub files, since type checkers automatically treat stubs as having those semantics |
| 109 | + "PYI055", # Multiple `type[T]` usages in a union. Combine them into one, e.g., `type[{union_str}]`. |
| 110 | + "PYI058", # Use `{return_type}` as the return value for simple `{method}` methods |
| 111 | + # "PYI059", # TODO: Add when dropping Python 3.9 support |
| 112 | + "PYI061", # Use `None` rather than `Literal[None]` |
| 113 | + "PYI062", # Duplicate literal member `{}` |
| 114 | + "PYI064", # `Final[Literal[{literal}]]` can be replaced with a bare Final |
| 115 | + # flake8-simplify, excluding rules that can reduce performance or readability due to long line formatting |
| 116 | + "SIM101", # Multiple `isinstance` calls for `{name}`, merge into a single call |
| 117 | + "SIM103", # Return the condition `{condition}` directly |
| 118 | + "SIM107", # Don't use return in `try-except` and `finally` |
| 119 | + "SIM109", # Use `{replacement}` instead of multiple equality comparisons |
| 120 | + "SIM112", # Use capitalized environment variable `{expected}` instead of `{actual}` |
| 121 | + "SIM113", # Use `enumerate()` for index variable `{index}` in `for` loop |
| 122 | + "SIM114", # Combine `if` branches using logical `or` operator |
| 123 | + "SIM115", # Use a context manager for opening files |
| 124 | + "SIM118", # Use key `{operator}` dict instead of key `{operator} dict.keys()` |
| 125 | + "SIM201", # Use `{left} != {right}` instead of not `{left} == {right}` |
| 126 | + "SIM202", # Use `{left} == {right}` instead of not `{left} != {right}` |
| 127 | + "SIM208", # Use `{expr}` instead of `not (not {expr})` |
| 128 | + "SIM210", # Remove unnecessary `True if ... else False` |
| 129 | + "SIM211", # Use `not ...` instead of `False if ... else True` |
| 130 | + "SIM212", # Use `{expr_else} if {expr_else} else {expr_body}` instead of `{expr_body} if not {expr_else} else {expr_else}` |
| 131 | + "SIM220", # Use `False` instead of `{name} and not {name}` |
| 132 | + "SIM221", # Use `True` instead of `{name} or not {name}` |
| 133 | + "SIM222", # Use `{expr}` instead of `{replaced}` |
| 134 | + "SIM223", # Use `{expr}` instead of `{replaced}` |
| 135 | + "SIM300", # Yoda condition detected |
| 136 | + "SIM401", # Use `{contents}` instead of an if block |
| 137 | + "SIM905", # Consider using a list literal instead of `str.{}` |
| 138 | + "SIM910", # Use `{expected}` instead of `{actual}` (dict-get-with-none-default) |
| 139 | + "SIM911", # Use `{expected}` instead of `{actual}` (zip-dict-keys-and-values) |
| 140 | + # Don't include TC rules that create a TYPE_CHECKING block or stringifies annotations |
| 141 | + "TC004", # Move import `{qualified_name}` out of type-checking block. Import is used for more than type hinting. |
| 142 | + "TC005", # Found empty type-checking block |
| 143 | + # "TC008", # TODO: Enable when out of preview |
| 144 | + "TC010", # Invalid string member in `X | Y`-style union type |
| 145 | + # Used for lint.flake8-import-conventions.aliases |
| 146 | + "TID251", # `{name}` is banned: {message} |
| 147 | +] |
| 148 | +extend-safe-fixes = [ |
| 149 | + "UP036", # Remove unnecessary `sys.version_info` blocks |
| 150 | +] |
| 151 | +ignore = [ |
| 152 | + ### |
| 153 | + # Rules that can conflict with the formatter (Black) |
| 154 | + # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules |
| 155 | + ### |
| 156 | + "E111", # indentation-with-invalid-multiple |
| 157 | + "E114", # indentation-with-invalid-multiple-comment |
| 158 | + "E117", # over-indented |
| 159 | + "W191", # tab-indentation |
| 160 | + ### |
| 161 | + # Rules we don't want or don't agree with |
| 162 | + ### |
| 163 | + # We're not a library, no need to document everything |
| 164 | + "D1", # Missing docstring in ... |
| 165 | + # Sometimes, an extra blank line is more readable |
| 166 | + "D202", # No blank lines allowed after function docstring |
| 167 | + # Doesn't support split "summary line" |
| 168 | + "D205", # 1 blank line required between summary line and description |
| 169 | + # Used for direct, non-subclass type comparison, for example: `type(val) is str` |
| 170 | + # see https://github.com/astral-sh/ruff/issues/6465 |
| 171 | + "E721", # Do not compare types, use `isinstance()` |
| 172 | + # Highly opinionated, and it's often necessary to violate it |
| 173 | + "PLC0415", # `import` should be at the top-level of a file |
| 174 | + # Leave the size and complexity of tests to human interpretation |
| 175 | + "PLR09", # Too many ... |
| 176 | + # Too many magic number "2" that are preferable inline. https://github.com/astral-sh/ruff/issues/10009 |
| 177 | + "PLR2004", # Magic value used in comparison, consider replacing `{value}` with a constant variable |
| 178 | + # Keep codeflow path separation explicit |
| 179 | + "PLR5501", # Use `elif` instead of `else` then `if`, to reduce indentation |
| 180 | + # Often just leads to redundant more verbose code when needing an actual str |
| 181 | + "PTH208", # Use `pathlib.Path.iterdir()` instead. |
| 182 | + # Allow FIXME |
| 183 | + "TD001", # Invalid TODO tag: `{tag}` |
| 184 | + # Git blame is sufficient |
| 185 | + "TD002", # Missing author in TODO; |
| 186 | + "TD003", # Missing issue link for this TODO |
| 187 | + # Mostly from scripts and tests, it's ok to have messages passed directly to exceptions |
| 188 | + "TRY003", # Avoid specifying long messages outside the exception class |
| 189 | + ### |
| 190 | + # False-positives, but already checked by type-checkers |
| 191 | + ### |
| 192 | + # Ruff doesn't support multi-file analysis yet: https://github.com/astral-sh/ruff/issues/5295 |
| 193 | + "RUF013", # PEP 484 prohibits implicit `Optional` |
| 194 | +] |
| 195 | + |
| 196 | +[tool.ruff.lint.per-file-ignores] |
| 197 | +"*.pyi" = [ |
| 198 | + # A lot of stubs are incomplete on purpose, and that's configured through pyright |
| 199 | + # Some ANN204 (special method) are autofixable in stubs, but not all. |
| 200 | + "ANN2", # Missing return type annotation for ... |
| 201 | + # Ruff 0.8.0 added sorting of __all__ and __slots_. |
| 202 | + # There is no consensus on whether we want to apply this to stubs, so keeping the status quo. |
| 203 | + # See https://github.com/python/typeshed/pull/13108 |
| 204 | + "RUF022", # `__all__` is not sorted |
| 205 | + "RUF023", # `{}.__slots__` is not sorted |
| 206 | + ### |
| 207 | + # Rules that are out of the control of stub authors: |
| 208 | + ### |
| 209 | + # Names in stubs should match the implementation, even if it's ambiguous. |
| 210 | + # https://github.com/astral-sh/ruff/issues/15293 |
| 211 | + "A", # flake8-builtins |
| 212 | + # Stubs can sometimes re-export entire modules. |
| 213 | + # Issues with using a star-imported name will be caught by type-checkers. |
| 214 | + "F403", # `from . import *` used; unable to detect undefined names |
| 215 | + "F405", # may be undefined, or defined from star imports |
| 216 | + # Most pep8-naming rules don't apply for third-party stubs like typeshed. |
| 217 | + # N811 to N814 could apply, but we often use them to disambiguate a name whilst making it look like a more common one |
| 218 | + "N8", # pep8-naming |
| 219 | + # Sometimes __slots__ really is a string at runtime |
| 220 | + "PLC0205", # Class `__slots__` should be a non-string iterable |
| 221 | + # Stubs are allowed to use private variables (pyright's reportPrivateUsage is also disabled) |
| 222 | + "PLC2701", # Private name import from external module |
| 223 | + # Names in stubs should match implementation |
| 224 | + "PLW0211", # First argument of a static method should not be named `{argument_name}` |
| 225 | +] |
| 226 | +"lib/ts_utils/**" = [ |
| 227 | + # Doesn't affect stubs. The only re-exports we have should be in our local lib ts_utils |
| 228 | + "PLC0414", # Import alias does not rename original package |
| 229 | +] |
| 230 | +"*_pb2.pyi" = [ |
| 231 | + # Special autogenerated typing --> typing_extensions aliases |
| 232 | + "ICN001", # `{name}` should be imported as `{asname}` |
| 233 | + # Leave the docstrings as-is, matching source |
| 234 | + "D", # pydocstyle |
| 235 | + # See comment on black's force-exclude config above |
| 236 | + "E501", # Line too long |
| 237 | +] |
| 238 | + |
| 239 | +[tool.ruff.lint.pydocstyle] |
| 240 | +convention = "pep257" # https://docs.astral.sh/ruff/settings/#lint_pydocstyle_convention |
| 241 | + |
| 242 | +[tool.ruff.lint.flake8-import-conventions.aliases] |
| 243 | +# Prevent aliasing these, as it causes false-negatives for certain rules |
| 244 | +typing_extensions = "typing_extensions" |
| 245 | +typing = "typing" |
| 246 | + |
| 247 | +[tool.ruff.lint.flake8-tidy-imports.banned-api] |
| 248 | +"tempfile.NamedTemporaryFile".msg = "Use `ts_util.util.NamedTemporaryFile` instead." |
| 249 | + |
| 250 | +[tool.ruff.lint.isort] |
| 251 | +split-on-trailing-comma = false |
| 252 | +combine-as-imports = true |
| 253 | +extra-standard-library = [ |
| 254 | + # Group these with stdlib |
| 255 | + "_typeshed", |
| 256 | + "typing_extensions", |
| 257 | + # Extra modules not recognized by Ruff |
| 258 | + # Added in Python 3.9 |
| 259 | + "zoneinfo", |
| 260 | + # Added in Python 3.14 |
| 261 | + "compression", |
| 262 | +] |
| 263 | +known-first-party = ["_utils", "ts_utils"] |
| 264 | + |
| 265 | +[tool.typeshed] |
| 266 | +oldest_supported_python = "3.9" |
0 commit comments