nomba-python 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,40 @@
1
+ from .client import AsyncNomba, Nomba
2
+ from .concurrency import gather_limited
3
+ from .exceptions import (
4
+ NombaAPIError,
5
+ NombaAuthError,
6
+ NombaError,
7
+ NombaValidationError,
8
+ )
9
+ from .flows import AsyncCardPaymentFlow, CardPaymentFlow, CardPaymentStep
10
+ from .http import AsyncNombaClient, NombaClient
11
+ from .pagination import apaginate, paginate
12
+ from .webhooks import (
13
+ check_timestamp_freshness,
14
+ compute_signature,
15
+ verify_webhook_request,
16
+ verify_webhook_signature,
17
+ )
18
+
19
+ __all__ = [
20
+ "Nomba",
21
+ "AsyncNomba",
22
+ "NombaClient",
23
+ "AsyncNombaClient",
24
+ "NombaError",
25
+ "NombaAPIError",
26
+ "NombaAuthError",
27
+ "NombaValidationError",
28
+ "CardPaymentFlow",
29
+ "AsyncCardPaymentFlow",
30
+ "CardPaymentStep",
31
+ "paginate",
32
+ "apaginate",
33
+ "gather_limited",
34
+ "verify_webhook_signature",
35
+ "verify_webhook_request",
36
+ "compute_signature",
37
+ "check_timestamp_freshness",
38
+ ]
39
+
40
+ __version__ = "0.1.0"
nomba_python/client.py ADDED
@@ -0,0 +1,161 @@
1
+ from __future__ import annotations
2
+
3
+ from .http import AsyncNombaClient, NombaClient
4
+ from .resources import (
5
+ Accounts,
6
+ AirtimeData,
7
+ AsyncAccounts,
8
+ AsyncAirtimeData,
9
+ AsyncCableTv,
10
+ AsyncCharge,
11
+ AsyncCheckout,
12
+ AsyncElectricity,
13
+ AsyncTerminals,
14
+ AsyncTransactions,
15
+ AsyncTransfers,
16
+ AsyncVirtualAccounts,
17
+ CableTv,
18
+ Charge,
19
+ Checkout,
20
+ Electricity,
21
+ Terminals,
22
+ Transactions,
23
+ Transfers,
24
+ VirtualAccounts,
25
+ )
26
+ from .flows import CardPaymentFlow, AsyncCardPaymentFlow
27
+
28
+
29
+ class Nomba:
30
+ """
31
+ High-level entry point for the Nomba SDK. Covers every endpoint in
32
+ Nomba's published OpenAPI spec.
33
+
34
+ Example:
35
+ from nomba import Nomba
36
+
37
+ nomba = Nomba(
38
+ client_id="...",
39
+ client_secret="...",
40
+ account_id="...",
41
+ sandbox=True,
42
+ )
43
+
44
+ account = nomba.virtual_accounts.create_virtual_account(
45
+ account_ref="ref-123",
46
+ account_name="Jane Doe",
47
+ )
48
+
49
+ Resource groups:
50
+ accounts, virtual_accounts, checkout, charge, transfers,
51
+ terminals, transactions, airtime_data, cabletv, electricity
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ client_id: str,
57
+ client_secret: str,
58
+ account_id: str,
59
+ *,
60
+ sandbox: bool = False,
61
+ timeout: float = 30.0,
62
+ ) -> None:
63
+ self.client = NombaClient(
64
+ client_id=client_id,
65
+ client_secret=client_secret,
66
+ account_id=account_id,
67
+ sandbox=sandbox,
68
+ timeout=timeout,
69
+ )
70
+ self.accounts = Accounts(self.client)
71
+ self.virtual_accounts = VirtualAccounts(self.client)
72
+ self.checkout = Checkout(self.client)
73
+ self.charge = Charge(self.client)
74
+ self.transfers = Transfers(self.client)
75
+ self.terminals = Terminals(self.client)
76
+ self.transactions = Transactions(self.client)
77
+ self.airtime_data = AirtimeData(self.client)
78
+ self.cabletv = CableTv(self.client)
79
+ self.electricity = Electricity(self.client)
80
+
81
+ def close(self) -> None:
82
+ self.client.close()
83
+
84
+ def card_payment(self, order_reference: str) -> "CardPaymentFlow":
85
+ """Start a guided card-payment flow for an existing checkout order.
86
+ See `nomba.flows.CardPaymentFlow` for the full step-by-step API."""
87
+ from .flows import CardPaymentFlow
88
+
89
+ return CardPaymentFlow(self.charge, order_reference=order_reference)
90
+
91
+ def __enter__(self) -> "Nomba":
92
+ return self
93
+
94
+ def __exit__(self, *exc_info: object) -> None:
95
+ self.close()
96
+
97
+
98
+ class AsyncNomba:
99
+ """
100
+ Async high-level entry point for the Nomba SDK (uses httpx.AsyncClient).
101
+ Covers every endpoint in Nomba's published OpenAPI spec.
102
+
103
+ Example:
104
+ from nomba import AsyncNomba
105
+
106
+ async def main():
107
+ nomba = AsyncNomba(
108
+ client_id="...",
109
+ client_secret="...",
110
+ account_id="...",
111
+ sandbox=True,
112
+ )
113
+ account = await nomba.virtual_accounts.create_virtual_account(
114
+ account_ref="ref-123",
115
+ account_name="Jane Doe",
116
+ )
117
+ await nomba.close()
118
+ """
119
+
120
+ def __init__(
121
+ self,
122
+ client_id: str,
123
+ client_secret: str,
124
+ account_id: str,
125
+ *,
126
+ sandbox: bool = False,
127
+ timeout: float = 30.0,
128
+ ) -> None:
129
+ self.client = AsyncNombaClient(
130
+ client_id=client_id,
131
+ client_secret=client_secret,
132
+ account_id=account_id,
133
+ sandbox=sandbox,
134
+ timeout=timeout,
135
+ )
136
+ self.accounts = AsyncAccounts(self.client)
137
+ self.virtual_accounts = AsyncVirtualAccounts(self.client)
138
+ self.checkout = AsyncCheckout(self.client)
139
+ self.charge = AsyncCharge(self.client)
140
+ self.transfers = AsyncTransfers(self.client)
141
+ self.terminals = AsyncTerminals(self.client)
142
+ self.transactions = AsyncTransactions(self.client)
143
+ self.airtime_data = AsyncAirtimeData(self.client)
144
+ self.cabletv = AsyncCableTv(self.client)
145
+ self.electricity = AsyncElectricity(self.client)
146
+
147
+ async def close(self) -> None:
148
+ await self.client.close()
149
+
150
+ def card_payment(self, order_reference: str) -> "AsyncCardPaymentFlow":
151
+ """Start a guided async card-payment flow for an existing checkout
152
+ order. See `nomba.flows.AsyncCardPaymentFlow` for the full API."""
153
+ from .flows import AsyncCardPaymentFlow
154
+
155
+ return AsyncCardPaymentFlow(self.charge, order_reference=order_reference)
156
+
157
+ async def __aenter__(self) -> "AsyncNomba":
158
+ return self
159
+
160
+ async def __aexit__(self, *exc_info: object) -> None:
161
+ await self.close()
@@ -0,0 +1,54 @@
1
+ """
2
+ Bounded concurrency helper.
3
+
4
+ `asyncio.gather` has no built-in concurrency limit -- firing off 200 async
5
+ calls with `asyncio.gather(*[nomba.transfers.send(...) for ...])` sends all
6
+ 200 at once. If several start failing (e.g. Nomba rate-limiting you), each
7
+ one independently retries with its own backoff, multiplying load right when
8
+ the API is already struggling, and you may also just trip the rate limit by
9
+ bursting too many requests in the same window.
10
+
11
+ `gather_limited` runs the same calls but caps how many are in flight at
12
+ once, which keeps both the retry storm and the burst size bounded.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import asyncio
17
+ from typing import Awaitable, Callable, Sequence, TypeVar
18
+
19
+ T = TypeVar("T")
20
+
21
+
22
+ async def gather_limited(
23
+ calls: Sequence[Callable[[], Awaitable[T]]],
24
+ *,
25
+ limit: int = 5,
26
+ return_exceptions: bool = False,
27
+ ) -> list[T| BaseException]:
28
+ """
29
+ Run a sequence of zero-arg async callables with at most `limit` running
30
+ concurrently, preserving input order in the returned results.
31
+
32
+ Example:
33
+ from nomba import AsyncNomba
34
+ from nomba.concurrency import gather_limited
35
+
36
+ async with AsyncNomba(...) as nomba:
37
+ calls = [
38
+ (lambda ref=ref: nomba.virtual_accounts.fetch_a_virtual_account(ref))
39
+ for ref in account_refs
40
+ ]
41
+ results = await gather_limited(calls, limit=5)
42
+
43
+ `return_exceptions=True` behaves like `asyncio.gather(..., return_exceptions=True)`:
44
+ exceptions are returned in place of results instead of propagating.
45
+ """
46
+ semaphore = asyncio.Semaphore(limit)
47
+
48
+ async def _run(call: Callable[[], Awaitable[T]]) -> T:
49
+ async with semaphore:
50
+ return await call()
51
+
52
+ return await asyncio.gather(
53
+ *(_run(call) for call in calls), return_exceptions=return_exceptions
54
+ )
File without changes