Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 6 additions & 6 deletions src/pyfly/admin/providers/cqrs_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,24 @@ async def get_handlers(self) -> dict[str, Any]:
if reg.instance is not None and isinstance(reg.instance, HandlerRegistry):
registry = reg.instance
for cmd_type in registry.get_registered_command_types():
handler = registry.find_command_handler(cmd_type)
cmd_handler = registry.find_command_handler(cmd_type)
handlers.append(
{
"message_type": f"{cmd_type.__module__}.{cmd_type.__qualname__}",
"message_name": cmd_type.__name__,
"handler_type": f"{type(handler).__module__}.{type(handler).__qualname__}",
"handler_name": type(handler).__name__,
"handler_type": f"{type(cmd_handler).__module__}.{type(cmd_handler).__qualname__}",
"handler_name": type(cmd_handler).__name__,
"kind": "command",
}
)
for query_type in registry.get_registered_query_types():
handler = registry.find_query_handler(query_type)
query_handler = registry.find_query_handler(query_type)
handlers.append(
{
"message_type": f"{query_type.__module__}.{query_type.__qualname__}",
"message_name": query_type.__name__,
"handler_type": f"{type(handler).__module__}.{type(handler).__qualname__}",
"handler_name": type(handler).__name__,
"handler_type": f"{type(query_handler).__module__}.{type(query_handler).__qualname__}",
"handler_name": type(query_handler).__name__,
"kind": "query",
}
)
Expand Down
5 changes: 3 additions & 2 deletions src/pyfly/client/protocols/graphql_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async def execute(
operation_name: str | None = None,
) -> dict[str, Any]:
try:
import httpx # type: ignore[import-not-found]
import httpx # type: ignore[import-not-found, unused-ignore]
except ImportError as exc: # noqa: BLE001
msg = "GraphQLClient requires httpx — `pip install pyfly[client]`"
raise ImportError(msg) from exc
Expand All @@ -46,7 +46,8 @@ async def execute(
data = resp.json()
if "errors" in data:
raise RuntimeError(f"GraphQL errors: {data['errors']}")
return data.get("data", {})
payload: dict[str, Any] = data.get("data") or {}
return payload


@dataclass
Expand Down
5 changes: 4 additions & 1 deletion src/pyfly/client/protocols/grpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ def channel(self) -> Any:
msg = "GrpcClientBuilder requires a target"
raise ValueError(msg)
try:
from grpc import aio, ssl_channel_credentials # type: ignore[import-not-found]
from grpc import ( # type: ignore[import-not-found, import-untyped, unused-ignore]
aio,
ssl_channel_credentials,
)
except ImportError as exc: # noqa: BLE001
msg = "GrpcClientBuilder requires grpcio — `pip install grpcio`"
raise ImportError(msg) from exc
Expand Down
4 changes: 1 addition & 3 deletions src/pyfly/client/protocols/soap_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any


_ENVELOPE = (
'<?xml version="1.0" encoding="UTF-8"?>'
Expand Down Expand Up @@ -43,7 +41,7 @@ def __init__(

async def call(self, body_xml: str) -> str:
try:
import httpx # type: ignore[import-not-found]
import httpx # type: ignore[import-not-found, unused-ignore]
except ImportError as exc: # noqa: BLE001
msg = "SoapClient requires httpx — `pip install pyfly[client]`"
raise ImportError(msg) from exc
Expand Down
2 changes: 1 addition & 1 deletion src/pyfly/client/protocols/websocket_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(

async def connect(self) -> Any:
try:
import websockets # type: ignore[import-not-found]
import websockets # type: ignore[import-not-found, unused-ignore]
except ImportError as exc: # noqa: BLE001
msg = "WebSocketClient requires websockets — `pip install websockets`"
raise ImportError(msg) from exc
Expand Down
16 changes: 7 additions & 9 deletions src/pyfly/config_server/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ async def fetch(self, application: str, profile: str, label: str = "main") -> Co
properties = await asyncio.get_event_loop().run_in_executor(
None, _parse_text, text, candidate.suffix.lstrip(".")
)
return ConfigSource(
application=application, profile=profile, label=label, properties=properties
)
return ConfigSource(application=application, profile=profile, label=label, properties=properties)
return None

async def save(self, source: ConfigSource) -> None:
Expand All @@ -87,9 +85,7 @@ async def save(self, source: ConfigSource) -> None:
target = self._root / source.label if source.label else self._root
target.mkdir(parents=True, exist_ok=True)
path = target / f"{source.application}-{source.profile}.json"
await asyncio.get_event_loop().run_in_executor(
None, path.write_text, json.dumps(source.properties, indent=2)
)
await asyncio.get_event_loop().run_in_executor(None, path.write_text, json.dumps(source.properties, indent=2))

async def list(self) -> list[ConfigSource]:
results: list[ConfigSource] = []
Expand All @@ -114,7 +110,9 @@ def _parse_text(text: str, fmt: str) -> dict[str, Any]:
if fmt == "json":
import json

return json.loads(text)
import yaml
result: dict[str, Any] = json.loads(text)
return result
import yaml # type: ignore[import-untyped]

return yaml.safe_load(text) or {}
parsed: dict[str, Any] | None = yaml.safe_load(text)
return parsed or {}
6 changes: 4 additions & 2 deletions src/pyfly/config_server/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ def __init__(

async def fetch(self) -> dict[str, Any]:
try:
import httpx # type: ignore[import-not-found]
import httpx # type: ignore[import-not-found, unused-ignore]
except ImportError as exc: # noqa: BLE001
msg = "ConfigClient requires httpx — `pip install pyfly[client]`"
raise ImportError(msg) from exc

path = f"{self._url}/{self._application}/{self._profile}/{self._label}"
auth = (self._username, self._password) if self._username else None
auth: tuple[str, str] | None = (
(self._username, self._password) if self._username is not None and self._password is not None else None
)
async with httpx.AsyncClient(timeout=15.0) as client:
resp = await client.get(path, auth=auth)
if resp.status_code != 200:
Expand Down
11 changes: 3 additions & 8 deletions src/pyfly/config_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ class ConfigServer:
def __init__(self, backend: ConfigBackend) -> None:
self._backend = backend

async def fetch(
self, application: str, profile: str = "default", label: str = "main"
) -> dict[str, Any] | None:
async def fetch(self, application: str, profile: str = "default", label: str = "main") -> dict[str, Any] | None:
source = await self._backend.fetch(application, profile, label)
if source is None:
return None
Expand All @@ -42,14 +40,11 @@ async def save(
properties: dict[str, Any],
label: str = "main",
) -> dict[str, Any]:
source = ConfigSource(
application=application, profile=profile, label=label, properties=properties
)
source = ConfigSource(application=application, profile=profile, label=label, properties=properties)
await self._backend.save(source)
return {"saved": True}

async def list(self) -> list[dict[str, Any]]:
return [
{"application": s.application, "profile": s.profile, "label": s.label}
for s in await self._backend.list()
{"application": s.application, "profile": s.profile, "label": s.label} for s in await self._backend.list()
]
6 changes: 2 additions & 4 deletions src/pyfly/ecm/adapters/adobe_sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(self, *, api_base: str, access_token: str) -> None:

async def _client(self) -> Any:
try:
import httpx # type: ignore[import-not-found]
import httpx # type: ignore[import-not-found, unused-ignore]
except ImportError as exc: # noqa: BLE001
msg = "AdobeSignESignatureAdapter requires httpx — `pip install pyfly[client]`"
raise ImportError(msg) from exc
Expand Down Expand Up @@ -61,9 +61,7 @@ async def send(self, request: SignatureRequest) -> ESignatureEnvelope:
"state": "IN_PROCESS",
"message": request.message,
}
resp = await client.post(
f"{self._api_base}/agreements", json=payload, headers=self._headers
)
resp = await client.post(f"{self._api_base}/agreements", json=payload, headers=self._headers)
resp.raise_for_status()
data = resp.json()
return ESignatureEnvelope(
Expand Down
10 changes: 3 additions & 7 deletions src/pyfly/ecm/adapters/aws_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,11 @@ def _ensure_client(self) -> Any:
if self._client is not None:
return self._client
try:
import boto3 # type: ignore[import-not-found]
import boto3 # type: ignore[import-not-found, unused-ignore]
except ImportError as exc: # noqa: BLE001
msg = "AwsS3StorageAdapter requires boto3 — `pip install boto3`"
raise ImportError(msg) from exc
self._client = (
boto3.client("s3", region_name=self._region) if self._region else boto3.client("s3")
)
self._client = boto3.client("s3", region_name=self._region) if self._region else boto3.client("s3")
return self._client

async def _run(self, fn: Any, /, *args: Any, **kwargs: Any) -> Any:
Expand Down Expand Up @@ -73,9 +71,7 @@ async def download(self, document: Document, version: int | None = None) -> byte
raise FileNotFoundError(msg)
target_version = version or document.versions[-1].version
client = self._ensure_client()
resp = await self._run(
client.get_object, Bucket=self._bucket, Key=self._key(document.id, target_version)
)
resp = await self._run(client.get_object, Bucket=self._bucket, Key=self._key(document.id, target_version))
body = resp["Body"].read() if hasattr(resp["Body"], "read") else resp["Body"]
return body if isinstance(body, bytes) else bytes(body)

Expand Down
11 changes: 4 additions & 7 deletions src/pyfly/ecm/adapters/azure_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from __future__ import annotations

import asyncio
import contextlib
import hashlib
from typing import Any

Expand Down Expand Up @@ -36,17 +37,15 @@ def _ensure_service(self) -> Any:
if self._service is not None:
return self._service
try:
from azure.storage.blob import BlobServiceClient # type: ignore[import-not-found]
from azure.storage.blob import BlobServiceClient # type: ignore[import-not-found, unused-ignore]
except ImportError as exc: # noqa: BLE001
msg = "AzureBlobStorageAdapter requires azure-storage-blob — `pip install azure-storage-blob`"
raise ImportError(msg) from exc
if self._connection_string is not None:
self._service = BlobServiceClient.from_connection_string(self._connection_string)
else:
assert self._account_url is not None
self._service = BlobServiceClient(
account_url=self._account_url, credential=self._credential
)
self._service = BlobServiceClient(account_url=self._account_url, credential=self._credential)
return self._service

async def _run(self, fn: Any, /, *args: Any, **kwargs: Any) -> Any:
Expand Down Expand Up @@ -84,10 +83,8 @@ async def delete(self, document: Document, version: int | None = None) -> bool:
if version is None:
for v in document.versions:
blob = service.get_blob_client(container=self._container, blob=self._key(document.id, v.version))
try:
with contextlib.suppress(Exception):
await self._run(blob.delete_blob)
except Exception: # noqa: BLE001
pass
return bool(document.versions)
blob = service.get_blob_client(container=self._container, blob=self._key(document.id, version))
try:
Expand Down
5 changes: 2 additions & 3 deletions src/pyfly/ecm/adapters/docusign.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from __future__ import annotations

import asyncio
import logging
from datetime import UTC, datetime
from typing import Any
Expand Down Expand Up @@ -42,7 +41,7 @@ def __init__(

async def _client(self) -> Any:
try:
import httpx # type: ignore[import-not-found]
import httpx # type: ignore[import-not-found, unused-ignore]
except ImportError as exc: # noqa: BLE001
msg = "DocuSignESignatureAdapter requires httpx — `pip install pyfly[client]`"
raise ImportError(msg) from exc
Expand Down Expand Up @@ -122,7 +121,7 @@ async def cancel(self, envelope_id: str) -> bool:
json={"status": "voided", "voidedReason": "cancelled by application"},
headers=self._headers,
)
return resp.status_code == 200
return bool(resp.status_code == 200)


def _map_status(value: str) -> ESignatureStatus:
Expand Down
1 change: 0 additions & 1 deletion src/pyfly/ecm/adapters/local_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import asyncio
import hashlib
import pathlib
from typing import Any

from pyfly.ecm.models import Document, DocumentVersion

Expand Down
11 changes: 3 additions & 8 deletions src/pyfly/ecm/adapters/logalty.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(self, *, api_base: str, api_key: str) -> None:

async def _client(self) -> Any:
try:
import httpx # type: ignore[import-not-found]
import httpx # type: ignore[import-not-found, unused-ignore]
except ImportError as exc: # noqa: BLE001
msg = "LogaltyESignatureAdapter requires httpx — `pip install pyfly[client]`"
raise ImportError(msg) from exc
Expand All @@ -50,14 +50,9 @@ async def send(self, request: SignatureRequest) -> ESignatureEnvelope:
"documentId": request.document_id,
"subject": request.subject,
"message": request.message,
"signers": [
{"name": r.name, "email": r.email, "role": r.role}
for r in request.recipients
],
"signers": [{"name": r.name, "email": r.email, "role": r.role} for r in request.recipients],
}
resp = await client.post(
f"{self._api_base}/envelopes", json=payload, headers=self._headers
)
resp = await client.post(f"{self._api_base}/envelopes", json=payload, headers=self._headers)
resp.raise_for_status()
data = resp.json()
return ESignatureEnvelope(
Expand Down
2 changes: 0 additions & 2 deletions src/pyfly/ecm/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@

from __future__ import annotations

import asyncio
import hashlib
from datetime import UTC, datetime

from pyfly.ecm.models import (
Document,
DocumentVersion,
ESignatureEnvelope,
Folder,
SignatureRequest,
Expand Down
4 changes: 1 addition & 3 deletions src/pyfly/eventsourcing/aggregate.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ class AggregateRoot:
id: str = ""
version: int = 0
_pending_events: list[DomainEvent] = field(default_factory=list, init=False, repr=False)
_handlers: dict[str, Callable[[Any, Any], None]] = field(
default_factory=dict, init=False, repr=False
)
_handlers: dict[str, Callable[[Any, Any], None]] = field(default_factory=dict, init=False, repr=False)

def when(
self,
Expand Down
5 changes: 2 additions & 3 deletions src/pyfly/eventsourcing/outbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from __future__ import annotations

import asyncio
import contextlib
import logging
import uuid
from collections.abc import Awaitable, Callable
Expand Down Expand Up @@ -81,10 +82,8 @@ async def stop(self) -> None:
if self._task is None:
return
self._stop.set()
try:
with contextlib.suppress(asyncio.CancelledError):
await self._task
except asyncio.CancelledError:
pass
self._task = None

async def pending(self) -> list[OutboxRecord]:
Expand Down
11 changes: 4 additions & 7 deletions src/pyfly/eventsourcing/projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
from __future__ import annotations

import asyncio
import contextlib
import logging
from collections.abc import Awaitable, Callable
from typing import Any, Protocol, runtime_checkable
from typing import Protocol, runtime_checkable

from pyfly.eventsourcing.event import StoredEventEnvelope
from pyfly.eventsourcing.store import EventStore
Expand Down Expand Up @@ -62,10 +63,8 @@ async def stop(self) -> None:
if self._task is None:
return
self._stop.set()
try:
with contextlib.suppress(asyncio.CancelledError):
await self._task
except asyncio.CancelledError:
pass
self._task = None

async def _loop(self) -> None:
Expand Down Expand Up @@ -94,9 +93,7 @@ async def _loop(self) -> None:
class FunctionProjection:
"""Quick projection wrapper around a single async callable."""

def __init__(
self, name: str, handler: Callable[[StoredEventEnvelope], Awaitable[None]]
) -> None:
def __init__(self, name: str, handler: Callable[[StoredEventEnvelope], Awaitable[None]]) -> None:
self.name = name
self._handler = handler

Expand Down
Loading