laplace-python-sdk 0.1.0__tar.gz → 0.3.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.
- {laplace_python_sdk-0.1.0/src/laplace_python_sdk.egg-info → laplace_python_sdk-0.3.0}/PKG-INFO +107 -3
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/README.md +106 -3
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/pyproject.toml +4 -3
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/src/laplace/__init__.py +2 -2
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/src/laplace/base.py +31 -29
- laplace_python_sdk-0.3.0/src/laplace/brokers.py +214 -0
- laplace_python_sdk-0.3.0/src/laplace/capital_increase.py +92 -0
- laplace_python_sdk-0.3.0/src/laplace/client.py +69 -0
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/src/laplace/collections.py +108 -78
- laplace_python_sdk-0.3.0/src/laplace/earnings.py +65 -0
- laplace_python_sdk-0.3.0/src/laplace/financials.py +91 -0
- laplace_python_sdk-0.3.0/src/laplace/funds.py +104 -0
- laplace_python_sdk-0.3.0/src/laplace/live_price.py +398 -0
- laplace_python_sdk-0.3.0/src/laplace/models.py +942 -0
- laplace_python_sdk-0.3.0/src/laplace/politician.py +59 -0
- laplace_python_sdk-0.3.0/src/laplace/search.py +51 -0
- laplace_python_sdk-0.3.0/src/laplace/state.py +107 -0
- laplace_python_sdk-0.3.0/src/laplace/stocks.py +345 -0
- laplace_python_sdk-0.3.0/src/laplace/websocket.py +514 -0
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0/src/laplace_python_sdk.egg-info}/PKG-INFO +107 -3
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/src/laplace_python_sdk.egg-info/SOURCES.txt +8 -1
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/src/laplace_python_sdk.egg-info/requires.txt +1 -0
- laplace_python_sdk-0.1.0/src/laplace/client.py +0 -29
- laplace_python_sdk-0.1.0/src/laplace/financials.py +0 -15
- laplace_python_sdk-0.1.0/src/laplace/funds.py +0 -15
- laplace_python_sdk-0.1.0/src/laplace/li.py +0 -15
- laplace_python_sdk-0.1.0/src/laplace/models.py +0 -210
- laplace_python_sdk-0.1.0/src/laplace/stocks.py +0 -203
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/LICENSE +0 -0
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/MANIFEST.in +0 -0
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/setup.cfg +0 -0
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/src/laplace_python_sdk.egg-info/dependency_links.txt +0 -0
- {laplace_python_sdk-0.1.0 → laplace_python_sdk-0.3.0}/src/laplace_python_sdk.egg-info/top_level.txt +0 -0
{laplace_python_sdk-0.1.0/src/laplace_python_sdk.egg-info → laplace_python_sdk-0.3.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: laplace-python-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Python SDK for Laplace stock data platform
|
|
5
5
|
Author: Laplace SDK Team
|
|
6
6
|
License: MIT
|
|
@@ -26,6 +26,7 @@ License-File: LICENSE
|
|
|
26
26
|
Requires-Dist: httpx>=0.24.0
|
|
27
27
|
Requires-Dist: pydantic>=2.0.0
|
|
28
28
|
Requires-Dist: typing-extensions>=4.0.0; python_version < "3.10"
|
|
29
|
+
Requires-Dist: websocket-client>=1.8.0
|
|
29
30
|
Provides-Extra: dev
|
|
30
31
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
31
32
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
@@ -51,6 +52,7 @@ The official Python SDK for the Laplace stock data platform. Get easy access to
|
|
|
51
52
|
- 🧪 **Well-tested**: Comprehensive test coverage with real API integration
|
|
52
53
|
- 🌍 **Multi-region**: Support for US and Turkish markets
|
|
53
54
|
- ⚡ **Fast**: Built on httpx for high performance
|
|
55
|
+
- 🔌 **Real-time**: WebSocket support for live price data
|
|
54
56
|
|
|
55
57
|
## Installation
|
|
56
58
|
|
|
@@ -82,12 +84,22 @@ for collection in collections:
|
|
|
82
84
|
|
|
83
85
|
# Get collection details
|
|
84
86
|
collection_detail = client.collections.get_collection_detail(
|
|
85
|
-
collection_id="620f455a0187ade00bb0d55f",
|
|
87
|
+
collection_id="620f455a0187ade00bb0d55f",
|
|
86
88
|
region="tr"
|
|
87
89
|
)
|
|
88
90
|
print(f"Stocks in {collection_detail.title}:")
|
|
89
91
|
for stock in collection_detail.stocks:
|
|
90
92
|
print(f" {stock.symbol}: {stock.name}")
|
|
93
|
+
|
|
94
|
+
# Get politicians and their holdings
|
|
95
|
+
politicians = client.politicians.get_politicians()
|
|
96
|
+
for politician in politicians:
|
|
97
|
+
print(f"{politician.politician_name}: {politician.total_holdings} holdings")
|
|
98
|
+
|
|
99
|
+
# Get holdings for a specific stock
|
|
100
|
+
holdings = client.politicians.get_politician_holdings_by_symbol("AAPL")
|
|
101
|
+
for holding in holdings:
|
|
102
|
+
print(f"{holding.politician_name}: {holding.holding} ({holding.allocation})")
|
|
91
103
|
```
|
|
92
104
|
|
|
93
105
|
## API Reference
|
|
@@ -113,7 +125,7 @@ from laplace.stocks import HistoricalPriceInterval
|
|
|
113
125
|
|
|
114
126
|
prices = client.stocks.get_price_with_interval(
|
|
115
127
|
symbol="AAPL",
|
|
116
|
-
region="us",
|
|
128
|
+
region="us",
|
|
117
129
|
from_date=datetime(2024, 1, 1),
|
|
118
130
|
to_date=datetime(2024, 1, 31),
|
|
119
131
|
interval=HistoricalPriceInterval.ONE_DAY
|
|
@@ -154,6 +166,97 @@ sectors = client.collections.get_sectors(region="tr", locale="en")
|
|
|
154
166
|
sector_detail = client.collections.get_sector_detail(sector_id="id", region="tr")
|
|
155
167
|
```
|
|
156
168
|
|
|
169
|
+
### Politicians Client
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
# Get all politicians
|
|
173
|
+
politicians = client.politicians.get_politicians()
|
|
174
|
+
|
|
175
|
+
# Get politician detail
|
|
176
|
+
politician = client.politicians.get_politician_detail(id=1)
|
|
177
|
+
|
|
178
|
+
# Get holdings by stock symbol
|
|
179
|
+
holdings = client.politicians.get_politician_holdings_by_symbol(symbol="AAPL")
|
|
180
|
+
|
|
181
|
+
# Get top holdings
|
|
182
|
+
top_holdings = client.politicians.get_top_holdings()
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### WebSocket Client (Live Price Data)
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
import asyncio
|
|
189
|
+
from laplace import LaplaceClient, LivePriceFeed, WebSocketOptions, LogLevel
|
|
190
|
+
|
|
191
|
+
# Initialize the client
|
|
192
|
+
client = LaplaceClient(api_key="your-api-key")
|
|
193
|
+
|
|
194
|
+
# Create WebSocket options
|
|
195
|
+
options = WebSocketOptions(
|
|
196
|
+
enable_logging=True,
|
|
197
|
+
log_level=LogLevel.INFO,
|
|
198
|
+
reconnect_attempts=5,
|
|
199
|
+
reconnect_delay=5000,
|
|
200
|
+
max_reconnect_delay=30000,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Create WebSocket client
|
|
204
|
+
websocket_client = client.create_websocket_client(
|
|
205
|
+
feeds=[LivePriceFeed.LIVE_BIST, LivePriceFeed.LIVE_US],
|
|
206
|
+
external_user_id="your-user-id",
|
|
207
|
+
options=options,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# Define callback function for price updates
|
|
211
|
+
def on_price_update(data):
|
|
212
|
+
print(f"Price update for {data.symbol}: {data.close_price}")
|
|
213
|
+
if hasattr(data, 'percent_change'):
|
|
214
|
+
print(f" Change: {data.percent_change}%")
|
|
215
|
+
print(f" Timestamp: {data.timestamp}")
|
|
216
|
+
|
|
217
|
+
async def main():
|
|
218
|
+
# Connect to WebSocket
|
|
219
|
+
await websocket_client.connect()
|
|
220
|
+
|
|
221
|
+
# Subscribe to symbols
|
|
222
|
+
symbols_bist = ["THYAO", "GARAN", "AKBNK"]
|
|
223
|
+
symbols_us = ["AAPL", "GOOGL", "MSFT"]
|
|
224
|
+
|
|
225
|
+
# Subscribe to BIST symbols
|
|
226
|
+
unsubscribe_bist = websocket_client.subscribe(
|
|
227
|
+
symbols=symbols_bist,
|
|
228
|
+
feed=LivePriceFeed.LIVE_BIST,
|
|
229
|
+
handler=on_price_update
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# Subscribe to US symbols
|
|
233
|
+
unsubscribe_us = websocket_client.subscribe(
|
|
234
|
+
symbols=symbols_us,
|
|
235
|
+
feed=LivePriceFeed.LIVE_US,
|
|
236
|
+
handler=on_price_update
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# Keep connection alive
|
|
240
|
+
try:
|
|
241
|
+
while True:
|
|
242
|
+
await asyncio.sleep(1)
|
|
243
|
+
except KeyboardInterrupt:
|
|
244
|
+
# Cleanup
|
|
245
|
+
unsubscribe_bist()
|
|
246
|
+
unsubscribe_us()
|
|
247
|
+
await websocket_client.close()
|
|
248
|
+
|
|
249
|
+
# Run the WebSocket client
|
|
250
|
+
asyncio.run(main())
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Available WebSocket Feeds
|
|
254
|
+
|
|
255
|
+
- `LivePriceFeed.LIVE_BIST`: Live BIST (Turkish) stock prices
|
|
256
|
+
- `LivePriceFeed.LIVE_US`: Live US stock prices
|
|
257
|
+
- `LivePriceFeed.DELAYED_BIST`: Delayed BIST stock prices
|
|
258
|
+
- `LivePriceFeed.DEPTH_TR`: Depth data for TR (commented out, available if needed)
|
|
259
|
+
|
|
157
260
|
## Supported Regions
|
|
158
261
|
|
|
159
262
|
- **US**: United States stock market
|
|
@@ -212,6 +315,7 @@ LAPLACE_API_KEY=your-key pytest -m integration
|
|
|
212
315
|
- Python 3.8+
|
|
213
316
|
- httpx >= 0.24.0
|
|
214
317
|
- pydantic >= 2.0.0
|
|
318
|
+
- websocket-client >= 1.8.0
|
|
215
319
|
|
|
216
320
|
## Documentation
|
|
217
321
|
|
|
@@ -14,6 +14,7 @@ The official Python SDK for the Laplace stock data platform. Get easy access to
|
|
|
14
14
|
- 🧪 **Well-tested**: Comprehensive test coverage with real API integration
|
|
15
15
|
- 🌍 **Multi-region**: Support for US and Turkish markets
|
|
16
16
|
- ⚡ **Fast**: Built on httpx for high performance
|
|
17
|
+
- 🔌 **Real-time**: WebSocket support for live price data
|
|
17
18
|
|
|
18
19
|
## Installation
|
|
19
20
|
|
|
@@ -45,12 +46,22 @@ for collection in collections:
|
|
|
45
46
|
|
|
46
47
|
# Get collection details
|
|
47
48
|
collection_detail = client.collections.get_collection_detail(
|
|
48
|
-
collection_id="620f455a0187ade00bb0d55f",
|
|
49
|
+
collection_id="620f455a0187ade00bb0d55f",
|
|
49
50
|
region="tr"
|
|
50
51
|
)
|
|
51
52
|
print(f"Stocks in {collection_detail.title}:")
|
|
52
53
|
for stock in collection_detail.stocks:
|
|
53
54
|
print(f" {stock.symbol}: {stock.name}")
|
|
55
|
+
|
|
56
|
+
# Get politicians and their holdings
|
|
57
|
+
politicians = client.politicians.get_politicians()
|
|
58
|
+
for politician in politicians:
|
|
59
|
+
print(f"{politician.politician_name}: {politician.total_holdings} holdings")
|
|
60
|
+
|
|
61
|
+
# Get holdings for a specific stock
|
|
62
|
+
holdings = client.politicians.get_politician_holdings_by_symbol("AAPL")
|
|
63
|
+
for holding in holdings:
|
|
64
|
+
print(f"{holding.politician_name}: {holding.holding} ({holding.allocation})")
|
|
54
65
|
```
|
|
55
66
|
|
|
56
67
|
## API Reference
|
|
@@ -76,7 +87,7 @@ from laplace.stocks import HistoricalPriceInterval
|
|
|
76
87
|
|
|
77
88
|
prices = client.stocks.get_price_with_interval(
|
|
78
89
|
symbol="AAPL",
|
|
79
|
-
region="us",
|
|
90
|
+
region="us",
|
|
80
91
|
from_date=datetime(2024, 1, 1),
|
|
81
92
|
to_date=datetime(2024, 1, 31),
|
|
82
93
|
interval=HistoricalPriceInterval.ONE_DAY
|
|
@@ -117,6 +128,97 @@ sectors = client.collections.get_sectors(region="tr", locale="en")
|
|
|
117
128
|
sector_detail = client.collections.get_sector_detail(sector_id="id", region="tr")
|
|
118
129
|
```
|
|
119
130
|
|
|
131
|
+
### Politicians Client
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
# Get all politicians
|
|
135
|
+
politicians = client.politicians.get_politicians()
|
|
136
|
+
|
|
137
|
+
# Get politician detail
|
|
138
|
+
politician = client.politicians.get_politician_detail(id=1)
|
|
139
|
+
|
|
140
|
+
# Get holdings by stock symbol
|
|
141
|
+
holdings = client.politicians.get_politician_holdings_by_symbol(symbol="AAPL")
|
|
142
|
+
|
|
143
|
+
# Get top holdings
|
|
144
|
+
top_holdings = client.politicians.get_top_holdings()
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### WebSocket Client (Live Price Data)
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
import asyncio
|
|
151
|
+
from laplace import LaplaceClient, LivePriceFeed, WebSocketOptions, LogLevel
|
|
152
|
+
|
|
153
|
+
# Initialize the client
|
|
154
|
+
client = LaplaceClient(api_key="your-api-key")
|
|
155
|
+
|
|
156
|
+
# Create WebSocket options
|
|
157
|
+
options = WebSocketOptions(
|
|
158
|
+
enable_logging=True,
|
|
159
|
+
log_level=LogLevel.INFO,
|
|
160
|
+
reconnect_attempts=5,
|
|
161
|
+
reconnect_delay=5000,
|
|
162
|
+
max_reconnect_delay=30000,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Create WebSocket client
|
|
166
|
+
websocket_client = client.create_websocket_client(
|
|
167
|
+
feeds=[LivePriceFeed.LIVE_BIST, LivePriceFeed.LIVE_US],
|
|
168
|
+
external_user_id="your-user-id",
|
|
169
|
+
options=options,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Define callback function for price updates
|
|
173
|
+
def on_price_update(data):
|
|
174
|
+
print(f"Price update for {data.symbol}: {data.close_price}")
|
|
175
|
+
if hasattr(data, 'percent_change'):
|
|
176
|
+
print(f" Change: {data.percent_change}%")
|
|
177
|
+
print(f" Timestamp: {data.timestamp}")
|
|
178
|
+
|
|
179
|
+
async def main():
|
|
180
|
+
# Connect to WebSocket
|
|
181
|
+
await websocket_client.connect()
|
|
182
|
+
|
|
183
|
+
# Subscribe to symbols
|
|
184
|
+
symbols_bist = ["THYAO", "GARAN", "AKBNK"]
|
|
185
|
+
symbols_us = ["AAPL", "GOOGL", "MSFT"]
|
|
186
|
+
|
|
187
|
+
# Subscribe to BIST symbols
|
|
188
|
+
unsubscribe_bist = websocket_client.subscribe(
|
|
189
|
+
symbols=symbols_bist,
|
|
190
|
+
feed=LivePriceFeed.LIVE_BIST,
|
|
191
|
+
handler=on_price_update
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Subscribe to US symbols
|
|
195
|
+
unsubscribe_us = websocket_client.subscribe(
|
|
196
|
+
symbols=symbols_us,
|
|
197
|
+
feed=LivePriceFeed.LIVE_US,
|
|
198
|
+
handler=on_price_update
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# Keep connection alive
|
|
202
|
+
try:
|
|
203
|
+
while True:
|
|
204
|
+
await asyncio.sleep(1)
|
|
205
|
+
except KeyboardInterrupt:
|
|
206
|
+
# Cleanup
|
|
207
|
+
unsubscribe_bist()
|
|
208
|
+
unsubscribe_us()
|
|
209
|
+
await websocket_client.close()
|
|
210
|
+
|
|
211
|
+
# Run the WebSocket client
|
|
212
|
+
asyncio.run(main())
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Available WebSocket Feeds
|
|
216
|
+
|
|
217
|
+
- `LivePriceFeed.LIVE_BIST`: Live BIST (Turkish) stock prices
|
|
218
|
+
- `LivePriceFeed.LIVE_US`: Live US stock prices
|
|
219
|
+
- `LivePriceFeed.DELAYED_BIST`: Delayed BIST stock prices
|
|
220
|
+
- `LivePriceFeed.DEPTH_TR`: Depth data for TR (commented out, available if needed)
|
|
221
|
+
|
|
120
222
|
## Supported Regions
|
|
121
223
|
|
|
122
224
|
- **US**: United States stock market
|
|
@@ -175,6 +277,7 @@ LAPLACE_API_KEY=your-key pytest -m integration
|
|
|
175
277
|
- Python 3.8+
|
|
176
278
|
- httpx >= 0.24.0
|
|
177
279
|
- pydantic >= 2.0.0
|
|
280
|
+
- websocket-client >= 1.8.0
|
|
178
281
|
|
|
179
282
|
## Documentation
|
|
180
283
|
|
|
@@ -182,4 +285,4 @@ Full API documentation is available at [laplace.finfree.co/en/docs](https://lapl
|
|
|
182
285
|
|
|
183
286
|
## License
|
|
184
287
|
|
|
185
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
288
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "laplace-python-sdk"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Python SDK for Laplace stock data platform"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -30,6 +30,7 @@ dependencies = [
|
|
|
30
30
|
"httpx>=0.24.0",
|
|
31
31
|
"pydantic>=2.0.0",
|
|
32
32
|
"typing-extensions>=4.0.0; python_version<'3.10'",
|
|
33
|
+
"websocket-client>=1.8.0",
|
|
33
34
|
]
|
|
34
35
|
|
|
35
36
|
[project.optional-dependencies]
|
|
@@ -63,14 +64,14 @@ profile = "black"
|
|
|
63
64
|
line_length = 100
|
|
64
65
|
|
|
65
66
|
[tool.mypy]
|
|
66
|
-
python_version = "0.
|
|
67
|
+
python_version = "0.3.0"
|
|
67
68
|
strict = true
|
|
68
69
|
warn_return_any = true
|
|
69
70
|
warn_unused_configs = true
|
|
70
71
|
|
|
71
72
|
[tool.ruff]
|
|
72
73
|
line-length = 100
|
|
73
|
-
target-version = "0.
|
|
74
|
+
target-version = "0.3.0"
|
|
74
75
|
select = ["E", "W", "F", "I", "N", "B", "UP"]
|
|
75
76
|
ignore = ["B008", "N805"]
|
|
76
77
|
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
"""Base client for Laplace API."""
|
|
2
2
|
|
|
3
|
-
from typing import Any, Dict, Optional
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
4
5
|
import httpx
|
|
5
|
-
from pydantic import BaseModel
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class LaplaceError(Exception):
|
|
9
9
|
"""Base exception for Laplace API errors."""
|
|
10
|
+
|
|
10
11
|
pass
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class LaplaceAPIError(LaplaceError):
|
|
14
15
|
"""Exception raised for API errors."""
|
|
15
|
-
|
|
16
|
-
def __init__(
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
message: str,
|
|
20
|
+
status_code: Optional[int] = None,
|
|
21
|
+
response: Optional[Dict[str, Any]] = None,
|
|
22
|
+
):
|
|
17
23
|
super().__init__(message)
|
|
18
24
|
self.status_code = status_code
|
|
19
25
|
self.response = response
|
|
@@ -21,10 +27,10 @@ class LaplaceAPIError(LaplaceError):
|
|
|
21
27
|
|
|
22
28
|
class BaseClient:
|
|
23
29
|
"""Base client for Laplace API communication."""
|
|
24
|
-
|
|
30
|
+
|
|
25
31
|
def __init__(self, api_key: str, base_url: str = "https://api.finfree.app/api"):
|
|
26
32
|
"""Initialize the base client.
|
|
27
|
-
|
|
33
|
+
|
|
28
34
|
Args:
|
|
29
35
|
api_key: Your Laplace API key
|
|
30
36
|
base_url: Base URL for the API (default: https://api.finfree.app/api)
|
|
@@ -37,83 +43,79 @@ class BaseClient:
|
|
|
37
43
|
},
|
|
38
44
|
timeout=30.0,
|
|
39
45
|
)
|
|
40
|
-
|
|
46
|
+
|
|
41
47
|
def __enter__(self):
|
|
42
48
|
return self
|
|
43
|
-
|
|
49
|
+
|
|
44
50
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
45
51
|
self.close()
|
|
46
|
-
|
|
52
|
+
|
|
47
53
|
def close(self):
|
|
48
54
|
"""Close the HTTP client."""
|
|
49
55
|
self._client.close()
|
|
50
|
-
|
|
56
|
+
|
|
51
57
|
def _request(
|
|
52
58
|
self,
|
|
53
59
|
method: str,
|
|
54
60
|
endpoint: str,
|
|
55
61
|
params: Optional[Dict[str, Any]] = None,
|
|
56
62
|
json: Optional[Dict[str, Any]] = None,
|
|
57
|
-
**kwargs
|
|
63
|
+
**kwargs,
|
|
58
64
|
) -> Dict[str, Any]:
|
|
59
65
|
"""Make a request to the API.
|
|
60
|
-
|
|
66
|
+
|
|
61
67
|
Args:
|
|
62
68
|
method: HTTP method
|
|
63
69
|
endpoint: API endpoint (relative to base_url)
|
|
64
70
|
params: Query parameters
|
|
65
71
|
json: JSON body data
|
|
66
72
|
**kwargs: Additional arguments passed to httpx
|
|
67
|
-
|
|
73
|
+
|
|
68
74
|
Returns:
|
|
69
75
|
Response data as dictionary
|
|
70
|
-
|
|
76
|
+
|
|
71
77
|
Raises:
|
|
72
78
|
LaplaceAPIError: If the API request fails
|
|
73
79
|
"""
|
|
74
80
|
url = f"{self.base_url}/{endpoint.lstrip('/')}"
|
|
75
|
-
|
|
81
|
+
|
|
76
82
|
# Add API key to params
|
|
77
83
|
if params is None:
|
|
78
84
|
params = {}
|
|
79
85
|
params["api_key"] = self.api_key
|
|
80
|
-
|
|
86
|
+
|
|
81
87
|
try:
|
|
82
88
|
response = self._client.request(
|
|
83
|
-
method=method,
|
|
84
|
-
url=url,
|
|
85
|
-
params=params,
|
|
86
|
-
json=json,
|
|
87
|
-
**kwargs
|
|
89
|
+
method=method, url=url, params=params, json=json, **kwargs
|
|
88
90
|
)
|
|
89
91
|
response.raise_for_status()
|
|
90
92
|
return response.json()
|
|
91
93
|
except httpx.HTTPStatusError as e:
|
|
92
94
|
try:
|
|
93
95
|
error_data = e.response.json()
|
|
94
|
-
except:
|
|
96
|
+
except Exception:
|
|
95
97
|
error_data = {"error": e.response.text}
|
|
96
|
-
|
|
98
|
+
|
|
97
99
|
raise LaplaceAPIError(
|
|
98
100
|
message=f"API request failed: {e.response.status_code} {e.response.reason_phrase}",
|
|
99
101
|
status_code=e.response.status_code,
|
|
100
|
-
response=error_data
|
|
102
|
+
response=error_data,
|
|
101
103
|
) from e
|
|
102
104
|
except httpx.RequestError as e:
|
|
103
105
|
raise LaplaceAPIError(f"Request failed: {str(e)}") from e
|
|
104
|
-
|
|
106
|
+
|
|
105
107
|
def get(self, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
106
108
|
"""Make a GET request."""
|
|
107
109
|
return self._request("GET", endpoint, params=params)
|
|
108
|
-
|
|
110
|
+
|
|
109
111
|
def post(self, endpoint: str, json: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
110
112
|
"""Make a POST request."""
|
|
111
113
|
return self._request("POST", endpoint, json=json)
|
|
112
|
-
|
|
114
|
+
|
|
113
115
|
def put(self, endpoint: str, json: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
114
116
|
"""Make a PUT request."""
|
|
115
117
|
return self._request("PUT", endpoint, json=json)
|
|
116
|
-
|
|
118
|
+
|
|
117
119
|
def delete(self, endpoint: str) -> Dict[str, Any]:
|
|
118
120
|
"""Make a DELETE request."""
|
|
119
|
-
return self._request("DELETE", endpoint)
|
|
121
|
+
return self._request("DELETE", endpoint)
|