Skip to content

Commit

Permalink
chore: adopt ruff (0b01001001#359)
Browse files Browse the repository at this point in the history
* chore: adopt ruff

Signed-off-by: Keming <kemingy94@gmail.com>

* incr ci parallel number

Signed-off-by: Keming <kemingy94@gmail.com>

* fix test

Signed-off-by: Keming <kemingy94@gmail.com>

---------

Signed-off-by: Keming <kemingy94@gmail.com>
  • Loading branch information
kemingy authored Oct 27, 2023
1 parent ac67c52 commit db9e74f
Show file tree
Hide file tree
Showing 25 changed files with 125 additions and 110 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
max-parallel: 6
max-parallel: 7
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "pypy3.9"]
os: [ubuntu-latest]
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,6 @@ venv.bak/

# pycharm project files
.idea

# ruff
.ruff_cache/
24 changes: 10 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,27 @@ update_snapshot:
@pytest --snapshot-update

doc:
cd docs && make html
@cd docs && make html

opendoc:
cd docs/build/html && python -m http.server 8765 -b 127.0.0.1
@cd docs/build/html && python -m http.server 8765 -b 127.0.0.1

clean:
rm -rf build/ dist/ *.egg-info .pytest_cache
find . -name '*.pyc' -type f -exec rm -rf {} +
find . -name '__pycache__' -exec rm -rf {} +
@-rm -rf build/ dist/ *.egg-info .pytest_cache
@find . -name '*.pyc' -type f -exec rm -rf {} +
@find . -name '__pycache__' -exec rm -rf {} +

package: clean
python -m build
@python -m build

publish: package
twine upload dist/*
@twine upload dist/*

format:
autoflake --in-place --recursive --remove-all-unused-imports --ignore-init-module-imports ${SOURCE_FILES}
isort --project=spectree ${SOURCE_FILES}
black ${SOURCE_FILES}
@ruff format ${SOURCE_FILES}

lint:
isort --check --diff --project=spectree ${SOURCE_FILES}
black --check --diff ${SOURCE_FILES}
flake8 ${SOURCE_FILES} --count --show-source --statistics --ignore=D203,E203,W503 --max-line-length=88 --max-complexity=15
mypy --install-types --non-interactive ${MYPY_SOURCE_FILES}
@ruff check ${SOURCE_FILES}
@mypy --install-types --non-interactive ${MYPY_SOURCE_FILES}

.PHONY: test doc
2 changes: 1 addition & 1 deletion examples/falcon_asgi_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async def on_post(self, req, resp, source, target):
demo for `query`, `data`, `resp`, `x`
"""
logger.debug(f"{source} => {target}")
logger.debug("%s => %s", source, target)
logger.info(req.context.query)
logger.info(req.context.json)
if random() < 0.5:
Expand Down
2 changes: 1 addition & 1 deletion examples/falcon_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def on_post(self, req, resp, source, target):
demo for `query`, `data`, `resp`, `x`
"""
logger.debug(f"{source} => {target}")
logger.debug("%s => %s", source, target)
logger.info(req.context.query)
logger.info(req.context.json)
if random() < 0.5:
Expand Down
16 changes: 10 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ dependencies = [

[project.optional-dependencies]
dev = [
"autoflake>=1.4,<3.0",
"black>=22.3,<24.0",
"flake8>=4,<7",
"isort~=5.10",
"ruff>=0.1.3",
"mypy>=0.971",
"pre-commit",
"pytest~=7.1",
Expand Down Expand Up @@ -61,8 +58,15 @@ documentation = "https://0b01001001.github.io/spectree/"
repository = "https://github.com/0b01001001/spectree"
changelog = "https://github.com/0b01001001/spectree/releases"

[tool.isort]
profile = "black"
[tool.ruff]
target-version = "py38"
line-length = 88
[tool.ruff.lint]
select = ["E", "F", "B", "G", "I", "SIM", "TID", "PL", "RUF"]
ignore = ["E501", "PLR2004", "RUF012"]
[tool.ruff.pylint]
max-args = 12
max-branches = 15

[tool.mypy]
plugins = ["pydantic.mypy"]
Expand Down
6 changes: 1 addition & 5 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from setuptools import setup


# this file is kept for GitHub's dependency graph

setup(
Expand All @@ -16,10 +15,7 @@
"starlette": ["starlette[full]"],
"dev": [
"pytest~=7.1",
"flake8>=4,<7",
"black>=22.3,<24.0",
"isort~=5.10",
"autoflake>=1.4,<3.0",
"ruff>=0.1.3",
"mypy>=0.971",
"syrupy>=4.0.0",
],
Expand Down
2 changes: 1 addition & 1 deletion spectree/_pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def is_partial_base_model_instance(instance: Any) -> bool:
is_partial_base_model_instance(key) or is_partial_base_model_instance(value)
for key, value in instance.items()
)
if isinstance(instance, list) or isinstance(instance, tuple):
if isinstance(instance, (list, tuple)):
return any(is_partial_base_model_instance(value) for value in instance)
return False

Expand Down
4 changes: 3 additions & 1 deletion spectree/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ def swagger_oauth2_config(self) -> Dict[str, str]:
ref: https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/
"""
if self.client_secret:
warnings.warn("Do not use client_secret in production", UserWarning)
warnings.warn(
"Do not use client_secret in production", UserWarning, stacklevel=1
)

config = self.dict(
include={
Expand Down
4 changes: 2 additions & 2 deletions spectree/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ValidationErrorElement(BaseModel):
...,
title="Error message",
)
type: str = Field( # noqa: WPS125
type: str = Field(
...,
title="Error type",
)
Expand Down Expand Up @@ -111,7 +111,7 @@ class SecuritySchemeData(BaseModel):

@root_validator
def check_type_required_fields(cls, values: dict):
exist_fields = {key for key in values.keys() if values[key]}
exist_fields = {key for key in values if values[key]}
if not values.get("type"):
raise ValueError("Type field is required")

Expand Down
6 changes: 3 additions & 3 deletions spectree/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<redoc spec-url='{spec_url}'></redoc>
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>
</body>
</html>""", # noqa: E501
</html>""",
# https://swagger.io
"swagger": """
<!-- HTML for static distribution bundle build -->
Expand Down Expand Up @@ -101,7 +101,7 @@
}}
</script>
</body>
</html>""", # noqa: E501
</html>""",
"swagger/oauth2-redirect.html": """
<!DOCTYPE html>
<html lang="en-US">
Expand Down Expand Up @@ -177,5 +177,5 @@
}});
</script>
</body>
</html>""", # noqa: E501
</html>""",
}
21 changes: 10 additions & 11 deletions spectree/plugins/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
Union,
)

from .._pydantic import is_partial_base_model_instance, serialize_model_instance
from .._types import JsonType, ModelType, OptionalModelType
from ..config import Configuration
from ..response import Response
from spectree._pydantic import is_partial_base_model_instance, serialize_model_instance
from spectree._types import JsonType, ModelType, OptionalModelType
from spectree.config import Configuration
from spectree.response import Response

if TYPE_CHECKING:
# to avoid cyclic import
from ..spec import SpecTree
from spectree.spec import SpecTree


class Context(NamedTuple):
Expand Down Expand Up @@ -157,13 +157,12 @@ def validate_response(
skip_validation = False
if isinstance(response_payload, RawResponsePayload):
final_response_payload = response_payload.payload
elif isinstance(response_payload, validation_model):
skip_validation = True
final_response_payload = serialize_model_instance(response_payload)
else:
if isinstance(response_payload, validation_model):
skip_validation = True
final_response_payload = serialize_model_instance(response_payload)
else:
# non-BaseModel response or partial BaseModel response
final_response_payload = response_payload
# non-BaseModel response or partial BaseModel response
final_response_payload = response_payload

if not skip_validation:
validator = (
Expand Down
11 changes: 6 additions & 5 deletions spectree/plugins/falcon_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
from falcon import HTTP_400, HTTP_415, HTTPError
from falcon.routing.compiled import _FIELD_PATTERN as FALCON_FIELD_PATTERN

from .._pydantic import ValidationError
from .._types import ModelType
from ..response import Response
from .base import BasePlugin, validate_response
from spectree._pydantic import ValidationError
from spectree._types import ModelType
from spectree.plugins.base import BasePlugin, validate_response
from spectree.response import Response


class OpenAPI:
Expand Down Expand Up @@ -124,8 +124,9 @@ def parse_path(self, route, path_parameter_descriptions):
argstr = ""

arg_values = [None, None, None]
for index, match in enumerate(self.INT_ARGS.finditer(argstr)):
for i, match in enumerate(self.INT_ARGS.finditer(argstr)):
name, value = match.group("name"), match.group("value")
index = i
if name:
index = self.INT_ARGS_NAMES.index(name)
arg_values[index] = value
Expand Down
16 changes: 10 additions & 6 deletions spectree/plugins/flask_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
from flask import Blueprint, abort, current_app, jsonify, make_response, request
from werkzeug.routing import parse_converter_args

from .._pydantic import ValidationError
from .._types import ModelType
from ..response import Response
from ..utils import flask_response_unpack, get_multidict_items, werkzeug_parse_rule
from .base import BasePlugin, Context, validate_response
from spectree._pydantic import ValidationError
from spectree._types import ModelType
from spectree.plugins.base import BasePlugin, Context, validate_response
from spectree.response import Response
from spectree.utils import (
flask_response_unpack,
get_multidict_items,
werkzeug_parse_rule,
)


class FlaskPlugin(BasePlugin):
Expand Down Expand Up @@ -47,7 +51,7 @@ def parse_func(self, route: Any):

# view class: https://flask.palletsprojects.com/en/1.1.x/views/
if getattr(func, "view_class", None):
cls = getattr(func, "view_class")
cls = func.view_class
for method in route.methods:
view = getattr(cls, method.lower(), None)
if view:
Expand Down
16 changes: 10 additions & 6 deletions spectree/plugins/quart_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
from quart import Blueprint, abort, current_app, jsonify, make_response, request
from werkzeug.routing import parse_converter_args

from .._pydantic import ValidationError
from .._types import ModelType
from ..response import Response
from ..utils import flask_response_unpack, get_multidict_items, werkzeug_parse_rule
from .base import BasePlugin, Context, validate_response
from spectree._pydantic import ValidationError
from spectree._types import ModelType
from spectree.plugins.base import BasePlugin, Context, validate_response
from spectree.response import Response
from spectree.utils import (
flask_response_unpack,
get_multidict_items,
werkzeug_parse_rule,
)


class QuartPlugin(BasePlugin):
Expand Down Expand Up @@ -50,7 +54,7 @@ def parse_func(self, route: Any):

# view class: https://flask.palletsprojects.com/en/1.1.x/views/
if getattr(func, "view_class", None):
cls = getattr(func, "view_class")
cls = func.view_class
for method in route.methods:
view = getattr(cls, method.lower(), None)
if view:
Expand Down
37 changes: 23 additions & 14 deletions spectree/plugins/starlette_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@
from starlette.responses import HTMLResponse, JSONResponse
from starlette.routing import compile_path

from .._pydantic import BaseModel, ValidationError, serialize_model_instance
from .._types import ModelType
from ..response import Response
from .base import BasePlugin, Context, RawResponsePayload, validate_response
from spectree._pydantic import BaseModel, ValidationError, serialize_model_instance
from spectree._types import ModelType
from spectree.plugins.base import (
BasePlugin,
Context,
RawResponsePayload,
validate_response,
)
from spectree.response import Response

METHODS = {"get", "post", "put", "patch", "delete"}
Route = namedtuple("Route", ["path", "methods", "func"])
Expand Down Expand Up @@ -128,19 +133,23 @@ async def validate(
else:
response = func(*args, **kwargs)

if not skip_validation and resp and response:
if not (
if (
not skip_validation
and resp
and response
and not (
isinstance(response, JSONResponse)
and hasattr(response, "_model_class")
and response._model_class == resp.find_model(response.status_code)
):
try:
validate_response(
validation_model=resp.find_model(response.status_code),
response_payload=RawResponsePayload(payload=response.body),
)
except ValidationError as err:
response = JSONResponse(err.errors(), 500)
)
):
try:
validate_response(
validation_model=resp.find_model(response.status_code),
response_payload=RawResponsePayload(payload=response.body),
)
except ValidationError as err:
response = JSONResponse(err.errors(), 500)

after(request, response, resp_validation_error, instance)

Expand Down
2 changes: 1 addition & 1 deletion spectree/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def __init__(
origin_type = getattr(model, "__origin__", None)
if origin_type is list or origin_type is List:
# type is List[BaseModel]
list_item_type = getattr(model, "__args__")[0]
list_item_type = model.__args__[0] # type: ignore
model = gen_list_model(list_item_type)
self.code_list_item_types[code] = list_item_type
assert issubclass(model, BaseModel), "invalid `pydantic.BaseModel`"
Expand Down
2 changes: 1 addition & 1 deletion spectree/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def bypass(self, func: Callable):
decorator = getattr(func, "_decorator", None)
return bool(decorator and decorator != self)

def validate(
def validate( # noqa: PLR0913 [too-many-arguments]
self,
query: Optional[ModelType] = None,
json: Optional[ModelType] = None,
Expand Down
Loading

0 comments on commit db9e74f

Please sign in to comment.