Skip to content

Commit

Permalink
Migrate from black, flake8 and isort to ruff
Browse files Browse the repository at this point in the history
Re-formatted and improved style to comply with additional rules.
  • Loading branch information
Cito committed Feb 8, 2024
1 parent 0c93b84 commit 4d240d4
Show file tree
Hide file tree
Showing 249 changed files with 2,449 additions and 2,474 deletions.
4 changes: 0 additions & 4 deletions .bandit

This file was deleted.

7 changes: 0 additions & 7 deletions .flake8

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ jobs:
- name: Run code quality tests with tox
run: tox
env:
TOXENV: black,flake8,isort,mypy,docs
TOXENV: ruff,mypy,docs
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install "tox>=4.4,<5" "tox-gh-actions>=3.1,<4"
pip install "tox>=4.12,<5" "tox-gh-actions>=3.2,<4"
- name: Run unit tests with tox
run: tox
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# GraphQL-core 3

GraphQL-core 3 is a Python 3.6+ port of [GraphQL.js](https://github.com/graphql/graphql-js),
GraphQL-core 3 is a Python 3.7+ port of [GraphQL.js](https://github.com/graphql/graphql-js),
the JavaScript reference implementation for [GraphQL](https://graphql.org/),
a query language for APIs created by Facebook.

Expand All @@ -15,7 +15,7 @@ replication of the complete test suite of GraphQL.js, making sure this port is
reliable and compatible with GraphQL.js.

The current stable version 3.2.3 of GraphQL-core is up-to-date with GraphQL.js
version 16.6.0 and supports Python version 3.6 and newer.
version 16.6.0 and supports Python version 3.7 and newer.

You can also try out the latest alpha version 3.3.0a3 of GraphQL-core
which is up-to-date with GraphQL.js version 17.0.0a2.
Expand Down Expand Up @@ -196,13 +196,14 @@ Design goals for the GraphQL-core 3 library were:
(and is now using TypeScript)
* to use [black](https://github.com/ambv/black) to achieve a consistent code style
while saving time and mental energy for more important matters
(we are now using [ruff](https://github.com/astral-sh/ruff) instead)
* to replicate the complete Mocha-based test suite of GraphQL.js
using [pytest](https://docs.pytest.org/)
with [pytest-describe](https://pypi.org/project/pytest-describe/)

Some restrictions (mostly in line with the design goals):

* requires Python 3.6 or newer
* requires Python 3.7 or newer
* does not support some already deprecated methods and options of GraphQL.js
* supports asynchronous operations only via async.io
(does not support the additional executors in GraphQL-core)
Expand Down
1,151 changes: 365 additions & 786 deletions poetry.lock

Large diffs are not rendered by default.

170 changes: 142 additions & 28 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ packages = [
{ include = "docs", format = "sdist" },
{ include = ".bumpversion.cfg", format = "sdist" },
{ include = ".editorconfig", format = "sdist" },
{ include = ".flake8", format = "sdist" },
{ include = ".readthedocs.yaml", format = "sdist" },
{ include = "poetry.lock", format = "sdist" },
{ include = "tox.ini", format = "sdist" },
Expand Down Expand Up @@ -56,28 +55,15 @@ pytest-cov = "^4.1"
pytest-describe = "^2.1"
pytest-timeout = "^2.1"
tox = [
{ version = ">=4.5,<5", python = ">=3.8" },
{ version = ">=4.12,<5", python = ">=3.8" },
{ version = ">=3.28,<4", python = "<3.8" }
]

[tool.poetry.group.lint]
optional = true

[tool.poetry.group.lint.dependencies]
black = "23.3.0"
flake8 = [
{ version = ">=5,<7", python = ">=3.8.1" },
{ version = ">=5,<6", python = "<3.8.1" }
]
flake8-bandit = "^4.1"
flake8-bugbear = [
{ version = "23.5.9", python = ">=3.8.1" },
{ version = "23.3.12", python = "<3.8.1" },
]
isort = [
{ version = "^5.12", python = ">=3.8" },
{ version = "^5.11", python = "<3.8" }
]
ruff = ">=0.2,<0.3"
mypy = "1.3.0"
bump2version = ">=1.0,<2"

Expand All @@ -91,11 +77,147 @@ sphinx = [
]
sphinx_rtd_theme = ">=1,<2"

[tool.bandit]
exclude_dirs = ["tests"]
[tool.ruff]
line-length = 88
target-version = "py37"

[tool.ruff.lint]
select = [
"A", # flake8-builtins
"ANN", # flake8-annotations
"ARG", # flake8-unused-arguments
"B", # flake8-bugbear
"BLE", # flake8-blind-except
"C4", # flake8-comprehensions
"C90", # McCabe cyclomatic complexity
"COM", # flake8-commas
"D", # pydocstyle
"DTZ", # flake8-datetimez
"E", # pycodestyle
"EM", # flake8-errmsg
"ERA", # eradicate
"EXE", # flake8-executable
"F", # Pyflakes
"FBT", # flake8-boolean-trap
"G", # flake8-logging-format
"I", # isort
"ICN", # flake8-import-conventions
"INP", # flake8-no-pep420
"INT", # flake8-gettext
"ISC", # flake8-implicit-str-concat
"N", # pep8-naming
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PL", # Pylint
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
"PYI", # flake8-pyi
"Q", # flake8-quotes
"RET", # flake8-return
"RSE", # flake8-raise
"RUF", # Ruff-specific rules
"S", # flake8-bandit
"SLF", # flake8-self
"SIM", # flake8-simplify
"T10", # flake8-debugger
"T20", # flake8-print
"TCH", # flake8-type-checking
"TID", # flake8-tidy-imports
"TRY", # tryceratops
"UP", # pyupgrade
"W", # pycodestyle
"YTT", # flake8-2020
]
ignore = [
"ANN101", "ANN102", # no type annotation for self and cls needed
"ANN401", # allow explicit Any
"COM812", # allow trailing commas for auto-formatting
"D105", "D107", # no docstring needed for magic methods
"D203", # no blank line before class docstring
"D213", # multi-line docstrings should not start at second line
"D400", "D415", # first line in docstring does not need to be a sentence
"D401", # do not always require imperative mood in first line
"FBT001", "FBT002", "FBT003", # allow boolean parameters
"ISC001", # allow string literal concatenation for auto-formatting
"PGH003", # type ignores do not need to be specific
"PLR2004", # allow some "magic" values
"PYI034", # do not check return value of new method
"TID252", # allow relative imports
"UP006", "UP007", # use old type annotations (for now)
"TRY003", # allow specific messages outside the exception class
]

[tool.ruff.lint.per-file-ignores]
"*/__init__.py" = [
"I001", # imports do not need to be sorted
]
"src/graphql/execution/*" = [
"BLE001", # allow catching blind exception
]
"src/graphql/language/ast.py" = [
"D101", # do not require docstrings
]
"src/graphql/language/parser.py" = [
"RSE102", # raised exception may need to be called
]
"src/graphql/type/introspection.py" = [
"ANN001", "ANN003", "ANN204", "ANN205", # allow missing type annotations
"N803", # allow JavaScript style arguments
]
"src/graphql/utilities/get_introspection_query.py" = [
"D101", # allow missing class docstrings
"N815", # allow JavaScript style class attributes
]
"src/graphql/utilities/type_info.py" = [
"D102", # allow missing method docstrings
]
"src/graphql/validation/rules/*" = [
"D102", # allow missing method docstrings
]
"src/graphql/validation/validation_context.py" = [
"D102", # allow missing method docstrings
]
"tests/*" = [
"ANN001", "ANN002", "ANN003", # allow missing type annotations
"ANN201", "ANN202", "ANN204", "ANN205", # allow missing type annotations
"B011", # allow always failing assertions
"B904", # allow raising exceptions without context
"C901", # allow complex functions
"D100", "D101", "D102", "D103", # allow missing docstrings
"EM101", "EM102", # allow passing literal strings to exceptions
"N802", "N803", "N806", "N815", "N816", # allow JavaScript style names
"PLR0915", # allow many statements
"PT015", # allow always failing assertions
"RUF012", # allow mutable class attributes
"S101", # allow assertions
"S301", # allow pickling
"TRY002", "TRY301", # less strict handling of exceptions
]
"tests/star_wars_schema.py" = [
"A002", # allow shadowin builtins
"ERA001", # allow commented-out code
]
"tests/test_docs.py" = [
"S102", # allow use of exec
]


[tool.ruff.lint.flake8-quotes]
inline-quotes = "double"

[tool.black]
target-version = ["py37", "py38", "py39", "py310", "py311"]
[tool.ruff.lint.mccabe]
max-complexity = 50

[tool.ruff.lint.pylint]
max-args = 15
max-branches = 50
max-returns = 25
max-statements = 125

[tool.ruff.format]
indent-style = "space"
quote-style = "double"
skip-magic-trailing-comma = false

[tool.coverage.run]
branch = true
Expand All @@ -116,7 +238,6 @@ exclude_lines = [
"except ImportError:",
"# Python <",
"raise NotImplementedError",
'raise TypeError\(f?"Unexpected',
"assert False,",
'\s+next\($',
"if MYPY:",
Expand All @@ -126,13 +247,6 @@ exclude_lines = [
]
ignore_errors = true

[tool.isort]
src_paths = ["src", "tests"]
skip_glob = ["src/**/__init__.py"]
profile = "black"
force_single_line = false
lines_after_imports = 2

[tool.mypy]
python_version = "3.11"
check_untyped_defs = true
Expand Down
14 changes: 8 additions & 6 deletions src/graphql/error/graphql_error.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""GraphQL Error"""

from sys import exc_info
from typing import TYPE_CHECKING, Any, Collection, Dict, List, Optional, Union


try:
from typing import TypedDict
except ImportError: # Python < 3.8
Expand All @@ -12,12 +13,12 @@
from typing_extensions import TypeAlias

if TYPE_CHECKING:
from ..language.ast import Node # noqa: F401
from ..language.location import ( # noqa: F401
from ..language.ast import Node
from ..language.location import (
FormattedSourceLocation,
SourceLocation,
)
from ..language.source import Source # noqa: F401
from ..language.source import Source

__all__ = ["GraphQLError", "GraphQLErrorExtensions", "GraphQLFormattedError"]

Expand Down Expand Up @@ -127,6 +128,7 @@ def __init__(
original_error: Optional[Exception] = None,
extensions: Optional[GraphQLErrorExtensions] = None,
) -> None:
"""Initialize a GraphQLError."""
super().__init__(message)
self.message = message

Expand Down Expand Up @@ -201,7 +203,7 @@ def __repr__(self) -> str:
args.append(f"extensions={self.extensions!r}")
return f"{self.__class__.__name__}({', '.join(args)})"

def __eq__(self, other: Any) -> bool:
def __eq__(self, other: object) -> bool:
return (
isinstance(other, GraphQLError)
and self.__class__ == other.__class__
Expand All @@ -220,7 +222,7 @@ def __eq__(self, other: Any) -> bool:
)
)

def __ne__(self, other: Any) -> bool:
def __ne__(self, other: object) -> bool:
return not self == other

@property
Expand Down
15 changes: 6 additions & 9 deletions src/graphql/error/located_error.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"""Located GraphQL Error"""

from contextlib import suppress
from typing import TYPE_CHECKING, Collection, Optional, Union

from ..pyutils import inspect
from .graphql_error import GraphQLError


if TYPE_CHECKING:
from ..language.ast import Node # noqa: F401
from ..language.ast import Node

__all__ = ["located_error"]

Expand All @@ -29,23 +31,18 @@ def located_error(
if isinstance(original_error, GraphQLError) and original_error.path is not None:
return original_error
try:
# noinspection PyUnresolvedReferences
message = str(original_error.message) # type: ignore
except AttributeError:
message = str(original_error)
try:
# noinspection PyUnresolvedReferences
source = original_error.source # type: ignore
except AttributeError:
source = None
try:
# noinspection PyUnresolvedReferences
positions = original_error.positions # type: ignore
except AttributeError:
positions = None
try:
# noinspection PyUnresolvedReferences

with suppress(AttributeError):
nodes = original_error.nodes or nodes # type: ignore
except AttributeError:
pass
return GraphQLError(message, nodes, source, positions, path, original_error)
8 changes: 5 additions & 3 deletions src/graphql/error/syntax_error.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
"""GraphQL Syntax Error"""

from __future__ import annotations # Python < 3.10

from typing import TYPE_CHECKING

from .graphql_error import GraphQLError


if TYPE_CHECKING:
from ..language.source import Source # noqa: F401
from ..language.source import Source

__all__ = ["GraphQLSyntaxError"]


class GraphQLSyntaxError(GraphQLError):
"""A GraphQLError representing a syntax error."""

def __init__(self, source: "Source", position: int, description: str) -> None:
def __init__(self, source: Source, position: int, description: str) -> None:
"""Initialize the GraphQLSyntaxError"""
super().__init__(
f"Syntax Error: {description}", source=source, positions=[position]
)
Expand Down
Loading

0 comments on commit 4d240d4

Please sign in to comment.