dataquery-sdk 0.1.4__tar.gz → 0.1.5__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.
Files changed (37) hide show
  1. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/CHANGELOG.md +3 -1
  2. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/CONTRIBUTING.md +3 -6
  3. dataquery_sdk-0.1.5/PKG-INFO +502 -0
  4. dataquery_sdk-0.1.5/README.md +437 -0
  5. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/__init__.py +12 -114
  6. dataquery_sdk-0.1.5/dataquery/_download_utils.py +110 -0
  7. dataquery_sdk-0.1.5/dataquery/_mixins.py +656 -0
  8. dataquery_sdk-0.1.5/dataquery/_parallel_download.py +300 -0
  9. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/auth.py +27 -9
  10. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/cli.py +80 -25
  11. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/client.py +115 -825
  12. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/config.py +4 -4
  13. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/connection_pool.py +46 -99
  14. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/dataquery.py +103 -459
  15. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/exceptions.py +15 -2
  16. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/models.py +26 -3
  17. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/rate_limiter.py +3 -27
  18. dataquery_sdk-0.1.5/dataquery/sse_client.py +280 -0
  19. dataquery_sdk-0.1.5/dataquery/sse_subscriber.py +437 -0
  20. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/utils.py +4 -4
  21. dataquery_sdk-0.1.5/dataquery_sdk.egg-info/PKG-INFO +502 -0
  22. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/SOURCES.txt +5 -1
  23. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/pyproject.toml +1 -1
  24. dataquery_sdk-0.1.4/PKG-INFO +0 -503
  25. dataquery_sdk-0.1.4/README.md +0 -438
  26. dataquery_sdk-0.1.4/dataquery/auto_download.py +0 -443
  27. dataquery_sdk-0.1.4/dataquery_sdk.egg-info/PKG-INFO +0 -503
  28. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/LICENSE +0 -0
  29. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/MANIFEST.in +0 -0
  30. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/logging_config.py +0 -0
  31. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/py.typed +0 -0
  32. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery/retry.py +0 -0
  33. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/dependency_links.txt +0 -0
  34. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/entry_points.txt +0 -0
  35. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/requires.txt +0 -0
  36. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/dataquery_sdk.egg-info/top_level.txt +0 -0
  37. {dataquery_sdk-0.1.4 → dataquery_sdk-0.1.5}/setup.cfg +0 -0
@@ -24,4 +24,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
24
24
  ## [0.1.3] - 2026-02-21
25
25
  - Historical file download added
26
26
  ## [0.1.4] - 2026-03-23
27
- - Introduced circuit breaker environment variable (`DATAQUERY_CIRCUIT_BREAKER_THRESHOLD`)
27
+ - Introduced circuit breaker environment variable (`DATAQUERY_CIRCUIT_BREAKER_THRESHOLD`)
28
+ ## [0.1.5] - 2026-04-16
29
+ - Introduced file-group-id to the group downloads
@@ -54,9 +54,8 @@ Thank you for your interest in contributing to the DataQuery SDK! This document
54
54
 
55
55
  5. Run linting and formatting:
56
56
  ```bash
57
- uv run black .
58
- uv run isort .
59
- uv run flake8 dataquery/ tests/
57
+ uv run ruff check dataquery/ tests/ examples/
58
+ uv run ruff format dataquery/ tests/ examples/
60
59
  uv run mypy dataquery/
61
60
  ```
62
61
 
@@ -71,9 +70,7 @@ Thank you for your interest in contributing to the DataQuery SDK! This document
71
70
  ### Coding Standards
72
71
 
73
72
  - **Python Style**: Follow PEP 8
74
- - **Formatting**: Use Black for code formatting
75
- - **Import Sorting**: Use isort for import organization
76
- - **Linting**: Use flake8 for code quality checks
73
+ - **Linting & Formatting**: Use [Ruff](https://github.com/astral-sh/ruff) for linting, formatting, and import sorting
77
74
  - **Type Hints**: Use mypy for type checking
78
75
  - **Docstrings**: Follow Google docstring format
79
76
 
@@ -0,0 +1,502 @@
1
+ Metadata-Version: 2.4
2
+ Name: dataquery-sdk
3
+ Version: 0.1.5
4
+ Summary: Python SDK for DATAQUERY Data API - Query, download, and check availability of economic data files
5
+ Author-email: DATAQUERY SDK Team <dataquery_support@jpmorgan.com>
6
+ Project-URL: Homepage, https://github.com/dataquery/dataquery-sdk
7
+ Project-URL: Bug Tracker, https://github.com/dataquery/dataquery-sdk/issues
8
+ Project-URL: Documentation, https://github.com/dataquery/dataquery-sdk/wiki
9
+ Project-URL: Source Code, https://github.com/dataquery/dataquery-sdk
10
+ Keywords: dataquery,data,api,economic,financial,download,async,oauth,rate-limiting,sdk
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Financial and Insurance Industry
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: Office/Business :: Financial
24
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
25
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
26
+ Requires-Python: >=3.10
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: aiohttp<4.0.0,>=3.8.0
30
+ Requires-Dist: pydantic<3.0.0,>=2.0.0
31
+ Requires-Dist: structlog>=23.0.0
32
+ Requires-Dist: python-dotenv>=1.0.0
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
35
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
36
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
37
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
38
+ Requires-Dist: mypy>=1.5.0; extra == "dev"
39
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
40
+ Requires-Dist: pip-audit>=2.7.0; extra == "dev"
41
+ Requires-Dist: build>=1.3.0; extra == "dev"
42
+ Requires-Dist: twine>=4.0.0; extra == "dev"
43
+ Provides-Extra: docs
44
+ Requires-Dist: mkdocs>=1.5.0; extra == "docs"
45
+ Requires-Dist: mkdocs-material>=9.0.0; extra == "docs"
46
+ Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "docs"
47
+ Requires-Dist: mike>=1.1.0; extra == "docs"
48
+ Provides-Extra: pandas
49
+ Requires-Dist: pandas>=2.0.0; extra == "pandas"
50
+ Provides-Extra: all
51
+ Requires-Dist: pytest>=7.0.0; extra == "all"
52
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
53
+ Requires-Dist: pytest-cov>=4.0.0; extra == "all"
54
+ Requires-Dist: ruff>=0.4.0; extra == "all"
55
+ Requires-Dist: mypy>=1.5.0; extra == "all"
56
+ Requires-Dist: pre-commit>=3.0.0; extra == "all"
57
+ Requires-Dist: mkdocs>=1.5.0; extra == "all"
58
+ Requires-Dist: mkdocs-material>=9.0.0; extra == "all"
59
+ Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "all"
60
+ Requires-Dist: mike>=1.1.0; extra == "all"
61
+ Requires-Dist: pandas>=2.0.0; extra == "all"
62
+ Requires-Dist: pip-audit>=2.7.0; extra == "all"
63
+ Requires-Dist: build>=1.3.0; extra == "all"
64
+ Dynamic: license-file
65
+
66
+ # DataQuery SDK
67
+
68
+ Python SDK for the J.P. Morgan DataQuery API — authenticated file downloads, time-series queries, and real-time notification-driven downloads with OAuth 2.0, rate limiting, and automatic retries built in.
69
+
70
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
71
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
72
+ [![Linting: Ruff](https://img.shields.io/badge/linting-ruff-261230.svg)](https://github.com/astral-sh/ruff)
73
+
74
+ ## Features
75
+
76
+ - **Parallel file downloads** — when `num_parts > 1`, HTTP range requests split the file into parallel chunks with bounded concurrency; `num_parts=1` (default) uses a simple streaming GET
77
+ - **Historical and date-range downloads** — fetch every file in a group (optionally filtered to one or many `file-group-id`s) between two dates
78
+ - **Notification-driven downloads (SSE)** — subscribe to the `/notification` stream and auto-download files as soon as they are published
79
+ - **Time-series queries** — by expression, by instrument, or by group with attribute / filter projections
80
+ - **OAuth 2.0 with token caching and refresh** — or supply a bearer token directly
81
+ - **Token-bucket rate limiter** — 300 rpm / 5 tps defaults (configurable up to API limits)
82
+ - **Retry + circuit breaker** — exponential backoff, configurable failure threshold
83
+ - **Sync and async APIs** — every operation has `_async` and sync variants
84
+ - **Optional pandas integration** — `to_dataframe(...)` on any response
85
+ - **CLI** — `dataquery groups | files | availability | download | download-group | auth | config`
86
+
87
+ ## Installation
88
+
89
+ ```bash
90
+ # Core install
91
+ pip install dataquery-sdk
92
+
93
+ # With pandas DataFrame conversion
94
+ pip install "dataquery-sdk[pandas]"
95
+
96
+ # With dev tooling (ruff, mypy, pytest)
97
+ pip install "dataquery-sdk[dev]"
98
+ ```
99
+
100
+ Python 3.10+ is required.
101
+
102
+ ## Configure credentials
103
+
104
+ Set OAuth client credentials via environment variables:
105
+
106
+ ```bash
107
+ export DATAQUERY_CLIENT_ID="your_client_id"
108
+ export DATAQUERY_CLIENT_SECRET="your_client_secret"
109
+ ```
110
+
111
+ Or create a `.env` file in the working directory:
112
+
113
+ ```env
114
+ DATAQUERY_CLIENT_ID=your_client_id
115
+ DATAQUERY_CLIENT_SECRET=your_client_secret
116
+ ```
117
+
118
+ Or pass them directly to the constructor:
119
+
120
+ ```python
121
+ from dataquery import DataQuery
122
+
123
+ dq = DataQuery(client_id="...", client_secret="...")
124
+ ```
125
+
126
+ A starter `.env` can be generated with `dataquery config template --output .env`.
127
+
128
+ ## Quick start
129
+
130
+ ### Download files for a date range
131
+
132
+ ```python
133
+ from dataquery import DataQuery
134
+
135
+ # async
136
+ async with DataQuery() as dq:
137
+ result = await dq.run_group_download_async(
138
+ group_id="JPMAQS_GENERIC_RETURNS",
139
+ start_date="20250101",
140
+ end_date="20250131",
141
+ destination_dir="./data",
142
+ )
143
+ print(f"{result['successful_downloads']}/{result['total_files']} files downloaded")
144
+
145
+ # sync
146
+ with DataQuery() as dq:
147
+ result = dq.run_group_download(
148
+ group_id="JPMAQS_GENERIC_RETURNS",
149
+ start_date="20250101",
150
+ end_date="20250131",
151
+ destination_dir="./data",
152
+ )
153
+ ```
154
+
155
+ ### Restrict a date-range download to specific file-group-ids
156
+
157
+ `file_group_id` accepts a single id or a list. When a list is supplied, availability
158
+ queries run in parallel per id and the union of dates is downloaded.
159
+
160
+ ```python
161
+ async with DataQuery() as dq:
162
+ result = await dq.run_group_download_async(
163
+ group_id="JPMAQS_GENERIC_RETURNS",
164
+ start_date="20250101",
165
+ end_date="20250131",
166
+ destination_dir="./data",
167
+ file_group_id=["FG_ABC", "FG_DEF", "FG_XYZ"],
168
+ )
169
+ ```
170
+
171
+ ### Download a single file
172
+
173
+ ```python
174
+ from pathlib import Path
175
+ from dataquery import DataQuery
176
+
177
+ async with DataQuery() as dq:
178
+ result = await dq.download_file_async(
179
+ file_group_id="JPMAQS_GENERIC_RETURNS",
180
+ file_datetime="20250115",
181
+ destination_path=Path("./downloads"),
182
+ num_parts=5, # parallel chunks
183
+ )
184
+ print(f"Downloaded: {result.local_path} ({result.file_size} bytes)")
185
+ ```
186
+
187
+ ### Time-series queries
188
+
189
+ ```python
190
+ async with DataQuery() as dq:
191
+ # By expression
192
+ ts = await dq.get_expressions_time_series_async(
193
+ expressions=["DB(MTE,IRISH EUR 1.100 15-May-2029 LON,,IE00BH3SQ895,MIDPRC)"],
194
+ start_date="20240101",
195
+ end_date="20240131",
196
+ )
197
+
198
+ # By group with attributes + filter
199
+ ts = await dq.get_group_time_series_async(
200
+ group_id="FI_GO_BO_EA",
201
+ attributes=["MIDPRC", "REPO_1M"],
202
+ filter="country(IRL)",
203
+ start_date="20240101",
204
+ end_date="20240131",
205
+ )
206
+
207
+ df = dq.to_dataframe(ts) # requires pandas extra
208
+ ```
209
+
210
+ ### Discover available data
211
+
212
+ ```python
213
+ async with DataQuery() as dq:
214
+ groups = await dq.list_groups_async(limit=100)
215
+ files = await dq.list_files_async(group_id="JPMAQS_GENERIC_RETURNS")
216
+ available = await dq.list_available_files_async(
217
+ group_id="JPMAQS_GENERIC_RETURNS",
218
+ start_date="20250101",
219
+ end_date="20250131",
220
+ )
221
+ instruments = await dq.search_instruments_async(
222
+ group_id="FI_GO_BO_EA", keywords="irish"
223
+ )
224
+ ```
225
+
226
+ ## Auto-download (coming soon)
227
+
228
+ Real-time notification-driven downloads via the DataQuery SSE stream are under
229
+ active development and will be available in a future release. Once released,
230
+ `auto_download_async` will subscribe to the `/notification` endpoint and
231
+ download files automatically as they are published — no polling required.
232
+
233
+ ## CLI
234
+
235
+ The installer registers a `dataquery` script:
236
+
237
+ ```bash
238
+ # List / search groups
239
+ dataquery groups --limit 100
240
+ dataquery groups --search "fixed income" --json
241
+
242
+ # List files in a group
243
+ dataquery files --group-id JPMAQS_GENERIC_RETURNS --json
244
+
245
+ # Check availability for a single file
246
+ dataquery availability --file-group-id JPMAQS_GENERIC_RETURNS --file-datetime 20250115
247
+
248
+ # Download a single file
249
+ dataquery download --file-group-id JPMAQS_GENERIC_RETURNS \
250
+ --file-datetime 20250115 \
251
+ --destination ./downloads \
252
+ --num-parts 5
253
+
254
+ # Watch a group and download as new files arrive
255
+ dataquery download --watch --group-id JPMAQS_GENERIC_RETURNS --destination ./downloads
256
+
257
+ # Download everything in a date range
258
+ dataquery download-group --group-id JPMAQS_GENERIC_RETURNS \
259
+ --start-date 20250101 --end-date 20250131 \
260
+ --destination ./data \
261
+ --max-concurrent 5 --num-parts 4
262
+
263
+ # Restrict to one or more file-group-ids
264
+ dataquery download-group --group-id JPMAQS_GENERIC_RETURNS \
265
+ --file-group-id FG_ABC FG_DEF \
266
+ --start-date 20250101 --end-date 20250131
267
+
268
+ # Config utilities
269
+ dataquery config show
270
+ dataquery config validate
271
+ dataquery config template --output .env
272
+
273
+ # Verify auth
274
+ dataquery auth test
275
+ ```
276
+
277
+ Every subcommand accepts `--env-file PATH` (to point at a non-default `.env`) and
278
+ most accept `--json` for machine-readable output.
279
+
280
+ ## Configuration
281
+
282
+ ### Environment variables
283
+
284
+ All environment variables use the `DATAQUERY_` prefix.
285
+
286
+ **Credentials**
287
+
288
+ | Variable | Default | Notes |
289
+ |---|---|---|
290
+ | `DATAQUERY_CLIENT_ID` | _(none)_ | Required for OAuth |
291
+ | `DATAQUERY_CLIENT_SECRET` | _(none)_ | Required for OAuth |
292
+ | `DATAQUERY_BEARER_TOKEN` | _(none)_ | Alternative to OAuth |
293
+ | `DATAQUERY_OAUTH_ENABLED` | `true` | Set `false` to use bearer-token mode |
294
+ | `DATAQUERY_OAUTH_TOKEN_URL` | `https://authe.jpmorgan.com/as/token.oauth2` | |
295
+ | `DATAQUERY_OAUTH_AUD` | `JPMC:URI:RS-06785-DataQueryExternalApi-PROD` | |
296
+
297
+ **API endpoints**
298
+
299
+ | Variable | Default |
300
+ |---|---|
301
+ | `DATAQUERY_BASE_URL` | `https://api-developer.jpmorgan.com` |
302
+ | `DATAQUERY_FILES_BASE_URL` | `https://api-dataquery.jpmchase.com` |
303
+ | `DATAQUERY_CONTEXT_PATH` | `/research/dataquery-authe/api/v2` |
304
+
305
+ **HTTP / retry / rate limit**
306
+
307
+ | Variable | Default |
308
+ |---|---|
309
+ | `DATAQUERY_TIMEOUT` | `600.0` |
310
+ | `DATAQUERY_MAX_RETRIES` | `3` |
311
+ | `DATAQUERY_RETRY_DELAY` | `1.0` |
312
+ | `DATAQUERY_CIRCUIT_BREAKER_THRESHOLD` | `5` |
313
+ | `DATAQUERY_REQUESTS_PER_MINUTE` | `300` |
314
+ | `DATAQUERY_BURST_CAPACITY` | `5` |
315
+ | `DATAQUERY_POOL_CONNECTIONS` | `10` |
316
+ | `DATAQUERY_POOL_MAXSIZE` | `20` |
317
+
318
+ **Proxy** (optional)
319
+
320
+ `DATAQUERY_PROXY_ENABLED`, `DATAQUERY_PROXY_URL`, `DATAQUERY_PROXY_USERNAME`,
321
+ `DATAQUERY_PROXY_PASSWORD`, `DATAQUERY_PROXY_VERIFY_SSL`.
322
+
323
+ ### Programmatic configuration
324
+
325
+ ```python
326
+ from dataquery import ClientConfig, DataQuery
327
+
328
+ config = ClientConfig(
329
+ client_id="...",
330
+ client_secret="...",
331
+ base_url="https://api-developer.jpmorgan.com",
332
+ timeout=60.0,
333
+ max_retries=3,
334
+ requests_per_minute=300,
335
+ )
336
+
337
+ async with DataQuery(config) as dq:
338
+ ...
339
+
340
+ # Or pass overrides as kwargs on top of env/.env resolution:
341
+ async with DataQuery(client_id="...", client_secret="...", timeout=60.0) as dq:
342
+ ...
343
+ ```
344
+
345
+ ## Error handling
346
+
347
+ All errors inherit from `DataQueryError`:
348
+
349
+ ```python
350
+ from dataquery import DataQuery
351
+ from dataquery.exceptions import (
352
+ DataQueryError,
353
+ AuthenticationError,
354
+ NotFoundError,
355
+ RateLimitError,
356
+ NetworkError,
357
+ DownloadError,
358
+ ConfigurationError,
359
+ )
360
+
361
+ async with DataQuery() as dq:
362
+ try:
363
+ ts = await dq.get_expressions_time_series_async(
364
+ expressions=["DB(...)"], start_date="20240101", end_date="20240131"
365
+ )
366
+ except AuthenticationError:
367
+ ... # check credentials
368
+ except RateLimitError:
369
+ ... # back off — SDK already retried
370
+ except NotFoundError:
371
+ ... # group / file / instrument not found
372
+ except NetworkError:
373
+ ... # transient; SDK already retried
374
+ except DataQueryError:
375
+ ... # any other SDK-level failure
376
+ ```
377
+
378
+ ## Date formats
379
+
380
+ ```python
381
+ start_date="20240101" # absolute, YYYYMMDD
382
+ start_date="TODAY"
383
+ start_date="TODAY-1D" # yesterday
384
+ start_date="TODAY-1W"
385
+ start_date="TODAY-1M"
386
+ start_date="TODAY-1Y"
387
+ ```
388
+
389
+ ## Performance tuning
390
+
391
+ `run_group_download_async` uses a flattened concurrency model — total concurrent
392
+ HTTP requests = `max_concurrent × num_parts`.
393
+
394
+ With `num_parts=1` (the default) each file downloads as a single streaming GET.
395
+ Set `num_parts > 1` to enable parallel HTTP range requests per file — the SDK
396
+ probes the file size first, then downloads byte ranges concurrently. Files under
397
+ 10 MB always use a single stream regardless of `num_parts`.
398
+
399
+ ```python
400
+ await dq.run_group_download_async(
401
+ group_id="JPMAQS_GENERIC_RETURNS",
402
+ start_date="20250101",
403
+ end_date="20250131",
404
+ destination_dir="./data",
405
+ max_concurrent=5, # parallel files
406
+ num_parts=4, # parallel chunks per file (1 = single stream)
407
+ max_retries=3,
408
+ )
409
+ ```
410
+
411
+ Typical settings: `max_concurrent` 3–5, `num_parts` 2–8. The SDK automatically
412
+ inserts delays between file starts so the configured `requests_per_minute` is not
413
+ exceeded.
414
+
415
+ ## API reference (most-used methods)
416
+
417
+ | Area | Method | Notes |
418
+ |---|---|---|
419
+ | Discovery | `list_groups_async(limit)` | |
420
+ | | `search_groups_async(keywords, limit, offset)` | |
421
+ | | `list_files_async(group_id, file_group_id=None)` | |
422
+ | | `list_available_files_async(group_id, file_group_id, start_date, end_date)` | |
423
+ | | `list_instruments_async(group_id, instrument_id=None, page=None)` | |
424
+ | | `search_instruments_async(group_id, keywords, page=None)` | |
425
+ | | `get_group_attributes_async(group_id, ...)` | |
426
+ | | `get_group_filters_async(group_id, page=None)` | |
427
+ | Downloads | `download_file_async(file_group_id, file_datetime, ...)` | single file |
428
+ | | `run_group_download_async(group_id, start_date, end_date, file_group_id=None, ...)` | date range, single or list of ids |
429
+ | | `download_historical_async(...)` | chunked historical backfill |
430
+ | | `auto_download_async(group_id, ...)` | SSE notifications (the only watch path) |
431
+ | Time series | `get_expressions_time_series_async(expressions, start_date, end_date)` | |
432
+ | | `get_instrument_time_series_async(instruments, attributes, start_date, end_date)` | |
433
+ | | `get_group_time_series_async(group_id, attributes, filter, start_date, end_date)` | |
434
+ | Grid data | `get_grid_data_async(...)` | |
435
+ | Utilities | `check_availability_async(file_group_id, file_datetime)` | |
436
+ | | `health_check_async()` | |
437
+ | | `to_dataframe(response)` | requires `pandas` extra |
438
+ | | `get_stats()` / `get_pool_stats()` / `get_rate_limit_info()` | diagnostics |
439
+
440
+ Every async method above has a sync counterpart (without the `_async` suffix, or
441
+ with an explicit `_sync` suffix) that runs the coroutine via `asyncio.run`.
442
+
443
+ ## Examples
444
+
445
+ The `examples/` directory is organised by feature:
446
+
447
+ - `examples/files/` — single-file and date-range downloads
448
+ - `examples/expressions/` — expression time series
449
+ - `examples/instruments/` — instrument discovery + time series
450
+ - `examples/groups/` and `examples/groups_advanced/` — group discovery and time series
451
+ - `examples/grid/` — grid data
452
+ - `examples/system/` — SSE notification subscriber, diagnostics
453
+
454
+ Run any example directly:
455
+
456
+ ```bash
457
+ python examples/files/download_file.py
458
+ python examples/system/sse_local_server_example.py
459
+ ```
460
+
461
+ ## Development
462
+
463
+ ```bash
464
+ # Clone
465
+ git clone https://github.com/jpmorganchase/dataquery-sdk.git
466
+ cd dataquery-sdk
467
+
468
+ # Install with dev + all extras
469
+ uv sync --all-extras --dev # using uv
470
+ # or
471
+ pip install -e ".[dev,pandas]"
472
+
473
+ # Run tests
474
+ pytest tests/ -v
475
+ pytest tests/ --cov=dataquery --cov-report=term-missing
476
+
477
+ # Lint / format / type-check
478
+ ruff check dataquery/ tests/ examples/
479
+ ruff format dataquery/ tests/ examples/
480
+ mypy dataquery/
481
+ ```
482
+
483
+ Pytest markers: `slow`, `integration`, `unit`, `asyncio`.
484
+
485
+ ## Requirements
486
+
487
+ - Python 3.10+
488
+ - `aiohttp>=3.8,<4`, `pydantic>=2,<3`, `structlog>=23`, `python-dotenv>=1`
489
+ - Optional: `pandas>=2` (for `to_dataframe`)
490
+
491
+ ## Support
492
+
493
+ - GitHub Issues: <https://github.com/jpmorganchase/dataquery-sdk/issues>
494
+ - Email: dataquery_support@jpmorgan.com
495
+
496
+ ## License
497
+
498
+ MIT — see [LICENSE](LICENSE).
499
+
500
+ ## Changelog
501
+
502
+ See [docs/changelog.md](docs/changelog.md).