Skip to content

Commit

Permalink
Update ruff rules
Browse files Browse the repository at this point in the history
  • Loading branch information
MrThearMan committed Jul 21, 2023
1 parent 170c659 commit a2eb145
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 48 deletions.
11 changes: 6 additions & 5 deletions manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
import sys


def main():
def main() -> None:
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.django.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
msg = (
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
"available on your PYTHONPATH environment variable? "
"Did you forget to activate a virtual environment?"
)
raise ImportError(msg) from exc
execute_from_command_line(sys.argv)


Expand Down
6 changes: 3 additions & 3 deletions pipeline_views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from .views import BasePipelineView

try:
import uvloop # noqa
import uvloop

uvloop.install() # pragma: no cover
except Exception: # noqa
pass # noqa
except ImportError:
pass


__all__ = [
Expand Down
8 changes: 4 additions & 4 deletions pipeline_views/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
]


class NextLogicBlock(Exception):
class NextLogicBlock(Exception): # noqa: N818
"""Used to escape from pipeline logic blocks prematurely.
Saves the kwargs that are given to it for the next step in the pipeline.
"""

def __init__(self, **kwargs: Any):
def __init__(self, **kwargs: Any) -> None:
self.output = kwargs
super().__init__()

@classmethod
def with_output(cls, output: Any):
instance = cls()
def with_output(cls, output: Any) -> "NextLogicBlock":
instance: NextLogicBlock = cls()
instance.output = output
return instance
6 changes: 4 additions & 2 deletions pipeline_views/meta.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import TYPE_CHECKING

from django.utils.encoding import force_str
from rest_framework.fields import DictField, Field, SerializerMethodField
from rest_framework.metadata import SimpleMetadata
Expand All @@ -11,7 +13,7 @@
Serializer,
)

from .typing import TYPE_CHECKING, Any, ClassVar, Union
from .typing import Any, ClassVar, Union

if TYPE_CHECKING:
from .views import BasePipelineView
Expand All @@ -32,7 +34,7 @@ class PipelineMetadata(SimpleMetadata):
skip_fields: ClassVar[set[type[Field]]] = {ReadOnlyField, HiddenField, SerializerMethodField}
used_attrs: ClassVar[list[str]] = ["label", "help_text", "min_length", "max_length", "min_value", "max_value"]

def determine_actions(self, request: Request, view: "BasePipelineView"):
def determine_actions(self, request: Request, view: "BasePipelineView") -> dict[str, Any]:
"""Return information about the fields that are accepted for methods in self.recognized_methods."""
actions = {}
for method in self.recognized_methods & set(view.allowed_methods):
Expand Down
8 changes: 4 additions & 4 deletions pipeline_views/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def request_from_context(self) -> Request:
api_settings.NON_FIELD_ERRORS_KEY: ErrorDetail(
string="Must include a Request object in the context of the Serializer.",
code="request_missing",
)
}
),
},
)
return request

Expand Down Expand Up @@ -53,7 +53,7 @@ def to_internal_value(self, data: dict[str, Any]) -> dict[str, Any]:
ret = self.add_headers(ret)
return ret

def to_representation(self, instance) -> dict[str, Any]:
def to_representation(self, instance: Any) -> dict[str, Any]:
ret = super().to_representation(instance)
ret = self.add_headers(ret)
return ret
Expand Down Expand Up @@ -82,7 +82,7 @@ def to_internal_value(self, data: dict[str, Any]) -> dict[str, Any]:
ret = self.add_cookies(ret)
return ret

def to_representation(self, instance) -> dict[str, Any]:
def to_representation(self, instance: Any) -> dict[str, Any]:
ret = super().to_representation(instance)
ret = self.add_cookies(ret)
return ret
Expand Down
1 change: 0 additions & 1 deletion pipeline_views/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
"Optional",
"ParamSpec",
"Protocol",
"TYPE_CHECKING",
"TypeAlias",
"TypedDict",
"TypeGuard",
Expand Down
17 changes: 9 additions & 8 deletions pipeline_views/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from contextlib import contextmanager
from functools import wraps
from itertools import chain
from typing import TYPE_CHECKING

from django.conf import settings
from django.utils.translation import get_language as current_language
Expand All @@ -16,7 +17,6 @@
BaseModel = None

from .typing import (
TYPE_CHECKING,
Any,
Callable,
DataDict,
Expand Down Expand Up @@ -59,7 +59,7 @@ def is_serializer_class(obj: Any) -> TypeGuard[BaseSerializer]:
return isinstance(obj, type) and issubclass(obj, BaseSerializer)


def is_pydantic_model(obj: Any):
def is_pydantic_model(obj: Any) -> bool:
if BaseModel is None: # pragma: no cover
return False

Expand Down Expand Up @@ -96,10 +96,11 @@ def decorator(*args: P.args, **kwargs: P.kwargs) -> Any:
break

if request is None:
raise ValueError("No Request-object in function parameters.")
msg = "No Request-object in function parameters."
raise ValueError(msg)

with override(get_language(request)):
return item(*args, **kwargs) # type: ignore
return item(*args, **kwargs)

return decorator

Expand All @@ -112,7 +113,7 @@ def context_manager(request: Request) -> Generator[Any, Any, None]:


async def run_parallel(step: tuple[Union[LogicCallable, SerializerType], ...], data: DataDict) -> tuple[DataDict, ...]:
return await asyncio.gather(*(task(**data) for task in step)) # noqa
return await asyncio.gather(*(task(**data) for task in step))


def get_view_method(method: HTTPMethod) -> GenericView:
Expand All @@ -121,16 +122,16 @@ def get_view_method(method: HTTPMethod) -> GenericView:
def inner(
self: "BasePipelineView",
request: Request,
*args: Any,
*args: Any, # noqa: ARG001
**kwargs: Any,
) -> Response:
kwargs.update(
{
key: value
for key, value in getattr(request, source, {}).items()
if key not in getattr(self, f"ignored_{method.lower()}_params", set())
}
},
)
return self.process_request(data=kwargs)

return inner # type: ignore
return inner
24 changes: 14 additions & 10 deletions pipeline_views/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class BasePipelineView(APIView):
ignored_patch_params: ClassVar[set[str]] = {"lang", "format"}
ignored_delete_params: ClassVar[set[str]] = {"lang", "format"}

def __new__(cls, *args, **kwargs):
def __new__(cls, *args: Any, **kwargs: Any) -> "BasePipelineView": # noqa: ARG003,
for key in cls.pipelines:
if not hasattr(cls, key.lower()):
setattr(cls, key.lower(), get_view_method(key))
Expand All @@ -63,11 +63,12 @@ def process_request(self, data: DataDict) -> Response:
def get_pipeline_for_current_request_method(self) -> PipelineLogic:
"""Get pipeline for the current HTTP method."""
try:
return self.pipelines[self.request.method] # type: ignore
return self.pipelines[self.request.method]
except KeyError as missing_method:
raise KeyError(f"Pipeline not configured for HTTP method '{self.request.method}'") from missing_method
msg = f"Pipeline not configured for HTTP method '{self.request.method}'"
raise KeyError(msg) from missing_method

def run_logic(self, logic: PipelineLogic, data: DataDict) -> DataReturn: # noqa: C901
def run_logic(self, logic: PipelineLogic, data: DataDict) -> DataReturn: # noqa: C901,PLR0912
"""Run pipeline logic recursively."""
if callable(logic):
if asyncio.iscoroutinefunction(logic):
Expand All @@ -81,9 +82,10 @@ def run_logic(self, logic: PipelineLogic, data: DataDict) -> DataReturn: # noqa
if isinstance(data, tuple):
key, data = data
try:
step = step[key]
step = step[key] # noqa: PLW2901
except (KeyError, TypeError) as error:
raise TypeError(f"Next logic step doesn't have a conditional logic path '{key}'.") from error
msg = f"Next logic step doesn't have a conditional logic path '{key}'."
raise TypeError(msg) from error

# Serializer
if is_serializer_class(step):
Expand All @@ -97,7 +99,7 @@ def run_logic(self, logic: PipelineLogic, data: DataDict) -> DataReturn: # noqa
elif isinstance(step, tuple):
old_kwargs: Optional[DataDict] = None
if ... in step:
step = tuple(task for task in step if task is not ...)
step = tuple(task for task in step if task is not ...) # noqa: PLW2901
old_kwargs = data

results: tuple[DataDict, ...] = async_to_sync(run_parallel)(step, data)
Expand All @@ -112,7 +114,8 @@ def run_logic(self, logic: PipelineLogic, data: DataDict) -> DataReturn: # noqa
data = self.run_logic(logic=step, data=data if data is not None else {})

else:
raise TypeError("Only Serializers, Pydantic Models, and callables are supported in the pipeline.")
msg = "Only Serializers, Pydantic Models, and callables are supported in the pipeline."
raise TypeError(msg)

except NextLogicBlock as premature_return:
return premature_return.output
Expand Down Expand Up @@ -143,7 +146,7 @@ def initialize_serializer(self, *args: Any, **kwargs: Any) -> Serializer:
kwargs["data"] = [] if kwargs["many"] else {}
return serializer_class(*args, **kwargs)

def get_serializer_class(self, output: bool = False) -> SerializerType:
def get_serializer_class(self, output: bool = False) -> SerializerType: # noqa: FBT001,FBT002
"""Get the first step in the current HTTP method's pipeline.
If it's a Serializer, return it. Otherwise, try to infer a serializer from the
logic callable's parameters.
Expand All @@ -169,7 +172,8 @@ def get_serializer_class(self, output: bool = False) -> SerializerType:
if callable(step):
return serializer_from_callable(step, output=output)

raise TypeError("Only Serializers and callables are supported in the pipeline.")
msg = "Only Serializers and callables are supported in the pipeline."
raise TypeError(msg)

def get_serializer_context(self) -> ViewContext:
"""Return serializer context, mainly for browsable api."""
Expand Down
56 changes: 45 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,53 @@ typing-modules = [
"pipeline_views.typing",
]
select = [
"F", # pyflakes
"E", # pycodestyle errors
"I", # isort
"S", # flake8-bandit
"C", # flake8-comprehensions
"B", # flake8-bugbear
"T", # flake8-print
"W", # pycodestyle warnings
"A", # flake8-builtins
"ANN", # flake8-annotations
"ARG", # flake8-unused-arguments
"ASYNC", # flake8-async
"B", # flake8-bugbear
"BLE", # flake8-blind-except
"C90", # mccabe
"C4", # flake8-comprehensions
"COM", # flake8-commas
"DJ", # flake8-django
"DTZ", # flake8-datetimez
"E", # pycodestyle errors
"EM", # flake8-errmsg
"ERA", # eradicate
"F", # pyflakes
"FA", # flake8-future-annotations
"FBT", # flake8-boolean-trap
"I", # isort
"ICN", # flake8-import-conventions
"INP", # flake8-no-pep420
"INT", # flake8-gettext
"ISC", # flake8-implicit-str-concat
"N", # pep8-naming
"PERF", # perflint
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PL", # pylint
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
"PYI", # flake8-pyi
"Q", # flake8-quotes
"RUF", # ruff-specific rules
"S", # flake8-bandit
"SIM", # flake8-simplify
"SLF", # flake8-self
"SLOT", # flake8-slots
"T10", # flake8-debugger
"T20", # flake8-print
"TCH", # flake8-type-checking
"TRY", # tryceratops
"W", # pycodestyle warnings
]
ignore = [
"B905", # `zip()` without an explicit `strict=` parameter
"F821", # Undefined name
"F722", # Syntax error in forward annotation:
"B905", # `zip()` without an explicit `strict=` parameter
"ANN101", # 'self' can be untyped
"ANN102", # 'cls' can be untyped
"ANN401", # 'typing.Any' is allowed
]

[tool.ruff.per-file-ignores]
Expand Down

0 comments on commit a2eb145

Please sign in to comment.