pysequence-client 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pysequence_client-0.1.0/PKG-INFO +16 -0
- pysequence_client-0.1.0/pyproject.toml +20 -0
- pysequence_client-0.1.0/src/pysequence_client/__init__.py +2 -0
- pysequence_client-0.1.0/src/pysequence_client/client.py +113 -0
- pysequence_client-0.1.0/src/pysequence_client/exceptions.py +8 -0
- pysequence_client-0.1.0/src/pysequence_client/models.py +70 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pysequence-client
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial Python client for the GetSequence API server
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Christian De Leon
|
|
7
|
+
Author-email: christian@deleon.me
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
16
|
+
Requires-Dist: pydantic (>=2.12.5,<3.0.0)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pysequence-client"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Unofficial Python client for the GetSequence API server"
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "Christian De Leon", email = "christian@deleon.me"}
|
|
7
|
+
]
|
|
8
|
+
license = {text = "MIT"}
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"httpx (>=0.28.1,<0.29.0)",
|
|
12
|
+
"pydantic (>=2.12.5,<3.0.0)",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[tool.poetry]
|
|
16
|
+
packages = [{include = "pysequence_client", from = "src"}]
|
|
17
|
+
|
|
18
|
+
[build-system]
|
|
19
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
20
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""HTTP client for the GetSequence API server."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
from pysequence_client.exceptions import ApiError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
log = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SequenceApiClient:
|
|
14
|
+
"""Client for the GetSequence REST API server."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, base_url: str, api_key: str, timeout: float = 30.0) -> None:
|
|
17
|
+
self._client = httpx.Client(
|
|
18
|
+
base_url=base_url,
|
|
19
|
+
headers={"X-API-Key": api_key},
|
|
20
|
+
timeout=timeout,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
def _request(self, method: str, path: str, **kwargs: Any) -> Any:
|
|
24
|
+
resp = self._client.request(method, path, **kwargs)
|
|
25
|
+
|
|
26
|
+
if resp.status_code >= 400:
|
|
27
|
+
content_type = resp.headers.get("content-type", "")
|
|
28
|
+
|
|
29
|
+
if content_type.startswith("application/json"):
|
|
30
|
+
detail = resp.json().get("detail", resp.text)
|
|
31
|
+
else:
|
|
32
|
+
detail = resp.text
|
|
33
|
+
|
|
34
|
+
raise ApiError(resp.status_code, detail)
|
|
35
|
+
|
|
36
|
+
return resp.json()
|
|
37
|
+
|
|
38
|
+
# -- Pod operations --
|
|
39
|
+
|
|
40
|
+
def get_pods(self) -> list[dict[str, Any]]:
|
|
41
|
+
return self._request("GET", "/api/pods")
|
|
42
|
+
|
|
43
|
+
def get_total_balance(self) -> dict[str, Any]:
|
|
44
|
+
return self._request("GET", "/api/pods/balance")
|
|
45
|
+
|
|
46
|
+
def get_pod_balance(self, pod_name: str) -> dict[str, Any] | None:
|
|
47
|
+
try:
|
|
48
|
+
return self._request("GET", f"/api/pods/{pod_name}/balance")
|
|
49
|
+
|
|
50
|
+
except ApiError as e:
|
|
51
|
+
if e.status_code == 404:
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
raise
|
|
55
|
+
|
|
56
|
+
def get_pod_detail(self, pod_id: str) -> dict[str, Any]:
|
|
57
|
+
return self._request("GET", f"/api/pods/detail/{pod_id}")
|
|
58
|
+
|
|
59
|
+
# -- Account operations --
|
|
60
|
+
|
|
61
|
+
def get_all_accounts(self) -> dict[str, Any]:
|
|
62
|
+
return self._request("GET", "/api/accounts")
|
|
63
|
+
|
|
64
|
+
# -- Activity operations --
|
|
65
|
+
|
|
66
|
+
def get_activity_summary(self) -> dict[str, Any]:
|
|
67
|
+
return self._request("GET", "/api/activity/summary")
|
|
68
|
+
|
|
69
|
+
def get_activity(
|
|
70
|
+
self,
|
|
71
|
+
first: int = 10,
|
|
72
|
+
statuses: list[str] | None = None,
|
|
73
|
+
directions: list[str] | None = None,
|
|
74
|
+
activity_types: list[str] | None = None,
|
|
75
|
+
) -> dict[str, Any]:
|
|
76
|
+
params: dict[str, Any] = {"first": first}
|
|
77
|
+
|
|
78
|
+
if statuses:
|
|
79
|
+
params["statuses"] = ",".join(statuses)
|
|
80
|
+
|
|
81
|
+
if directions:
|
|
82
|
+
params["directions"] = ",".join(directions)
|
|
83
|
+
|
|
84
|
+
if activity_types:
|
|
85
|
+
params["activity_types"] = ",".join(activity_types)
|
|
86
|
+
|
|
87
|
+
return self._request("GET", "/api/activity", params=params)
|
|
88
|
+
|
|
89
|
+
def get_transfer_detail(self, transfer_id: str) -> dict[str, Any]:
|
|
90
|
+
return self._request("GET", f"/api/transfers/{transfer_id}")
|
|
91
|
+
|
|
92
|
+
# -- Transfer operations --
|
|
93
|
+
|
|
94
|
+
def transfer(
|
|
95
|
+
self,
|
|
96
|
+
source_id: str,
|
|
97
|
+
destination_id: str,
|
|
98
|
+
amount_cents: int,
|
|
99
|
+
description: str = "",
|
|
100
|
+
) -> dict[str, Any]:
|
|
101
|
+
return self._request(
|
|
102
|
+
"POST",
|
|
103
|
+
"/api/transfers",
|
|
104
|
+
json={
|
|
105
|
+
"source_id": source_id,
|
|
106
|
+
"destination_id": destination_id,
|
|
107
|
+
"amount_cents": amount_cents,
|
|
108
|
+
"description": description,
|
|
109
|
+
},
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def close(self) -> None:
|
|
113
|
+
self._client.close()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Pod(BaseModel):
|
|
5
|
+
id: str
|
|
6
|
+
name: str
|
|
7
|
+
organization_id: str
|
|
8
|
+
balance_cents: int
|
|
9
|
+
balance: str
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Port(BaseModel):
|
|
13
|
+
id: str
|
|
14
|
+
name: str
|
|
15
|
+
organization_id: str
|
|
16
|
+
balance_cents: int
|
|
17
|
+
balance: str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ExternalAccount(BaseModel):
|
|
21
|
+
id: str
|
|
22
|
+
name: str
|
|
23
|
+
organization_id: str
|
|
24
|
+
balance_cents: int
|
|
25
|
+
balance: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TotalBalance(BaseModel):
|
|
29
|
+
total_balance_cents: int
|
|
30
|
+
total_balance: str
|
|
31
|
+
pod_count: int
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TransferParty(BaseModel):
|
|
35
|
+
name: str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Transfer(BaseModel):
|
|
39
|
+
id: str
|
|
40
|
+
status: str
|
|
41
|
+
amount: str
|
|
42
|
+
amount_cents: int
|
|
43
|
+
source: TransferParty
|
|
44
|
+
destination: TransferParty
|
|
45
|
+
direction: str
|
|
46
|
+
activity_type: str
|
|
47
|
+
created_at: str | None = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class PageInfo(BaseModel):
|
|
51
|
+
end_cursor: str
|
|
52
|
+
has_next_page: bool
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ActivityPage(BaseModel):
|
|
56
|
+
transfers: list[Transfer]
|
|
57
|
+
page_info: PageInfo
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ActivitySummary(BaseModel):
|
|
61
|
+
transfer_count: int
|
|
62
|
+
rule_executions: int
|
|
63
|
+
total_incoming_cents: int
|
|
64
|
+
total_incoming: str
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AllAccounts(BaseModel):
|
|
68
|
+
pods: list[Pod]
|
|
69
|
+
ports: list[Port]
|
|
70
|
+
accounts: list[ExternalAccount]
|