Use ruff instead of black+isort (#644)

* Use ruff

* Update .gitignore

* Format code

* Use Ruff on generated code

* Update pre-commit hook

* Wrong commit

* Remove wrong imports

* Update hook

* Format code

* Target Python 3.8

* Reformat

* Pin ruff version
This commit is contained in:
Adrien 2025-01-03 02:59:43 +01:00 committed by GitHub
parent 37fa3abbac
commit f41934a0e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 539 additions and 559 deletions

1
.gitignore vendored
View File

@ -18,3 +18,4 @@ output
.asv .asv
venv venv
.devcontainer .devcontainer
.ruff_cache

View File

@ -2,16 +2,13 @@ ci:
autofix_prs: false autofix_prs: false
repos: repos:
- repo: https://github.com/pycqa/isort - repo: https://github.com/astral-sh/ruff-pre-commit
rev: 5.11.5 rev: v0.7.4
hooks: hooks:
- id: isort - id: ruff-format
args: ["--diff", "src", "tests"]
- repo: https://github.com/psf/black - id: ruff
rev: 23.1.0 args: ["--select", "I", "src", "tests"]
hooks:
- id: black
args: ["--target-version", "py310"]
- repo: https://github.com/PyCQA/doc8 - repo: https://github.com/PyCQA/doc8
rev: 0.10.1 rev: 0.10.1

941
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -13,11 +13,11 @@ packages = [
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.8" python = "^3.8"
black = { version = ">=23.1.0", optional = true } # The Ruff version is pinned. To update it, also update it in .pre-commit-config.yaml
ruff = { version = "~0.7.4", optional = true }
grpclib = "^0.4.1" grpclib = "^0.4.1"
jinja2 = { version = ">=3.0.3", optional = true } jinja2 = { version = ">=3.0.3", optional = true }
python-dateutil = "^2.8" python-dateutil = "^2.8"
isort = { version = "^5.11.5", optional = true }
typing-extensions = "^4.7.1" typing-extensions = "^4.7.1"
betterproto-rust-codec = { version = "0.1.1", optional = true } betterproto-rust-codec = { version = "0.1.1", optional = true }
@ -47,9 +47,16 @@ tomlkit = ">=0.7.0"
protoc-gen-python_betterproto = "betterproto.plugin:main" protoc-gen-python_betterproto = "betterproto.plugin:main"
[tool.poetry.extras] [tool.poetry.extras]
compiler = ["black", "isort", "jinja2"] compiler = ["ruff", "jinja2"]
rust-codec = ["betterproto-rust-codec"] rust-codec = ["betterproto-rust-codec"]
[tool.ruff]
extend-exclude = ["tests/output_*"]
target-version = "py38"
[tool.ruff.lint.isort]
combine-as-imports = true
lines-after-imports = 2
# Dev workflow tasks # Dev workflow tasks
@ -65,13 +72,29 @@ help = "Run tests"
cmd = "mypy src --ignore-missing-imports" cmd = "mypy src --ignore-missing-imports"
help = "Check types with mypy" help = "Check types with mypy"
[tool.poe.tasks]
_black = "black . --exclude tests/output_ --target-version py310"
_isort = "isort . --extend-skip-glob 'tests/output_*/**/*'"
[tool.poe.tasks.format] [tool.poe.tasks.format]
sequence = ["_black", "_isort"] sequence = ["_format", "_sort-imports"]
help = "Apply black and isort formatting to source code" help = "Format the source code, and sort the imports"
[tool.poe.tasks.check]
sequence = ["_check-format", "_check-imports"]
help = "Check that the source code is formatted and the imports sorted"
[tool.poe.tasks._format]
cmd = "ruff format src tests"
help = "Format the source code without sorting the imports"
[tool.poe.tasks._sort-imports]
cmd = "ruff check --select I --fix src tests"
help = "Sort the imports"
[tool.poe.tasks._check-format]
cmd = "ruff format --diff src tests"
help = "Check that the source code is formatted"
[tool.poe.tasks._check-imports]
cmd = "ruff check --select I src tests"
help = "Check that the imports are sorted"
[tool.poe.tasks.docs] [tool.poe.tasks.docs]
cmd = "sphinx-build docs docs/build" cmd = "sphinx-build docs docs/build"
@ -106,23 +129,6 @@ help = "Regenerate the types in betterproto.lib.std.google"
shell = "poe generate && tox" shell = "poe generate && tox"
help = "Run tests with multiple pythons" help = "Run tests with multiple pythons"
[tool.poe.tasks.check-style]
cmd = "black . --check --diff"
help = "Check if code style is correct"
[tool.isort]
py_version = 37
profile = "black"
force_single_line = false
combine_as_imports = true
lines_after_imports = 2
include_trailing_comma = true
force_grid_wrap = 2
src_paths = ["src", "tests"]
[tool.black]
target-version = ['py37']
[tool.doc8] [tool.doc8]
paths = ["docs"] paths = ["docs"]
max_line_length = 88 max_line_length = 88

View File

@ -66,8 +66,7 @@ if sys.version_info >= (3, 10):
from types import UnionType as _types_UnionType from types import UnionType as _types_UnionType
else: else:
class _types_UnionType: class _types_UnionType: ...
...
# Proto 3 data types # Proto 3 data types

View File

@ -1204,9 +1204,9 @@ class EnumDescriptorProto(betterproto.Message):
name: str = betterproto.string_field(1) name: str = betterproto.string_field(1)
value: List["EnumValueDescriptorProto"] = betterproto.message_field(2) value: List["EnumValueDescriptorProto"] = betterproto.message_field(2)
options: "EnumOptions" = betterproto.message_field(3) options: "EnumOptions" = betterproto.message_field(3)
reserved_range: List[ reserved_range: List["EnumDescriptorProtoEnumReservedRange"] = (
"EnumDescriptorProtoEnumReservedRange" betterproto.message_field(4)
] = betterproto.message_field(4) )
""" """
Range of reserved numeric values. Reserved numeric values may not be used Range of reserved numeric values. Reserved numeric values may not be used
by enum values in the same enum declaration. Reserved ranges may not by enum values in the same enum declaration. Reserved ranges may not
@ -1792,9 +1792,9 @@ class FeatureSetDefaults(betterproto.Message):
for the closest matching edition, followed by proto merges. for the closest matching edition, followed by proto merges.
""" """
defaults: List[ defaults: List["FeatureSetDefaultsFeatureSetEditionDefault"] = (
"FeatureSetDefaultsFeatureSetEditionDefault" betterproto.message_field(1)
] = betterproto.message_field(1) )
minimum_edition: "Edition" = betterproto.enum_field(4) minimum_edition: "Edition" = betterproto.enum_field(4)
""" """
The minimum supported edition (inclusive) when this was constructed. The minimum supported edition (inclusive) when this was constructed.

View File

@ -53,9 +53,9 @@ class CodeGeneratorRequest(betterproto.Message):
parameter: str = betterproto.string_field(2) parameter: str = betterproto.string_field(2)
"""The generator parameter passed on the command-line.""" """The generator parameter passed on the command-line."""
proto_file: List[ proto_file: List["betterproto_lib_pydantic_google_protobuf.FileDescriptorProto"] = (
"betterproto_lib_pydantic_google_protobuf.FileDescriptorProto" betterproto.message_field(15)
] = betterproto.message_field(15) )
""" """
FileDescriptorProtos for all files in files_to_generate and everything FileDescriptorProtos for all files in files_to_generate and everything
they import. The files will appear in topological order, so each file they import. The files will appear in topological order, so each file
@ -195,9 +195,9 @@ class CodeGeneratorResponseFile(betterproto.Message):
content: str = betterproto.string_field(15) content: str = betterproto.string_field(15)
"""The file contents.""" """The file contents."""
generated_code_info: ( generated_code_info: "betterproto_lib_pydantic_google_protobuf.GeneratedCodeInfo" = betterproto.message_field(
"betterproto_lib_pydantic_google_protobuf.GeneratedCodeInfo" 16
) = betterproto.message_field(16) )
""" """
Information describing the file content being inserted. If an insertion Information describing the file content being inserted. If an insertion
point is used, this information will be appropriately offset and inserted point is used, this information will be appropriately offset and inserted

View File

@ -1064,9 +1064,9 @@ class EnumDescriptorProto(betterproto.Message):
name: str = betterproto.string_field(1) name: str = betterproto.string_field(1)
value: List["EnumValueDescriptorProto"] = betterproto.message_field(2) value: List["EnumValueDescriptorProto"] = betterproto.message_field(2)
options: "EnumOptions" = betterproto.message_field(3) options: "EnumOptions" = betterproto.message_field(3)
reserved_range: List[ reserved_range: List["EnumDescriptorProtoEnumReservedRange"] = (
"EnumDescriptorProtoEnumReservedRange" betterproto.message_field(4)
] = betterproto.message_field(4) )
""" """
Range of reserved numeric values. Reserved numeric values may not be used Range of reserved numeric values. Reserved numeric values may not be used
by enum values in the same enum declaration. Reserved ranges may not by enum values in the same enum declaration. Reserved ranges may not
@ -1688,9 +1688,9 @@ class FeatureSetDefaults(betterproto.Message):
for the closest matching edition, followed by proto merges. for the closest matching edition, followed by proto merges.
""" """
defaults: List[ defaults: List["FeatureSetDefaultsFeatureSetEditionDefault"] = (
"FeatureSetDefaultsFeatureSetEditionDefault" betterproto.message_field(1)
] = betterproto.message_field(1) )
minimum_edition: "Edition" = betterproto.enum_field(4) minimum_edition: "Edition" = betterproto.enum_field(4)
""" """
The minimum supported edition (inclusive) when this was constructed. The minimum supported edition (inclusive) when this was constructed.

View File

@ -46,9 +46,9 @@ class CodeGeneratorRequest(betterproto.Message):
parameter: str = betterproto.string_field(2) parameter: str = betterproto.string_field(2)
"""The generator parameter passed on the command-line.""" """The generator parameter passed on the command-line."""
proto_file: List[ proto_file: List["betterproto_lib_google_protobuf.FileDescriptorProto"] = (
"betterproto_lib_google_protobuf.FileDescriptorProto" betterproto.message_field(15)
] = betterproto.message_field(15) )
""" """
FileDescriptorProtos for all files in files_to_generate and everything FileDescriptorProtos for all files in files_to_generate and everything
they import. The files will appear in topological order, so each file they import. The files will appear in topological order, so each file

View File

@ -1,4 +1,5 @@
import os.path import os.path
import subprocess
import sys import sys
from .module_validation import ModuleValidator from .module_validation import ModuleValidator
@ -6,8 +7,6 @@ from .module_validation import ModuleValidator
try: try:
# betterproto[compiler] specific dependencies # betterproto[compiler] specific dependencies
import black
import isort.api
import jinja2 import jinja2
except ImportError as err: except ImportError as err:
print( print(
@ -40,20 +39,17 @@ def outputfile_compiler(output_file: OutputTemplate) -> str:
code = body_template.render(output_file=output_file) code = body_template.render(output_file=output_file)
code = header_template.render(output_file=output_file) + code code = header_template.render(output_file=output_file) + code
code = isort.api.sort_code_string(
code=code, # Sort imports, delete unused ones
show_diff=False, code = subprocess.check_output(
py_version=37, ["ruff", "check", "--select", "I,F401", "--fix", "--silent", "-"],
profile="black", input=code,
combine_as_imports=True, encoding="utf-8",
lines_after_imports=2,
quiet=True,
force_grid_wrap=2,
known_third_party=["grpclib", "betterproto"],
) )
code = black.format_str(
src_contents=code, # Format the code
mode=black.Mode(), code = subprocess.check_output(
["ruff", "format", "-"], input=code, encoding="utf-8"
) )
# Validate the generated code. # Validate the generated code.

View File

@ -621,9 +621,7 @@ iso_candidates = """2009-12-12T12:34
2010-02-18T16:00:00.23334444 2010-02-18T16:00:00.23334444
2010-02-18T16:00:00,2283 2010-02-18T16:00:00,2283
2009-05-19 143922 2009-05-19 143922
2009-05-19 1439""".split( 2009-05-19 1439""".split("\n")
"\n"
)
def test_iso_datetime(): def test_iso_datetime():

View File

@ -62,7 +62,7 @@ def test_load_varint_file():
stream.read(2) # Skip until first multi-byte stream.read(2) # Skip until first multi-byte
assert betterproto.load_varint(stream) == ( assert betterproto.load_varint(stream) == (
123456789, 123456789,
b"\x95\x9A\xEF\x3A", b"\x95\x9a\xef\x3a",
) # Multi-byte varint ) # Multi-byte varint
@ -338,7 +338,7 @@ def run_java_single_varint(value: int, tmp_path) -> int:
def test_single_varint(compile_jar, tmp_path): def test_single_varint(compile_jar, tmp_path):
single_byte = (1, b"\x01") single_byte = (1, b"\x01")
multi_byte = (123456789, b"\x95\x9A\xEF\x3A") multi_byte = (123456789, b"\x95\x9a\xef\x3a")
# Write a single-byte varint to a file and have Java read it back # Write a single-byte varint to a file and have Java read it back
returned = run_java_single_varint(single_byte[0], tmp_path) returned = run_java_single_varint(single_byte[0], tmp_path)
@ -351,8 +351,8 @@ def test_single_varint(compile_jar, tmp_path):
def test_multiple_varints(compile_jar, tmp_path): def test_multiple_varints(compile_jar, tmp_path):
single_byte = (1, b"\x01") single_byte = (1, b"\x01")
multi_byte = (123456789, b"\x95\x9A\xEF\x3A") multi_byte = (123456789, b"\x95\x9a\xef\x3a")
over32 = (3000000000, b"\x80\xBC\xC1\x96\x0B") over32 = (3000000000, b"\x80\xbc\xc1\x96\x0b")
# Write two varints to the same file # Write two varints to the same file
with open(tmp_path / "py_multiple_varints.out", "wb") as stream: with open(tmp_path / "py_multiple_varints.out", "wb") as stream: