pfmsoft-api-request 0.1.3__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.
Files changed (40) hide show
  1. pfmsoft/api_request/__init__.py +37 -0
  2. pfmsoft/api_request/cache/__init__.py +36 -0
  3. pfmsoft/api_request/cache/memory_cache.py +177 -0
  4. pfmsoft/api_request/cache/metadata_helpers.py +55 -0
  5. pfmsoft/api_request/cache/models.py +83 -0
  6. pfmsoft/api_request/cache/protocols.py +166 -0
  7. pfmsoft/api_request/cache/sqlite_cache/__init__.py +7 -0
  8. pfmsoft/api_request/cache/sqlite_cache/connection_helpers.py +126 -0
  9. pfmsoft/api_request/cache/sqlite_cache/query_helpers.py +107 -0
  10. pfmsoft/api_request/cache/sqlite_cache/sqlite_cache.py +233 -0
  11. pfmsoft/api_request/cache/sqlite_cache/table_definitions.sql +23 -0
  12. pfmsoft/api_request/cli/__init__.py +17 -0
  13. pfmsoft/api_request/cli/cache/__init__.py +12 -0
  14. pfmsoft/api_request/cli/cache/info.py +11 -0
  15. pfmsoft/api_request/cli/helpers.py +41 -0
  16. pfmsoft/api_request/cli/main_typer.py +52 -0
  17. pfmsoft/api_request/cli/request/__init__.py +11 -0
  18. pfmsoft/api_request/cli/request/request.py +222 -0
  19. pfmsoft/api_request/cli/request/validate.py +11 -0
  20. pfmsoft/api_request/helpers/http_session_factory.py +80 -0
  21. pfmsoft/api_request/helpers/json_io.py +256 -0
  22. pfmsoft/api_request/helpers/save_text_file.py +43 -0
  23. pfmsoft/api_request/helpers/whenever/__init__.py +4 -0
  24. pfmsoft/api_request/helpers/whenever/instant_helpers.py +41 -0
  25. pfmsoft/api_request/logging_config.py +202 -0
  26. pfmsoft/api_request/py.typed +0 -0
  27. pfmsoft/api_request/rate_limit/__init__.py +24 -0
  28. pfmsoft/api_request/rate_limit/aio_limiter.py +89 -0
  29. pfmsoft/api_request/rate_limit/protocols.py +101 -0
  30. pfmsoft/api_request/request/__init__.py +11 -0
  31. pfmsoft/api_request/request/api_requester.py +681 -0
  32. pfmsoft/api_request/request/intermediate_models.py +143 -0
  33. pfmsoft/api_request/request/models.py +355 -0
  34. pfmsoft/api_request/request/protocols.py +54 -0
  35. pfmsoft/api_request/settings.py +65 -0
  36. pfmsoft_api_request-0.1.3.dist-info/METADATA +171 -0
  37. pfmsoft_api_request-0.1.3.dist-info/RECORD +40 -0
  38. pfmsoft_api_request-0.1.3.dist-info/WHEEL +4 -0
  39. pfmsoft_api_request-0.1.3.dist-info/entry_points.txt +3 -0
  40. pfmsoft_api_request-0.1.3.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.4
2
+ Name: pfmsoft-api-request
3
+ Version: 0.1.3
4
+ Summary: A command line api request tool with caching and rate limiting.
5
+ Author: Chad Lowe
6
+ Author-email: Chad Lowe <pfmsoft.dev@gmail.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Requires-Dist: aiolimiter>=1.2.1
10
+ Requires-Dist: httpx2>=2.5.0
11
+ Requires-Dist: pfmsoft-eve-snippets>=0.1.4
12
+ Requires-Dist: pydantic>=2.13.4
13
+ Requires-Dist: pydantic-settings>=2.14.2
14
+ Requires-Dist: typer>=0.26.8
15
+ Requires-Dist: whenever>=0.10.2
16
+ Requires-Python: >=3.14
17
+ Project-URL: Documentation, https://github.com/DonalChilde/pfmsoft-api-request#readme
18
+ Project-URL: Issues, https://github.com/DonalChilde/pfmsoft-api-request/issues
19
+ Project-URL: Source, https://github.com/DonalChilde/pfmsoft-api-request
20
+ Description-Content-Type: text/markdown
21
+
22
+ # api-request
23
+
24
+ `api-request` is an API-first Python project for executing batched HTTP requests with:
25
+
26
+ - async request orchestration
27
+ - optional SQLite-backed caching
28
+ - configurable rate limiting
29
+ - JSON in / JSON out workflows
30
+
31
+ It includes a simple CLI for running request batches from stdin or files, and a Python API for integrating the same behavior in application code.
32
+
33
+ ## Project Status
34
+
35
+ - Package manager: `uv`
36
+ - Distribution: source-only for now (no PyPI release yet)
37
+ - Python: `>=3.14`
38
+
39
+ ## Installation
40
+
41
+ Clone the repository and sync dependencies with `uv`:
42
+
43
+ ```bash
44
+ uv sync
45
+ ```
46
+
47
+ This creates/updates the local `.venv` and installs app + dev dependencies.
48
+
49
+ ## Quick Start (CLI)
50
+
51
+ Show CLI help:
52
+
53
+ ```bash
54
+ uv run api-request --help
55
+ ```
56
+
57
+ Run a batch from stdin and print plain JSON to stdout:
58
+
59
+ ```bash
60
+ cat requests.json | uv run api-request --from - --to - --plain --indent 2
61
+ ```
62
+
63
+ Run from file and write to file:
64
+
65
+ ```bash
66
+ uv run api-request --from requests.json --to responses.json --overwrite --indent 2
67
+ ```
68
+
69
+ Show version and resolved runtime directories:
70
+
71
+ ```bash
72
+ uv run api-request --version
73
+ ```
74
+
75
+ ### Input JSON Shape
76
+
77
+ The CLI expects a JSON object keyed by request UUID. Each value is a request definition.
78
+
79
+ Minimal example:
80
+
81
+ ```json
82
+ {
83
+ "00000000-0000-0000-0000-000000000001": {
84
+ "url": "https://esi.evetech.net/status/",
85
+ "method": "GET"
86
+ }
87
+ }
88
+ ```
89
+
90
+ Supported request fields include:
91
+
92
+ - `url` (required)
93
+ - `method` (required)
94
+ - `headers` (optional map)
95
+ - `body` (optional)
96
+ - `parameters` (optional query param map)
97
+ - `cache_key` (optional UUID)
98
+ - `rate_key` (optional string)
99
+
100
+ ### Output JSON Shape
101
+
102
+ The CLI returns a JSON object with:
103
+
104
+ - `successful`: map of request UUID -> response
105
+ - `failed`: map of request UUID -> failed response
106
+
107
+ ## Python API Usage
108
+
109
+ ```python
110
+ import asyncio
111
+ from uuid import uuid4
112
+
113
+ from api_request import ApiRequester, Request
114
+ from api_request.cache import InMemoryCache
115
+ from api_request.rate_limit import AiolimiterRateLimiterFactory
116
+
117
+
118
+ async def main() -> None:
119
+ request = Request(
120
+ request_key=uuid4(),
121
+ method="GET",
122
+ url="https://esi.evetech.net/status/",
123
+ cache_key=uuid4(),
124
+ rate_key="esi-status",
125
+ )
126
+
127
+ async with ApiRequester(
128
+ cache_factory=InMemoryCache,
129
+ rate_limiter_factory=AiolimiterRateLimiterFactory(
130
+ max_rate=50.0,
131
+ time_period=60.0,
132
+ ),
133
+ ) as requester:
134
+ responses = await requester.process_requests({request.request_key: request})
135
+ print(responses)
136
+
137
+
138
+ if __name__ == "__main__":
139
+ asyncio.run(main())
140
+ ```
141
+
142
+ ## Configuration
143
+
144
+ Runtime settings use environment variables with the `API_REQUEST_` prefix.
145
+
146
+ - `API_REQUEST_APPLICATION_DIRECTORY`: overrides the app directory used for cache and logs.
147
+
148
+ You can also set this from the CLI with `--application-directory`.
149
+
150
+ ## Development
151
+
152
+ Common commands:
153
+
154
+ ```bash
155
+ uv sync
156
+ uv run ruff format
157
+ uv run ruff check
158
+ uv run pytest
159
+ ```
160
+
161
+ ## Repository Layout
162
+
163
+ - `src/api_request/`: package source
164
+ - `src/api_request/cli/`: Typer CLI entrypoints
165
+ - `src/api_request/request/`: request orchestration and models
166
+ - `src/api_request/cache/`: cache implementations and protocols
167
+ - `tests/`: test suite
168
+
169
+ ## License
170
+
171
+ MIT. See `LICENSE`.
@@ -0,0 +1,40 @@
1
+ pfmsoft/api_request/__init__.py,sha256=Opu2pMtL8_PGWBG6rDFR26X54UA5liz1FDsvb1-ZxzE,922
2
+ pfmsoft/api_request/cache/__init__.py,sha256=lp5QuVM9GIP2QGPMV0UeTH4kaH3G8PErFyYFEiQjYvw,1114
3
+ pfmsoft/api_request/cache/memory_cache.py,sha256=cK2AYCKQDUPXcb8MIscQH6Fve1D7lkzk6UvQ3LSucuI,5989
4
+ pfmsoft/api_request/cache/metadata_helpers.py,sha256=vslD4QkY2ABhSdZe83VT5bciUx2zo6jiV3fhV6-GCXI,2093
5
+ pfmsoft/api_request/cache/models.py,sha256=qpxOWbcnzKui3IyHqXBGN-G2DN_eXl8dy9M_z77RpKk,2763
6
+ pfmsoft/api_request/cache/protocols.py,sha256=vuaM8ktqy_tn_mpV5HSCaKDQ6yj4tj-EVCnte8Ib3eg,5798
7
+ pfmsoft/api_request/cache/sqlite_cache/__init__.py,sha256=2zODFz3DZFDs7BssOZ1lTY_8KRmoFJIE7-PLjhwd_7I,308
8
+ pfmsoft/api_request/cache/sqlite_cache/connection_helpers.py,sha256=K9yh0fBRh-cY0Y5crk6JwrKilWN9mz_UnPNXQq5jlqc,4042
9
+ pfmsoft/api_request/cache/sqlite_cache/query_helpers.py,sha256=b09n16j6k4aOVq6evqZT7YUhTIo2yBt2wPuzV4eM6vM,3118
10
+ pfmsoft/api_request/cache/sqlite_cache/sqlite_cache.py,sha256=Pj0S1Lnx93BVb7goqB0zYIuWrpAb2O4ZRGuw7RG2uQQ,8301
11
+ pfmsoft/api_request/cache/sqlite_cache/table_definitions.sql,sha256=aASaqvvEKeFXfi1PmzuBhD_kUXo7uzBP_JZ8eT8kBL4,925
12
+ pfmsoft/api_request/cli/__init__.py,sha256=RsI5_x7mc_YEOxGKJT36ffiByxIL_5orJWrS06ic9yI,487
13
+ pfmsoft/api_request/cli/cache/__init__.py,sha256=D6u1cGn5awj3PlT8kB81mhMtvW6ukxBWu1Uk74yghsU,249
14
+ pfmsoft/api_request/cli/cache/info.py,sha256=bFKa0sCdmA4SKP0-JItrqooAzaFXtQPJmu4yFRGt8V0,210
15
+ pfmsoft/api_request/cli/helpers.py,sha256=2wlriaICKSZObs_cSUikNXCRkxktjK-LewWI5v0l8YI,1249
16
+ pfmsoft/api_request/cli/main_typer.py,sha256=48ecfkO2Wsk7ha-ygudfpTOsqwotxRy3J7HZpha8aqA,1646
17
+ pfmsoft/api_request/cli/request/__init__.py,sha256=RVMXNWh-9bKp9Z0wyWpTG3DYVbQpB0oOCCZN27qBVoo,236
18
+ pfmsoft/api_request/cli/request/request.py,sha256=_PSS-cPCp7eXP-U0hLtYoMedeqxRF-N1tUkpFP1Xtww,6805
19
+ pfmsoft/api_request/cli/request/validate.py,sha256=wYZyeD5WMaA6eV1VwdrK4G6A2ID8qXdIZe553HXjOwA,224
20
+ pfmsoft/api_request/helpers/http_session_factory.py,sha256=81vaOLvzHtYOsA85IVKx5rolXn1SLNz6_5LCZSl-Rck,2296
21
+ pfmsoft/api_request/helpers/json_io.py,sha256=b9GRcZyIrnI_DLJZBfvcV-cCaMhXIAOXpVQOEz-DL6A,8243
22
+ pfmsoft/api_request/helpers/save_text_file.py,sha256=7qMBER_OWB9mtccB8FilxQy3cyrUqNlh5-tJr9tYoxA,1307
23
+ pfmsoft/api_request/helpers/whenever/__init__.py,sha256=xyHFXbilArMhsgOPUqk6EtASY7gKchJNMLHT6pQdAIU,106
24
+ pfmsoft/api_request/helpers/whenever/instant_helpers.py,sha256=mq07gEIm3_iGcyh6eVX5rLl6Ubl9fsk5sHhlXtotiyY,1289
25
+ pfmsoft/api_request/logging_config.py,sha256=OT7F0Ru88yzM2cGwMB-CNILd6JLgVyET16fIjHDLzqs,7709
26
+ pfmsoft/api_request/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ pfmsoft/api_request/rate_limit/__init__.py,sha256=7GYbM2505tNLfb2jkU2u7dbXxODtJ81M7NE6XKwYQlU,726
28
+ pfmsoft/api_request/rate_limit/aio_limiter.py,sha256=WTgTy6Koco9Dz8mQxQG0voyWA32PRm3FchHGxErZemc,2707
29
+ pfmsoft/api_request/rate_limit/protocols.py,sha256=1SumbrKYGlr8n46hdSsjAthYxk5Tiw0osuBkILu3OIw,3429
30
+ pfmsoft/api_request/request/__init__.py,sha256=Vl0ykMOAXmXuiQgpihmXHeYfZF9wHZrfCsbEU0LNEvw,441
31
+ pfmsoft/api_request/request/api_requester.py,sha256=kk2aNoI-KKtACULzAwrZfWHOB6fXbtK2k7eW7JMPrto,27122
32
+ pfmsoft/api_request/request/intermediate_models.py,sha256=8AdeTbI-jrXQLZSN2irsgpQ1zrZfG9ZMrYeRIZCkDaw,4457
33
+ pfmsoft/api_request/request/models.py,sha256=DAdUJhgmO_F2geKh-XU6bYhIeRePq-mkzX3BcAJUY54,13421
34
+ pfmsoft/api_request/request/protocols.py,sha256=XIBsxlJ40JsE5W45l3UCHJf2nrfO1HI2wLuq91qlqWA,1534
35
+ pfmsoft/api_request/settings.py,sha256=OARLZrZ2t6rgMhSGONoW0f4gC9bem80UdtUteh5UeBw,2107
36
+ pfmsoft_api_request-0.1.3.dist-info/licenses/LICENSE,sha256=13NS5_XEPeh-i7AW3Hw7MzlU9iZnhazUBaA6hvm-STY,1066
37
+ pfmsoft_api_request-0.1.3.dist-info/WHEEL,sha256=YR4QUxGCbsyoOnWBVTv-p1I4yc3seKGPev46mvmc8Cg,81
38
+ pfmsoft_api_request-0.1.3.dist-info/entry_points.txt,sha256=uiuBq5jF74PHlAaWu5mKp9OXGxbqNnsyABwMgV4EnlQ,72
39
+ pfmsoft_api_request-0.1.3.dist-info/METADATA,sha256=WKXcCFICtmJIZXgJy592lJFJMFN0FdEJXO5IGjsOTbM,4008
40
+ pfmsoft_api_request-0.1.3.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.11.29
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ api-request = pfmsoft.api_request.cli.main_typer:app
3
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chad Lowe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.