catapa-private 1.0.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.
- catapa_private-1.0.0/PKG-INFO +276 -0
- catapa_private-1.0.0/README.md +246 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private/__init__.py +30 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private/auth/__init__.py +18 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private/auth/catapa_private_auth.py +188 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private/auth/constant.py +12 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private/client.py +81 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private/session_client.py +175 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private.egg-info/PKG-INFO +276 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private.egg-info/SOURCES.txt +13 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private.egg-info/dependency_links.txt +1 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private.egg-info/requires.txt +12 -0
- catapa_private-1.0.0/catapa_private_python/catapa_private.egg-info/top_level.txt +1 -0
- catapa_private-1.0.0/pyproject.toml +96 -0
- catapa_private-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: catapa-private
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python client library for CATAPA Private API
|
|
5
|
+
Author-email: Catapa Team <dev@catapa.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/GDP-ADMIN/CATAPA-API
|
|
7
|
+
Project-URL: Documentation, https://api-docs.catapa.com/
|
|
8
|
+
Project-URL: Repository, https://github.com/GDP-ADMIN/CATAPA-API
|
|
9
|
+
Keywords: catapa,api,client,hr,payroll,private
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: requests>=2.32.0
|
|
20
|
+
Requires-Dist: pydantic>=2.0.0
|
|
21
|
+
Requires-Dist: typing-extensions>=4.7.1
|
|
22
|
+
Requires-Dist: flake8<7.3.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
26
|
+
Requires-Dist: coverage>=7.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pre-commit>=4.2.0; extra == "dev"
|
|
28
|
+
Requires-Dist: ruff>=0.14.0; extra == "dev"
|
|
29
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
30
|
+
|
|
31
|
+
# CATAPA Private Python SDK
|
|
32
|
+
|
|
33
|
+
A Python client library for the CATAPA Private API with session-based authentication.
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- 🔐 **Session-Based Authentication** - Automatic login and session management with cookie handling
|
|
38
|
+
- 🚀 **Simple API** - Clean interface for making authenticated requests to CATAPA Private API
|
|
39
|
+
- 🔄 **Automatic Session Management** - Sessions are automatically maintained and refreshed
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
**Using pip**
|
|
44
|
+
```bash
|
|
45
|
+
pip install catapa-private
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Using poetry**
|
|
49
|
+
```bash
|
|
50
|
+
poetry add catapa-private
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Using uv**
|
|
54
|
+
```bash
|
|
55
|
+
uv add catapa-private
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
A complete Hello World example to get you started immediately.
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from catapa_private import CatapaPrivate
|
|
64
|
+
|
|
65
|
+
def main() -> None:
|
|
66
|
+
client = CatapaPrivate(
|
|
67
|
+
tenant="zfrl",
|
|
68
|
+
username="demo",
|
|
69
|
+
password="dmo-password"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
response = client.get("/core/countries", params={"page": 0, "size": 10})
|
|
73
|
+
response.raise_for_status()
|
|
74
|
+
data = response.json()
|
|
75
|
+
print(f"Found {len(data.get('content', []))} countries")
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
main()
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
> **💡 Tip:** By default, the SDK connects to `https://api.catapa.com`. To use a different base URL (e.g., for staging or testing), pass the `base_url` parameter:
|
|
82
|
+
>
|
|
83
|
+
> ```python
|
|
84
|
+
> client = CatapaPrivate(
|
|
85
|
+
> tenant="your-tenant",
|
|
86
|
+
> username="your-username",
|
|
87
|
+
> password="your-password",
|
|
88
|
+
> base_url="https://staging-api.catapa.com" # Optional: override default base URL
|
|
89
|
+
> )
|
|
90
|
+
> ```
|
|
91
|
+
|
|
92
|
+
## Getting Your Credentials
|
|
93
|
+
|
|
94
|
+
To use the SDK with your own account, you'll need the following authentication credentials:
|
|
95
|
+
|
|
96
|
+
### Tenant ID
|
|
97
|
+
|
|
98
|
+
Your **tenant ID** is your organization's unique identifier in CATAPA. To obtain it, please contact [support@catapa.com](mailto:support@catapa.com).
|
|
99
|
+
|
|
100
|
+
### Username and Password
|
|
101
|
+
|
|
102
|
+
Your **username** and **password** are your CATAPA account credentials used for session-based authentication.
|
|
103
|
+
|
|
104
|
+
> **⚠️ Important:** Keep your credentials secure and never commit them to version control. Consider using environment variables or a secrets management system.
|
|
105
|
+
|
|
106
|
+
## Tutorials
|
|
107
|
+
|
|
108
|
+
More intermediate examples to help you learn the SDK.
|
|
109
|
+
|
|
110
|
+
### Tutorial 1: Complete CRUD Operations
|
|
111
|
+
|
|
112
|
+
A complete example showing how to perform Create, Read, Update, and Delete operations.
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import random
|
|
116
|
+
import string
|
|
117
|
+
|
|
118
|
+
from catapa_private import CatapaPrivate
|
|
119
|
+
|
|
120
|
+
def main() -> None:
|
|
121
|
+
"""Main function demonstrating CRUD operations."""
|
|
122
|
+
client = CatapaPrivate(
|
|
123
|
+
tenant="zfrl",
|
|
124
|
+
username="demo",
|
|
125
|
+
password="dmo-password"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Step 1: GET - Retrieve list of countries
|
|
129
|
+
response = client.get("/core/countries", params={"page": 0, "size": 10})
|
|
130
|
+
response.raise_for_status()
|
|
131
|
+
data = response.json()
|
|
132
|
+
countries = data.get("content", [])
|
|
133
|
+
print(f"Found {len(countries)} countries")
|
|
134
|
+
|
|
135
|
+
# Step 2: POST - Create a new country
|
|
136
|
+
random_suffix = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
|
137
|
+
new_country = {
|
|
138
|
+
"code": f"IDN{random_suffix[:3].upper()}",
|
|
139
|
+
"callingCode": "+62",
|
|
140
|
+
"name": f"Indonesia_{random_suffix}",
|
|
141
|
+
"taxTreaty": True,
|
|
142
|
+
}
|
|
143
|
+
response = client.post("/core/countries", json=new_country)
|
|
144
|
+
response.raise_for_status()
|
|
145
|
+
created_country = response.json()
|
|
146
|
+
country_id = created_country.get("id")
|
|
147
|
+
print(f"Created country: {created_country.get('name')} (ID: {country_id})")
|
|
148
|
+
|
|
149
|
+
# Step 3: GET - Retrieve the created country by ID
|
|
150
|
+
response = client.get(f"/core/countries/{country_id}")
|
|
151
|
+
response.raise_for_status()
|
|
152
|
+
retrieved_country = response.json()
|
|
153
|
+
print(f"Retrieved country: {retrieved_country.get('name')}")
|
|
154
|
+
|
|
155
|
+
# Step 4: PUT - Update the country
|
|
156
|
+
retrieved_country["name"] = f"Indonesia_{random_suffix}_updated"
|
|
157
|
+
response = client.put(f"/core/countries/{country_id}", json=retrieved_country)
|
|
158
|
+
response.raise_for_status()
|
|
159
|
+
updated_country = response.json()
|
|
160
|
+
print(f"Updated country: {updated_country.get('name')}")
|
|
161
|
+
|
|
162
|
+
# Step 5: DELETE - Delete the country
|
|
163
|
+
payload = [{"id": country_id}]
|
|
164
|
+
response = client.delete("/core/countries", json=payload)
|
|
165
|
+
response.raise_for_status()
|
|
166
|
+
print(f"Deleted country (ID: {country_id})")
|
|
167
|
+
|
|
168
|
+
if __name__ == "__main__":
|
|
169
|
+
main()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Tutorial 2: Error Handling and Response Management
|
|
173
|
+
|
|
174
|
+
A complete example showing how to handle errors and manage responses properly.
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from catapa_private import CatapaPrivate
|
|
178
|
+
from requests.exceptions import HTTPError, RequestException
|
|
179
|
+
|
|
180
|
+
def main() -> None:
|
|
181
|
+
"""Main function demonstrating error handling."""
|
|
182
|
+
client = CatapaPrivate(
|
|
183
|
+
tenant="zfrl",
|
|
184
|
+
username="demo",
|
|
185
|
+
password="dmo-password"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
response = client.get("/core/countries", params={"page": 0, "size": 10})
|
|
190
|
+
response.raise_for_status()
|
|
191
|
+
data = response.json()
|
|
192
|
+
print(f"Success: Retrieved {len(data.get('content', []))} countries")
|
|
193
|
+
except HTTPError as e:
|
|
194
|
+
print(f"HTTP Error {e.response.status_code}: {e.response.text}")
|
|
195
|
+
except RequestException as e:
|
|
196
|
+
print(f"Request failed: {e}")
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
main()
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Cookbook
|
|
203
|
+
|
|
204
|
+
Intermediate to Advanced examples for real-world scenarios.
|
|
205
|
+
|
|
206
|
+
### Cookbook 1: Concurrent API Calls
|
|
207
|
+
|
|
208
|
+
A complete example for making concurrent API calls efficiently.
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from catapa_private import CatapaPrivate
|
|
212
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
213
|
+
|
|
214
|
+
def main() -> None:
|
|
215
|
+
"""Main function for concurrent API calls example."""
|
|
216
|
+
client = CatapaPrivate(
|
|
217
|
+
tenant="zfrl",
|
|
218
|
+
username="demo",
|
|
219
|
+
password="dmo-password"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
# Define API call functions
|
|
223
|
+
def get_countries():
|
|
224
|
+
response = client.get("/core/countries", params={"page": 0, "size": 10})
|
|
225
|
+
response.raise_for_status()
|
|
226
|
+
return response.json()
|
|
227
|
+
|
|
228
|
+
def get_banks():
|
|
229
|
+
response = client.get("/core/banks", params={"page": 0, "size": 10})
|
|
230
|
+
response.raise_for_status()
|
|
231
|
+
return response.json()
|
|
232
|
+
|
|
233
|
+
def get_companies():
|
|
234
|
+
response = client.get("/core/companies", params={"page": 0, "size": 10})
|
|
235
|
+
response.raise_for_status()
|
|
236
|
+
return response.json()
|
|
237
|
+
|
|
238
|
+
# Execute API calls concurrently
|
|
239
|
+
with ThreadPoolExecutor(max_workers=3) as executor:
|
|
240
|
+
futures = {
|
|
241
|
+
executor.submit(get_countries): "countries",
|
|
242
|
+
executor.submit(get_banks): "banks",
|
|
243
|
+
executor.submit(get_companies): "companies"
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
results = {}
|
|
247
|
+
for future in as_completed(futures):
|
|
248
|
+
task_name = futures[future]
|
|
249
|
+
try:
|
|
250
|
+
results[task_name] = future.result()
|
|
251
|
+
print(f"✅ {task_name} retrieved successfully")
|
|
252
|
+
except Exception as e:
|
|
253
|
+
print(f"❌ {task_name} failed: {e}")
|
|
254
|
+
|
|
255
|
+
# Use the results
|
|
256
|
+
if "countries" in results:
|
|
257
|
+
data = results["countries"]
|
|
258
|
+
print(f"Countries: {len(data.get('content', []))}")
|
|
259
|
+
if "banks" in results:
|
|
260
|
+
data = results["banks"]
|
|
261
|
+
print(f"Banks: {len(data.get('content', []))}")
|
|
262
|
+
if "companies" in results:
|
|
263
|
+
data = results["companies"]
|
|
264
|
+
print(f"Companies: {len(data.get('content', []))}")
|
|
265
|
+
|
|
266
|
+
if __name__ == "__main__":
|
|
267
|
+
main()
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## More Examples
|
|
271
|
+
|
|
272
|
+
For additional examples including tutorials, cookbooks, and advanced usage patterns, please see the [`examples/`](examples/) directory in this repository.
|
|
273
|
+
|
|
274
|
+
## Requirements
|
|
275
|
+
|
|
276
|
+
- Python 3.11+
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# CATAPA Private Python SDK
|
|
2
|
+
|
|
3
|
+
A Python client library for the CATAPA Private API with session-based authentication.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔐 **Session-Based Authentication** - Automatic login and session management with cookie handling
|
|
8
|
+
- 🚀 **Simple API** - Clean interface for making authenticated requests to CATAPA Private API
|
|
9
|
+
- 🔄 **Automatic Session Management** - Sessions are automatically maintained and refreshed
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
**Using pip**
|
|
14
|
+
```bash
|
|
15
|
+
pip install catapa-private
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Using poetry**
|
|
19
|
+
```bash
|
|
20
|
+
poetry add catapa-private
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Using uv**
|
|
24
|
+
```bash
|
|
25
|
+
uv add catapa-private
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
A complete Hello World example to get you started immediately.
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from catapa_private import CatapaPrivate
|
|
34
|
+
|
|
35
|
+
def main() -> None:
|
|
36
|
+
client = CatapaPrivate(
|
|
37
|
+
tenant="zfrl",
|
|
38
|
+
username="demo",
|
|
39
|
+
password="dmo-password"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
response = client.get("/core/countries", params={"page": 0, "size": 10})
|
|
43
|
+
response.raise_for_status()
|
|
44
|
+
data = response.json()
|
|
45
|
+
print(f"Found {len(data.get('content', []))} countries")
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
main()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
> **💡 Tip:** By default, the SDK connects to `https://api.catapa.com`. To use a different base URL (e.g., for staging or testing), pass the `base_url` parameter:
|
|
52
|
+
>
|
|
53
|
+
> ```python
|
|
54
|
+
> client = CatapaPrivate(
|
|
55
|
+
> tenant="your-tenant",
|
|
56
|
+
> username="your-username",
|
|
57
|
+
> password="your-password",
|
|
58
|
+
> base_url="https://staging-api.catapa.com" # Optional: override default base URL
|
|
59
|
+
> )
|
|
60
|
+
> ```
|
|
61
|
+
|
|
62
|
+
## Getting Your Credentials
|
|
63
|
+
|
|
64
|
+
To use the SDK with your own account, you'll need the following authentication credentials:
|
|
65
|
+
|
|
66
|
+
### Tenant ID
|
|
67
|
+
|
|
68
|
+
Your **tenant ID** is your organization's unique identifier in CATAPA. To obtain it, please contact [support@catapa.com](mailto:support@catapa.com).
|
|
69
|
+
|
|
70
|
+
### Username and Password
|
|
71
|
+
|
|
72
|
+
Your **username** and **password** are your CATAPA account credentials used for session-based authentication.
|
|
73
|
+
|
|
74
|
+
> **⚠️ Important:** Keep your credentials secure and never commit them to version control. Consider using environment variables or a secrets management system.
|
|
75
|
+
|
|
76
|
+
## Tutorials
|
|
77
|
+
|
|
78
|
+
More intermediate examples to help you learn the SDK.
|
|
79
|
+
|
|
80
|
+
### Tutorial 1: Complete CRUD Operations
|
|
81
|
+
|
|
82
|
+
A complete example showing how to perform Create, Read, Update, and Delete operations.
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import random
|
|
86
|
+
import string
|
|
87
|
+
|
|
88
|
+
from catapa_private import CatapaPrivate
|
|
89
|
+
|
|
90
|
+
def main() -> None:
|
|
91
|
+
"""Main function demonstrating CRUD operations."""
|
|
92
|
+
client = CatapaPrivate(
|
|
93
|
+
tenant="zfrl",
|
|
94
|
+
username="demo",
|
|
95
|
+
password="dmo-password"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Step 1: GET - Retrieve list of countries
|
|
99
|
+
response = client.get("/core/countries", params={"page": 0, "size": 10})
|
|
100
|
+
response.raise_for_status()
|
|
101
|
+
data = response.json()
|
|
102
|
+
countries = data.get("content", [])
|
|
103
|
+
print(f"Found {len(countries)} countries")
|
|
104
|
+
|
|
105
|
+
# Step 2: POST - Create a new country
|
|
106
|
+
random_suffix = "".join(random.choices(string.ascii_lowercase + string.digits, k=6))
|
|
107
|
+
new_country = {
|
|
108
|
+
"code": f"IDN{random_suffix[:3].upper()}",
|
|
109
|
+
"callingCode": "+62",
|
|
110
|
+
"name": f"Indonesia_{random_suffix}",
|
|
111
|
+
"taxTreaty": True,
|
|
112
|
+
}
|
|
113
|
+
response = client.post("/core/countries", json=new_country)
|
|
114
|
+
response.raise_for_status()
|
|
115
|
+
created_country = response.json()
|
|
116
|
+
country_id = created_country.get("id")
|
|
117
|
+
print(f"Created country: {created_country.get('name')} (ID: {country_id})")
|
|
118
|
+
|
|
119
|
+
# Step 3: GET - Retrieve the created country by ID
|
|
120
|
+
response = client.get(f"/core/countries/{country_id}")
|
|
121
|
+
response.raise_for_status()
|
|
122
|
+
retrieved_country = response.json()
|
|
123
|
+
print(f"Retrieved country: {retrieved_country.get('name')}")
|
|
124
|
+
|
|
125
|
+
# Step 4: PUT - Update the country
|
|
126
|
+
retrieved_country["name"] = f"Indonesia_{random_suffix}_updated"
|
|
127
|
+
response = client.put(f"/core/countries/{country_id}", json=retrieved_country)
|
|
128
|
+
response.raise_for_status()
|
|
129
|
+
updated_country = response.json()
|
|
130
|
+
print(f"Updated country: {updated_country.get('name')}")
|
|
131
|
+
|
|
132
|
+
# Step 5: DELETE - Delete the country
|
|
133
|
+
payload = [{"id": country_id}]
|
|
134
|
+
response = client.delete("/core/countries", json=payload)
|
|
135
|
+
response.raise_for_status()
|
|
136
|
+
print(f"Deleted country (ID: {country_id})")
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
main()
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Tutorial 2: Error Handling and Response Management
|
|
143
|
+
|
|
144
|
+
A complete example showing how to handle errors and manage responses properly.
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from catapa_private import CatapaPrivate
|
|
148
|
+
from requests.exceptions import HTTPError, RequestException
|
|
149
|
+
|
|
150
|
+
def main() -> None:
|
|
151
|
+
"""Main function demonstrating error handling."""
|
|
152
|
+
client = CatapaPrivate(
|
|
153
|
+
tenant="zfrl",
|
|
154
|
+
username="demo",
|
|
155
|
+
password="dmo-password"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
response = client.get("/core/countries", params={"page": 0, "size": 10})
|
|
160
|
+
response.raise_for_status()
|
|
161
|
+
data = response.json()
|
|
162
|
+
print(f"Success: Retrieved {len(data.get('content', []))} countries")
|
|
163
|
+
except HTTPError as e:
|
|
164
|
+
print(f"HTTP Error {e.response.status_code}: {e.response.text}")
|
|
165
|
+
except RequestException as e:
|
|
166
|
+
print(f"Request failed: {e}")
|
|
167
|
+
|
|
168
|
+
if __name__ == "__main__":
|
|
169
|
+
main()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Cookbook
|
|
173
|
+
|
|
174
|
+
Intermediate to Advanced examples for real-world scenarios.
|
|
175
|
+
|
|
176
|
+
### Cookbook 1: Concurrent API Calls
|
|
177
|
+
|
|
178
|
+
A complete example for making concurrent API calls efficiently.
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from catapa_private import CatapaPrivate
|
|
182
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
183
|
+
|
|
184
|
+
def main() -> None:
|
|
185
|
+
"""Main function for concurrent API calls example."""
|
|
186
|
+
client = CatapaPrivate(
|
|
187
|
+
tenant="zfrl",
|
|
188
|
+
username="demo",
|
|
189
|
+
password="dmo-password"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Define API call functions
|
|
193
|
+
def get_countries():
|
|
194
|
+
response = client.get("/core/countries", params={"page": 0, "size": 10})
|
|
195
|
+
response.raise_for_status()
|
|
196
|
+
return response.json()
|
|
197
|
+
|
|
198
|
+
def get_banks():
|
|
199
|
+
response = client.get("/core/banks", params={"page": 0, "size": 10})
|
|
200
|
+
response.raise_for_status()
|
|
201
|
+
return response.json()
|
|
202
|
+
|
|
203
|
+
def get_companies():
|
|
204
|
+
response = client.get("/core/companies", params={"page": 0, "size": 10})
|
|
205
|
+
response.raise_for_status()
|
|
206
|
+
return response.json()
|
|
207
|
+
|
|
208
|
+
# Execute API calls concurrently
|
|
209
|
+
with ThreadPoolExecutor(max_workers=3) as executor:
|
|
210
|
+
futures = {
|
|
211
|
+
executor.submit(get_countries): "countries",
|
|
212
|
+
executor.submit(get_banks): "banks",
|
|
213
|
+
executor.submit(get_companies): "companies"
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
results = {}
|
|
217
|
+
for future in as_completed(futures):
|
|
218
|
+
task_name = futures[future]
|
|
219
|
+
try:
|
|
220
|
+
results[task_name] = future.result()
|
|
221
|
+
print(f"✅ {task_name} retrieved successfully")
|
|
222
|
+
except Exception as e:
|
|
223
|
+
print(f"❌ {task_name} failed: {e}")
|
|
224
|
+
|
|
225
|
+
# Use the results
|
|
226
|
+
if "countries" in results:
|
|
227
|
+
data = results["countries"]
|
|
228
|
+
print(f"Countries: {len(data.get('content', []))}")
|
|
229
|
+
if "banks" in results:
|
|
230
|
+
data = results["banks"]
|
|
231
|
+
print(f"Banks: {len(data.get('content', []))}")
|
|
232
|
+
if "companies" in results:
|
|
233
|
+
data = results["companies"]
|
|
234
|
+
print(f"Companies: {len(data.get('content', []))}")
|
|
235
|
+
|
|
236
|
+
if __name__ == "__main__":
|
|
237
|
+
main()
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## More Examples
|
|
241
|
+
|
|
242
|
+
For additional examples including tutorials, cookbooks, and advanced usage patterns, please see the [`examples/`](examples/) directory in this repository.
|
|
243
|
+
|
|
244
|
+
## Requirements
|
|
245
|
+
|
|
246
|
+
- Python 3.11+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""CATAPA Private Python Client.
|
|
2
|
+
|
|
3
|
+
Main entry point for the CATAPA Private Python SDK with session-based authentication.
|
|
4
|
+
|
|
5
|
+
This package provides:
|
|
6
|
+
- CatapaPrivate: Main wrapper class with automatic session-based authentication.
|
|
7
|
+
- CatapaPrivateAuth & CatapaPrivateConfig: Authentication utilities.
|
|
8
|
+
- SessionClient: Low-level session-based HTTP client.
|
|
9
|
+
|
|
10
|
+
Authors:
|
|
11
|
+
Handrian Alandi (handrian.alandi@gdplabs.id)
|
|
12
|
+
|
|
13
|
+
References:
|
|
14
|
+
NONE
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from catapa_private.auth.catapa_private_auth import CatapaPrivateAuth, CatapaPrivateConfig
|
|
18
|
+
from catapa_private.client import CatapaPrivate
|
|
19
|
+
from catapa_private.session_client import SessionClient
|
|
20
|
+
|
|
21
|
+
__version__ = "1.0.0"
|
|
22
|
+
__author__ = "Catapa Team"
|
|
23
|
+
__email__ = "dev@catapa.com"
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"CatapaPrivate",
|
|
27
|
+
"CatapaPrivateAuth",
|
|
28
|
+
"CatapaPrivateConfig",
|
|
29
|
+
"SessionClient",
|
|
30
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""CATAPA Private Authentication Module.
|
|
2
|
+
|
|
3
|
+
This module provides authentication utilities for the CATAPA Private API.
|
|
4
|
+
|
|
5
|
+
Authors:
|
|
6
|
+
Handrian Alandi (handrian.alandi@gdplabs.id)
|
|
7
|
+
|
|
8
|
+
References:
|
|
9
|
+
NONE
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from catapa_private.auth.catapa_private_auth import CatapaPrivateAuth, CatapaPrivateConfig
|
|
13
|
+
|
|
14
|
+
__all__ = ["CatapaPrivateAuth", "CatapaPrivateConfig"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|