Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore/enable ruff checks #63

Merged
merged 5 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,13 @@ exec-typecheck:
@${printMsg} typecheck OK

exec-format:
@ruff format
@ruff format && ruff check --fix && ruff check --fix --select I


exec-code-qa: exec-lint exec-typecheck

exec-test: exec-code-qa
pytest ${PYTEST_ARGS} test/unit
pytest ${PYTEST_ARGS} test/unit test/integration

format: install
${VENV_ACTIVATE} && make exec-format exec-lint-fix
Expand Down
9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ asyncio_mode = "auto"
include = ["pyproject.toml", "src/**/*.py", "test/**/*.py"]

[tool.ruff.lint]
select = ["E", "F", "B", "SIM", "FA", "D"]
ignore = ["D203", "D213"]

[tool.ruff.lint.isort]
from-first = false
known-first-party = ["waylay*"]

[tool.ruff.lint.per-file-ignores]
"test/**/*.py" = ["D"] # no docstyle required

[tool.coverage.report]
exclude_also = [
Expand Down
16 changes: 8 additions & 8 deletions src/waylay/sdk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
"""The Waylay Python SDK."""

from .client import WaylayClient
from .config import WaylayConfig
from ._version import __version__
from .api import ApiClient
from .auth import (
WaylayCredentials,
ClientCredentials,
ApplicationCredentials,
TokenCredentials,
ClientCredentials,
NoCredentials,
TokenCredentials,
WaylayCredentials,
WaylayToken,
)
from .plugin import WaylayService, WaylayTool, WaylayPlugin, PluginAccess
from .api import ApiClient
from .client import WaylayClient
from .config import WaylayConfig
from .exceptions import WaylayError
from ._version import __version__
from .plugin import PluginAccess, WaylayPlugin, WaylayService, WaylayTool

__all__ = [
"WaylayClient",
Expand Down
10 changes: 5 additions & 5 deletions src/waylay/sdk/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
"""Waylay Api Configuration."""

# export api classes
from ._models import Model, Primitive
from .client import ApiClient, RESTTimeout
from .exceptions import ApiError, ApiValueError
from .http import (
AsyncClient,
HttpClientOptions,
HeaderTypes,
HttpClientOptions,
QueryParamTypes,
Request,
Response,
RequestFiles,
RequestContent,
RequestData,
RequestFiles,
Response,
)
from .exceptions import ApiError, ApiValueError
from ._models import Model, Primitive

__all__ = [
"ApiClient",
Expand Down
48 changes: 33 additions & 15 deletions src/waylay/sdk/api/_models.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
from __future__ import annotations
from abc import ABC

import contextlib
from abc import ABC
from copy import deepcopy
from datetime import date, datetime
from decimal import Decimal
from inspect import isclass
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Union, get_type_hints
from typing import (
TYPE_CHECKING,
Annotated,
Any,
Callable,
Dict,
List,
Union,
get_type_hints,
)

from typing_extensions import (
Annotated, # >=3.9
Self, # >=3.12
TypeAliasType, # >=3.12
)
Expand All @@ -18,6 +27,8 @@

from pydantic import (
BaseModel as PydanticBaseModel,
)
from pydantic import (
ConfigDict,
SerializationInfo,
StrictStr,
Expand All @@ -33,13 +44,16 @@


class BaseModel(PydanticBaseModel, ABC):
"""Waylay base model class that adds some additional methods to Pydantic's `BaseModel`, including a custom validator and serializer."""
"""Waylay base model class that adds additional methods to Pydantic's `BaseModel`.

Includes a custom validator and serializer.
"""

@model_serializer(mode="wrap")
def _model_serializer(
self, handler: Callable, info: SerializationInfo
) -> Dict[StrictStr, Any]:
"""The default serializer of the model.
"""Get the default serializer of the model.

* Excludes `None` fields that were not set at model initialization.
"""
Expand All @@ -54,10 +68,13 @@ def _model_serializer(
def _model_validator(
cls, value: Any, handler: ModelWrapValidatorHandler, info: ValidationInfo
):
"""The default validator of the model.
"""Get the default validator of the model.

When validation is called with a `skip_validation=True` context (e.g. `cls.model_validate(data, context={"skip_validation": True})`), the model is constructed without validation.
Any fields with a `Model` type will be constructed from their dict representation recursively.
When validation is called with a `skip_validation=True` context
(e.g. `cls.model_validate(data, context={"skip_validation": True})`),
the model is constructed without validation.
Any fields with a `Model` type will be constructed
from their dict representation recursively.
"""
context = info.context or {}
try:
Expand Down Expand Up @@ -85,16 +102,14 @@ def _model_validator(
for field_name in model_fields_set:
field_value = getattr(model, field_name)
strict = (info.config or {}).get("strict")
try:
with contextlib.suppress(BaseException):
cls.__pydantic_validator__.validate_assignment(
model,
field_name,
field_value,
strict=strict,
context=context,
)
except BaseException:
pass
return model
else:
raise
Expand All @@ -103,10 +118,12 @@ def _model_validator(
def _field_validator(
cls, value: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
):
"""The default field validator of the model.
"""Get the default field validator of the model.

When validation is called with a `skip_validation=True` context, the field is assigned without validation.
If the field is a `Model` type, the model will be constructed from its dict representation recursively.
When validation is called with a `skip_validation=True` context,
the field is assigned without validation.
If the field is a `Model` type, the model will be constructed
from its dict representation recursively.
"""
context = info.context or {}
try:
Expand Down Expand Up @@ -180,6 +197,7 @@ def __model_construct_recursive(cls, obj: Any):
"Model",
Annotated[
Union[List["Model"], "_Model", Primitive], # type: ignore[misc,possible cyclic definition]
"A basic model that acts like a `simpleNamespace`, or a collection over such models.",
"A basic model that acts like a `simpleNamespace` "
"or a collection over such models.",
],
)
7 changes: 4 additions & 3 deletions src/waylay/sdk/api/client.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
"""API client."""

from __future__ import annotations
from typing import Mapping, Optional, Tuple, Union

from collections.abc import Mapping
from typing import Optional, Tuple, Union

from .._version import __version__
from ..config import WaylayConfig

from .exceptions import SyncCtxMgtNotSupportedError
from .serialization import WithSerializationSupport
from .http import AsyncClient, HttpClientOptions, Request, Response
from .serialization import WithSerializationSupport

RESTTimeout = Union[
Optional[float],
Expand Down
2 changes: 2 additions & 0 deletions src/waylay/sdk/api/constants.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
"""Api client constants."""

STREAM_TIMEOUTS = (5.0, None, 5.0, 5.0)
25 changes: 15 additions & 10 deletions src/waylay/sdk/api/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
"""Exceptions."""

from typing import Any, Optional
from __future__ import annotations

from .http import Response
from typing import Any

from ..exceptions import WaylayError, RequestError, RestResponseError
from ..exceptions import RequestError, RestResponseError, WaylayError
from .http import Response


class ApiValueError(RequestError, ValueError):
"""Inappropriate argument value (of correct type) in a Waylay API request."""

def __init__(self, msg, path_to_item=None) -> None:
def __init__(self, msg: str, path_to_item=None) -> None:
"""Raise a value error.

Args:
----
msg (str): the exception message
path_to_item (str): path into the request object

Keyword Args:
------------
path_to_item (list) the path to the exception in the
received_data dict. None if unset

"""

self.path_to_item = path_to_item
full_msg = msg
if path_to_item:
Expand All @@ -32,25 +35,27 @@ def __init__(self, msg, path_to_item=None) -> None:
class ApiError(RestResponseError):
"""Exception class wrapping the response data of a REST call."""

data: Optional[Any]
data: Any | None

def __init__(
self,
*args,
response: Response,
data: Optional[Any],
data: Any | None,
) -> None:
"""Create an instance."""
super().__init__(response)
super().__init__(*args, response=response)
self.data = data

@classmethod
def from_response(
cls,
message: str,
response: Response,
data: Optional[Any],
data: Any | None,
):
"""Create an instance from a REST exception response."""
return cls(response, data)
return cls(message, response=response, data=data)

def __str__(self):
"""Get the string representation of the exception."""
Expand Down
20 changes: 10 additions & 10 deletions src/waylay/sdk/api/http.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
"""Aliases for the http client."""

from __future__ import annotations

from collections.abc import Mapping, Sequence
from typing import (
TypedDict,
Mapping,
Optional,
Callable,
IO,
Any,
Union,
Sequence,
Tuple,
Callable,
List,
IO,
Optional,
Tuple,
TypedDict,
Union,
)
from typing_extensions import Required # >=3.11

import httpx._client as httpx_types
import httpx
import httpx._client as httpx_types
from typing_extensions import Required # >=3.11

AsyncClient = httpx.AsyncClient
Response = httpx.Response
Expand Down
Loading