From b8f8ce51a48f05e8d4d64665598692485a6a79cf Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 00:14:29 -0330 Subject: [PATCH 01/14] chore: clean out old generated stackcoin-python, set up new SDK structure --- justfile | 11 +- openapi-python-client-config.yml | 2 - stackcoin/README.md | 124 -------- stackcoin/pyproject.toml | 31 +- stackcoin/stackcoin/__init__.py | 5 + stackcoin/stackcoin/errors.py | 8 + stackcoin/stackcoin_python/__init__.py | 8 - stackcoin/stackcoin_python/api/__init__.py | 1 - .../stackcoin_python/api/default/__init__.py | 1 - .../api/default/stackcoin_accept_request.py | 171 ----------- .../api/default/stackcoin_create_request.py | 197 ------------- .../api/default/stackcoin_deny_request.py | 171 ----------- .../api/default/stackcoin_discord_guild.py | 163 ----------- .../api/default/stackcoin_discord_guilds.py | 211 -------------- .../api/default/stackcoin_request.py | 163 ----------- .../api/default/stackcoin_requests.py | 246 ---------------- .../api/default/stackcoin_send_stk.py | 201 ------------- .../api/default/stackcoin_transaction.py | 163 ----------- .../api/default/stackcoin_transactions.py | 261 ----------------- .../api/default/stackcoin_user.py | 163 ----------- .../api/default/stackcoin_user_me.py | 130 --------- .../api/default/stackcoin_users.py | 237 ---------------- stackcoin/stackcoin_python/client.py | 268 ------------------ stackcoin/stackcoin_python/errors.py | 16 -- stackcoin/stackcoin_python/models/__init__.py | 69 ----- .../models/create_request_params.py | 85 ------ .../models/create_request_response.py | 122 -------- .../create_request_response_requester.py | 68 ----- .../create_request_response_responder.py | 68 ----- .../stackcoin_python/models/discord_guild.py | 112 -------- .../models/discord_guild_response.py | 112 -------- .../models/discord_guilds_response.py | 101 ------- .../discord_guilds_response_pagination.py | 86 ------ .../stackcoin_python/models/error_response.py | 63 ---- stackcoin/stackcoin_python/models/request.py | 187 ------------ .../models/request_action_response.py | 112 -------- .../models/request_requester.py | 68 ----- .../models/request_responder.py | 68 ----- .../models/request_response.py | 187 ------------ .../models/request_response_requester.py | 68 ----- .../models/request_response_responder.py | 68 ----- .../models/requests_response.py | 100 ------- .../models/requests_response_pagination.py | 86 ------ .../models/send_stk_params.py | 85 ------ .../models/send_stk_response.py | 95 ------- .../stackcoin_python/models/transaction.py | 128 --------- .../models/transaction_from.py | 68 ----- .../models/transaction_response.py | 128 --------- .../models/transaction_response_from.py | 68 ----- .../models/transaction_response_to.py | 68 ----- .../stackcoin_python/models/transaction_to.py | 68 ----- .../models/transactions_response.py | 99 ------- .../transactions_response_pagination.py | 86 ------ stackcoin/stackcoin_python/models/user.py | 133 --------- .../stackcoin_python/models/user_response.py | 133 --------- .../stackcoin_python/models/users_response.py | 99 ------- .../models/users_response_pagination.py | 86 ------ stackcoin/stackcoin_python/py.typed | 1 - stackcoin/stackcoin_python/types.py | 54 ---- 59 files changed, 34 insertions(+), 6147 deletions(-) delete mode 100644 openapi-python-client-config.yml delete mode 100644 stackcoin/README.md create mode 100644 stackcoin/stackcoin/__init__.py create mode 100644 stackcoin/stackcoin/errors.py delete mode 100644 stackcoin/stackcoin_python/__init__.py delete mode 100644 stackcoin/stackcoin_python/api/__init__.py delete mode 100644 stackcoin/stackcoin_python/api/default/__init__.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_accept_request.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_create_request.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_deny_request.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_discord_guild.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_discord_guilds.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_request.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_requests.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_send_stk.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_transaction.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_transactions.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_user.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_user_me.py delete mode 100644 stackcoin/stackcoin_python/api/default/stackcoin_users.py delete mode 100644 stackcoin/stackcoin_python/client.py delete mode 100644 stackcoin/stackcoin_python/errors.py delete mode 100644 stackcoin/stackcoin_python/models/__init__.py delete mode 100644 stackcoin/stackcoin_python/models/create_request_params.py delete mode 100644 stackcoin/stackcoin_python/models/create_request_response.py delete mode 100644 stackcoin/stackcoin_python/models/create_request_response_requester.py delete mode 100644 stackcoin/stackcoin_python/models/create_request_response_responder.py delete mode 100644 stackcoin/stackcoin_python/models/discord_guild.py delete mode 100644 stackcoin/stackcoin_python/models/discord_guild_response.py delete mode 100644 stackcoin/stackcoin_python/models/discord_guilds_response.py delete mode 100644 stackcoin/stackcoin_python/models/discord_guilds_response_pagination.py delete mode 100644 stackcoin/stackcoin_python/models/error_response.py delete mode 100644 stackcoin/stackcoin_python/models/request.py delete mode 100644 stackcoin/stackcoin_python/models/request_action_response.py delete mode 100644 stackcoin/stackcoin_python/models/request_requester.py delete mode 100644 stackcoin/stackcoin_python/models/request_responder.py delete mode 100644 stackcoin/stackcoin_python/models/request_response.py delete mode 100644 stackcoin/stackcoin_python/models/request_response_requester.py delete mode 100644 stackcoin/stackcoin_python/models/request_response_responder.py delete mode 100644 stackcoin/stackcoin_python/models/requests_response.py delete mode 100644 stackcoin/stackcoin_python/models/requests_response_pagination.py delete mode 100644 stackcoin/stackcoin_python/models/send_stk_params.py delete mode 100644 stackcoin/stackcoin_python/models/send_stk_response.py delete mode 100644 stackcoin/stackcoin_python/models/transaction.py delete mode 100644 stackcoin/stackcoin_python/models/transaction_from.py delete mode 100644 stackcoin/stackcoin_python/models/transaction_response.py delete mode 100644 stackcoin/stackcoin_python/models/transaction_response_from.py delete mode 100644 stackcoin/stackcoin_python/models/transaction_response_to.py delete mode 100644 stackcoin/stackcoin_python/models/transaction_to.py delete mode 100644 stackcoin/stackcoin_python/models/transactions_response.py delete mode 100644 stackcoin/stackcoin_python/models/transactions_response_pagination.py delete mode 100644 stackcoin/stackcoin_python/models/user.py delete mode 100644 stackcoin/stackcoin_python/models/user_response.py delete mode 100644 stackcoin/stackcoin_python/models/users_response.py delete mode 100644 stackcoin/stackcoin_python/models/users_response_pagination.py delete mode 100644 stackcoin/stackcoin_python/py.typed delete mode 100644 stackcoin/stackcoin_python/types.py diff --git a/justfile b/justfile index 30977f7..0a6c676 100644 --- a/justfile +++ b/justfile @@ -1,8 +1,11 @@ generate: - rm -rf stackcoin - uvx openapi-python-client generate --url http://localhost:4000/api/openapi --config openapi-python-client-config.yml - uvx ruff format + datamodel-codegen \ + --input ../../openapi.json \ + --input-file-type openapi \ + --output-model-type pydantic_v2.BaseModel \ + --output stackcoin/stackcoin/models.py \ + --target-python-version 3.13 + uvx ruff format stackcoin/ dev: uv pip install -e "stackcoin @ ./stackcoin" - diff --git a/openapi-python-client-config.yml b/openapi-python-client-config.yml deleted file mode 100644 index d6856a0..0000000 --- a/openapi-python-client-config.yml +++ /dev/null @@ -1,2 +0,0 @@ -project_name_override: stackcoin -package_name_override: stackcoin_python diff --git a/stackcoin/README.md b/stackcoin/README.md deleted file mode 100644 index 176553b..0000000 --- a/stackcoin/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# stackcoin -A client library for accessing StackCoin API - -## Usage -First, create a client: - -```python -from stackcoin_python import Client - -client = Client(base_url="https://api.example.com") -``` - -If the endpoints you're going to hit require authentication, use `AuthenticatedClient` instead: - -```python -from stackcoin_python import AuthenticatedClient - -client = AuthenticatedClient(base_url="https://api.example.com", token="SuperSecretToken") -``` - -Now call your endpoint and use your models: - -```python -from stackcoin_python.models import MyDataModel -from stackcoin_python.api.my_tag import get_my_data_model -from stackcoin_python.types import Response - -with client as client: - my_data: MyDataModel = get_my_data_model.sync(client=client) - # or if you need more info (e.g. status_code) - response: Response[MyDataModel] = get_my_data_model.sync_detailed(client=client) -``` - -Or do the same thing with an async version: - -```python -from stackcoin_python.models import MyDataModel -from stackcoin_python.api.my_tag import get_my_data_model -from stackcoin_python.types import Response - -async with client as client: - my_data: MyDataModel = await get_my_data_model.asyncio(client=client) - response: Response[MyDataModel] = await get_my_data_model.asyncio_detailed(client=client) -``` - -By default, when you're calling an HTTPS API it will attempt to verify that SSL is working correctly. Using certificate verification is highly recommended most of the time, but sometimes you may need to authenticate to a server (especially an internal server) using a custom certificate bundle. - -```python -client = AuthenticatedClient( - base_url="https://internal_api.example.com", - token="SuperSecretToken", - verify_ssl="/path/to/certificate_bundle.pem", -) -``` - -You can also disable certificate validation altogether, but beware that **this is a security risk**. - -```python -client = AuthenticatedClient( - base_url="https://internal_api.example.com", - token="SuperSecretToken", - verify_ssl=False -) -``` - -Things to know: -1. Every path/method combo becomes a Python module with four functions: - 1. `sync`: Blocking request that returns parsed data (if successful) or `None` - 1. `sync_detailed`: Blocking request that always returns a `Request`, optionally with `parsed` set if the request was successful. - 1. `asyncio`: Like `sync` but async instead of blocking - 1. `asyncio_detailed`: Like `sync_detailed` but async instead of blocking - -1. All path/query params, and bodies become method arguments. -1. If your endpoint had any tags on it, the first tag will be used as a module name for the function (my_tag above) -1. Any endpoint which did not have a tag will be in `stackcoin_python.api.default` - -## Advanced customizations - -There are more settings on the generated `Client` class which let you control more runtime behavior, check out the docstring on that class for more info. You can also customize the underlying `httpx.Client` or `httpx.AsyncClient` (depending on your use-case): - -```python -from stackcoin_python import Client - -def log_request(request): - print(f"Request event hook: {request.method} {request.url} - Waiting for response") - -def log_response(response): - request = response.request - print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}") - -client = Client( - base_url="https://api.example.com", - httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}}, -) - -# Or get the underlying httpx client to modify directly with client.get_httpx_client() or client.get_async_httpx_client() -``` - -You can even set the httpx client directly, but beware that this will override any existing settings (e.g., base_url): - -```python -import httpx -from stackcoin_python import Client - -client = Client( - base_url="https://api.example.com", -) -# Note that base_url needs to be re-set, as would any shared cookies, headers, etc. -client.set_httpx_client(httpx.Client(base_url="https://api.example.com", proxies="http://localhost:8030")) -``` - -## Building / publishing this package -This project uses [Poetry](https://python-poetry.org/) to manage dependencies and packaging. Here are the basics: -1. Update the metadata in pyproject.toml (e.g. authors, version) -1. If you're using a private repository, configure it with Poetry - 1. `poetry config repositories. ` - 1. `poetry config http-basic. ` -1. Publish the client with `poetry publish --build -r ` or, if for public PyPI, just `poetry publish --build` - -If you want to install this client into another project without publishing it (e.g. for development) then: -1. If that project **is using Poetry**, you can simply do `poetry add ` from that project -1. If that project is not using Poetry: - 1. Build a wheel with `poetry build -f wheel` - 1. Install that wheel from the other project `pip install ` diff --git a/stackcoin/pyproject.toml b/stackcoin/pyproject.toml index afef53d..d36fe89 100644 --- a/stackcoin/pyproject.toml +++ b/stackcoin/pyproject.toml @@ -1,26 +1,23 @@ -[tool.poetry] +[project] name = "stackcoin" -version = "0.1" -description = "A client library for accessing StackCoin API" -authors = [] -readme = "README.md" -packages = [ - { include = "stackcoin_python" }, +version = "0.1.0" +description = "Python SDK for the StackCoin API" +requires-python = ">=3.13" +dependencies = [ + "httpx>=0.27", + "pydantic>=2.0", + "websockets>=13.0", ] -include = ["CHANGELOG.md", "stackcoin_python/py.typed"] - -[tool.poetry.dependencies] -python = "^3.9" -httpx = ">=0.23.0,<0.29.0" -attrs = ">=22.2.0" -python-dateutil = "^2.8.0" [build-system] -requires = ["poetry-core>=2.0.0,<3.0.0"] -build-backend = "poetry.core.masonry.api" +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["stackcoin"] [tool.ruff] -line-length = 120 +line-length = 100 [tool.ruff.lint] select = ["F", "I", "UP"] diff --git a/stackcoin/stackcoin/__init__.py b/stackcoin/stackcoin/__init__.py new file mode 100644 index 0000000..217be0f --- /dev/null +++ b/stackcoin/stackcoin/__init__.py @@ -0,0 +1,5 @@ +"""StackCoin Python SDK.""" + +from .errors import StackCoinError + +__all__ = ["StackCoinError"] diff --git a/stackcoin/stackcoin/errors.py b/stackcoin/stackcoin/errors.py new file mode 100644 index 0000000..8411ffe --- /dev/null +++ b/stackcoin/stackcoin/errors.py @@ -0,0 +1,8 @@ +class StackCoinError(Exception): + """Raised when the StackCoin API returns an error response.""" + + def __init__(self, status_code: int, error: str, message: str | None = None): + self.status_code = status_code + self.error = error + self.message = message + super().__init__(f"{status_code} {error}: {message}") diff --git a/stackcoin/stackcoin_python/__init__.py b/stackcoin/stackcoin_python/__init__.py deleted file mode 100644 index b93c6a1..0000000 --- a/stackcoin/stackcoin_python/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""A client library for accessing StackCoin API""" - -from .client import AuthenticatedClient, Client - -__all__ = ( - "AuthenticatedClient", - "Client", -) diff --git a/stackcoin/stackcoin_python/api/__init__.py b/stackcoin/stackcoin_python/api/__init__.py deleted file mode 100644 index 81f9fa2..0000000 --- a/stackcoin/stackcoin_python/api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Contains methods for accessing the API""" diff --git a/stackcoin/stackcoin_python/api/default/__init__.py b/stackcoin/stackcoin_python/api/default/__init__.py deleted file mode 100644 index 2d7c0b2..0000000 --- a/stackcoin/stackcoin_python/api/default/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Contains endpoint functions for accessing the API""" diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_accept_request.py b/stackcoin/stackcoin_python/api/default/stackcoin_accept_request.py deleted file mode 100644 index 36ff0fd..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_accept_request.py +++ /dev/null @@ -1,171 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.request_action_response import RequestActionResponse -from ...types import Response - - -def _get_kwargs( - request_id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/api/requests/{request_id}/accept", - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[ErrorResponse, RequestActionResponse]]: - if response.status_code == 200: - response_200 = RequestActionResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[ErrorResponse, RequestActionResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, RequestActionResponse]]: - """Accept a STK request - - Accepts a pending STK request, creating a transaction. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, RequestActionResponse]] - """ - - kwargs = _get_kwargs( - request_id=request_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, RequestActionResponse]]: - """Accept a STK request - - Accepts a pending STK request, creating a transaction. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, RequestActionResponse] - """ - - return sync_detailed( - request_id=request_id, - client=client, - ).parsed - - -async def asyncio_detailed( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, RequestActionResponse]]: - """Accept a STK request - - Accepts a pending STK request, creating a transaction. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, RequestActionResponse]] - """ - - kwargs = _get_kwargs( - request_id=request_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, RequestActionResponse]]: - """Accept a STK request - - Accepts a pending STK request, creating a transaction. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, RequestActionResponse] - """ - - return ( - await asyncio_detailed( - request_id=request_id, - client=client, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_create_request.py b/stackcoin/stackcoin_python/api/default/stackcoin_create_request.py deleted file mode 100644 index 74d199f..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_create_request.py +++ /dev/null @@ -1,197 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.create_request_params import CreateRequestParams -from ...models.create_request_response import CreateRequestResponse -from ...models.error_response import ErrorResponse -from ...types import Response - - -def _get_kwargs( - user_id: int, - *, - body: CreateRequestParams, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/api/user/{user_id}/request", - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[CreateRequestResponse, ErrorResponse]]: - if response.status_code == 200: - response_200 = CreateRequestResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[CreateRequestResponse, ErrorResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], - body: CreateRequestParams, -) -> Response[Union[CreateRequestResponse, ErrorResponse]]: - """Create a STK request - - Creates a request for STK from a specified user. - - Args: - user_id (int): - body (CreateRequestParams): Parameters for creating a STK request Example: {'amount': 200, - 'label': 'Payment request'}. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[CreateRequestResponse, ErrorResponse]] - """ - - kwargs = _get_kwargs( - user_id=user_id, - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], - body: CreateRequestParams, -) -> Optional[Union[CreateRequestResponse, ErrorResponse]]: - """Create a STK request - - Creates a request for STK from a specified user. - - Args: - user_id (int): - body (CreateRequestParams): Parameters for creating a STK request Example: {'amount': 200, - 'label': 'Payment request'}. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[CreateRequestResponse, ErrorResponse] - """ - - return sync_detailed( - user_id=user_id, - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], - body: CreateRequestParams, -) -> Response[Union[CreateRequestResponse, ErrorResponse]]: - """Create a STK request - - Creates a request for STK from a specified user. - - Args: - user_id (int): - body (CreateRequestParams): Parameters for creating a STK request Example: {'amount': 200, - 'label': 'Payment request'}. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[CreateRequestResponse, ErrorResponse]] - """ - - kwargs = _get_kwargs( - user_id=user_id, - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], - body: CreateRequestParams, -) -> Optional[Union[CreateRequestResponse, ErrorResponse]]: - """Create a STK request - - Creates a request for STK from a specified user. - - Args: - user_id (int): - body (CreateRequestParams): Parameters for creating a STK request Example: {'amount': 200, - 'label': 'Payment request'}. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[CreateRequestResponse, ErrorResponse] - """ - - return ( - await asyncio_detailed( - user_id=user_id, - client=client, - body=body, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_deny_request.py b/stackcoin/stackcoin_python/api/default/stackcoin_deny_request.py deleted file mode 100644 index 12689fc..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_deny_request.py +++ /dev/null @@ -1,171 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.request_action_response import RequestActionResponse -from ...types import Response - - -def _get_kwargs( - request_id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/api/requests/{request_id}/deny", - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[ErrorResponse, RequestActionResponse]]: - if response.status_code == 200: - response_200 = RequestActionResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[ErrorResponse, RequestActionResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, RequestActionResponse]]: - """Deny a STK request - - Denies a pending STK request without creating a transaction. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, RequestActionResponse]] - """ - - kwargs = _get_kwargs( - request_id=request_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, RequestActionResponse]]: - """Deny a STK request - - Denies a pending STK request without creating a transaction. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, RequestActionResponse] - """ - - return sync_detailed( - request_id=request_id, - client=client, - ).parsed - - -async def asyncio_detailed( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, RequestActionResponse]]: - """Deny a STK request - - Denies a pending STK request without creating a transaction. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, RequestActionResponse]] - """ - - kwargs = _get_kwargs( - request_id=request_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, RequestActionResponse]]: - """Deny a STK request - - Denies a pending STK request without creating a transaction. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, RequestActionResponse] - """ - - return ( - await asyncio_detailed( - request_id=request_id, - client=client, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_discord_guild.py b/stackcoin/stackcoin_python/api/default/stackcoin_discord_guild.py deleted file mode 100644 index 38fca85..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_discord_guild.py +++ /dev/null @@ -1,163 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.discord_guild_response import DiscordGuildResponse -from ...models.error_response import ErrorResponse -from ...types import Response - - -def _get_kwargs( - snowflake: str, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/api/discord/guild/{snowflake}", - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[DiscordGuildResponse, ErrorResponse]]: - if response.status_code == 200: - response_200 = DiscordGuildResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[DiscordGuildResponse, ErrorResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - snowflake: str, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[DiscordGuildResponse, ErrorResponse]]: - """Get Discord guild by snowflake - - Retrieves a single Discord guild by its snowflake ID. - - Args: - snowflake (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[DiscordGuildResponse, ErrorResponse]] - """ - - kwargs = _get_kwargs( - snowflake=snowflake, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - snowflake: str, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[DiscordGuildResponse, ErrorResponse]]: - """Get Discord guild by snowflake - - Retrieves a single Discord guild by its snowflake ID. - - Args: - snowflake (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[DiscordGuildResponse, ErrorResponse] - """ - - return sync_detailed( - snowflake=snowflake, - client=client, - ).parsed - - -async def asyncio_detailed( - snowflake: str, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[DiscordGuildResponse, ErrorResponse]]: - """Get Discord guild by snowflake - - Retrieves a single Discord guild by its snowflake ID. - - Args: - snowflake (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[DiscordGuildResponse, ErrorResponse]] - """ - - kwargs = _get_kwargs( - snowflake=snowflake, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - snowflake: str, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[DiscordGuildResponse, ErrorResponse]]: - """Get Discord guild by snowflake - - Retrieves a single Discord guild by its snowflake ID. - - Args: - snowflake (str): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[DiscordGuildResponse, ErrorResponse] - """ - - return ( - await asyncio_detailed( - snowflake=snowflake, - client=client, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_discord_guilds.py b/stackcoin/stackcoin_python/api/default/stackcoin_discord_guilds.py deleted file mode 100644 index c2e2dc9..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_discord_guilds.py +++ /dev/null @@ -1,211 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.discord_guilds_response import DiscordGuildsResponse -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - *, - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - name: Union[Unset, str] = UNSET, - snowflake: Union[Unset, str] = UNSET, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["page"] = page - - params["limit"] = limit - - params["name"] = name - - params["snowflake"] = snowflake - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/api/discord/guilds", - "params": params, - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[DiscordGuildsResponse]: - if response.status_code == 200: - response_200 = DiscordGuildsResponse.from_dict(response.json()) - - return response_200 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[DiscordGuildsResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - name: Union[Unset, str] = UNSET, - snowflake: Union[Unset, str] = UNSET, -) -> Response[DiscordGuildsResponse]: - """Get Discord guilds - - Retrieves Discord guilds with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - name (Union[Unset, str]): - snowflake (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[DiscordGuildsResponse] - """ - - kwargs = _get_kwargs( - page=page, - limit=limit, - name=name, - snowflake=snowflake, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - name: Union[Unset, str] = UNSET, - snowflake: Union[Unset, str] = UNSET, -) -> Optional[DiscordGuildsResponse]: - """Get Discord guilds - - Retrieves Discord guilds with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - name (Union[Unset, str]): - snowflake (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - DiscordGuildsResponse - """ - - return sync_detailed( - client=client, - page=page, - limit=limit, - name=name, - snowflake=snowflake, - ).parsed - - -async def asyncio_detailed( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - name: Union[Unset, str] = UNSET, - snowflake: Union[Unset, str] = UNSET, -) -> Response[DiscordGuildsResponse]: - """Get Discord guilds - - Retrieves Discord guilds with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - name (Union[Unset, str]): - snowflake (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[DiscordGuildsResponse] - """ - - kwargs = _get_kwargs( - page=page, - limit=limit, - name=name, - snowflake=snowflake, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - name: Union[Unset, str] = UNSET, - snowflake: Union[Unset, str] = UNSET, -) -> Optional[DiscordGuildsResponse]: - """Get Discord guilds - - Retrieves Discord guilds with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - name (Union[Unset, str]): - snowflake (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - DiscordGuildsResponse - """ - - return ( - await asyncio_detailed( - client=client, - page=page, - limit=limit, - name=name, - snowflake=snowflake, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_request.py b/stackcoin/stackcoin_python/api/default/stackcoin_request.py deleted file mode 100644 index a5adc48..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_request.py +++ /dev/null @@ -1,163 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.request_response import RequestResponse -from ...types import Response - - -def _get_kwargs( - request_id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/api/request/{request_id}", - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[ErrorResponse, RequestResponse]]: - if response.status_code == 200: - response_200 = RequestResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[ErrorResponse, RequestResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, RequestResponse]]: - """Get request by ID - - Retrieves a single request by its ID. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, RequestResponse]] - """ - - kwargs = _get_kwargs( - request_id=request_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, RequestResponse]]: - """Get request by ID - - Retrieves a single request by its ID. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, RequestResponse] - """ - - return sync_detailed( - request_id=request_id, - client=client, - ).parsed - - -async def asyncio_detailed( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, RequestResponse]]: - """Get request by ID - - Retrieves a single request by its ID. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, RequestResponse]] - """ - - kwargs = _get_kwargs( - request_id=request_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - request_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, RequestResponse]]: - """Get request by ID - - Retrieves a single request by its ID. - - Args: - request_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, RequestResponse] - """ - - return ( - await asyncio_detailed( - request_id=request_id, - client=client, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_requests.py b/stackcoin/stackcoin_python/api/default/stackcoin_requests.py deleted file mode 100644 index 72c1884..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_requests.py +++ /dev/null @@ -1,246 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.requests_response import RequestsResponse -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - *, - role: Union[Unset, str] = UNSET, - status: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - since: Union[Unset, str] = UNSET, - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["role"] = role - - params["status"] = status - - params["discord_id"] = discord_id - - params["since"] = since - - params["page"] = page - - params["limit"] = limit - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/api/requests", - "params": params, - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[ErrorResponse, RequestsResponse]]: - if response.status_code == 200: - response_200 = RequestsResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[ErrorResponse, RequestsResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: Union[AuthenticatedClient, Client], - role: Union[Unset, str] = UNSET, - status: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - since: Union[Unset, str] = UNSET, - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, -) -> Response[Union[ErrorResponse, RequestsResponse]]: - """Get requests for the authenticated user - - Retrieves requests involving the authenticated user, with optional filtering and pagination. - - Args: - role (Union[Unset, str]): - status (Union[Unset, str]): - discord_id (Union[Unset, str]): - since (Union[Unset, str]): - page (Union[Unset, int]): - limit (Union[Unset, int]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, RequestsResponse]] - """ - - kwargs = _get_kwargs( - role=role, - status=status, - discord_id=discord_id, - since=since, - page=page, - limit=limit, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: Union[AuthenticatedClient, Client], - role: Union[Unset, str] = UNSET, - status: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - since: Union[Unset, str] = UNSET, - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, -) -> Optional[Union[ErrorResponse, RequestsResponse]]: - """Get requests for the authenticated user - - Retrieves requests involving the authenticated user, with optional filtering and pagination. - - Args: - role (Union[Unset, str]): - status (Union[Unset, str]): - discord_id (Union[Unset, str]): - since (Union[Unset, str]): - page (Union[Unset, int]): - limit (Union[Unset, int]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, RequestsResponse] - """ - - return sync_detailed( - client=client, - role=role, - status=status, - discord_id=discord_id, - since=since, - page=page, - limit=limit, - ).parsed - - -async def asyncio_detailed( - *, - client: Union[AuthenticatedClient, Client], - role: Union[Unset, str] = UNSET, - status: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - since: Union[Unset, str] = UNSET, - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, -) -> Response[Union[ErrorResponse, RequestsResponse]]: - """Get requests for the authenticated user - - Retrieves requests involving the authenticated user, with optional filtering and pagination. - - Args: - role (Union[Unset, str]): - status (Union[Unset, str]): - discord_id (Union[Unset, str]): - since (Union[Unset, str]): - page (Union[Unset, int]): - limit (Union[Unset, int]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, RequestsResponse]] - """ - - kwargs = _get_kwargs( - role=role, - status=status, - discord_id=discord_id, - since=since, - page=page, - limit=limit, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: Union[AuthenticatedClient, Client], - role: Union[Unset, str] = UNSET, - status: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - since: Union[Unset, str] = UNSET, - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, -) -> Optional[Union[ErrorResponse, RequestsResponse]]: - """Get requests for the authenticated user - - Retrieves requests involving the authenticated user, with optional filtering and pagination. - - Args: - role (Union[Unset, str]): - status (Union[Unset, str]): - discord_id (Union[Unset, str]): - since (Union[Unset, str]): - page (Union[Unset, int]): - limit (Union[Unset, int]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, RequestsResponse] - """ - - return ( - await asyncio_detailed( - client=client, - role=role, - status=status, - discord_id=discord_id, - since=since, - page=page, - limit=limit, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_send_stk.py b/stackcoin/stackcoin_python/api/default/stackcoin_send_stk.py deleted file mode 100644 index 841c1f7..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_send_stk.py +++ /dev/null @@ -1,201 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.send_stk_params import SendStkParams -from ...models.send_stk_response import SendStkResponse -from ...types import Response - - -def _get_kwargs( - user_id: int, - *, - body: SendStkParams, -) -> dict[str, Any]: - headers: dict[str, Any] = {} - - _kwargs: dict[str, Any] = { - "method": "post", - "url": f"/api/user/{user_id}/send", - } - - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[ErrorResponse, SendStkResponse]]: - if response.status_code == 200: - response_200 = SendStkResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - if response.status_code == 403: - response_403 = ErrorResponse.from_dict(response.json()) - - return response_403 - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - if response.status_code == 422: - response_422 = ErrorResponse.from_dict(response.json()) - - return response_422 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[ErrorResponse, SendStkResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], - body: SendStkParams, -) -> Response[Union[ErrorResponse, SendStkResponse]]: - """Send STK to a user - - Transfers STK from the authenticated user to a specified user. - - Args: - user_id (int): - body (SendStkParams): Parameters for sending STK Example: {'amount': 100, 'label': - 'Payment for services'}. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, SendStkResponse]] - """ - - kwargs = _get_kwargs( - user_id=user_id, - body=body, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], - body: SendStkParams, -) -> Optional[Union[ErrorResponse, SendStkResponse]]: - """Send STK to a user - - Transfers STK from the authenticated user to a specified user. - - Args: - user_id (int): - body (SendStkParams): Parameters for sending STK Example: {'amount': 100, 'label': - 'Payment for services'}. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, SendStkResponse] - """ - - return sync_detailed( - user_id=user_id, - client=client, - body=body, - ).parsed - - -async def asyncio_detailed( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], - body: SendStkParams, -) -> Response[Union[ErrorResponse, SendStkResponse]]: - """Send STK to a user - - Transfers STK from the authenticated user to a specified user. - - Args: - user_id (int): - body (SendStkParams): Parameters for sending STK Example: {'amount': 100, 'label': - 'Payment for services'}. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, SendStkResponse]] - """ - - kwargs = _get_kwargs( - user_id=user_id, - body=body, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], - body: SendStkParams, -) -> Optional[Union[ErrorResponse, SendStkResponse]]: - """Send STK to a user - - Transfers STK from the authenticated user to a specified user. - - Args: - user_id (int): - body (SendStkParams): Parameters for sending STK Example: {'amount': 100, 'label': - 'Payment for services'}. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, SendStkResponse] - """ - - return ( - await asyncio_detailed( - user_id=user_id, - client=client, - body=body, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_transaction.py b/stackcoin/stackcoin_python/api/default/stackcoin_transaction.py deleted file mode 100644 index e6bf2bd..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_transaction.py +++ /dev/null @@ -1,163 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.transaction_response import TransactionResponse -from ...types import Response - - -def _get_kwargs( - transaction_id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/api/transaction/{transaction_id}", - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[ErrorResponse, TransactionResponse]]: - if response.status_code == 200: - response_200 = TransactionResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[ErrorResponse, TransactionResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - transaction_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, TransactionResponse]]: - """Get transaction by ID - - Retrieves a single transaction by its ID. - - Args: - transaction_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, TransactionResponse]] - """ - - kwargs = _get_kwargs( - transaction_id=transaction_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - transaction_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, TransactionResponse]]: - """Get transaction by ID - - Retrieves a single transaction by its ID. - - Args: - transaction_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, TransactionResponse] - """ - - return sync_detailed( - transaction_id=transaction_id, - client=client, - ).parsed - - -async def asyncio_detailed( - transaction_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, TransactionResponse]]: - """Get transaction by ID - - Retrieves a single transaction by its ID. - - Args: - transaction_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, TransactionResponse]] - """ - - kwargs = _get_kwargs( - transaction_id=transaction_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - transaction_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, TransactionResponse]]: - """Get transaction by ID - - Retrieves a single transaction by its ID. - - Args: - transaction_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, TransactionResponse] - """ - - return ( - await asyncio_detailed( - transaction_id=transaction_id, - client=client, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_transactions.py b/stackcoin/stackcoin_python/api/default/stackcoin_transactions.py deleted file mode 100644 index 566466a..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_transactions.py +++ /dev/null @@ -1,261 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.transactions_response import TransactionsResponse -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - *, - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - from_user_id: Union[Unset, int] = UNSET, - to_user_id: Union[Unset, int] = UNSET, - from_discord_id: Union[Unset, str] = UNSET, - to_discord_id: Union[Unset, str] = UNSET, - includes_discord_id: Union[Unset, str] = UNSET, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["page"] = page - - params["limit"] = limit - - params["from_user_id"] = from_user_id - - params["to_user_id"] = to_user_id - - params["from_discord_id"] = from_discord_id - - params["to_discord_id"] = to_discord_id - - params["includes_discord_id"] = includes_discord_id - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/api/transactions", - "params": params, - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[ErrorResponse, TransactionsResponse]]: - if response.status_code == 200: - response_200 = TransactionsResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 400: - response_400 = ErrorResponse.from_dict(response.json()) - - return response_400 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[ErrorResponse, TransactionsResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - from_user_id: Union[Unset, int] = UNSET, - to_user_id: Union[Unset, int] = UNSET, - from_discord_id: Union[Unset, str] = UNSET, - to_discord_id: Union[Unset, str] = UNSET, - includes_discord_id: Union[Unset, str] = UNSET, -) -> Response[Union[ErrorResponse, TransactionsResponse]]: - """Get transactions for the authenticated user - - Retrieves transactions involving the authenticated user, with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - from_user_id (Union[Unset, int]): - to_user_id (Union[Unset, int]): - from_discord_id (Union[Unset, str]): - to_discord_id (Union[Unset, str]): - includes_discord_id (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, TransactionsResponse]] - """ - - kwargs = _get_kwargs( - page=page, - limit=limit, - from_user_id=from_user_id, - to_user_id=to_user_id, - from_discord_id=from_discord_id, - to_discord_id=to_discord_id, - includes_discord_id=includes_discord_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - from_user_id: Union[Unset, int] = UNSET, - to_user_id: Union[Unset, int] = UNSET, - from_discord_id: Union[Unset, str] = UNSET, - to_discord_id: Union[Unset, str] = UNSET, - includes_discord_id: Union[Unset, str] = UNSET, -) -> Optional[Union[ErrorResponse, TransactionsResponse]]: - """Get transactions for the authenticated user - - Retrieves transactions involving the authenticated user, with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - from_user_id (Union[Unset, int]): - to_user_id (Union[Unset, int]): - from_discord_id (Union[Unset, str]): - to_discord_id (Union[Unset, str]): - includes_discord_id (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, TransactionsResponse] - """ - - return sync_detailed( - client=client, - page=page, - limit=limit, - from_user_id=from_user_id, - to_user_id=to_user_id, - from_discord_id=from_discord_id, - to_discord_id=to_discord_id, - includes_discord_id=includes_discord_id, - ).parsed - - -async def asyncio_detailed( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - from_user_id: Union[Unset, int] = UNSET, - to_user_id: Union[Unset, int] = UNSET, - from_discord_id: Union[Unset, str] = UNSET, - to_discord_id: Union[Unset, str] = UNSET, - includes_discord_id: Union[Unset, str] = UNSET, -) -> Response[Union[ErrorResponse, TransactionsResponse]]: - """Get transactions for the authenticated user - - Retrieves transactions involving the authenticated user, with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - from_user_id (Union[Unset, int]): - to_user_id (Union[Unset, int]): - from_discord_id (Union[Unset, str]): - to_discord_id (Union[Unset, str]): - includes_discord_id (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, TransactionsResponse]] - """ - - kwargs = _get_kwargs( - page=page, - limit=limit, - from_user_id=from_user_id, - to_user_id=to_user_id, - from_discord_id=from_discord_id, - to_discord_id=to_discord_id, - includes_discord_id=includes_discord_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - from_user_id: Union[Unset, int] = UNSET, - to_user_id: Union[Unset, int] = UNSET, - from_discord_id: Union[Unset, str] = UNSET, - to_discord_id: Union[Unset, str] = UNSET, - includes_discord_id: Union[Unset, str] = UNSET, -) -> Optional[Union[ErrorResponse, TransactionsResponse]]: - """Get transactions for the authenticated user - - Retrieves transactions involving the authenticated user, with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - from_user_id (Union[Unset, int]): - to_user_id (Union[Unset, int]): - from_discord_id (Union[Unset, str]): - to_discord_id (Union[Unset, str]): - includes_discord_id (Union[Unset, str]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, TransactionsResponse] - """ - - return ( - await asyncio_detailed( - client=client, - page=page, - limit=limit, - from_user_id=from_user_id, - to_user_id=to_user_id, - from_discord_id=from_discord_id, - to_discord_id=to_discord_id, - includes_discord_id=includes_discord_id, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_user.py b/stackcoin/stackcoin_python/api/default/stackcoin_user.py deleted file mode 100644 index c0b9dac..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_user.py +++ /dev/null @@ -1,163 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.error_response import ErrorResponse -from ...models.user_response import UserResponse -from ...types import Response - - -def _get_kwargs( - user_id: int, -) -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": f"/api/user/{user_id}", - } - - return _kwargs - - -def _parse_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Optional[Union[ErrorResponse, UserResponse]]: - if response.status_code == 200: - response_200 = UserResponse.from_dict(response.json()) - - return response_200 - if response.status_code == 404: - response_404 = ErrorResponse.from_dict(response.json()) - - return response_404 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response( - *, client: Union[AuthenticatedClient, Client], response: httpx.Response -) -> Response[Union[ErrorResponse, UserResponse]]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, UserResponse]]: - """Get user by ID - - Retrieves a single user by their ID. - - Args: - user_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, UserResponse]] - """ - - kwargs = _get_kwargs( - user_id=user_id, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, UserResponse]]: - """Get user by ID - - Retrieves a single user by their ID. - - Args: - user_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, UserResponse] - """ - - return sync_detailed( - user_id=user_id, - client=client, - ).parsed - - -async def asyncio_detailed( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Response[Union[ErrorResponse, UserResponse]]: - """Get user by ID - - Retrieves a single user by their ID. - - Args: - user_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[Union[ErrorResponse, UserResponse]] - """ - - kwargs = _get_kwargs( - user_id=user_id, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - user_id: int, - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[Union[ErrorResponse, UserResponse]]: - """Get user by ID - - Retrieves a single user by their ID. - - Args: - user_id (int): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Union[ErrorResponse, UserResponse] - """ - - return ( - await asyncio_detailed( - user_id=user_id, - client=client, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_user_me.py b/stackcoin/stackcoin_python/api/default/stackcoin_user_me.py deleted file mode 100644 index d4479b6..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_user_me.py +++ /dev/null @@ -1,130 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.user_response import UserResponse -from ...types import Response - - -def _get_kwargs() -> dict[str, Any]: - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/api/user/me", - } - - return _kwargs - - -def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[UserResponse]: - if response.status_code == 200: - response_200 = UserResponse.from_dict(response.json()) - - return response_200 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[UserResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: Union[AuthenticatedClient, Client], -) -> Response[UserResponse]: - """Get authenticated user's profile - - Returns the full profile of the authenticated bot user. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[UserResponse] - """ - - kwargs = _get_kwargs() - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[UserResponse]: - """Get authenticated user's profile - - Returns the full profile of the authenticated bot user. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - UserResponse - """ - - return sync_detailed( - client=client, - ).parsed - - -async def asyncio_detailed( - *, - client: Union[AuthenticatedClient, Client], -) -> Response[UserResponse]: - """Get authenticated user's profile - - Returns the full profile of the authenticated bot user. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[UserResponse] - """ - - kwargs = _get_kwargs() - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: Union[AuthenticatedClient, Client], -) -> Optional[UserResponse]: - """Get authenticated user's profile - - Returns the full profile of the authenticated bot user. - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - UserResponse - """ - - return ( - await asyncio_detailed( - client=client, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/api/default/stackcoin_users.py b/stackcoin/stackcoin_python/api/default/stackcoin_users.py deleted file mode 100644 index b5820d7..0000000 --- a/stackcoin/stackcoin_python/api/default/stackcoin_users.py +++ /dev/null @@ -1,237 +0,0 @@ -from http import HTTPStatus -from typing import Any, Optional, Union - -import httpx - -from ... import errors -from ...client import AuthenticatedClient, Client -from ...models.users_response import UsersResponse -from ...types import UNSET, Response, Unset - - -def _get_kwargs( - *, - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - username: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - banned: Union[Unset, bool] = UNSET, - admin: Union[Unset, bool] = UNSET, -) -> dict[str, Any]: - params: dict[str, Any] = {} - - params["page"] = page - - params["limit"] = limit - - params["username"] = username - - params["discord_id"] = discord_id - - params["banned"] = banned - - params["admin"] = admin - - params = {k: v for k, v in params.items() if v is not UNSET and v is not None} - - _kwargs: dict[str, Any] = { - "method": "get", - "url": "/api/users", - "params": params, - } - - return _kwargs - - -def _parse_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Optional[UsersResponse]: - if response.status_code == 200: - response_200 = UsersResponse.from_dict(response.json()) - - return response_200 - if client.raise_on_unexpected_status: - raise errors.UnexpectedStatus(response.status_code, response.content) - else: - return None - - -def _build_response(*, client: Union[AuthenticatedClient, Client], response: httpx.Response) -> Response[UsersResponse]: - return Response( - status_code=HTTPStatus(response.status_code), - content=response.content, - headers=response.headers, - parsed=_parse_response(client=client, response=response), - ) - - -def sync_detailed( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - username: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - banned: Union[Unset, bool] = UNSET, - admin: Union[Unset, bool] = UNSET, -) -> Response[UsersResponse]: - """Get users - - Retrieves users with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - username (Union[Unset, str]): - discord_id (Union[Unset, str]): - banned (Union[Unset, bool]): - admin (Union[Unset, bool]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[UsersResponse] - """ - - kwargs = _get_kwargs( - page=page, - limit=limit, - username=username, - discord_id=discord_id, - banned=banned, - admin=admin, - ) - - response = client.get_httpx_client().request( - **kwargs, - ) - - return _build_response(client=client, response=response) - - -def sync( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - username: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - banned: Union[Unset, bool] = UNSET, - admin: Union[Unset, bool] = UNSET, -) -> Optional[UsersResponse]: - """Get users - - Retrieves users with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - username (Union[Unset, str]): - discord_id (Union[Unset, str]): - banned (Union[Unset, bool]): - admin (Union[Unset, bool]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - UsersResponse - """ - - return sync_detailed( - client=client, - page=page, - limit=limit, - username=username, - discord_id=discord_id, - banned=banned, - admin=admin, - ).parsed - - -async def asyncio_detailed( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - username: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - banned: Union[Unset, bool] = UNSET, - admin: Union[Unset, bool] = UNSET, -) -> Response[UsersResponse]: - """Get users - - Retrieves users with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - username (Union[Unset, str]): - discord_id (Union[Unset, str]): - banned (Union[Unset, bool]): - admin (Union[Unset, bool]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - Response[UsersResponse] - """ - - kwargs = _get_kwargs( - page=page, - limit=limit, - username=username, - discord_id=discord_id, - banned=banned, - admin=admin, - ) - - response = await client.get_async_httpx_client().request(**kwargs) - - return _build_response(client=client, response=response) - - -async def asyncio( - *, - client: Union[AuthenticatedClient, Client], - page: Union[Unset, int] = UNSET, - limit: Union[Unset, int] = UNSET, - username: Union[Unset, str] = UNSET, - discord_id: Union[Unset, str] = UNSET, - banned: Union[Unset, bool] = UNSET, - admin: Union[Unset, bool] = UNSET, -) -> Optional[UsersResponse]: - """Get users - - Retrieves users with optional filtering and pagination. - - Args: - page (Union[Unset, int]): - limit (Union[Unset, int]): - username (Union[Unset, str]): - discord_id (Union[Unset, str]): - banned (Union[Unset, bool]): - admin (Union[Unset, bool]): - - Raises: - errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. - httpx.TimeoutException: If the request takes longer than Client.timeout. - - Returns: - UsersResponse - """ - - return ( - await asyncio_detailed( - client=client, - page=page, - limit=limit, - username=username, - discord_id=discord_id, - banned=banned, - admin=admin, - ) - ).parsed diff --git a/stackcoin/stackcoin_python/client.py b/stackcoin/stackcoin_python/client.py deleted file mode 100644 index e80446f..0000000 --- a/stackcoin/stackcoin_python/client.py +++ /dev/null @@ -1,268 +0,0 @@ -import ssl -from typing import Any, Optional, Union - -import httpx -from attrs import define, evolve, field - - -@define -class Client: - """A class for keeping track of data related to the API - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - def with_headers(self, headers: dict[str, str]) -> "Client": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "Client": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "Client": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - def set_httpx_client(self, client: httpx.Client) -> "Client": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "Client": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "Client": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) - - -@define -class AuthenticatedClient: - """A Client which has been authenticated for use on secured endpoints - - The following are accepted as keyword arguments and will be used to construct httpx Clients internally: - - ``base_url``: The base URL for the API, all requests are made to a relative path to this URL - - ``cookies``: A dictionary of cookies to be sent with every request - - ``headers``: A dictionary of headers to be sent with every request - - ``timeout``: The maximum amount of a time a request can take. API functions will raise - httpx.TimeoutException if this is exceeded. - - ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, - but can be set to False for testing purposes. - - ``follow_redirects``: Whether or not to follow redirects. Default value is False. - - ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. - - - Attributes: - raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a - status code that was not documented in the source OpenAPI document. Can also be provided as a keyword - argument to the constructor. - token: The token to use for authentication - prefix: The prefix to use for the Authorization header - auth_header_name: The name of the Authorization header - """ - - raise_on_unexpected_status: bool = field(default=False, kw_only=True) - _base_url: str = field(alias="base_url") - _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") - _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") - _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout") - _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl") - _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") - _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") - _client: Optional[httpx.Client] = field(default=None, init=False) - _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False) - - token: str - prefix: str = "Bearer" - auth_header_name: str = "Authorization" - - def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional headers""" - if self._client is not None: - self._client.headers.update(headers) - if self._async_client is not None: - self._async_client.headers.update(headers) - return evolve(self, headers={**self._headers, **headers}) - - def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": - """Get a new client matching this one with additional cookies""" - if self._client is not None: - self._client.cookies.update(cookies) - if self._async_client is not None: - self._async_client.cookies.update(cookies) - return evolve(self, cookies={**self._cookies, **cookies}) - - def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": - """Get a new client matching this one with a new timeout (in seconds)""" - if self._client is not None: - self._client.timeout = timeout - if self._async_client is not None: - self._async_client.timeout = timeout - return evolve(self, timeout=timeout) - - def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": - """Manually set the underlying httpx.Client - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._client = client - return self - - def get_httpx_client(self) -> httpx.Client: - """Get the underlying httpx.Client, constructing a new one if not previously set""" - if self._client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._client = httpx.Client( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._client - - def __enter__(self) -> "AuthenticatedClient": - """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" - self.get_httpx_client().__enter__() - return self - - def __exit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for internal httpx.Client (see httpx docs)""" - self.get_httpx_client().__exit__(*args, **kwargs) - - def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": - """Manually the underlying httpx.AsyncClient - - **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. - """ - self._async_client = async_client - return self - - def get_async_httpx_client(self) -> httpx.AsyncClient: - """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" - if self._async_client is None: - self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token - self._async_client = httpx.AsyncClient( - base_url=self._base_url, - cookies=self._cookies, - headers=self._headers, - timeout=self._timeout, - verify=self._verify_ssl, - follow_redirects=self._follow_redirects, - **self._httpx_args, - ) - return self._async_client - - async def __aenter__(self) -> "AuthenticatedClient": - """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" - await self.get_async_httpx_client().__aenter__() - return self - - async def __aexit__(self, *args: Any, **kwargs: Any) -> None: - """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" - await self.get_async_httpx_client().__aexit__(*args, **kwargs) diff --git a/stackcoin/stackcoin_python/errors.py b/stackcoin/stackcoin_python/errors.py deleted file mode 100644 index 5f92e76..0000000 --- a/stackcoin/stackcoin_python/errors.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Contains shared errors types that can be raised from API functions""" - - -class UnexpectedStatus(Exception): - """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" - - def __init__(self, status_code: int, content: bytes): - self.status_code = status_code - self.content = content - - super().__init__( - f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}" - ) - - -__all__ = ["UnexpectedStatus"] diff --git a/stackcoin/stackcoin_python/models/__init__.py b/stackcoin/stackcoin_python/models/__init__.py deleted file mode 100644 index fe146b6..0000000 --- a/stackcoin/stackcoin_python/models/__init__.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Contains all the data models used in inputs/outputs""" - -from .create_request_params import CreateRequestParams -from .create_request_response import CreateRequestResponse -from .create_request_response_requester import CreateRequestResponseRequester -from .create_request_response_responder import CreateRequestResponseResponder -from .discord_guild import DiscordGuild -from .discord_guild_response import DiscordGuildResponse -from .discord_guilds_response import DiscordGuildsResponse -from .discord_guilds_response_pagination import DiscordGuildsResponsePagination -from .error_response import ErrorResponse -from .request import Request -from .request_action_response import RequestActionResponse -from .request_requester import RequestRequester -from .request_responder import RequestResponder -from .request_response import RequestResponse -from .request_response_requester import RequestResponseRequester -from .request_response_responder import RequestResponseResponder -from .requests_response import RequestsResponse -from .requests_response_pagination import RequestsResponsePagination -from .send_stk_params import SendStkParams -from .send_stk_response import SendStkResponse -from .transaction import Transaction -from .transaction_from import TransactionFrom -from .transaction_response import TransactionResponse -from .transaction_response_from import TransactionResponseFrom -from .transaction_response_to import TransactionResponseTo -from .transaction_to import TransactionTo -from .transactions_response import TransactionsResponse -from .transactions_response_pagination import TransactionsResponsePagination -from .user import User -from .user_response import UserResponse -from .users_response import UsersResponse -from .users_response_pagination import UsersResponsePagination - -__all__ = ( - "CreateRequestParams", - "CreateRequestResponse", - "CreateRequestResponseRequester", - "CreateRequestResponseResponder", - "DiscordGuild", - "DiscordGuildResponse", - "DiscordGuildsResponse", - "DiscordGuildsResponsePagination", - "ErrorResponse", - "Request", - "RequestActionResponse", - "RequestRequester", - "RequestResponder", - "RequestResponse", - "RequestResponseRequester", - "RequestResponseResponder", - "RequestsResponse", - "RequestsResponsePagination", - "SendStkParams", - "SendStkResponse", - "Transaction", - "TransactionFrom", - "TransactionResponse", - "TransactionResponseFrom", - "TransactionResponseTo", - "TransactionsResponse", - "TransactionsResponsePagination", - "TransactionTo", - "User", - "UserResponse", - "UsersResponse", - "UsersResponsePagination", -) diff --git a/stackcoin/stackcoin_python/models/create_request_params.py b/stackcoin/stackcoin_python/models/create_request_params.py deleted file mode 100644 index afd5798..0000000 --- a/stackcoin/stackcoin_python/models/create_request_params.py +++ /dev/null @@ -1,85 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateRequestParams") - - -@_attrs_define -class CreateRequestParams: - """Parameters for creating a STK request - - Example: - {'amount': 200, 'label': 'Payment request'} - - Attributes: - amount (int): Amount of STK to request - label (Union[None, Unset, str]): Optional request label - """ - - amount: int - label: Union[None, Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - amount = self.amount - - label: Union[None, Unset, str] - if isinstance(self.label, Unset): - label = UNSET - else: - label = self.label - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "amount": amount, - } - ) - if label is not UNSET: - field_dict["label"] = label - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - amount = d.pop("amount") - - def _parse_label(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - label = _parse_label(d.pop("label", UNSET)) - - create_request_params = cls( - amount=amount, - label=label, - ) - - create_request_params.additional_properties = d - return create_request_params - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/create_request_response.py b/stackcoin/stackcoin_python/models/create_request_response.py deleted file mode 100644 index 0ea2bba..0000000 --- a/stackcoin/stackcoin_python/models/create_request_response.py +++ /dev/null @@ -1,122 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -if TYPE_CHECKING: - from ..models.create_request_response_requester import CreateRequestResponseRequester - from ..models.create_request_response_responder import CreateRequestResponseResponder - - -T = TypeVar("T", bound="CreateRequestResponse") - - -@_attrs_define -class CreateRequestResponse: - """Response schema for creating a request - - Example: - {'amount': 200, 'request_id': 789, 'requested_at': '2019-09-12T12:34:55Z', 'requester': {'id': 123, 'username': - 'johndoe'}, 'responder': {'id': 456, 'username': 'janedoe'}, 'status': 'pending', 'success': True} - - Attributes: - amount (int): Requested amount - request_id (int): Created request ID - requested_at (datetime.datetime): Request timestamp - requester (CreateRequestResponseRequester): - responder (CreateRequestResponseResponder): - status (str): Request status - success (bool): Whether the operation succeeded - """ - - amount: int - request_id: int - requested_at: datetime.datetime - requester: "CreateRequestResponseRequester" - responder: "CreateRequestResponseResponder" - status: str - success: bool - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - amount = self.amount - - request_id = self.request_id - - requested_at = self.requested_at.isoformat() - - requester = self.requester.to_dict() - - responder = self.responder.to_dict() - - status = self.status - - success = self.success - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "amount": amount, - "request_id": request_id, - "requested_at": requested_at, - "requester": requester, - "responder": responder, - "status": status, - "success": success, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.create_request_response_requester import CreateRequestResponseRequester - from ..models.create_request_response_responder import CreateRequestResponseResponder - - d = dict(src_dict) - amount = d.pop("amount") - - request_id = d.pop("request_id") - - requested_at = isoparse(d.pop("requested_at")) - - requester = CreateRequestResponseRequester.from_dict(d.pop("requester")) - - responder = CreateRequestResponseResponder.from_dict(d.pop("responder")) - - status = d.pop("status") - - success = d.pop("success") - - create_request_response = cls( - amount=amount, - request_id=request_id, - requested_at=requested_at, - requester=requester, - responder=responder, - status=status, - success=success, - ) - - create_request_response.additional_properties = d - return create_request_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/create_request_response_requester.py b/stackcoin/stackcoin_python/models/create_request_response_requester.py deleted file mode 100644 index f56268c..0000000 --- a/stackcoin/stackcoin_python/models/create_request_response_requester.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateRequestResponseRequester") - - -@_attrs_define -class CreateRequestResponseRequester: - """ - Attributes: - id (Union[Unset, int]): Requester user ID - username (Union[Unset, str]): Requester username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - create_request_response_requester = cls( - id=id, - username=username, - ) - - create_request_response_requester.additional_properties = d - return create_request_response_requester - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/create_request_response_responder.py b/stackcoin/stackcoin_python/models/create_request_response_responder.py deleted file mode 100644 index 323369a..0000000 --- a/stackcoin/stackcoin_python/models/create_request_response_responder.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="CreateRequestResponseResponder") - - -@_attrs_define -class CreateRequestResponseResponder: - """ - Attributes: - id (Union[Unset, int]): Responder user ID - username (Union[Unset, str]): Responder username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - create_request_response_responder = cls( - id=id, - username=username, - ) - - create_request_response_responder.additional_properties = d - return create_request_response_responder - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/discord_guild.py b/stackcoin/stackcoin_python/models/discord_guild.py deleted file mode 100644 index 8a9b35e..0000000 --- a/stackcoin/stackcoin_python/models/discord_guild.py +++ /dev/null @@ -1,112 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="DiscordGuild") - - -@_attrs_define -class DiscordGuild: - """A Discord guild - - Example: - {'designated_channel_snowflake': '987654321098765432', 'id': 123, 'last_updated': '2019-09-12T12:34:55Z', - 'name': 'My Discord Server', 'snowflake': '123456789012345678'} - - Attributes: - id (int): Guild ID - last_updated (datetime.datetime): Last updated timestamp - name (str): Guild name - snowflake (str): Discord guild snowflake ID - designated_channel_snowflake (Union[None, Unset, str]): Designated channel snowflake ID - """ - - id: int - last_updated: datetime.datetime - name: str - snowflake: str - designated_channel_snowflake: Union[None, Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - last_updated = self.last_updated.isoformat() - - name = self.name - - snowflake = self.snowflake - - designated_channel_snowflake: Union[None, Unset, str] - if isinstance(self.designated_channel_snowflake, Unset): - designated_channel_snowflake = UNSET - else: - designated_channel_snowflake = self.designated_channel_snowflake - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "id": id, - "last_updated": last_updated, - "name": name, - "snowflake": snowflake, - } - ) - if designated_channel_snowflake is not UNSET: - field_dict["designated_channel_snowflake"] = designated_channel_snowflake - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id") - - last_updated = isoparse(d.pop("last_updated")) - - name = d.pop("name") - - snowflake = d.pop("snowflake") - - def _parse_designated_channel_snowflake(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - designated_channel_snowflake = _parse_designated_channel_snowflake(d.pop("designated_channel_snowflake", UNSET)) - - discord_guild = cls( - id=id, - last_updated=last_updated, - name=name, - snowflake=snowflake, - designated_channel_snowflake=designated_channel_snowflake, - ) - - discord_guild.additional_properties = d - return discord_guild - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/discord_guild_response.py b/stackcoin/stackcoin_python/models/discord_guild_response.py deleted file mode 100644 index 2b8e19a..0000000 --- a/stackcoin/stackcoin_python/models/discord_guild_response.py +++ /dev/null @@ -1,112 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="DiscordGuildResponse") - - -@_attrs_define -class DiscordGuildResponse: - """Response schema for single Discord guild - - Example: - {'designated_channel_snowflake': '987654321098765432', 'id': 123, 'last_updated': '2019-09-12T12:34:55Z', - 'name': 'My Discord Server', 'snowflake': '123456789012345678'} - - Attributes: - id (int): Guild ID - last_updated (datetime.datetime): Last updated timestamp - name (str): Guild name - snowflake (str): Discord guild snowflake ID - designated_channel_snowflake (Union[None, Unset, str]): Designated channel snowflake ID - """ - - id: int - last_updated: datetime.datetime - name: str - snowflake: str - designated_channel_snowflake: Union[None, Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - last_updated = self.last_updated.isoformat() - - name = self.name - - snowflake = self.snowflake - - designated_channel_snowflake: Union[None, Unset, str] - if isinstance(self.designated_channel_snowflake, Unset): - designated_channel_snowflake = UNSET - else: - designated_channel_snowflake = self.designated_channel_snowflake - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "id": id, - "last_updated": last_updated, - "name": name, - "snowflake": snowflake, - } - ) - if designated_channel_snowflake is not UNSET: - field_dict["designated_channel_snowflake"] = designated_channel_snowflake - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id") - - last_updated = isoparse(d.pop("last_updated")) - - name = d.pop("name") - - snowflake = d.pop("snowflake") - - def _parse_designated_channel_snowflake(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - designated_channel_snowflake = _parse_designated_channel_snowflake(d.pop("designated_channel_snowflake", UNSET)) - - discord_guild_response = cls( - id=id, - last_updated=last_updated, - name=name, - snowflake=snowflake, - designated_channel_snowflake=designated_channel_snowflake, - ) - - discord_guild_response.additional_properties = d - return discord_guild_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/discord_guilds_response.py b/stackcoin/stackcoin_python/models/discord_guilds_response.py deleted file mode 100644 index 79f5b36..0000000 --- a/stackcoin/stackcoin_python/models/discord_guilds_response.py +++ /dev/null @@ -1,101 +0,0 @@ -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.discord_guild import DiscordGuild - from ..models.discord_guilds_response_pagination import DiscordGuildsResponsePagination - - -T = TypeVar("T", bound="DiscordGuildsResponse") - - -@_attrs_define -class DiscordGuildsResponse: - """Response schema for multiple Discord guilds - - Example: - {'guilds': [{'designated_channel_snowflake': '987654321098765432', 'id': 123, 'last_updated': - '2019-09-12T12:34:55Z', 'name': 'My Discord Server', 'snowflake': '123456789012345678'}, - {'designated_channel_snowflake': None, 'id': 456, 'last_updated': '2019-09-13T10:11:12Z', 'name': 'Another - Server', 'snowflake': '876543210987654321'}], 'pagination': {'limit': 20, 'page': 1, 'total': 2, 'total_pages': - 1}} - - Attributes: - guilds (Union[Unset, list['DiscordGuild']]): The guilds list - pagination (Union[Unset, DiscordGuildsResponsePagination]): - """ - - guilds: Union[Unset, list["DiscordGuild"]] = UNSET - pagination: Union[Unset, "DiscordGuildsResponsePagination"] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - guilds: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.guilds, Unset): - guilds = [] - for guilds_item_data in self.guilds: - guilds_item = guilds_item_data.to_dict() - guilds.append(guilds_item) - - pagination: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.pagination, Unset): - pagination = self.pagination.to_dict() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if guilds is not UNSET: - field_dict["guilds"] = guilds - if pagination is not UNSET: - field_dict["pagination"] = pagination - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.discord_guild import DiscordGuild - from ..models.discord_guilds_response_pagination import DiscordGuildsResponsePagination - - d = dict(src_dict) - guilds = [] - _guilds = d.pop("guilds", UNSET) - for guilds_item_data in _guilds or []: - guilds_item = DiscordGuild.from_dict(guilds_item_data) - - guilds.append(guilds_item) - - _pagination = d.pop("pagination", UNSET) - pagination: Union[Unset, DiscordGuildsResponsePagination] - if isinstance(_pagination, Unset): - pagination = UNSET - else: - pagination = DiscordGuildsResponsePagination.from_dict(_pagination) - - discord_guilds_response = cls( - guilds=guilds, - pagination=pagination, - ) - - discord_guilds_response.additional_properties = d - return discord_guilds_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/discord_guilds_response_pagination.py b/stackcoin/stackcoin_python/models/discord_guilds_response_pagination.py deleted file mode 100644 index 95ba938..0000000 --- a/stackcoin/stackcoin_python/models/discord_guilds_response_pagination.py +++ /dev/null @@ -1,86 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="DiscordGuildsResponsePagination") - - -@_attrs_define -class DiscordGuildsResponsePagination: - """ - Attributes: - limit (Union[Unset, int]): Items per page - page (Union[Unset, int]): Current page - total (Union[Unset, int]): Total items - total_pages (Union[Unset, int]): Total pages - """ - - limit: Union[Unset, int] = UNSET - page: Union[Unset, int] = UNSET - total: Union[Unset, int] = UNSET - total_pages: Union[Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - limit = self.limit - - page = self.page - - total = self.total - - total_pages = self.total_pages - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if limit is not UNSET: - field_dict["limit"] = limit - if page is not UNSET: - field_dict["page"] = page - if total is not UNSET: - field_dict["total"] = total - if total_pages is not UNSET: - field_dict["total_pages"] = total_pages - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - limit = d.pop("limit", UNSET) - - page = d.pop("page", UNSET) - - total = d.pop("total", UNSET) - - total_pages = d.pop("total_pages", UNSET) - - discord_guilds_response_pagination = cls( - limit=limit, - page=page, - total=total, - total_pages=total_pages, - ) - - discord_guilds_response_pagination.additional_properties = d - return discord_guilds_response_pagination - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/error_response.py b/stackcoin/stackcoin_python/models/error_response.py deleted file mode 100644 index aa4a460..0000000 --- a/stackcoin/stackcoin_python/models/error_response.py +++ /dev/null @@ -1,63 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="ErrorResponse") - - -@_attrs_define -class ErrorResponse: - """Error response schema - - Example: - {'error': 'User not found'} - - Attributes: - error (str): Error message - """ - - error: str - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - error = self.error - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "error": error, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - error = d.pop("error") - - error_response = cls( - error=error, - ) - - error_response.additional_properties = d - return error_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/request.py b/stackcoin/stackcoin_python/models/request.py deleted file mode 100644 index e013fb7..0000000 --- a/stackcoin/stackcoin_python/models/request.py +++ /dev/null @@ -1,187 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.request_requester import RequestRequester - from ..models.request_responder import RequestResponder - - -T = TypeVar("T", bound="Request") - - -@_attrs_define -class Request: - """A STK request - - Example: - {'amount': 200, 'id': 789, 'label': 'Payment request', 'requested_at': '2019-09-12T12:34:55Z', 'requester': - {'id': 123, 'username': 'johndoe'}, 'resolved_at': None, 'responder': {'id': 456, 'username': 'janedoe'}, - 'status': 'pending', 'transaction_id': None} - - Attributes: - amount (int): Requested amount - id (int): Request ID - requested_at (datetime.datetime): Request timestamp - requester (RequestRequester): - responder (RequestResponder): - status (str): Request status - label (Union[None, Unset, str]): Request label - resolved_at (Union[None, Unset, datetime.datetime]): Resolution timestamp - transaction_id (Union[None, Unset, int]): Associated transaction ID - """ - - amount: int - id: int - requested_at: datetime.datetime - requester: "RequestRequester" - responder: "RequestResponder" - status: str - label: Union[None, Unset, str] = UNSET - resolved_at: Union[None, Unset, datetime.datetime] = UNSET - transaction_id: Union[None, Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - amount = self.amount - - id = self.id - - requested_at = self.requested_at.isoformat() - - requester = self.requester.to_dict() - - responder = self.responder.to_dict() - - status = self.status - - label: Union[None, Unset, str] - if isinstance(self.label, Unset): - label = UNSET - else: - label = self.label - - resolved_at: Union[None, Unset, str] - if isinstance(self.resolved_at, Unset): - resolved_at = UNSET - elif isinstance(self.resolved_at, datetime.datetime): - resolved_at = self.resolved_at.isoformat() - else: - resolved_at = self.resolved_at - - transaction_id: Union[None, Unset, int] - if isinstance(self.transaction_id, Unset): - transaction_id = UNSET - else: - transaction_id = self.transaction_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "amount": amount, - "id": id, - "requested_at": requested_at, - "requester": requester, - "responder": responder, - "status": status, - } - ) - if label is not UNSET: - field_dict["label"] = label - if resolved_at is not UNSET: - field_dict["resolved_at"] = resolved_at - if transaction_id is not UNSET: - field_dict["transaction_id"] = transaction_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.request_requester import RequestRequester - from ..models.request_responder import RequestResponder - - d = dict(src_dict) - amount = d.pop("amount") - - id = d.pop("id") - - requested_at = isoparse(d.pop("requested_at")) - - requester = RequestRequester.from_dict(d.pop("requester")) - - responder = RequestResponder.from_dict(d.pop("responder")) - - status = d.pop("status") - - def _parse_label(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - label = _parse_label(d.pop("label", UNSET)) - - def _parse_resolved_at(data: object) -> Union[None, Unset, datetime.datetime]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, str): - raise TypeError() - resolved_at_type_0 = isoparse(data) - - return resolved_at_type_0 - except: # noqa: E722 - pass - return cast(Union[None, Unset, datetime.datetime], data) - - resolved_at = _parse_resolved_at(d.pop("resolved_at", UNSET)) - - def _parse_transaction_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - transaction_id = _parse_transaction_id(d.pop("transaction_id", UNSET)) - - request = cls( - amount=amount, - id=id, - requested_at=requested_at, - requester=requester, - responder=responder, - status=status, - label=label, - resolved_at=resolved_at, - transaction_id=transaction_id, - ) - - request.additional_properties = d - return request - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/request_action_response.py b/stackcoin/stackcoin_python/models/request_action_response.py deleted file mode 100644 index cbf1922..0000000 --- a/stackcoin/stackcoin_python/models/request_action_response.py +++ /dev/null @@ -1,112 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="RequestActionResponse") - - -@_attrs_define -class RequestActionResponse: - """Response schema for request actions (accept/deny) - - Example: - {'request_id': 789, 'resolved_at': '2025-09-12T13:34:55Z', 'status': 'accepted', 'success': True, - 'transaction_id': 456} - - Attributes: - request_id (int): Request ID - resolved_at (datetime.datetime): Resolution timestamp - status (str): New request status - success (bool): Whether the operation succeeded - transaction_id (Union[None, Unset, int]): Associated transaction ID - """ - - request_id: int - resolved_at: datetime.datetime - status: str - success: bool - transaction_id: Union[None, Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - request_id = self.request_id - - resolved_at = self.resolved_at.isoformat() - - status = self.status - - success = self.success - - transaction_id: Union[None, Unset, int] - if isinstance(self.transaction_id, Unset): - transaction_id = UNSET - else: - transaction_id = self.transaction_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "request_id": request_id, - "resolved_at": resolved_at, - "status": status, - "success": success, - } - ) - if transaction_id is not UNSET: - field_dict["transaction_id"] = transaction_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - request_id = d.pop("request_id") - - resolved_at = isoparse(d.pop("resolved_at")) - - status = d.pop("status") - - success = d.pop("success") - - def _parse_transaction_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - transaction_id = _parse_transaction_id(d.pop("transaction_id", UNSET)) - - request_action_response = cls( - request_id=request_id, - resolved_at=resolved_at, - status=status, - success=success, - transaction_id=transaction_id, - ) - - request_action_response.additional_properties = d - return request_action_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/request_requester.py b/stackcoin/stackcoin_python/models/request_requester.py deleted file mode 100644 index af653ce..0000000 --- a/stackcoin/stackcoin_python/models/request_requester.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="RequestRequester") - - -@_attrs_define -class RequestRequester: - """ - Attributes: - id (Union[Unset, int]): Requester user ID - username (Union[Unset, str]): Requester username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - request_requester = cls( - id=id, - username=username, - ) - - request_requester.additional_properties = d - return request_requester - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/request_responder.py b/stackcoin/stackcoin_python/models/request_responder.py deleted file mode 100644 index 3f0d4c6..0000000 --- a/stackcoin/stackcoin_python/models/request_responder.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="RequestResponder") - - -@_attrs_define -class RequestResponder: - """ - Attributes: - id (Union[Unset, int]): Responder user ID - username (Union[Unset, str]): Responder username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - request_responder = cls( - id=id, - username=username, - ) - - request_responder.additional_properties = d - return request_responder - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/request_response.py b/stackcoin/stackcoin_python/models/request_response.py deleted file mode 100644 index 3d3f5a5..0000000 --- a/stackcoin/stackcoin_python/models/request_response.py +++ /dev/null @@ -1,187 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.request_response_requester import RequestResponseRequester - from ..models.request_response_responder import RequestResponseResponder - - -T = TypeVar("T", bound="RequestResponse") - - -@_attrs_define -class RequestResponse: - """Response schema for single request - - Example: - {'amount': 200, 'id': 789, 'label': 'Payment request', 'requested_at': '2019-09-12T12:34:55Z', 'requester': - {'id': 123, 'username': 'johndoe'}, 'resolved_at': None, 'responder': {'id': 456, 'username': 'janedoe'}, - 'status': 'pending', 'transaction_id': None} - - Attributes: - amount (int): Requested amount - id (int): Request ID - requested_at (datetime.datetime): Request timestamp - requester (RequestResponseRequester): - responder (RequestResponseResponder): - status (str): Request status - label (Union[None, Unset, str]): Request label - resolved_at (Union[None, Unset, datetime.datetime]): Resolution timestamp - transaction_id (Union[None, Unset, int]): Associated transaction ID - """ - - amount: int - id: int - requested_at: datetime.datetime - requester: "RequestResponseRequester" - responder: "RequestResponseResponder" - status: str - label: Union[None, Unset, str] = UNSET - resolved_at: Union[None, Unset, datetime.datetime] = UNSET - transaction_id: Union[None, Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - amount = self.amount - - id = self.id - - requested_at = self.requested_at.isoformat() - - requester = self.requester.to_dict() - - responder = self.responder.to_dict() - - status = self.status - - label: Union[None, Unset, str] - if isinstance(self.label, Unset): - label = UNSET - else: - label = self.label - - resolved_at: Union[None, Unset, str] - if isinstance(self.resolved_at, Unset): - resolved_at = UNSET - elif isinstance(self.resolved_at, datetime.datetime): - resolved_at = self.resolved_at.isoformat() - else: - resolved_at = self.resolved_at - - transaction_id: Union[None, Unset, int] - if isinstance(self.transaction_id, Unset): - transaction_id = UNSET - else: - transaction_id = self.transaction_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "amount": amount, - "id": id, - "requested_at": requested_at, - "requester": requester, - "responder": responder, - "status": status, - } - ) - if label is not UNSET: - field_dict["label"] = label - if resolved_at is not UNSET: - field_dict["resolved_at"] = resolved_at - if transaction_id is not UNSET: - field_dict["transaction_id"] = transaction_id - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.request_response_requester import RequestResponseRequester - from ..models.request_response_responder import RequestResponseResponder - - d = dict(src_dict) - amount = d.pop("amount") - - id = d.pop("id") - - requested_at = isoparse(d.pop("requested_at")) - - requester = RequestResponseRequester.from_dict(d.pop("requester")) - - responder = RequestResponseResponder.from_dict(d.pop("responder")) - - status = d.pop("status") - - def _parse_label(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - label = _parse_label(d.pop("label", UNSET)) - - def _parse_resolved_at(data: object) -> Union[None, Unset, datetime.datetime]: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, str): - raise TypeError() - resolved_at_type_0 = isoparse(data) - - return resolved_at_type_0 - except: # noqa: E722 - pass - return cast(Union[None, Unset, datetime.datetime], data) - - resolved_at = _parse_resolved_at(d.pop("resolved_at", UNSET)) - - def _parse_transaction_id(data: object) -> Union[None, Unset, int]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, int], data) - - transaction_id = _parse_transaction_id(d.pop("transaction_id", UNSET)) - - request_response = cls( - amount=amount, - id=id, - requested_at=requested_at, - requester=requester, - responder=responder, - status=status, - label=label, - resolved_at=resolved_at, - transaction_id=transaction_id, - ) - - request_response.additional_properties = d - return request_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/request_response_requester.py b/stackcoin/stackcoin_python/models/request_response_requester.py deleted file mode 100644 index 92ecb2b..0000000 --- a/stackcoin/stackcoin_python/models/request_response_requester.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="RequestResponseRequester") - - -@_attrs_define -class RequestResponseRequester: - """ - Attributes: - id (Union[Unset, int]): Requester user ID - username (Union[Unset, str]): Requester username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - request_response_requester = cls( - id=id, - username=username, - ) - - request_response_requester.additional_properties = d - return request_response_requester - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/request_response_responder.py b/stackcoin/stackcoin_python/models/request_response_responder.py deleted file mode 100644 index f5577bc..0000000 --- a/stackcoin/stackcoin_python/models/request_response_responder.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="RequestResponseResponder") - - -@_attrs_define -class RequestResponseResponder: - """ - Attributes: - id (Union[Unset, int]): Responder user ID - username (Union[Unset, str]): Responder username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - request_response_responder = cls( - id=id, - username=username, - ) - - request_response_responder.additional_properties = d - return request_response_responder - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/requests_response.py b/stackcoin/stackcoin_python/models/requests_response.py deleted file mode 100644 index f8bd46c..0000000 --- a/stackcoin/stackcoin_python/models/requests_response.py +++ /dev/null @@ -1,100 +0,0 @@ -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.request import Request - from ..models.requests_response_pagination import RequestsResponsePagination - - -T = TypeVar("T", bound="RequestsResponse") - - -@_attrs_define -class RequestsResponse: - """Response schema for multiple requests - - Example: - {'pagination': {'limit': 20, 'page': 1, 'total': 1, 'total_pages': 1}, 'requests': [{'amount': 200, 'id': 789, - 'label': 'Payment request', 'requested_at': '2019-09-12T12:34:55Z', 'requester': {'id': 123, 'username': - 'johndoe'}, 'resolved_at': None, 'responder': {'id': 456, 'username': 'janedoe'}, 'status': 'pending', - 'transaction_id': None}]} - - Attributes: - pagination (Union[Unset, RequestsResponsePagination]): - requests (Union[Unset, list['Request']]): The requests list - """ - - pagination: Union[Unset, "RequestsResponsePagination"] = UNSET - requests: Union[Unset, list["Request"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - pagination: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.pagination, Unset): - pagination = self.pagination.to_dict() - - requests: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.requests, Unset): - requests = [] - for requests_item_data in self.requests: - requests_item = requests_item_data.to_dict() - requests.append(requests_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if pagination is not UNSET: - field_dict["pagination"] = pagination - if requests is not UNSET: - field_dict["requests"] = requests - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.request import Request - from ..models.requests_response_pagination import RequestsResponsePagination - - d = dict(src_dict) - _pagination = d.pop("pagination", UNSET) - pagination: Union[Unset, RequestsResponsePagination] - if isinstance(_pagination, Unset): - pagination = UNSET - else: - pagination = RequestsResponsePagination.from_dict(_pagination) - - requests = [] - _requests = d.pop("requests", UNSET) - for requests_item_data in _requests or []: - requests_item = Request.from_dict(requests_item_data) - - requests.append(requests_item) - - requests_response = cls( - pagination=pagination, - requests=requests, - ) - - requests_response.additional_properties = d - return requests_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/requests_response_pagination.py b/stackcoin/stackcoin_python/models/requests_response_pagination.py deleted file mode 100644 index 9cfd344..0000000 --- a/stackcoin/stackcoin_python/models/requests_response_pagination.py +++ /dev/null @@ -1,86 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="RequestsResponsePagination") - - -@_attrs_define -class RequestsResponsePagination: - """ - Attributes: - limit (Union[Unset, int]): Items per page - page (Union[Unset, int]): Current page - total (Union[Unset, int]): Total items - total_pages (Union[Unset, int]): Total pages - """ - - limit: Union[Unset, int] = UNSET - page: Union[Unset, int] = UNSET - total: Union[Unset, int] = UNSET - total_pages: Union[Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - limit = self.limit - - page = self.page - - total = self.total - - total_pages = self.total_pages - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if limit is not UNSET: - field_dict["limit"] = limit - if page is not UNSET: - field_dict["page"] = page - if total is not UNSET: - field_dict["total"] = total - if total_pages is not UNSET: - field_dict["total_pages"] = total_pages - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - limit = d.pop("limit", UNSET) - - page = d.pop("page", UNSET) - - total = d.pop("total", UNSET) - - total_pages = d.pop("total_pages", UNSET) - - requests_response_pagination = cls( - limit=limit, - page=page, - total=total, - total_pages=total_pages, - ) - - requests_response_pagination.additional_properties = d - return requests_response_pagination - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/send_stk_params.py b/stackcoin/stackcoin_python/models/send_stk_params.py deleted file mode 100644 index 4476eec..0000000 --- a/stackcoin/stackcoin_python/models/send_stk_params.py +++ /dev/null @@ -1,85 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="SendStkParams") - - -@_attrs_define -class SendStkParams: - """Parameters for sending STK - - Example: - {'amount': 100, 'label': 'Payment for services'} - - Attributes: - amount (int): Amount of STK to send - label (Union[None, Unset, str]): Optional transaction label - """ - - amount: int - label: Union[None, Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - amount = self.amount - - label: Union[None, Unset, str] - if isinstance(self.label, Unset): - label = UNSET - else: - label = self.label - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "amount": amount, - } - ) - if label is not UNSET: - field_dict["label"] = label - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - amount = d.pop("amount") - - def _parse_label(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - label = _parse_label(d.pop("label", UNSET)) - - send_stk_params = cls( - amount=amount, - label=label, - ) - - send_stk_params.additional_properties = d - return send_stk_params - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/send_stk_response.py b/stackcoin/stackcoin_python/models/send_stk_response.py deleted file mode 100644 index 51bcd97..0000000 --- a/stackcoin/stackcoin_python/models/send_stk_response.py +++ /dev/null @@ -1,95 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -T = TypeVar("T", bound="SendStkResponse") - - -@_attrs_define -class SendStkResponse: - """Response schema for sending STK - - Example: - {'amount': 100, 'from_new_balance': 900, 'success': True, 'to_new_balance': 600, 'transaction_id': 456} - - Attributes: - amount (int): Amount sent - from_new_balance (int): Sender's new balance - success (bool): Whether the operation succeeded - to_new_balance (int): Recipient's new balance - transaction_id (int): Created transaction ID - """ - - amount: int - from_new_balance: int - success: bool - to_new_balance: int - transaction_id: int - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - amount = self.amount - - from_new_balance = self.from_new_balance - - success = self.success - - to_new_balance = self.to_new_balance - - transaction_id = self.transaction_id - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "amount": amount, - "from_new_balance": from_new_balance, - "success": success, - "to_new_balance": to_new_balance, - "transaction_id": transaction_id, - } - ) - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - amount = d.pop("amount") - - from_new_balance = d.pop("from_new_balance") - - success = d.pop("success") - - to_new_balance = d.pop("to_new_balance") - - transaction_id = d.pop("transaction_id") - - send_stk_response = cls( - amount=amount, - from_new_balance=from_new_balance, - success=success, - to_new_balance=to_new_balance, - transaction_id=transaction_id, - ) - - send_stk_response.additional_properties = d - return send_stk_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/transaction.py b/stackcoin/stackcoin_python/models/transaction.py deleted file mode 100644 index f8be30f..0000000 --- a/stackcoin/stackcoin_python/models/transaction.py +++ /dev/null @@ -1,128 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.transaction_from import TransactionFrom - from ..models.transaction_to import TransactionTo - - -T = TypeVar("T", bound="Transaction") - - -@_attrs_define -class Transaction: - """A STK transaction - - Example: - {'amount': 100, 'from': {'id': 123, 'username': 'johndoe'}, 'id': 456, 'label': 'Payment for services', 'time': - '2019-09-12T12:34:55Z', 'to': {'id': 789, 'username': 'janedoe'}} - - Attributes: - amount (int): Transaction amount - from_ (TransactionFrom): - id (int): Transaction ID - time (datetime.datetime): Transaction timestamp - to (TransactionTo): - label (Union[None, Unset, str]): Transaction label - """ - - amount: int - from_: "TransactionFrom" - id: int - time: datetime.datetime - to: "TransactionTo" - label: Union[None, Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - amount = self.amount - - from_ = self.from_.to_dict() - - id = self.id - - time = self.time.isoformat() - - to = self.to.to_dict() - - label: Union[None, Unset, str] - if isinstance(self.label, Unset): - label = UNSET - else: - label = self.label - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "amount": amount, - "from": from_, - "id": id, - "time": time, - "to": to, - } - ) - if label is not UNSET: - field_dict["label"] = label - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.transaction_from import TransactionFrom - from ..models.transaction_to import TransactionTo - - d = dict(src_dict) - amount = d.pop("amount") - - from_ = TransactionFrom.from_dict(d.pop("from")) - - id = d.pop("id") - - time = isoparse(d.pop("time")) - - to = TransactionTo.from_dict(d.pop("to")) - - def _parse_label(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - label = _parse_label(d.pop("label", UNSET)) - - transaction = cls( - amount=amount, - from_=from_, - id=id, - time=time, - to=to, - label=label, - ) - - transaction.additional_properties = d - return transaction - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/transaction_from.py b/stackcoin/stackcoin_python/models/transaction_from.py deleted file mode 100644 index 08d9e43..0000000 --- a/stackcoin/stackcoin_python/models/transaction_from.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="TransactionFrom") - - -@_attrs_define -class TransactionFrom: - """ - Attributes: - id (Union[Unset, int]): From user ID - username (Union[Unset, str]): From username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - transaction_from = cls( - id=id, - username=username, - ) - - transaction_from.additional_properties = d - return transaction_from - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/transaction_response.py b/stackcoin/stackcoin_python/models/transaction_response.py deleted file mode 100644 index a6e21fb..0000000 --- a/stackcoin/stackcoin_python/models/transaction_response.py +++ /dev/null @@ -1,128 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, Union, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.transaction_response_from import TransactionResponseFrom - from ..models.transaction_response_to import TransactionResponseTo - - -T = TypeVar("T", bound="TransactionResponse") - - -@_attrs_define -class TransactionResponse: - """Response schema for single transaction - - Example: - {'amount': 100, 'from': {'id': 123, 'username': 'johndoe'}, 'id': 456, 'label': 'Payment for services', 'time': - '2019-09-12T12:34:55Z', 'to': {'id': 789, 'username': 'janedoe'}} - - Attributes: - amount (int): Transaction amount - from_ (TransactionResponseFrom): - id (int): Transaction ID - time (datetime.datetime): Transaction timestamp - to (TransactionResponseTo): - label (Union[None, Unset, str]): Transaction label - """ - - amount: int - from_: "TransactionResponseFrom" - id: int - time: datetime.datetime - to: "TransactionResponseTo" - label: Union[None, Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - amount = self.amount - - from_ = self.from_.to_dict() - - id = self.id - - time = self.time.isoformat() - - to = self.to.to_dict() - - label: Union[None, Unset, str] - if isinstance(self.label, Unset): - label = UNSET - else: - label = self.label - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "amount": amount, - "from": from_, - "id": id, - "time": time, - "to": to, - } - ) - if label is not UNSET: - field_dict["label"] = label - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.transaction_response_from import TransactionResponseFrom - from ..models.transaction_response_to import TransactionResponseTo - - d = dict(src_dict) - amount = d.pop("amount") - - from_ = TransactionResponseFrom.from_dict(d.pop("from")) - - id = d.pop("id") - - time = isoparse(d.pop("time")) - - to = TransactionResponseTo.from_dict(d.pop("to")) - - def _parse_label(data: object) -> Union[None, Unset, str]: - if data is None: - return data - if isinstance(data, Unset): - return data - return cast(Union[None, Unset, str], data) - - label = _parse_label(d.pop("label", UNSET)) - - transaction_response = cls( - amount=amount, - from_=from_, - id=id, - time=time, - to=to, - label=label, - ) - - transaction_response.additional_properties = d - return transaction_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/transaction_response_from.py b/stackcoin/stackcoin_python/models/transaction_response_from.py deleted file mode 100644 index 59866b7..0000000 --- a/stackcoin/stackcoin_python/models/transaction_response_from.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="TransactionResponseFrom") - - -@_attrs_define -class TransactionResponseFrom: - """ - Attributes: - id (Union[Unset, int]): From user ID - username (Union[Unset, str]): From username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - transaction_response_from = cls( - id=id, - username=username, - ) - - transaction_response_from.additional_properties = d - return transaction_response_from - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/transaction_response_to.py b/stackcoin/stackcoin_python/models/transaction_response_to.py deleted file mode 100644 index 3a07f36..0000000 --- a/stackcoin/stackcoin_python/models/transaction_response_to.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="TransactionResponseTo") - - -@_attrs_define -class TransactionResponseTo: - """ - Attributes: - id (Union[Unset, int]): To user ID - username (Union[Unset, str]): To username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - transaction_response_to = cls( - id=id, - username=username, - ) - - transaction_response_to.additional_properties = d - return transaction_response_to - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/transaction_to.py b/stackcoin/stackcoin_python/models/transaction_to.py deleted file mode 100644 index 3c2ed8d..0000000 --- a/stackcoin/stackcoin_python/models/transaction_to.py +++ /dev/null @@ -1,68 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="TransactionTo") - - -@_attrs_define -class TransactionTo: - """ - Attributes: - id (Union[Unset, int]): To user ID - username (Union[Unset, str]): To username - """ - - id: Union[Unset, int] = UNSET - username: Union[Unset, str] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - id = self.id - - username = self.username - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if id is not UNSET: - field_dict["id"] = id - if username is not UNSET: - field_dict["username"] = username - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - id = d.pop("id", UNSET) - - username = d.pop("username", UNSET) - - transaction_to = cls( - id=id, - username=username, - ) - - transaction_to.additional_properties = d - return transaction_to - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/transactions_response.py b/stackcoin/stackcoin_python/models/transactions_response.py deleted file mode 100644 index 9353bff..0000000 --- a/stackcoin/stackcoin_python/models/transactions_response.py +++ /dev/null @@ -1,99 +0,0 @@ -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.transaction import Transaction - from ..models.transactions_response_pagination import TransactionsResponsePagination - - -T = TypeVar("T", bound="TransactionsResponse") - - -@_attrs_define -class TransactionsResponse: - """Response schema for multiple transactions - - Example: - {'pagination': {'limit': 20, 'page': 1, 'total': 1, 'total_pages': 1}, 'transactions': [{'amount': 100, 'from': - {'id': 123, 'username': 'johndoe'}, 'id': 456, 'label': 'Payment for services', 'time': '2019-09-12T12:34:55Z', - 'to': {'id': 789, 'username': 'janedoe'}}]} - - Attributes: - pagination (Union[Unset, TransactionsResponsePagination]): - transactions (Union[Unset, list['Transaction']]): The transactions list - """ - - pagination: Union[Unset, "TransactionsResponsePagination"] = UNSET - transactions: Union[Unset, list["Transaction"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - pagination: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.pagination, Unset): - pagination = self.pagination.to_dict() - - transactions: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.transactions, Unset): - transactions = [] - for transactions_item_data in self.transactions: - transactions_item = transactions_item_data.to_dict() - transactions.append(transactions_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if pagination is not UNSET: - field_dict["pagination"] = pagination - if transactions is not UNSET: - field_dict["transactions"] = transactions - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.transaction import Transaction - from ..models.transactions_response_pagination import TransactionsResponsePagination - - d = dict(src_dict) - _pagination = d.pop("pagination", UNSET) - pagination: Union[Unset, TransactionsResponsePagination] - if isinstance(_pagination, Unset): - pagination = UNSET - else: - pagination = TransactionsResponsePagination.from_dict(_pagination) - - transactions = [] - _transactions = d.pop("transactions", UNSET) - for transactions_item_data in _transactions or []: - transactions_item = Transaction.from_dict(transactions_item_data) - - transactions.append(transactions_item) - - transactions_response = cls( - pagination=pagination, - transactions=transactions, - ) - - transactions_response.additional_properties = d - return transactions_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/transactions_response_pagination.py b/stackcoin/stackcoin_python/models/transactions_response_pagination.py deleted file mode 100644 index ddbd02a..0000000 --- a/stackcoin/stackcoin_python/models/transactions_response_pagination.py +++ /dev/null @@ -1,86 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="TransactionsResponsePagination") - - -@_attrs_define -class TransactionsResponsePagination: - """ - Attributes: - limit (Union[Unset, int]): Items per page - page (Union[Unset, int]): Current page - total (Union[Unset, int]): Total items - total_pages (Union[Unset, int]): Total pages - """ - - limit: Union[Unset, int] = UNSET - page: Union[Unset, int] = UNSET - total: Union[Unset, int] = UNSET - total_pages: Union[Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - limit = self.limit - - page = self.page - - total = self.total - - total_pages = self.total_pages - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if limit is not UNSET: - field_dict["limit"] = limit - if page is not UNSET: - field_dict["page"] = page - if total is not UNSET: - field_dict["total"] = total - if total_pages is not UNSET: - field_dict["total_pages"] = total_pages - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - limit = d.pop("limit", UNSET) - - page = d.pop("page", UNSET) - - total = d.pop("total", UNSET) - - total_pages = d.pop("total_pages", UNSET) - - transactions_response_pagination = cls( - limit=limit, - page=page, - total=total, - total_pages=total_pages, - ) - - transactions_response_pagination.additional_properties = d - return transactions_response_pagination - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/user.py b/stackcoin/stackcoin_python/models/user.py deleted file mode 100644 index 8cc4f8a..0000000 --- a/stackcoin/stackcoin_python/models/user.py +++ /dev/null @@ -1,133 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="User") - - -@_attrs_define -class User: - """A StackCoin user - - Example: - {'admin': False, 'balance': 1000, 'banned': False, 'id': 123, 'inserted_at': '2019-09-12T12:34:55Z', - 'updated_at': '2025-09-13T10:11:12Z', 'username': 'johndoe'} - - Attributes: - admin (bool): Whether user is an admin - balance (int): User's STK balance - banned (bool): Whether user is banned - username (str): Username - id (Union[Unset, int]): User ID - inserted_at (Union[Unset, datetime.datetime]): Creation timestamp - updated_at (Union[Unset, datetime.datetime]): Update timestamp - """ - - admin: bool - balance: int - banned: bool - username: str - id: Union[Unset, int] = UNSET - inserted_at: Union[Unset, datetime.datetime] = UNSET - updated_at: Union[Unset, datetime.datetime] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - admin = self.admin - - balance = self.balance - - banned = self.banned - - username = self.username - - id = self.id - - inserted_at: Union[Unset, str] = UNSET - if not isinstance(self.inserted_at, Unset): - inserted_at = self.inserted_at.isoformat() - - updated_at: Union[Unset, str] = UNSET - if not isinstance(self.updated_at, Unset): - updated_at = self.updated_at.isoformat() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "admin": admin, - "balance": balance, - "banned": banned, - "username": username, - } - ) - if id is not UNSET: - field_dict["id"] = id - if inserted_at is not UNSET: - field_dict["inserted_at"] = inserted_at - if updated_at is not UNSET: - field_dict["updated_at"] = updated_at - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - admin = d.pop("admin") - - balance = d.pop("balance") - - banned = d.pop("banned") - - username = d.pop("username") - - id = d.pop("id", UNSET) - - _inserted_at = d.pop("inserted_at", UNSET) - inserted_at: Union[Unset, datetime.datetime] - if isinstance(_inserted_at, Unset): - inserted_at = UNSET - else: - inserted_at = isoparse(_inserted_at) - - _updated_at = d.pop("updated_at", UNSET) - updated_at: Union[Unset, datetime.datetime] - if isinstance(_updated_at, Unset): - updated_at = UNSET - else: - updated_at = isoparse(_updated_at) - - user = cls( - admin=admin, - balance=balance, - banned=banned, - username=username, - id=id, - inserted_at=inserted_at, - updated_at=updated_at, - ) - - user.additional_properties = d - return user - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/user_response.py b/stackcoin/stackcoin_python/models/user_response.py deleted file mode 100644 index 2c8a5d7..0000000 --- a/stackcoin/stackcoin_python/models/user_response.py +++ /dev/null @@ -1,133 +0,0 @@ -import datetime -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field -from dateutil.parser import isoparse - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="UserResponse") - - -@_attrs_define -class UserResponse: - """Response schema for single user - - Example: - {'admin': False, 'balance': 1000, 'banned': False, 'id': 123, 'inserted_at': '2019-09-12T12:34:55Z', - 'updated_at': '2025-09-13T10:11:12Z', 'username': 'johndoe'} - - Attributes: - admin (bool): Whether user is an admin - balance (int): User's STK balance - banned (bool): Whether user is banned - username (str): Username - id (Union[Unset, int]): User ID - inserted_at (Union[Unset, datetime.datetime]): Creation timestamp - updated_at (Union[Unset, datetime.datetime]): Update timestamp - """ - - admin: bool - balance: int - banned: bool - username: str - id: Union[Unset, int] = UNSET - inserted_at: Union[Unset, datetime.datetime] = UNSET - updated_at: Union[Unset, datetime.datetime] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - admin = self.admin - - balance = self.balance - - banned = self.banned - - username = self.username - - id = self.id - - inserted_at: Union[Unset, str] = UNSET - if not isinstance(self.inserted_at, Unset): - inserted_at = self.inserted_at.isoformat() - - updated_at: Union[Unset, str] = UNSET - if not isinstance(self.updated_at, Unset): - updated_at = self.updated_at.isoformat() - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update( - { - "admin": admin, - "balance": balance, - "banned": banned, - "username": username, - } - ) - if id is not UNSET: - field_dict["id"] = id - if inserted_at is not UNSET: - field_dict["inserted_at"] = inserted_at - if updated_at is not UNSET: - field_dict["updated_at"] = updated_at - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - admin = d.pop("admin") - - balance = d.pop("balance") - - banned = d.pop("banned") - - username = d.pop("username") - - id = d.pop("id", UNSET) - - _inserted_at = d.pop("inserted_at", UNSET) - inserted_at: Union[Unset, datetime.datetime] - if isinstance(_inserted_at, Unset): - inserted_at = UNSET - else: - inserted_at = isoparse(_inserted_at) - - _updated_at = d.pop("updated_at", UNSET) - updated_at: Union[Unset, datetime.datetime] - if isinstance(_updated_at, Unset): - updated_at = UNSET - else: - updated_at = isoparse(_updated_at) - - user_response = cls( - admin=admin, - balance=balance, - banned=banned, - username=username, - id=id, - inserted_at=inserted_at, - updated_at=updated_at, - ) - - user_response.additional_properties = d - return user_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/users_response.py b/stackcoin/stackcoin_python/models/users_response.py deleted file mode 100644 index 89a8f7d..0000000 --- a/stackcoin/stackcoin_python/models/users_response.py +++ /dev/null @@ -1,99 +0,0 @@ -from collections.abc import Mapping -from typing import TYPE_CHECKING, Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -if TYPE_CHECKING: - from ..models.user import User - from ..models.users_response_pagination import UsersResponsePagination - - -T = TypeVar("T", bound="UsersResponse") - - -@_attrs_define -class UsersResponse: - """Response schema for multiple users - - Example: - {'pagination': {'limit': 20, 'page': 1, 'total': 2, 'total_pages': 1}, 'users': [{'admin': False, 'balance': - 1000, 'banned': False, 'id': 123, 'username': 'johndoe'}, {'admin': True, 'balance': 500, 'banned': False, 'id': - 456, 'username': 'janedoe'}]} - - Attributes: - pagination (Union[Unset, UsersResponsePagination]): - users (Union[Unset, list['User']]): The users list - """ - - pagination: Union[Unset, "UsersResponsePagination"] = UNSET - users: Union[Unset, list["User"]] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - pagination: Union[Unset, dict[str, Any]] = UNSET - if not isinstance(self.pagination, Unset): - pagination = self.pagination.to_dict() - - users: Union[Unset, list[dict[str, Any]]] = UNSET - if not isinstance(self.users, Unset): - users = [] - for users_item_data in self.users: - users_item = users_item_data.to_dict() - users.append(users_item) - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if pagination is not UNSET: - field_dict["pagination"] = pagination - if users is not UNSET: - field_dict["users"] = users - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - from ..models.user import User - from ..models.users_response_pagination import UsersResponsePagination - - d = dict(src_dict) - _pagination = d.pop("pagination", UNSET) - pagination: Union[Unset, UsersResponsePagination] - if isinstance(_pagination, Unset): - pagination = UNSET - else: - pagination = UsersResponsePagination.from_dict(_pagination) - - users = [] - _users = d.pop("users", UNSET) - for users_item_data in _users or []: - users_item = User.from_dict(users_item_data) - - users.append(users_item) - - users_response = cls( - pagination=pagination, - users=users, - ) - - users_response.additional_properties = d - return users_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/models/users_response_pagination.py b/stackcoin/stackcoin_python/models/users_response_pagination.py deleted file mode 100644 index 66d6bbf..0000000 --- a/stackcoin/stackcoin_python/models/users_response_pagination.py +++ /dev/null @@ -1,86 +0,0 @@ -from collections.abc import Mapping -from typing import Any, TypeVar, Union - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="UsersResponsePagination") - - -@_attrs_define -class UsersResponsePagination: - """ - Attributes: - limit (Union[Unset, int]): Items per page - page (Union[Unset, int]): Current page - total (Union[Unset, int]): Total items - total_pages (Union[Unset, int]): Total pages - """ - - limit: Union[Unset, int] = UNSET - page: Union[Unset, int] = UNSET - total: Union[Unset, int] = UNSET - total_pages: Union[Unset, int] = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - limit = self.limit - - page = self.page - - total = self.total - - total_pages = self.total_pages - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if limit is not UNSET: - field_dict["limit"] = limit - if page is not UNSET: - field_dict["page"] = page - if total is not UNSET: - field_dict["total"] = total - if total_pages is not UNSET: - field_dict["total_pages"] = total_pages - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - limit = d.pop("limit", UNSET) - - page = d.pop("page", UNSET) - - total = d.pop("total", UNSET) - - total_pages = d.pop("total_pages", UNSET) - - users_response_pagination = cls( - limit=limit, - page=page, - total=total, - total_pages=total_pages, - ) - - users_response_pagination.additional_properties = d - return users_response_pagination - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/stackcoin/stackcoin_python/py.typed b/stackcoin/stackcoin_python/py.typed deleted file mode 100644 index 1aad327..0000000 --- a/stackcoin/stackcoin_python/py.typed +++ /dev/null @@ -1 +0,0 @@ -# Marker file for PEP 561 \ No newline at end of file diff --git a/stackcoin/stackcoin_python/types.py b/stackcoin/stackcoin_python/types.py deleted file mode 100644 index 1b96ca4..0000000 --- a/stackcoin/stackcoin_python/types.py +++ /dev/null @@ -1,54 +0,0 @@ -"""Contains some shared types for properties""" - -from collections.abc import Mapping, MutableMapping -from http import HTTPStatus -from typing import IO, BinaryIO, Generic, Literal, Optional, TypeVar, Union - -from attrs import define - - -class Unset: - def __bool__(self) -> Literal[False]: - return False - - -UNSET: Unset = Unset() - -# The types that `httpx.Client(files=)` can accept, copied from that library. -FileContent = Union[IO[bytes], bytes, str] -FileTypes = Union[ - # (filename, file (or bytes), content_type) - tuple[Optional[str], FileContent, Optional[str]], - # (filename, file (or bytes), content_type, headers) - tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], -] -RequestFiles = list[tuple[str, FileTypes]] - - -@define -class File: - """Contains information for file uploads""" - - payload: BinaryIO - file_name: Optional[str] = None - mime_type: Optional[str] = None - - def to_tuple(self) -> FileTypes: - """Return a tuple representation that httpx will accept for multipart/form-data""" - return self.file_name, self.payload, self.mime_type - - -T = TypeVar("T") - - -@define -class Response(Generic[T]): - """A response from an endpoint""" - - status_code: HTTPStatus - content: bytes - headers: MutableMapping[str, str] - parsed: Optional[T] - - -__all__ = ["UNSET", "File", "FileTypes", "RequestFiles", "Response", "Unset"] From 3d4be38c67332463276d196abe0ed42effb77a7d Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 00:16:24 -0330 Subject: [PATCH 02/14] feat: generate Pydantic v2 models from OpenAPI spec --- justfile | 4 +- stackcoin/stackcoin/models.py | 176 ++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 stackcoin/stackcoin/models.py diff --git a/justfile b/justfile index 0a6c676..b5c8358 100644 --- a/justfile +++ b/justfile @@ -1,6 +1,8 @@ +stackcoin_root := env("STACKCOIN_ROOT", "../StackCoin") + generate: datamodel-codegen \ - --input ../../openapi.json \ + --input {{stackcoin_root}}/openapi.json \ --input-file-type openapi \ --output-model-type pydantic_v2.BaseModel \ --output stackcoin/stackcoin/models.py \ diff --git a/stackcoin/stackcoin/models.py b/stackcoin/stackcoin/models.py new file mode 100644 index 0000000..8c98a55 --- /dev/null +++ b/stackcoin/stackcoin/models.py @@ -0,0 +1,176 @@ +# generated by datamodel-codegen: +# filename: openapi.json +# timestamp: 2026-03-05T03:46:00+00:00 + +from __future__ import annotations + +from pydantic import AwareDatetime, BaseModel, Field + + +class CreateRequestParams(BaseModel): + amount: int = Field(..., description="Amount of STK to request") + label: str | None = Field(None, description="Optional request label") + + +class Requester(BaseModel): + id: int | None = Field(None, description="Requester user ID") + username: str | None = Field(None, description="Requester username") + + +class Responder(BaseModel): + id: int | None = Field(None, description="Responder user ID") + username: str | None = Field(None, description="Responder username") + + +class CreateRequestResponse(BaseModel): + amount: int = Field(..., description="Requested amount") + request_id: int = Field(..., description="Created request ID") + requested_at: AwareDatetime = Field(..., description="Request timestamp") + requester: Requester + responder: Responder + status: str = Field(..., description="Request status") + success: bool = Field(..., description="Whether the operation succeeded") + + +class DiscordGuild(BaseModel): + designated_channel_snowflake: str | None = Field( + None, description="Designated channel snowflake ID" + ) + id: int = Field(..., description="Guild ID") + last_updated: AwareDatetime = Field(..., description="Last updated timestamp") + name: str = Field(..., description="Guild name") + snowflake: str = Field(..., description="Discord guild snowflake ID") + + +class DiscordGuildResponse(BaseModel): + designated_channel_snowflake: str | None = Field( + None, description="Designated channel snowflake ID" + ) + id: int = Field(..., description="Guild ID") + last_updated: AwareDatetime = Field(..., description="Last updated timestamp") + name: str = Field(..., description="Guild name") + snowflake: str = Field(..., description="Discord guild snowflake ID") + + +class Pagination(BaseModel): + limit: int | None = Field(None, description="Items per page") + page: int | None = Field(None, description="Current page") + total: int | None = Field(None, description="Total items") + total_pages: int | None = Field(None, description="Total pages") + + +class DiscordGuildsResponse(BaseModel): + guilds: list[DiscordGuild] | None = Field(None, description="The guilds list") + pagination: Pagination | None = None + + +class ErrorResponse(BaseModel): + error: str = Field(..., description="Error message") + + +class Request(BaseModel): + amount: int = Field(..., description="Requested amount") + id: int = Field(..., description="Request ID") + label: str | None = Field(None, description="Request label") + requested_at: AwareDatetime = Field(..., description="Request timestamp") + requester: Requester + resolved_at: AwareDatetime | None = Field(None, description="Resolution timestamp") + responder: Responder + status: str = Field(..., description="Request status") + transaction_id: int | None = Field(None, description="Associated transaction ID") + + +class RequestActionResponse(BaseModel): + request_id: int = Field(..., description="Request ID") + resolved_at: AwareDatetime = Field(..., description="Resolution timestamp") + status: str = Field(..., description="New request status") + success: bool = Field(..., description="Whether the operation succeeded") + transaction_id: int | None = Field(None, description="Associated transaction ID") + + +class RequestResponse(BaseModel): + amount: int = Field(..., description="Requested amount") + id: int = Field(..., description="Request ID") + label: str | None = Field(None, description="Request label") + requested_at: AwareDatetime = Field(..., description="Request timestamp") + requester: Requester + resolved_at: AwareDatetime | None = Field(None, description="Resolution timestamp") + responder: Responder + status: str = Field(..., description="Request status") + transaction_id: int | None = Field(None, description="Associated transaction ID") + + +class RequestsResponse(BaseModel): + pagination: Pagination | None = None + requests: list[Request] | None = Field(None, description="The requests list") + + +class SendStkParams(BaseModel): + amount: int = Field(..., description="Amount of STK to send") + label: str | None = Field(None, description="Optional transaction label") + + +class SendStkResponse(BaseModel): + amount: int = Field(..., description="Amount sent") + from_new_balance: int = Field(..., description="Sender's new balance") + success: bool = Field(..., description="Whether the operation succeeded") + to_new_balance: int = Field(..., description="Recipient's new balance") + transaction_id: int = Field(..., description="Created transaction ID") + + +class From(BaseModel): + id: int | None = Field(None, description="From user ID") + username: str | None = Field(None, description="From username") + + +class To(BaseModel): + id: int | None = Field(None, description="To user ID") + username: str | None = Field(None, description="To username") + + +class Transaction(BaseModel): + amount: int = Field(..., description="Transaction amount") + from_: From = Field(..., alias="from") + id: int = Field(..., description="Transaction ID") + label: str | None = Field(None, description="Transaction label") + time: AwareDatetime = Field(..., description="Transaction timestamp") + to: To + + +class TransactionResponse(BaseModel): + amount: int = Field(..., description="Transaction amount") + from_: From = Field(..., alias="from") + id: int = Field(..., description="Transaction ID") + label: str | None = Field(None, description="Transaction label") + time: AwareDatetime = Field(..., description="Transaction timestamp") + to: To + + +class TransactionsResponse(BaseModel): + pagination: Pagination | None = None + transactions: list[Transaction] | None = Field(None, description="The transactions list") + + +class User(BaseModel): + admin: bool = Field(..., description="Whether user is an admin") + balance: int = Field(..., description="User's STK balance") + banned: bool = Field(..., description="Whether user is banned") + id: int | None = Field(None, description="User ID") + inserted_at: AwareDatetime | None = Field(None, description="Creation timestamp") + updated_at: AwareDatetime | None = Field(None, description="Update timestamp") + username: str = Field(..., description="Username") + + +class UserResponse(BaseModel): + admin: bool = Field(..., description="Whether user is an admin") + balance: int = Field(..., description="User's STK balance") + banned: bool = Field(..., description="Whether user is banned") + id: int | None = Field(None, description="User ID") + inserted_at: AwareDatetime | None = Field(None, description="Creation timestamp") + updated_at: AwareDatetime | None = Field(None, description="Update timestamp") + username: str = Field(..., description="Username") + + +class UsersResponse(BaseModel): + pagination: Pagination | None = None + users: list[User] | None = Field(None, description="The users list") From 196ae93698f474d18e6057471b1fd2876c810d3f Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 00:24:46 -0330 Subject: [PATCH 03/14] feat: add REST client and WebSocket gateway --- stackcoin/stackcoin/__init__.py | 4 +- stackcoin/stackcoin/client.py | 227 ++++++++++++++++++++++++++++++++ stackcoin/stackcoin/gateway.py | 150 +++++++++++++++++++++ 3 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 stackcoin/stackcoin/client.py create mode 100644 stackcoin/stackcoin/gateway.py diff --git a/stackcoin/stackcoin/__init__.py b/stackcoin/stackcoin/__init__.py index 217be0f..26a7ea6 100644 --- a/stackcoin/stackcoin/__init__.py +++ b/stackcoin/stackcoin/__init__.py @@ -1,5 +1,7 @@ """StackCoin Python SDK.""" +from .client import Client from .errors import StackCoinError +from .gateway import Event, Gateway -__all__ = ["StackCoinError"] +__all__ = ["Client", "Event", "Gateway", "StackCoinError"] diff --git a/stackcoin/stackcoin/client.py b/stackcoin/stackcoin/client.py new file mode 100644 index 0000000..e77d503 --- /dev/null +++ b/stackcoin/stackcoin/client.py @@ -0,0 +1,227 @@ +"""Async REST client for the StackCoin API.""" + +from __future__ import annotations + +from typing import Any + +import httpx + +from .errors import StackCoinError +from .models import ( + CreateRequestResponse, + DiscordGuild, + DiscordGuildsResponse, + Request, + RequestActionResponse, + RequestsResponse, + SendStkResponse, + Transaction, + TransactionsResponse, + User, + UsersResponse, +) + + +class Client: + """Async client for the StackCoin REST API. + + Usage:: + + async with Client("https://stackcoin.example.com", token="sk-...") as client: + me = await client.get_me() + print(me.username, me.balance) + """ + + def __init__( + self, + base_url: str, + token: str, + *, + timeout: float = 10.0, + ) -> None: + self._http = httpx.AsyncClient( + base_url=base_url, + headers={ + "Authorization": f"Bearer {token}", + "Accept": "application/json", + }, + timeout=timeout, + ) + + # -- context manager -------------------------------------------------- # + + async def __aenter__(self) -> Client: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: Any, + ) -> None: + await self.close() + + async def close(self) -> None: + """Close the underlying HTTP connection pool.""" + await self._http.aclose() + + # -- shared helpers --------------------------------------------------- # + + @staticmethod + def _raise_for_error(resp: httpx.Response) -> None: + """Raise :class:`StackCoinError` on any 4xx/5xx response.""" + if resp.status_code >= 400: + try: + body = resp.json() + except Exception: + body = {} + error = body.get("error", f"http_{resp.status_code}") + message = body.get("message") + raise StackCoinError(resp.status_code, error, message) + + # -- users ------------------------------------------------------------ # + + async def get_me(self) -> User: + """Return the authenticated user's profile.""" + resp = await self._http.get("/api/user/me") + self._raise_for_error(resp) + return User.model_validate(resp.json()) + + async def get_user(self, user_id: int) -> User: + """Return a user by their ID.""" + resp = await self._http.get(f"/api/user/{user_id}") + self._raise_for_error(resp) + return User.model_validate(resp.json()) + + async def get_users(self, *, discord_id: str | None = None) -> list[User]: + """Return a list of users, optionally filtered by Discord ID.""" + params: dict[str, Any] = {} + if discord_id is not None: + params["discord_id"] = discord_id + resp = await self._http.get("/api/users", params=params) + self._raise_for_error(resp) + wrapper = UsersResponse.model_validate(resp.json()) + return wrapper.users or [] + + # -- send ------------------------------------------------------------- # + + async def send( + self, + to_user_id: int, + amount: int, + *, + label: str | None = None, + idempotency_key: str | None = None, + ) -> SendStkResponse: + """Send STK to another user.""" + body: dict[str, Any] = {"amount": amount} + if label is not None: + body["label"] = label + headers: dict[str, str] = {} + if idempotency_key is not None: + headers["Idempotency-Key"] = idempotency_key + resp = await self._http.post( + f"/api/user/{to_user_id}/send", + json=body, + headers=headers, + ) + self._raise_for_error(resp) + return SendStkResponse.model_validate(resp.json()) + + # -- requests --------------------------------------------------------- # + + async def create_request( + self, + to_user_id: int, + amount: int, + *, + label: str | None = None, + idempotency_key: str | None = None, + ) -> CreateRequestResponse: + """Create a STK request to another user.""" + body: dict[str, Any] = {"amount": amount} + if label is not None: + body["label"] = label + headers: dict[str, str] = {} + if idempotency_key is not None: + headers["Idempotency-Key"] = idempotency_key + resp = await self._http.post( + f"/api/user/{to_user_id}/request", + json=body, + headers=headers, + ) + self._raise_for_error(resp) + return CreateRequestResponse.model_validate(resp.json()) + + async def get_request(self, request_id: int) -> Request: + """Return a single request by its ID.""" + resp = await self._http.get(f"/api/request/{request_id}") + self._raise_for_error(resp) + return Request.model_validate(resp.json()) + + async def get_requests(self, *, status: str | None = None) -> list[Request]: + """Return requests for the authenticated user, optionally filtered by status.""" + params: dict[str, Any] = {} + if status is not None: + params["status"] = status + resp = await self._http.get("/api/requests", params=params) + self._raise_for_error(resp) + wrapper = RequestsResponse.model_validate(resp.json()) + return wrapper.requests or [] + + async def accept_request(self, request_id: int) -> RequestActionResponse: + """Accept a pending STK request.""" + resp = await self._http.post(f"/api/requests/{request_id}/accept") + self._raise_for_error(resp) + return RequestActionResponse.model_validate(resp.json()) + + async def deny_request(self, request_id: int) -> RequestActionResponse: + """Deny a pending STK request.""" + resp = await self._http.post(f"/api/requests/{request_id}/deny") + self._raise_for_error(resp) + return RequestActionResponse.model_validate(resp.json()) + + # -- transactions ----------------------------------------------------- # + + async def get_transactions(self) -> list[Transaction]: + """Return transactions for the authenticated user.""" + resp = await self._http.get("/api/transactions") + self._raise_for_error(resp) + wrapper = TransactionsResponse.model_validate(resp.json()) + return wrapper.transactions or [] + + async def get_transaction(self, transaction_id: int) -> Transaction: + """Return a single transaction by its ID.""" + resp = await self._http.get(f"/api/transaction/{transaction_id}") + self._raise_for_error(resp) + return Transaction.model_validate(resp.json()) + + # -- events ----------------------------------------------------------- # + + async def get_events(self, *, since_id: int = 0) -> list[dict[str, Any]]: + """Return events since the given ID. + + Events are not yet in the OpenAPI spec, so this returns raw dicts. + """ + params: dict[str, Any] = {} + if since_id: + params["since_id"] = since_id + resp = await self._http.get("/api/events", params=params) + self._raise_for_error(resp) + data = resp.json() + return data.get("events", data) if isinstance(data, dict) else data + + # -- discord guilds --------------------------------------------------- # + + async def get_discord_guilds(self) -> list[DiscordGuild]: + """Return all Discord guilds.""" + resp = await self._http.get("/api/discord/guilds") + self._raise_for_error(resp) + wrapper = DiscordGuildsResponse.model_validate(resp.json()) + return wrapper.guilds or [] + + async def get_discord_guild(self, snowflake: str) -> DiscordGuild: + """Return a single Discord guild by its snowflake ID.""" + resp = await self._http.get(f"/api/discord/guild/{snowflake}") + self._raise_for_error(resp) + return DiscordGuild.model_validate(resp.json()) diff --git a/stackcoin/stackcoin/gateway.py b/stackcoin/stackcoin/gateway.py new file mode 100644 index 0000000..44a13e0 --- /dev/null +++ b/stackcoin/stackcoin/gateway.py @@ -0,0 +1,150 @@ +"""StackCoin WebSocket Gateway client.""" + +import asyncio +import json +from typing import Any, Callable, Awaitable + +from pydantic import BaseModel + + +EventHandler = Callable[["Event"], Awaitable[None]] + + +class Event(BaseModel): + """A StackCoin event received via the gateway.""" + id: int + type: str + data: dict[str, Any] + inserted_at: str + + +class Gateway: + """WebSocket gateway for receiving real-time StackCoin events. + + Usage:: + + gateway = stackcoin.Gateway( + ws_url="ws://localhost:4000/bot/websocket", + token="...", + ) + + @gateway.on("request.accepted") + async def handle_accepted(event: stackcoin.Event): + print(event.data["request_id"]) + + await gateway.connect() + """ + + def __init__( + self, + ws_url: str, + token: str, + last_event_id: int = 0, + on_event_id: Callable[[int], None] | None = None, + ): + # ws_url should be the full websocket URL like "ws://localhost:4000/bot/websocket" + self._ws_url = ws_url.rstrip("/") + self._token = token + self._handlers: dict[str, list[EventHandler]] = {} + self._last_event_id = last_event_id + self._on_event_id = on_event_id # callback to persist cursor position + self._ws = None + self._running = False + self._ref_counter = 0 + + @property + def last_event_id(self) -> int: + return self._last_event_id + + def on(self, event_type: str) -> Callable[[EventHandler], EventHandler]: + """Decorator to register an event handler.""" + def decorator(func: EventHandler) -> EventHandler: + self.register_handler(event_type, func) + return func + return decorator + + def register_handler(self, event_type: str, handler: EventHandler) -> None: + """Register an event handler programmatically.""" + if event_type not in self._handlers: + self._handlers[event_type] = [] + self._handlers[event_type].append(handler) + + async def connect(self) -> None: + """Connect and listen for events. Reconnects automatically on failure.""" + import websockets + + self._running = True + + while self._running: + try: + url = f"{self._ws_url}?token={self._token}&vsn=2.0.0" + + async with websockets.connect(url) as ws: + self._ws = ws + await self._join_channel(ws) + + heartbeat_task = asyncio.create_task(self._heartbeat(ws)) + try: + async for raw_msg in ws: + msg = json.loads(raw_msg) + await self._handle_message(msg) + finally: + heartbeat_task.cancel() + + except Exception: + if self._running: + await asyncio.sleep(5) + + async def _join_channel(self, ws: Any) -> None: + """Join the user:self channel with event replay.""" + self._ref_counter += 1 + join_msg = json.dumps([ + None, + str(self._ref_counter), + "user:self", + "phx_join", + {"last_event_id": self._last_event_id}, + ]) + await ws.send(join_msg) + + reply = json.loads(await asyncio.wait_for(ws.recv(), timeout=10)) + if not (reply[3] == "phx_reply" and reply[4].get("status") == "ok"): + raise ConnectionError(f"Failed to join channel: {reply}") + + async def _heartbeat(self, ws: Any) -> None: + """Send periodic heartbeats.""" + while True: + await asyncio.sleep(30) + self._ref_counter += 1 + hb = json.dumps([None, str(self._ref_counter), "phoenix", "heartbeat", {}]) + await ws.send(hb) + + async def _handle_message(self, msg: list[Any]) -> None: + """Dispatch incoming message to registered handlers.""" + if len(msg) < 5: + return + + event_name = msg[3] + payload = msg[4] + + if event_name == "event": + event = Event.model_validate(payload) + + if event.id > self._last_event_id: + self._last_event_id = event.id + + for handler in self._handlers.get(event.type, []): + try: + await handler(event) + except Exception: + pass + + if event.id > 0 and self._on_event_id: + try: + self._on_event_id(event.id) + except Exception: + pass + + def stop(self) -> None: + """Signal the gateway to stop.""" + self._running = False From 3be1d668890f06e6cd73ccd37ac7d67a81ac927d Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 00:35:03 -0330 Subject: [PATCH 04/14] fix: use plain datetime for model fields (server returns naive datetimes) --- justfile | 3 ++- stackcoin/stackcoin/gateway.py | 41 +++++++++++++++++++--------------- stackcoin/stackcoin/models.py | 34 +++++++++++++++------------- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/justfile b/justfile index b5c8358..1078cb2 100644 --- a/justfile +++ b/justfile @@ -6,7 +6,8 @@ generate: --input-file-type openapi \ --output-model-type pydantic_v2.BaseModel \ --output stackcoin/stackcoin/models.py \ - --target-python-version 3.13 + --target-python-version 3.13 \ + --output-datetime-class datetime uvx ruff format stackcoin/ dev: diff --git a/stackcoin/stackcoin/gateway.py b/stackcoin/stackcoin/gateway.py index 44a13e0..a747950 100644 --- a/stackcoin/stackcoin/gateway.py +++ b/stackcoin/stackcoin/gateway.py @@ -12,6 +12,7 @@ class Event(BaseModel): """A StackCoin event received via the gateway.""" + id: int type: str data: dict[str, Any] @@ -20,21 +21,21 @@ class Event(BaseModel): class Gateway: """WebSocket gateway for receiving real-time StackCoin events. - + Usage:: - + gateway = stackcoin.Gateway( ws_url="ws://localhost:4000/bot/websocket", token="...", ) - + @gateway.on("request.accepted") async def handle_accepted(event: stackcoin.Event): print(event.data["request_id"]) - + await gateway.connect() """ - + def __init__( self, ws_url: str, @@ -58,9 +59,11 @@ def last_event_id(self) -> int: def on(self, event_type: str) -> Callable[[EventHandler], EventHandler]: """Decorator to register an event handler.""" + def decorator(func: EventHandler) -> EventHandler: self.register_handler(event_type, func) return func + return decorator def register_handler(self, event_type: str, handler: EventHandler) -> None: @@ -72,17 +75,17 @@ def register_handler(self, event_type: str, handler: EventHandler) -> None: async def connect(self) -> None: """Connect and listen for events. Reconnects automatically on failure.""" import websockets - + self._running = True - + while self._running: try: url = f"{self._ws_url}?token={self._token}&vsn=2.0.0" - + async with websockets.connect(url) as ws: self._ws = ws await self._join_channel(ws) - + heartbeat_task = asyncio.create_task(self._heartbeat(ws)) try: async for raw_msg in ws: @@ -90,7 +93,7 @@ async def connect(self) -> None: await self._handle_message(msg) finally: heartbeat_task.cancel() - + except Exception: if self._running: await asyncio.sleep(5) @@ -98,15 +101,17 @@ async def connect(self) -> None: async def _join_channel(self, ws: Any) -> None: """Join the user:self channel with event replay.""" self._ref_counter += 1 - join_msg = json.dumps([ - None, - str(self._ref_counter), - "user:self", - "phx_join", - {"last_event_id": self._last_event_id}, - ]) + join_msg = json.dumps( + [ + None, + str(self._ref_counter), + "user:self", + "phx_join", + {"last_event_id": self._last_event_id}, + ] + ) await ws.send(join_msg) - + reply = json.loads(await asyncio.wait_for(ws.recv(), timeout=10)) if not (reply[3] == "phx_reply" and reply[4].get("status") == "ok"): raise ConnectionError(f"Failed to join channel: {reply}") diff --git a/stackcoin/stackcoin/models.py b/stackcoin/stackcoin/models.py index 8c98a55..adbaa0c 100644 --- a/stackcoin/stackcoin/models.py +++ b/stackcoin/stackcoin/models.py @@ -1,10 +1,12 @@ # generated by datamodel-codegen: # filename: openapi.json -# timestamp: 2026-03-05T03:46:00+00:00 +# timestamp: 2026-03-05T04:04:56+00:00 from __future__ import annotations -from pydantic import AwareDatetime, BaseModel, Field +from datetime import datetime + +from pydantic import BaseModel, Field class CreateRequestParams(BaseModel): @@ -25,7 +27,7 @@ class Responder(BaseModel): class CreateRequestResponse(BaseModel): amount: int = Field(..., description="Requested amount") request_id: int = Field(..., description="Created request ID") - requested_at: AwareDatetime = Field(..., description="Request timestamp") + requested_at: datetime = Field(..., description="Request timestamp") requester: Requester responder: Responder status: str = Field(..., description="Request status") @@ -37,7 +39,7 @@ class DiscordGuild(BaseModel): None, description="Designated channel snowflake ID" ) id: int = Field(..., description="Guild ID") - last_updated: AwareDatetime = Field(..., description="Last updated timestamp") + last_updated: datetime = Field(..., description="Last updated timestamp") name: str = Field(..., description="Guild name") snowflake: str = Field(..., description="Discord guild snowflake ID") @@ -47,7 +49,7 @@ class DiscordGuildResponse(BaseModel): None, description="Designated channel snowflake ID" ) id: int = Field(..., description="Guild ID") - last_updated: AwareDatetime = Field(..., description="Last updated timestamp") + last_updated: datetime = Field(..., description="Last updated timestamp") name: str = Field(..., description="Guild name") snowflake: str = Field(..., description="Discord guild snowflake ID") @@ -72,9 +74,9 @@ class Request(BaseModel): amount: int = Field(..., description="Requested amount") id: int = Field(..., description="Request ID") label: str | None = Field(None, description="Request label") - requested_at: AwareDatetime = Field(..., description="Request timestamp") + requested_at: datetime = Field(..., description="Request timestamp") requester: Requester - resolved_at: AwareDatetime | None = Field(None, description="Resolution timestamp") + resolved_at: datetime | None = Field(None, description="Resolution timestamp") responder: Responder status: str = Field(..., description="Request status") transaction_id: int | None = Field(None, description="Associated transaction ID") @@ -82,7 +84,7 @@ class Request(BaseModel): class RequestActionResponse(BaseModel): request_id: int = Field(..., description="Request ID") - resolved_at: AwareDatetime = Field(..., description="Resolution timestamp") + resolved_at: datetime = Field(..., description="Resolution timestamp") status: str = Field(..., description="New request status") success: bool = Field(..., description="Whether the operation succeeded") transaction_id: int | None = Field(None, description="Associated transaction ID") @@ -92,9 +94,9 @@ class RequestResponse(BaseModel): amount: int = Field(..., description="Requested amount") id: int = Field(..., description="Request ID") label: str | None = Field(None, description="Request label") - requested_at: AwareDatetime = Field(..., description="Request timestamp") + requested_at: datetime = Field(..., description="Request timestamp") requester: Requester - resolved_at: AwareDatetime | None = Field(None, description="Resolution timestamp") + resolved_at: datetime | None = Field(None, description="Resolution timestamp") responder: Responder status: str = Field(..., description="Request status") transaction_id: int | None = Field(None, description="Associated transaction ID") @@ -133,7 +135,7 @@ class Transaction(BaseModel): from_: From = Field(..., alias="from") id: int = Field(..., description="Transaction ID") label: str | None = Field(None, description="Transaction label") - time: AwareDatetime = Field(..., description="Transaction timestamp") + time: datetime = Field(..., description="Transaction timestamp") to: To @@ -142,7 +144,7 @@ class TransactionResponse(BaseModel): from_: From = Field(..., alias="from") id: int = Field(..., description="Transaction ID") label: str | None = Field(None, description="Transaction label") - time: AwareDatetime = Field(..., description="Transaction timestamp") + time: datetime = Field(..., description="Transaction timestamp") to: To @@ -156,8 +158,8 @@ class User(BaseModel): balance: int = Field(..., description="User's STK balance") banned: bool = Field(..., description="Whether user is banned") id: int | None = Field(None, description="User ID") - inserted_at: AwareDatetime | None = Field(None, description="Creation timestamp") - updated_at: AwareDatetime | None = Field(None, description="Update timestamp") + inserted_at: datetime | None = Field(None, description="Creation timestamp") + updated_at: datetime | None = Field(None, description="Update timestamp") username: str = Field(..., description="Username") @@ -166,8 +168,8 @@ class UserResponse(BaseModel): balance: int = Field(..., description="User's STK balance") banned: bool = Field(..., description="Whether user is banned") id: int | None = Field(None, description="User ID") - inserted_at: AwareDatetime | None = Field(None, description="Creation timestamp") - updated_at: AwareDatetime | None = Field(None, description="Update timestamp") + inserted_at: datetime | None = Field(None, description="Creation timestamp") + updated_at: datetime | None = Field(None, description="Update timestamp") username: str = Field(..., description="Username") From bbd15a5de67e9eede6761d9403d732e7e590aac9 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 00:43:49 -0330 Subject: [PATCH 05/14] docs: update examples to use new SDK, add gateway events to CLI --- examples/basic_usage.py | 111 +++--------- examples/simple_cli.py | 384 +++++++++++++++++++--------------------- 2 files changed, 207 insertions(+), 288 deletions(-) diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 039120e..1930a42 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -1,96 +1,38 @@ +"""Basic usage of the stackcoin SDK.""" + import asyncio import os -from stackcoin_python import AuthenticatedClient -from stackcoin_python.models import ( - CreateRequestParams, - BalanceResponse, - CreateRequestResponse, - RequestsResponse, - TransactionsResponse, - UsersResponse, -) -from stackcoin_python.api.default import ( - stackcoin_self_balance, - stackcoin_create_request, - stackcoin_users, - stackcoin_requests, - stackcoin_transactions, -) - - -async def main(token, base_url): - client = AuthenticatedClient(base_url=base_url, token=token) - - async with client as client: - print("Getting balance") - - my_balance = await stackcoin_self_balance.asyncio(client=client) - - if not isinstance(my_balance, BalanceResponse): - raise Exception("Failed to get balance") - - print(f"Logged in as {my_balance.username} with balance {my_balance.balance}") - - print("Creating request") - - request = await stackcoin_create_request.asyncio( - client=client, - user_id=2, - body=CreateRequestParams( - amount=100, - label="pay up buddy", - ), - ) - - if not isinstance(request, CreateRequestResponse): - raise Exception("Failed to create request") - print( - f"Created request {request.request_id} to {request.responder.username} with amount {request.amount}" - ) +import stackcoin - print("Getting requests") - requests = await stackcoin_requests.asyncio(client=client) +async def main(token: str, base_url: str): + async with stackcoin.Client(base_url=base_url, token=token) as client: + # Who am I? + me = await client.get_me() + print(f"Logged in as {me.username} with balance {me.balance} STK") - if not isinstance(requests, RequestsResponse): - raise Exception("Failed to get requests") + # Create a request + req = await client.create_request(to_user_id=2, amount=100, label="pay up buddy") + print(f"Created request #{req.request_id} to {req.responder.username} for {req.amount} STK") - if not isinstance(requests.requests, list): - raise Exception("Failed to get requests") + # List pending requests + requests = await client.get_requests() + print(f"\n{len(requests)} request(s):") + for r in requests: + print(f" #{r.id} -> {r.responder.username}: {r.amount} STK ({r.status})") - for request in requests.requests: - print( - f"Request {request.id} to {request.responder.username} with amount {request.amount}" - ) + # List recent transactions + transactions = await client.get_transactions() + print(f"\n{len(transactions)} transaction(s):") + for txn in transactions: + print(f" #{txn.id} {txn.from_.username} -> {txn.to.username}: {txn.amount} STK") - print("Getting transactions") - - transactions = await stackcoin_transactions.asyncio(client=client) - - if not isinstance(transactions, TransactionsResponse): - raise Exception("Failed to get transactions") - - if not isinstance(transactions.transactions, list): - raise Exception("Failed to get transactions") - - for transaction in transactions.transactions: - print( - f"Transaction {transaction.id} from {transaction.from_.username} to {transaction.to.username} with amount {transaction.amount}" - ) - - print("Getting users") - - users = await stackcoin_users.asyncio(client=client) - - if not isinstance(users, UsersResponse): - raise Exception("Failed to get users") - - if not isinstance(users.users, list): - raise Exception("Failed to get users") - - for user in users.users: - print(f"User {user.id} {user.username}") + # List users + users = await client.get_users() + print(f"\n{len(users)} user(s):") + for user in users: + print(f" #{user.id} {user.username} ({user.balance} STK)") if __name__ == "__main__": @@ -102,5 +44,4 @@ async def main(token, base_url): exit(1) base_url = os.getenv("STACKCOIN_BASE_URL", "https://stackcoin.world") - asyncio.run(main(token, base_url)) diff --git a/examples/simple_cli.py b/examples/simple_cli.py index f794fb4..bd2dc65 100644 --- a/examples/simple_cli.py +++ b/examples/simple_cli.py @@ -1,211 +1,121 @@ +"""Interactive StackCoin bot REPL with live gateway events. + +Demonstrates the REST client and WebSocket gateway working together: +the REPL handles commands while the gateway prints real-time events +in the background. +""" + import asyncio import os -from stackcoin_python import AuthenticatedClient -from stackcoin_python.types import Unset -from stackcoin_python.models import ( - CreateRequestParams, - SendStkParams, - BalanceResponse, - CreateRequestResponse, - RequestsResponse, - TransactionsResponse, - UsersResponse, - SendStkResponse, - RequestActionResponse, -) -from stackcoin_python.api.default import ( - stackcoin_self_balance, - stackcoin_user_balance, - stackcoin_users, - stackcoin_send_stk, - stackcoin_create_request, - stackcoin_requests, - stackcoin_transactions, - stackcoin_accept_request, - stackcoin_deny_request, -) +import sys + +import stackcoin def print_help(): print("\nAvailable commands:") - print(" balance - Get your bot's balance") - print(" user - Get a user's balance") - print(" users [username] - List/search users") - print(" send [label] - Send tokens to a user") - print(" request [label] - Request tokens from a user") - print(" requests [requester|responder] - List payment requests") - print(" transactions [from_user_id] [to_user_id] - List transactions") - print(" accept - Accept a payment request") - print(" deny - Deny a payment request") - print(" help - Show this help") - print(" quit - Exit the REPL") - - -async def run_repl(client): - print("StackCoin Bot REPL - Type 'help' for commands") + print(" balance - Get your bot's balance") + print(" user - Get a user by ID") + print(" users [discord_id] - List/search users") + print(" send [label] - Send STK to a user") + print(" request [label] - Request STK from a user") + print(" requests [status] - List payment requests") + print(" accept - Accept a payment request") + print(" deny - Deny a payment request") + print(" transactions - List recent transactions") + print(" events [since_id] - List recent events (REST)") + print(" help - Show this help") + print(" quit - Exit") - while True: - try: - command = input("\n> ").strip() - if not command: - continue - - parts = command.split() - cmd = parts[0].lower() - - if cmd == "quit": - break - elif cmd == "help": - print_help() - elif cmd == "balance": - balance = await stackcoin_self_balance.asyncio(client=client) - if not isinstance(balance, BalanceResponse): - print("Error: Failed to get balance") - continue - print(f"Bot: {balance.username}, Balance: {balance.balance} STK") - elif cmd == "user" and len(parts) >= 2: - user_id = int(parts[1]) - balance = await stackcoin_user_balance.asyncio( - client=client, user_id=user_id - ) - if not isinstance(balance, BalanceResponse): - print("Error: Failed to get user balance") - continue - print(f"User: {balance.username}, Balance: {balance.balance} STK") - elif cmd == "users": - username_filter = parts[1] if len(parts) > 1 else Unset() - users_response = await stackcoin_users.asyncio( - client=client, username=username_filter - ) - if not isinstance(users_response, UsersResponse) or not isinstance( - users_response.users, list - ): - print("Error: Failed to get users") - continue - count = 0 - print("Users:") - for user in users_response.users: - status_flags = [] - if user.admin: - status_flags.append("ADMIN") - if user.banned: - status_flags.append("BANNED") - status_str = f" [{', '.join(status_flags)}]" if status_flags else "" - print( - f" #{user.id}: {user.username} - {user.balance} STK{status_str}" - ) - count += 1 - if count >= 20: - break - print(f"Showing first {count} users") - elif cmd == "send" and len(parts) >= 3: - user_id = int(parts[1]) - amount = int(parts[2]) - label = " ".join(parts[3:]) if len(parts) > 3 else None - result = await stackcoin_send_stk.asyncio( - client=client, - user_id=user_id, - body=SendStkParams(amount=amount, label=label), - ) - if not isinstance(result, SendStkResponse): - print("Error: Failed to send STK") - continue - print( - f"Sent {result.amount} STK! Your new balance: {result.from_new_balance}" - ) - elif cmd == "request" and len(parts) >= 3: - user_id = int(parts[1]) - amount = int(parts[2]) - label = " ".join(parts[3:]) if len(parts) > 3 else None - result = await stackcoin_create_request.asyncio( - client=client, - user_id=user_id, - body=CreateRequestParams(amount=amount, label=label), - ) - if not isinstance(result, CreateRequestResponse): - print("Error: Failed to create request") - continue - print( - f"Created request {result.request_id} for {result.amount} STK from {result.responder.username}" - ) - elif cmd == "requests": - role = parts[1] if len(parts) > 1 else "requester" - requests_response = await stackcoin_requests.asyncio( - client=client, role=role - ) - if not isinstance( - requests_response, RequestsResponse - ) or not isinstance(requests_response.requests, list): - print("Error: Failed to get requests") - continue - count = 0 - print(f"Requests as {role}:") - for req in requests_response.requests: - if role == "requester": - print( - f" #{req.id}: {req.amount} STK to {req.responder.username} - {req.status}" - ) - else: - print( - f" #{req.id}: {req.amount} STK from {req.requester.username} - {req.status}" - ) - count += 1 - if count >= 10: - break - print(f"Showing first {count} requests") - elif cmd == "transactions": - from_user_id = ( - int(parts[1]) if len(parts) > 1 and parts[1].isdigit() else Unset() - ) - to_user_id = ( - int(parts[2]) if len(parts) > 2 and parts[2].isdigit() else Unset() - ) - transactions_response = await stackcoin_transactions.asyncio( - client=client, from_user_id=from_user_id, to_user_id=to_user_id - ) - if not isinstance( - transactions_response, TransactionsResponse - ) or not isinstance(transactions_response.transactions, list): - print("Error: Failed to get transactions") - continue - count = 0 - print("Recent transactions:") - for txn in transactions_response.transactions: - label_str = f" ({txn.label})" if txn.label else "" - print( - f" #{txn.id}: {txn.from_.username} → {txn.to.username} {txn.amount} STK{label_str} at {txn.time}" - ) - count += 1 - if count >= 10: - break - print(f"Showing first {count} transactions") - elif cmd == "accept" and len(parts) >= 2: - request_id = int(parts[1]) - result = await stackcoin_accept_request.asyncio( - client=client, request_id=request_id - ) - if not isinstance(result, RequestActionResponse): - print("Error: Failed to accept request") - continue - print(f"Accepted request {result.request_id}, status: {result.status}") - elif cmd == "deny" and len(parts) >= 2: - request_id = int(parts[1]) - result = await stackcoin_deny_request.asyncio( - client=client, request_id=request_id - ) - if not isinstance(result, RequestActionResponse): - print("Error: Failed to deny request") - continue - print(f"Denied request {result.request_id}, status: {result.status}") - else: - print("Unknown command. Type 'help' for available commands.") - except KeyboardInterrupt: +async def handle_command(client: stackcoin.Client, line: str): + parts = line.split() + cmd = parts[0].lower() + + if cmd == "help": + print_help() + + elif cmd == "balance": + me = await client.get_me() + print(f"{me.username}: {me.balance} STK") + + elif cmd == "user" and len(parts) >= 2: + user = await client.get_user(int(parts[1])) + flags = [] + if user.admin: + flags.append("ADMIN") + if user.banned: + flags.append("BANNED") + flag_str = f" [{', '.join(flags)}]" if flags else "" + print(f"#{user.id} {user.username}: {user.balance} STK{flag_str}") + + elif cmd == "users": + discord_id = parts[1] if len(parts) > 1 else None + users = await client.get_users(discord_id=discord_id) + for u in users[:20]: + print(f" #{u.id} {u.username}: {u.balance} STK") + print(f"({len(users)} total)") + + elif cmd == "send" and len(parts) >= 3: + user_id = int(parts[1]) + amount = int(parts[2]) + label = " ".join(parts[3:]) or None + result = await client.send(user_id, amount, label=label) + print(f"Sent {result.amount} STK (txn #{result.transaction_id}). " + f"Your balance: {result.from_new_balance} STK") + + elif cmd == "request" and len(parts) >= 3: + user_id = int(parts[1]) + amount = int(parts[2]) + label = " ".join(parts[3:]) or None + result = await client.create_request(user_id, amount, label=label) + print(f"Request #{result.request_id} for {result.amount} STK " + f"from {result.responder.username} ({result.status})") + + elif cmd == "requests": + status = parts[1] if len(parts) > 1 else None + reqs = await client.get_requests(status=status) + for r in reqs[:10]: + print(f" #{r.id} {r.requester.username} -> {r.responder.username}: " + f"{r.amount} STK ({r.status})") + print(f"({len(reqs)} total)") + + elif cmd == "accept" and len(parts) >= 2: + result = await client.accept_request(int(parts[1])) + print(f"Accepted request #{result.request_id} -> {result.status}") + + elif cmd == "deny" and len(parts) >= 2: + result = await client.deny_request(int(parts[1])) + print(f"Denied request #{result.request_id} -> {result.status}") + + elif cmd == "transactions": + txns = await client.get_transactions() + for t in txns[:10]: + label_str = f" ({t.label})" if t.label else "" + print(f" #{t.id} {t.from_.username} -> {t.to.username}: " + f"{t.amount} STK{label_str}") + print(f"({len(txns)} total)") + + elif cmd == "events": + since = int(parts[1]) if len(parts) > 1 else 0 + events = await client.get_events(since_id=since) + for e in events[:10]: + print(f" [{e['id']}] {e['type']}: {e['data']}") + print(f"({len(events)} total)") + + else: + print("Unknown command. Type 'help' for available commands.") + + +async def read_stdin_lines(queue: asyncio.Queue[str | None]): + """Read lines from stdin in a thread and push them into a queue.""" + loop = asyncio.get_event_loop() + while True: + line = await loop.run_in_executor(None, sys.stdin.readline) + if not line: + await queue.put(None) break - except ValueError as e: - print(f"Invalid input: {e}") - except Exception as e: - print(f"Error: {e}") + await queue.put(line.strip()) async def main(): @@ -217,11 +127,79 @@ async def main(): return base_url = os.getenv("STACKCOIN_BASE_URL", "https://stackcoin.world") + ws_url = os.getenv("STACKCOIN_WS_URL", + base_url.replace("https://", "wss://") + .replace("http://", "ws://") + + "/bot/websocket") + + async with stackcoin.Client(base_url=base_url, token=token) as client: + me = await client.get_me() + print(f"Connected to {base_url} as {me.username} ({me.balance} STK)") + + # Set up gateway for live events + gateway = stackcoin.Gateway(ws_url=ws_url, token=token) - client = AuthenticatedClient(base_url=base_url, token=token) - async with client as client: - print(f"Connected to {base_url}") - await run_repl(client) + @gateway.on("transfer.completed") + async def on_transfer(event: stackcoin.Event): + d = event.data + role = d.get("role", "?") + if role == "sender": + print(f"\n [event] Sent {d['amount']} STK to user #{d['to_id']}") + else: + print(f"\n [event] Received {d['amount']} STK from user #{d['from_id']}") + print("> ", end="", flush=True) + + @gateway.on("request.created") + async def on_request_created(event: stackcoin.Event): + d = event.data + print(f"\n [event] New request #{d['request_id']} for {d['amount']} STK") + print("> ", end="", flush=True) + + @gateway.on("request.accepted") + async def on_request_accepted(event: stackcoin.Event): + d = event.data + print(f"\n [event] Request #{d['request_id']} accepted") + print("> ", end="", flush=True) + + @gateway.on("request.denied") + async def on_request_denied(event: stackcoin.Event): + d = event.data + print(f"\n [event] Request #{d['request_id']} denied") + print("> ", end="", flush=True) + + # Run gateway in background + gateway_task = asyncio.create_task(gateway.connect()) + + # REPL loop using async stdin reader + input_queue: asyncio.Queue[str | None] = asyncio.Queue() + reader_task = asyncio.create_task(read_stdin_lines(input_queue)) + + print_help() + print("\nLive events from the gateway will appear inline.\n") + + try: + while True: + print("> ", end="", flush=True) + line = await input_queue.get() + if line is None: + break + if not line: + continue + if line.lower() == "quit": + break + try: + await handle_command(client, line) + except stackcoin.StackCoinError as e: + print(f"API error: {e}") + except ValueError as e: + print(f"Invalid input: {e}") + except KeyboardInterrupt: + pass + finally: + gateway.stop() + gateway_task.cancel() + reader_task.cancel() + print("\nBye!") if __name__ == "__main__": From 71bf7e7f77789893696a4bad5da4f5f162143457 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 00:49:39 -0330 Subject: [PATCH 06/14] fix gateway path --- examples/simple_cli.py | 2 +- stackcoin/stackcoin/gateway.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/simple_cli.py b/examples/simple_cli.py index bd2dc65..18b69c8 100644 --- a/examples/simple_cli.py +++ b/examples/simple_cli.py @@ -130,7 +130,7 @@ async def main(): ws_url = os.getenv("STACKCOIN_WS_URL", base_url.replace("https://", "wss://") .replace("http://", "ws://") - + "/bot/websocket") + + "/ws") async with stackcoin.Client(base_url=base_url, token=token) as client: me = await client.get_me() diff --git a/stackcoin/stackcoin/gateway.py b/stackcoin/stackcoin/gateway.py index a747950..4d99127 100644 --- a/stackcoin/stackcoin/gateway.py +++ b/stackcoin/stackcoin/gateway.py @@ -25,7 +25,7 @@ class Gateway: Usage:: gateway = stackcoin.Gateway( - ws_url="ws://localhost:4000/bot/websocket", + ws_url="ws://localhost:4000/ws", token="...", ) @@ -43,7 +43,7 @@ def __init__( last_event_id: int = 0, on_event_id: Callable[[int], None] | None = None, ): - # ws_url should be the full websocket URL like "ws://localhost:4000/bot/websocket" + # ws_url should be the full websocket URL like "ws://localhost:4000/ws" self._ws_url = ws_url.rstrip("/") self._token = token self._handlers: dict[str, list[EventHandler]] = {} From a159d77f51976290c092f078e693b75bf34d3154 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 01:07:10 -0330 Subject: [PATCH 07/14] events are typed --- examples/simple_cli.py | 25 ++++----- stackcoin/stackcoin/__init__.py | 31 ++++++++++- stackcoin/stackcoin/client.py | 19 ++++--- stackcoin/stackcoin/gateway.py | 33 +++++------ stackcoin/stackcoin/models.py | 97 ++++++++++++++++++++++++++++++++- 5 files changed, 158 insertions(+), 47 deletions(-) diff --git a/examples/simple_cli.py b/examples/simple_cli.py index 18b69c8..2c94da6 100644 --- a/examples/simple_cli.py +++ b/examples/simple_cli.py @@ -140,31 +140,26 @@ async def main(): gateway = stackcoin.Gateway(ws_url=ws_url, token=token) @gateway.on("transfer.completed") - async def on_transfer(event: stackcoin.Event): - d = event.data - role = d.get("role", "?") - if role == "sender": - print(f"\n [event] Sent {d['amount']} STK to user #{d['to_id']}") + async def on_transfer(event: stackcoin.TransferCompletedEvent): + if event.data.role == "sender": + print(f"\n [event] Sent {event.data.amount} STK to user #{event.data.to_id}") else: - print(f"\n [event] Received {d['amount']} STK from user #{d['from_id']}") + print(f"\n [event] Received {event.data.amount} STK from user #{event.data.from_id}") print("> ", end="", flush=True) @gateway.on("request.created") - async def on_request_created(event: stackcoin.Event): - d = event.data - print(f"\n [event] New request #{d['request_id']} for {d['amount']} STK") + async def on_request_created(event: stackcoin.RequestCreatedEvent): + print(f"\n [event] New request #{event.data.request_id} for {event.data.amount} STK") print("> ", end="", flush=True) @gateway.on("request.accepted") - async def on_request_accepted(event: stackcoin.Event): - d = event.data - print(f"\n [event] Request #{d['request_id']} accepted") + async def on_request_accepted(event: stackcoin.RequestAcceptedEvent): + print(f"\n [event] Request #{event.data.request_id} accepted") print("> ", end="", flush=True) @gateway.on("request.denied") - async def on_request_denied(event: stackcoin.Event): - d = event.data - print(f"\n [event] Request #{d['request_id']} denied") + async def on_request_denied(event: stackcoin.RequestDeniedEvent): + print(f"\n [event] Request #{event.data.request_id} denied") print("> ", end="", flush=True) # Run gateway in background diff --git a/stackcoin/stackcoin/__init__.py b/stackcoin/stackcoin/__init__.py index 26a7ea6..9b16345 100644 --- a/stackcoin/stackcoin/__init__.py +++ b/stackcoin/stackcoin/__init__.py @@ -1,7 +1,32 @@ """StackCoin Python SDK.""" -from .client import Client +from .client import AnyEvent, Client from .errors import StackCoinError -from .gateway import Event, Gateway +from .gateway import Gateway +from .models import ( + Event, + RequestAcceptedData, + RequestAcceptedEvent, + RequestCreatedData, + RequestCreatedEvent, + RequestDeniedData, + RequestDeniedEvent, + TransferCompletedData, + TransferCompletedEvent, +) -__all__ = ["Client", "Event", "Gateway", "StackCoinError"] +__all__ = [ + "AnyEvent", + "Client", + "Event", + "Gateway", + "RequestAcceptedData", + "RequestAcceptedEvent", + "RequestCreatedData", + "RequestCreatedEvent", + "RequestDeniedData", + "RequestDeniedEvent", + "StackCoinError", + "TransferCompletedData", + "TransferCompletedEvent", +] diff --git a/stackcoin/stackcoin/client.py b/stackcoin/stackcoin/client.py index e77d503..ad4de2b 100644 --- a/stackcoin/stackcoin/client.py +++ b/stackcoin/stackcoin/client.py @@ -11,16 +11,24 @@ CreateRequestResponse, DiscordGuild, DiscordGuildsResponse, + EventsResponse, Request, + RequestAcceptedEvent, RequestActionResponse, + RequestCreatedEvent, + RequestDeniedEvent, RequestsResponse, SendStkResponse, Transaction, TransactionsResponse, + TransferCompletedEvent, User, UsersResponse, ) +# Union of all concrete event types (unwrapped from Event RootModel) +AnyEvent = TransferCompletedEvent | RequestCreatedEvent | RequestAcceptedEvent | RequestDeniedEvent + class Client: """Async client for the StackCoin REST API. @@ -198,18 +206,15 @@ async def get_transaction(self, transaction_id: int) -> Transaction: # -- events ----------------------------------------------------------- # - async def get_events(self, *, since_id: int = 0) -> list[dict[str, Any]]: - """Return events since the given ID. - - Events are not yet in the OpenAPI spec, so this returns raw dicts. - """ + async def get_events(self, *, since_id: int = 0) -> list[AnyEvent]: + """Return typed events since the given ID.""" params: dict[str, Any] = {} if since_id: params["since_id"] = since_id resp = await self._http.get("/api/events", params=params) self._raise_for_error(resp) - data = resp.json() - return data.get("events", data) if isinstance(data, dict) else data + wrapper = EventsResponse.model_validate(resp.json()) + return [e.root for e in wrapper.events] # -- discord guilds --------------------------------------------------- # diff --git a/stackcoin/stackcoin/gateway.py b/stackcoin/stackcoin/gateway.py index 4d99127..d154d03 100644 --- a/stackcoin/stackcoin/gateway.py +++ b/stackcoin/stackcoin/gateway.py @@ -4,19 +4,11 @@ import json from typing import Any, Callable, Awaitable -from pydantic import BaseModel +from .client import AnyEvent +from .models import Event -EventHandler = Callable[["Event"], Awaitable[None]] - - -class Event(BaseModel): - """A StackCoin event received via the gateway.""" - - id: int - type: str - data: dict[str, Any] - inserted_at: str +EventHandler = Callable[[AnyEvent], Awaitable[None]] class Gateway: @@ -30,8 +22,8 @@ class Gateway: ) @gateway.on("request.accepted") - async def handle_accepted(event: stackcoin.Event): - print(event.data["request_id"]) + async def handle_accepted(event: stackcoin.RequestAcceptedEvent): + print(event.data.request_id) await gateway.connect() """ @@ -133,20 +125,21 @@ async def _handle_message(self, msg: list[Any]) -> None: payload = msg[4] if event_name == "event": - event = Event.model_validate(payload) + # Parse via discriminated union RootModel, then unwrap + typed_event = Event.model_validate(payload).root - if event.id > self._last_event_id: - self._last_event_id = event.id + if typed_event.id > self._last_event_id: + self._last_event_id = typed_event.id - for handler in self._handlers.get(event.type, []): + for handler in self._handlers.get(typed_event.type, []): try: - await handler(event) + await handler(typed_event) except Exception: pass - if event.id > 0 and self._on_event_id: + if typed_event.id > 0 and self._on_event_id: try: - self._on_event_id(event.id) + self._on_event_id(typed_event.id) except Exception: pass diff --git a/stackcoin/stackcoin/models.py b/stackcoin/stackcoin/models.py index adbaa0c..f4d5a23 100644 --- a/stackcoin/stackcoin/models.py +++ b/stackcoin/stackcoin/models.py @@ -1,12 +1,14 @@ # generated by datamodel-codegen: # filename: openapi.json -# timestamp: 2026-03-05T04:04:56+00:00 +# timestamp: 2026-03-05T04:32:37+00:00 from __future__ import annotations from datetime import datetime +from enum import StrEnum +from typing import Literal -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, RootModel class CreateRequestParams(BaseModel): @@ -82,6 +84,24 @@ class Request(BaseModel): transaction_id: int | None = Field(None, description="Associated transaction ID") +class RequestAcceptedData(BaseModel): + amount: int = Field(..., description="Request amount") + request_id: int = Field(..., description="Request ID") + status: str = Field(..., description="New request status") + transaction_id: int = Field(..., description="Created transaction ID") + + +class Type(StrEnum): + request_accepted = "request.accepted" + + +class RequestAcceptedEvent(BaseModel): + data: RequestAcceptedData + id: int = Field(..., description="Event ID") + inserted_at: datetime = Field(..., description="Event timestamp") + type: Literal["request.accepted"] = Field(..., description="Event type") + + class RequestActionResponse(BaseModel): request_id: int = Field(..., description="Request ID") resolved_at: datetime = Field(..., description="Resolution timestamp") @@ -90,6 +110,41 @@ class RequestActionResponse(BaseModel): transaction_id: int | None = Field(None, description="Associated transaction ID") +class RequestCreatedData(BaseModel): + amount: int = Field(..., description="Requested amount") + label: str | None = Field(None, description="Request label") + request_id: int = Field(..., description="Request ID") + requester_id: int = Field(..., description="Requester user ID") + responder_id: int = Field(..., description="Responder user ID") + + +class Type1(StrEnum): + request_created = "request.created" + + +class RequestCreatedEvent(BaseModel): + data: RequestCreatedData + id: int = Field(..., description="Event ID") + inserted_at: datetime = Field(..., description="Event timestamp") + type: Literal["request.created"] = Field(..., description="Event type") + + +class RequestDeniedData(BaseModel): + request_id: int = Field(..., description="Request ID") + status: str = Field(..., description="New request status") + + +class Type2(StrEnum): + request_denied = "request.denied" + + +class RequestDeniedEvent(BaseModel): + data: RequestDeniedData + id: int = Field(..., description="Event ID") + inserted_at: datetime = Field(..., description="Event timestamp") + type: Literal["request.denied"] = Field(..., description="Event type") + + class RequestResponse(BaseModel): amount: int = Field(..., description="Requested amount") id: int = Field(..., description="Request ID") @@ -153,6 +208,25 @@ class TransactionsResponse(BaseModel): transactions: list[Transaction] | None = Field(None, description="The transactions list") +class TransferCompletedData(BaseModel): + amount: int = Field(..., description="Amount transferred") + from_id: int = Field(..., description="Sender user ID") + role: str = Field(..., description="Role of the event recipient (sender or receiver)") + to_id: int = Field(..., description="Recipient user ID") + transaction_id: int = Field(..., description="Transaction ID") + + +class Type3(StrEnum): + transfer_completed = "transfer.completed" + + +class TransferCompletedEvent(BaseModel): + data: TransferCompletedData + id: int = Field(..., description="Event ID") + inserted_at: datetime = Field(..., description="Event timestamp") + type: Literal["transfer.completed"] = Field(..., description="Event type") + + class User(BaseModel): admin: bool = Field(..., description="Whether user is an admin") balance: int = Field(..., description="User's STK balance") @@ -176,3 +250,22 @@ class UserResponse(BaseModel): class UsersResponse(BaseModel): pagination: Pagination | None = None users: list[User] | None = Field(None, description="The users list") + + +class Event( + RootModel[ + TransferCompletedEvent | RequestCreatedEvent | RequestAcceptedEvent | RequestDeniedEvent + ] +): + root: ( + TransferCompletedEvent | RequestCreatedEvent | RequestAcceptedEvent | RequestDeniedEvent + ) = Field( + ..., + description="A StackCoin event (discriminated by type)", + discriminator="type", + title="Event", + ) + + +class EventsResponse(BaseModel): + events: list[Event] = Field(..., description="The events list") From a66656fe0ca82c26143fbe01096688d0bf857ef0 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 01:13:30 -0330 Subject: [PATCH 08/14] fix cli usage, no more [] usage --- examples/simple_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/simple_cli.py b/examples/simple_cli.py index 2c94da6..4968c22 100644 --- a/examples/simple_cli.py +++ b/examples/simple_cli.py @@ -100,7 +100,7 @@ async def handle_command(client: stackcoin.Client, line: str): since = int(parts[1]) if len(parts) > 1 else 0 events = await client.get_events(since_id=since) for e in events[:10]: - print(f" [{e['id']}] {e['type']}: {e['data']}") + print(f" [{e.id}] {e.type}: {e.data}") print(f"({len(events)} total)") else: From 3d0154ccb692a555d1b4a2d125d52b29020fe623 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 10:15:58 -0330 Subject: [PATCH 09/14] update readme --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 94e2d72..c9dd330 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,62 @@ # stackcoin-python -Python client for interacting with the StackCoin HTTP API. +Python library for the StackCoin API. Provides a typed async REST client and a WebSocket gateway for real-time events. -https://pypi.org/project/stackcoin/ +## Install ```sh pip install stackcoin ``` +Requires Python 3.13+. Dependencies: `httpx`, `pydantic>=2`, `websockets`. + +## Quick start + +```python +import asyncio +import stackcoin + +async def main(): + async with stackcoin.Client(token="...") as client: + me = await client.get_me() + print(f"{me.username}: {me.balance} STK") + + events = await client.get_events() + for event in events: + print(f"[{event.type}] {event.data}") + +asyncio.run(main()) +``` + +## Gateway (real-time events) + +```python +import stackcoin + +gateway = stackcoin.Gateway(token="...") + +@gateway.on("transfer.completed") +async def on_transfer(event: stackcoin.TransferCompletedEvent): + print(f"Transfer of {event.data.amount} STK from #{event.data.from_id} to #{event.data.to_id}") + +@gateway.on("request.accepted") +async def on_accepted(event: stackcoin.RequestAcceptedEvent): + print(f"Request #{event.data.request_id} accepted") + +await gateway.connect() +``` + ## Examples -- `./examples/basic_usage.py`, bare bones creation of `AuthenticatedClient`, checking balance, making some requests, etc. -- `./examples/simple_cli.py`, thorough usage of the API in a bare-bones command line interface. +- `examples/basic_usage.py` -- REST client basics (balance, requests, transactions) +- `examples/simple_cli.py` -- interactive REPL with live gateway events ---- +## Development + +Models are generated from the StackCoin OpenAPI spec using `datamodel-codegen`: + +```sh +STACKCOIN_ROOT=/path/to/StackCoin just generate +``` -This package is generated by running [openapi-python-client](https://github.com/openapi-generators/openapi-python-client) against [StackCoin's OpenAPI specification](https://stackcoin.world/swaggerui), the `./stackcoin` directory in this repository is the package, and is generated by running `just generate` (or running the commands under `generate` in the `Justfile`). +This regenerates `stackcoin/stackcoin/models.py` from `openapi.json`. From fc777aaeaf630e5421b1c9e6c2ed13a0f98e1452 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 10:29:43 -0330 Subject: [PATCH 10/14] denote alt url for examples, mostly for meeee --- examples/basic_usage.py | 4 +++- examples/simple_cli.py | 6 ++++-- stackcoin/stackcoin/client.py | 4 ++-- stackcoin/stackcoin/gateway.py | 9 +++------ 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 1930a42..24405d2 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -7,7 +7,7 @@ async def main(token: str, base_url: str): - async with stackcoin.Client(base_url=base_url, token=token) as client: + async with stackcoin.Client(token, base_url=base_url) as client: # Who am I? me = await client.get_me() print(f"Logged in as {me.username} with balance {me.balance} STK") @@ -43,5 +43,7 @@ async def main(token: str, base_url: str): print("Token is required") exit(1) + # Can be omitted to hit production (https://stackcoin.world). + # Set STACKCOIN_BASE_URL for local development, e.g. http://localhost:4000 base_url = os.getenv("STACKCOIN_BASE_URL", "https://stackcoin.world") asyncio.run(main(token, base_url)) diff --git a/examples/simple_cli.py b/examples/simple_cli.py index 4968c22..d3a409b 100644 --- a/examples/simple_cli.py +++ b/examples/simple_cli.py @@ -126,18 +126,20 @@ async def main(): print("Token is required") return + # Can be omitted to hit production (https://stackcoin.world). + # Set STACKCOIN_BASE_URL for local development, e.g. http://localhost:4000 base_url = os.getenv("STACKCOIN_BASE_URL", "https://stackcoin.world") ws_url = os.getenv("STACKCOIN_WS_URL", base_url.replace("https://", "wss://") .replace("http://", "ws://") + "/ws") - async with stackcoin.Client(base_url=base_url, token=token) as client: + async with stackcoin.Client(token, base_url=base_url) as client: me = await client.get_me() print(f"Connected to {base_url} as {me.username} ({me.balance} STK)") # Set up gateway for live events - gateway = stackcoin.Gateway(ws_url=ws_url, token=token) + gateway = stackcoin.Gateway(token, ws_url=ws_url) @gateway.on("transfer.completed") async def on_transfer(event: stackcoin.TransferCompletedEvent): diff --git a/stackcoin/stackcoin/client.py b/stackcoin/stackcoin/client.py index ad4de2b..e8683c9 100644 --- a/stackcoin/stackcoin/client.py +++ b/stackcoin/stackcoin/client.py @@ -35,16 +35,16 @@ class Client: Usage:: - async with Client("https://stackcoin.example.com", token="sk-...") as client: + async with Client(token="sk-...") as client: me = await client.get_me() print(me.username, me.balance) """ def __init__( self, - base_url: str, token: str, *, + base_url: str = "https://stackcoin.world", timeout: float = 10.0, ) -> None: self._http = httpx.AsyncClient( diff --git a/stackcoin/stackcoin/gateway.py b/stackcoin/stackcoin/gateway.py index d154d03..8ba9c59 100644 --- a/stackcoin/stackcoin/gateway.py +++ b/stackcoin/stackcoin/gateway.py @@ -16,10 +16,7 @@ class Gateway: Usage:: - gateway = stackcoin.Gateway( - ws_url="ws://localhost:4000/ws", - token="...", - ) + gateway = stackcoin.Gateway(token="...") @gateway.on("request.accepted") async def handle_accepted(event: stackcoin.RequestAcceptedEvent): @@ -30,12 +27,12 @@ async def handle_accepted(event: stackcoin.RequestAcceptedEvent): def __init__( self, - ws_url: str, token: str, + *, + ws_url: str = "wss://stackcoin.world/ws", last_event_id: int = 0, on_event_id: Callable[[int], None] | None = None, ): - # ws_url should be the full websocket URL like "ws://localhost:4000/ws" self._ws_url = ws_url.rstrip("/") self._token = token self._handlers: dict[str, list[EventHandler]] = {} From 20b58887ac70cc2b7e1906adbd89019faf4ede66 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 10:35:02 -0330 Subject: [PATCH 11/14] sdk -> library --- examples/basic_usage.py | 2 +- stackcoin/pyproject.toml | 2 +- stackcoin/stackcoin/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 24405d2..5643501 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -1,4 +1,4 @@ -"""Basic usage of the stackcoin SDK.""" +"""Basic usage of the stackcoin library.""" import asyncio import os diff --git a/stackcoin/pyproject.toml b/stackcoin/pyproject.toml index d36fe89..2ed42fc 100644 --- a/stackcoin/pyproject.toml +++ b/stackcoin/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "stackcoin" version = "0.1.0" -description = "Python SDK for the StackCoin API" +description = "Python library for the StackCoin API" requires-python = ">=3.13" dependencies = [ "httpx>=0.27", diff --git a/stackcoin/stackcoin/__init__.py b/stackcoin/stackcoin/__init__.py index 9b16345..5015200 100644 --- a/stackcoin/stackcoin/__init__.py +++ b/stackcoin/stackcoin/__init__.py @@ -1,4 +1,4 @@ -"""StackCoin Python SDK.""" +"""StackCoin Python library.""" from .client import AnyEvent, Client from .errors import StackCoinError From 81e493133aa3f75d6b4b9c86314fb80d833a8ee8 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 11:47:54 -0330 Subject: [PATCH 12/14] remove useless comments --- stackcoin/stackcoin/client.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/stackcoin/stackcoin/client.py b/stackcoin/stackcoin/client.py index e8683c9..65c2b97 100644 --- a/stackcoin/stackcoin/client.py +++ b/stackcoin/stackcoin/client.py @@ -56,8 +56,6 @@ def __init__( timeout=timeout, ) - # -- context manager -------------------------------------------------- # - async def __aenter__(self) -> Client: return self @@ -73,8 +71,6 @@ async def close(self) -> None: """Close the underlying HTTP connection pool.""" await self._http.aclose() - # -- shared helpers --------------------------------------------------- # - @staticmethod def _raise_for_error(resp: httpx.Response) -> None: """Raise :class:`StackCoinError` on any 4xx/5xx response.""" @@ -87,8 +83,6 @@ def _raise_for_error(resp: httpx.Response) -> None: message = body.get("message") raise StackCoinError(resp.status_code, error, message) - # -- users ------------------------------------------------------------ # - async def get_me(self) -> User: """Return the authenticated user's profile.""" resp = await self._http.get("/api/user/me") @@ -111,8 +105,6 @@ async def get_users(self, *, discord_id: str | None = None) -> list[User]: wrapper = UsersResponse.model_validate(resp.json()) return wrapper.users or [] - # -- send ------------------------------------------------------------- # - async def send( self, to_user_id: int, @@ -136,8 +128,6 @@ async def send( self._raise_for_error(resp) return SendStkResponse.model_validate(resp.json()) - # -- requests --------------------------------------------------------- # - async def create_request( self, to_user_id: int, @@ -189,8 +179,6 @@ async def deny_request(self, request_id: int) -> RequestActionResponse: self._raise_for_error(resp) return RequestActionResponse.model_validate(resp.json()) - # -- transactions ----------------------------------------------------- # - async def get_transactions(self) -> list[Transaction]: """Return transactions for the authenticated user.""" resp = await self._http.get("/api/transactions") @@ -204,8 +192,6 @@ async def get_transaction(self, transaction_id: int) -> Transaction: self._raise_for_error(resp) return Transaction.model_validate(resp.json()) - # -- events ----------------------------------------------------------- # - async def get_events(self, *, since_id: int = 0) -> list[AnyEvent]: """Return typed events since the given ID.""" params: dict[str, Any] = {} @@ -216,8 +202,6 @@ async def get_events(self, *, since_id: int = 0) -> list[AnyEvent]: wrapper = EventsResponse.model_validate(resp.json()) return [e.root for e in wrapper.events] - # -- discord guilds --------------------------------------------------- # - async def get_discord_guilds(self) -> list[DiscordGuild]: """Return all Discord guilds.""" resp = await self._http.get("/api/discord/guilds") From 2f9a3d7ff6d8d07f7175ad1c18439468832e5e38 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 11:48:08 -0330 Subject: [PATCH 13/14] ruff check --- stackcoin/stackcoin/gateway.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stackcoin/stackcoin/gateway.py b/stackcoin/stackcoin/gateway.py index 8ba9c59..1e14fa0 100644 --- a/stackcoin/stackcoin/gateway.py +++ b/stackcoin/stackcoin/gateway.py @@ -2,12 +2,12 @@ import asyncio import json -from typing import Any, Callable, Awaitable +from collections.abc import Awaitable, Callable +from typing import Any from .client import AnyEvent from .models import Event - EventHandler = Callable[[AnyEvent], Awaitable[None]] From 377883650c097f32d96a2cae89a7a82af84954c0 Mon Sep 17 00:00:00 2001 From: Jack Arthur Harrhy Date: Thu, 5 Mar 2026 11:48:24 -0330 Subject: [PATCH 14/14] ruff format --- examples/basic_usage.py | 12 ++++++++--- examples/simple_cli.py | 44 +++++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/examples/basic_usage.py b/examples/basic_usage.py index 5643501..acfe6e0 100644 --- a/examples/basic_usage.py +++ b/examples/basic_usage.py @@ -13,8 +13,12 @@ async def main(token: str, base_url: str): print(f"Logged in as {me.username} with balance {me.balance} STK") # Create a request - req = await client.create_request(to_user_id=2, amount=100, label="pay up buddy") - print(f"Created request #{req.request_id} to {req.responder.username} for {req.amount} STK") + req = await client.create_request( + to_user_id=2, amount=100, label="pay up buddy" + ) + print( + f"Created request #{req.request_id} to {req.responder.username} for {req.amount} STK" + ) # List pending requests requests = await client.get_requests() @@ -26,7 +30,9 @@ async def main(token: str, base_url: str): transactions = await client.get_transactions() print(f"\n{len(transactions)} transaction(s):") for txn in transactions: - print(f" #{txn.id} {txn.from_.username} -> {txn.to.username}: {txn.amount} STK") + print( + f" #{txn.id} {txn.from_.username} -> {txn.to.username}: {txn.amount} STK" + ) # List users users = await client.get_users() diff --git a/examples/simple_cli.py b/examples/simple_cli.py index d3a409b..0cfd827 100644 --- a/examples/simple_cli.py +++ b/examples/simple_cli.py @@ -61,23 +61,29 @@ async def handle_command(client: stackcoin.Client, line: str): amount = int(parts[2]) label = " ".join(parts[3:]) or None result = await client.send(user_id, amount, label=label) - print(f"Sent {result.amount} STK (txn #{result.transaction_id}). " - f"Your balance: {result.from_new_balance} STK") + print( + f"Sent {result.amount} STK (txn #{result.transaction_id}). " + f"Your balance: {result.from_new_balance} STK" + ) elif cmd == "request" and len(parts) >= 3: user_id = int(parts[1]) amount = int(parts[2]) label = " ".join(parts[3:]) or None result = await client.create_request(user_id, amount, label=label) - print(f"Request #{result.request_id} for {result.amount} STK " - f"from {result.responder.username} ({result.status})") + print( + f"Request #{result.request_id} for {result.amount} STK " + f"from {result.responder.username} ({result.status})" + ) elif cmd == "requests": status = parts[1] if len(parts) > 1 else None reqs = await client.get_requests(status=status) for r in reqs[:10]: - print(f" #{r.id} {r.requester.username} -> {r.responder.username}: " - f"{r.amount} STK ({r.status})") + print( + f" #{r.id} {r.requester.username} -> {r.responder.username}: " + f"{r.amount} STK ({r.status})" + ) print(f"({len(reqs)} total)") elif cmd == "accept" and len(parts) >= 2: @@ -92,8 +98,10 @@ async def handle_command(client: stackcoin.Client, line: str): txns = await client.get_transactions() for t in txns[:10]: label_str = f" ({t.label})" if t.label else "" - print(f" #{t.id} {t.from_.username} -> {t.to.username}: " - f"{t.amount} STK{label_str}") + print( + f" #{t.id} {t.from_.username} -> {t.to.username}: " + f"{t.amount} STK{label_str}" + ) print(f"({len(txns)} total)") elif cmd == "events": @@ -129,10 +137,10 @@ async def main(): # Can be omitted to hit production (https://stackcoin.world). # Set STACKCOIN_BASE_URL for local development, e.g. http://localhost:4000 base_url = os.getenv("STACKCOIN_BASE_URL", "https://stackcoin.world") - ws_url = os.getenv("STACKCOIN_WS_URL", - base_url.replace("https://", "wss://") - .replace("http://", "ws://") - + "/ws") + ws_url = os.getenv( + "STACKCOIN_WS_URL", + base_url.replace("https://", "wss://").replace("http://", "ws://") + "/ws", + ) async with stackcoin.Client(token, base_url=base_url) as client: me = await client.get_me() @@ -144,14 +152,20 @@ async def main(): @gateway.on("transfer.completed") async def on_transfer(event: stackcoin.TransferCompletedEvent): if event.data.role == "sender": - print(f"\n [event] Sent {event.data.amount} STK to user #{event.data.to_id}") + print( + f"\n [event] Sent {event.data.amount} STK to user #{event.data.to_id}" + ) else: - print(f"\n [event] Received {event.data.amount} STK from user #{event.data.from_id}") + print( + f"\n [event] Received {event.data.amount} STK from user #{event.data.from_id}" + ) print("> ", end="", flush=True) @gateway.on("request.created") async def on_request_created(event: stackcoin.RequestCreatedEvent): - print(f"\n [event] New request #{event.data.request_id} for {event.data.amount} STK") + print( + f"\n [event] New request #{event.data.request_id} for {event.data.amount} STK" + ) print("> ", end="", flush=True) @gateway.on("request.accepted")