gunspec 0.1.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.
- gunspec-0.1.0/.gitignore +39 -0
- gunspec-0.1.0/PKG-INFO +210 -0
- gunspec-0.1.0/README.md +178 -0
- gunspec-0.1.0/pyproject.toml +60 -0
- gunspec-0.1.0/src/gunspec/__init__.py +57 -0
- gunspec-0.1.0/src/gunspec/_client.py +213 -0
- gunspec-0.1.0/src/gunspec/_core/__init__.py +70 -0
- gunspec-0.1.0/src/gunspec/_core/_auth.py +28 -0
- gunspec-0.1.0/src/gunspec/_core/_errors.py +190 -0
- gunspec-0.1.0/src/gunspec/_core/_http_client.py +580 -0
- gunspec-0.1.0/src/gunspec/_core/_pagination.py +95 -0
- gunspec-0.1.0/src/gunspec/_core/_retry.py +111 -0
- gunspec-0.1.0/src/gunspec/_resources/__init__.py +51 -0
- gunspec-0.1.0/src/gunspec/_resources/_ammunition.py +70 -0
- gunspec-0.1.0/src/gunspec/_resources/_calibers.py +96 -0
- gunspec-0.1.0/src/gunspec/_resources/_categories.py +37 -0
- gunspec-0.1.0/src/gunspec/_resources/_conflicts.py +26 -0
- gunspec-0.1.0/src/gunspec/_resources/_countries.py +33 -0
- gunspec-0.1.0/src/gunspec/_resources/_data_quality.py +32 -0
- gunspec-0.1.0/src/gunspec/_resources/_favorites.py +39 -0
- gunspec-0.1.0/src/gunspec/_resources/_firearms.py +228 -0
- gunspec-0.1.0/src/gunspec/_resources/_game.py +50 -0
- gunspec-0.1.0/src/gunspec/_resources/_game_stats.py +47 -0
- gunspec-0.1.0/src/gunspec/_resources/_manufacturers.py +74 -0
- gunspec-0.1.0/src/gunspec/_resources/_reports.py +32 -0
- gunspec-0.1.0/src/gunspec/_resources/_stats.py +98 -0
- gunspec-0.1.0/src/gunspec/_resources/_support.py +49 -0
- gunspec-0.1.0/src/gunspec/_resources/_usage.py +26 -0
- gunspec-0.1.0/src/gunspec/_resources/_webhooks.py +59 -0
- gunspec-0.1.0/src/gunspec/_version.py +1 -0
- gunspec-0.1.0/src/gunspec/py.typed +0 -0
- gunspec-0.1.0/src/gunspec/types/__init__.py +402 -0
- gunspec-0.1.0/src/gunspec/types/errors.py +17 -0
- gunspec-0.1.0/src/gunspec/types/models.py +1577 -0
- gunspec-0.1.0/src/gunspec/types/params.py +482 -0
- gunspec-0.1.0/tests/__init__.py +0 -0
- gunspec-0.1.0/tests/conftest.py +76 -0
- gunspec-0.1.0/tests/unit/__init__.py +0 -0
- gunspec-0.1.0/tests/unit/core/__init__.py +0 -0
- gunspec-0.1.0/tests/unit/core/test_auth.py +64 -0
- gunspec-0.1.0/tests/unit/core/test_errors.py +243 -0
- gunspec-0.1.0/tests/unit/core/test_http_client.py +267 -0
- gunspec-0.1.0/tests/unit/core/test_retry.py +240 -0
- gunspec-0.1.0/tests/unit/resources/__init__.py +0 -0
- gunspec-0.1.0/tests/unit/resources/test_ammunition.py +107 -0
- gunspec-0.1.0/tests/unit/resources/test_calibers.py +179 -0
- gunspec-0.1.0/tests/unit/resources/test_categories.py +55 -0
- gunspec-0.1.0/tests/unit/resources/test_conflicts.py +23 -0
- gunspec-0.1.0/tests/unit/resources/test_countries.py +39 -0
- gunspec-0.1.0/tests/unit/resources/test_data_quality.py +53 -0
- gunspec-0.1.0/tests/unit/resources/test_favorites.py +73 -0
- gunspec-0.1.0/tests/unit/resources/test_firearms.py +473 -0
- gunspec-0.1.0/tests/unit/resources/test_game.py +121 -0
- gunspec-0.1.0/tests/unit/resources/test_game_stats.py +73 -0
- gunspec-0.1.0/tests/unit/resources/test_manufacturers.py +117 -0
- gunspec-0.1.0/tests/unit/resources/test_reports.py +59 -0
- gunspec-0.1.0/tests/unit/resources/test_stats.py +226 -0
- gunspec-0.1.0/tests/unit/resources/test_support.py +91 -0
- gunspec-0.1.0/tests/unit/resources/test_usage.py +35 -0
- gunspec-0.1.0/tests/unit/resources/test_webhooks.py +119 -0
- gunspec-0.1.0/uv.lock +699 -0
gunspec-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
node_modules/
|
|
2
|
+
dist/
|
|
3
|
+
.dev.vars
|
|
4
|
+
.wrangler/
|
|
5
|
+
.seed-tmp/
|
|
6
|
+
.seed-hashes.json
|
|
7
|
+
*.tsbuildinfo
|
|
8
|
+
.env
|
|
9
|
+
.env.local
|
|
10
|
+
|
|
11
|
+
# Drizzle
|
|
12
|
+
drizzle/meta/
|
|
13
|
+
|
|
14
|
+
# IDE
|
|
15
|
+
.idea/
|
|
16
|
+
.vscode/
|
|
17
|
+
*.swp
|
|
18
|
+
*.swo
|
|
19
|
+
|
|
20
|
+
# OS
|
|
21
|
+
.DS_Store
|
|
22
|
+
Thumbs.db
|
|
23
|
+
|
|
24
|
+
# Test
|
|
25
|
+
coverage/
|
|
26
|
+
|
|
27
|
+
# Scraped data (ephemeral)
|
|
28
|
+
data/scraped/*.csv
|
|
29
|
+
|
|
30
|
+
# Inspiration
|
|
31
|
+
inspiration/
|
|
32
|
+
|
|
33
|
+
frontend/public/models/animations/
|
|
34
|
+
frontend/public/models/people/
|
|
35
|
+
frontend/public/firearms/photos/
|
|
36
|
+
frontend/public/firearms/archive/
|
|
37
|
+
frontend/public/firearms/line/*.png
|
|
38
|
+
frontend/public/manufacturers/archived
|
|
39
|
+
frontend/public/firearms/packs/
|
gunspec-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gunspec
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for the GunSpec.io firearms specification API
|
|
5
|
+
Project-URL: Homepage, https://gunspec.io
|
|
6
|
+
Project-URL: Documentation, https://gunspec.io/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/buun-group/gunspec
|
|
8
|
+
Project-URL: Issues, https://github.com/buun-group/gunspec/issues
|
|
9
|
+
Author: GunSpec.io
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: api,database,firearms,gunspec,sdk,specifications
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: httpx<1,>=0.25
|
|
24
|
+
Requires-Dist: pydantic<3,>=2
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
29
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# gunspec
|
|
34
|
+
|
|
35
|
+
Official Python SDK for the [GunSpec.io](https://gunspec.io) firearms specification database API.
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install gunspec
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from gunspec import GunSpec
|
|
47
|
+
|
|
48
|
+
# Reads GUNSPEC_API_KEY from environment automatically
|
|
49
|
+
client = GunSpec()
|
|
50
|
+
|
|
51
|
+
# List firearms
|
|
52
|
+
result = client.firearms.list({"category": "pistol", "manufacturer": "glock"})
|
|
53
|
+
for firearm in result.data:
|
|
54
|
+
print(firearm["name"], firearm["caliber"])
|
|
55
|
+
|
|
56
|
+
# Get a single firearm
|
|
57
|
+
result = client.firearms.get("glock-g17")
|
|
58
|
+
print(result.data["name"])
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Async Usage
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from gunspec import AsyncGunSpec
|
|
65
|
+
|
|
66
|
+
async with AsyncGunSpec() as client:
|
|
67
|
+
result = await client.firearms.list({"category": "rifle"})
|
|
68
|
+
for firearm in result.data:
|
|
69
|
+
print(firearm["name"])
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Configuration
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from gunspec import GunSpec, RetryConfig
|
|
76
|
+
|
|
77
|
+
# Reads GUNSPEC_API_KEY from env automatically
|
|
78
|
+
client = GunSpec()
|
|
79
|
+
|
|
80
|
+
# Or configure explicitly
|
|
81
|
+
client = GunSpec(
|
|
82
|
+
api_key="gs_...", # or set GUNSPEC_API_KEY env var
|
|
83
|
+
base_url="https://api.gunspec.io", # default
|
|
84
|
+
timeout=30.0, # 30s default
|
|
85
|
+
retry=RetryConfig(
|
|
86
|
+
max_retries=2, # default
|
|
87
|
+
initial_delay_s=0.5, # default
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Resources
|
|
93
|
+
|
|
94
|
+
| Resource | Methods |
|
|
95
|
+
|----------|---------|
|
|
96
|
+
| `client.firearms` | `list`, `get`, `search`, `compare`, `game_meta`, `action_types`, `filter_options`, `random`, `top`, `head_to_head`, `by_feature`, `by_action`, `by_material`, `by_designer`, `power_rating`, `timeline`, `by_conflict`, `get_variants`, `get_images`, `get_game_stats`, `get_dimensions`, `get_users`, `get_family_tree`, `get_similar`, `get_adoption_map`, `get_game_profile`, `get_silhouette`, `calculate`, `load`, `list_auto_paging` |
|
|
97
|
+
| `client.manufacturers` | `list`, `get`, `get_firearms`, `get_timeline`, `get_stats`, `list_auto_paging` |
|
|
98
|
+
| `client.calibers` | `list`, `get`, `compare`, `ballistics`, `get_firearms`, `get_parent_chain`, `get_family`, `get_ammunition`, `list_auto_paging` |
|
|
99
|
+
| `client.categories` | `list`, `get_firearms` |
|
|
100
|
+
| `client.stats` | `summary`, `production_status`, `field_coverage`, `popular_calibers`, `prolific_manufacturers`, `by_category`, `by_era`, `materials`, `adoption_by_country`, `adoption_by_type`, `action_types`, `feature_frequency`, `caliber_popularity_by_era` |
|
|
101
|
+
| `client.game` | `balance_report`, `tier_list`, `matchups`, `role_roster`, `stat_distribution` |
|
|
102
|
+
| `client.game_stats` | `list_versions`, `list_firearms`, `get_firearm` |
|
|
103
|
+
| `client.ammunition` | `list`, `get`, `get_bullet_svg`, `ballistics`, `list_auto_paging` |
|
|
104
|
+
| `client.countries` | `list`, `get_arsenal` |
|
|
105
|
+
| `client.conflicts` | `list` |
|
|
106
|
+
| `client.data_quality` | `coverage`, `confidence` |
|
|
107
|
+
| `client.favorites` | `list`, `add`, `remove` |
|
|
108
|
+
| `client.reports` | `create`, `list` |
|
|
109
|
+
| `client.support` | `create`, `list`, `get`, `reply` |
|
|
110
|
+
| `client.webhooks` | `list`, `create`, `get`, `update`, `delete`, `test` |
|
|
111
|
+
| `client.usage` | `get` |
|
|
112
|
+
|
|
113
|
+
## Auto-Pagination
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
# Sync
|
|
117
|
+
for firearm in client.firearms.list_auto_paging({"category": "rifle"}):
|
|
118
|
+
print(firearm["name"])
|
|
119
|
+
|
|
120
|
+
# Async
|
|
121
|
+
async for firearm in client.firearms.list_auto_paging({"category": "rifle"}):
|
|
122
|
+
print(firearm["name"])
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Error Handling
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from gunspec import (
|
|
129
|
+
GunSpec,
|
|
130
|
+
NotFoundError,
|
|
131
|
+
RateLimitError,
|
|
132
|
+
AuthenticationError,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
client = GunSpec()
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
result = client.firearms.get("nonexistent")
|
|
139
|
+
except NotFoundError as e:
|
|
140
|
+
print(f"Not found: {e.message}")
|
|
141
|
+
print(f"Request ID: {e.request_id}")
|
|
142
|
+
except RateLimitError as e:
|
|
143
|
+
print(f"Retry after: {e.retry_after}s")
|
|
144
|
+
except AuthenticationError:
|
|
145
|
+
print("Invalid API key")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Context Managers
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
# Sync
|
|
152
|
+
with GunSpec() as client:
|
|
153
|
+
result = client.firearms.list()
|
|
154
|
+
|
|
155
|
+
# Async
|
|
156
|
+
async with AsyncGunSpec() as client:
|
|
157
|
+
result = await client.firearms.list()
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Requirements
|
|
161
|
+
|
|
162
|
+
- Python >= 3.9
|
|
163
|
+
- httpx >= 0.25
|
|
164
|
+
- pydantic >= 2
|
|
165
|
+
|
|
166
|
+
## Publishing
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
cd packages/sdk-python
|
|
170
|
+
|
|
171
|
+
# Install build tools
|
|
172
|
+
pip install build twine
|
|
173
|
+
|
|
174
|
+
# Build sdist and wheel
|
|
175
|
+
python -m build
|
|
176
|
+
|
|
177
|
+
# Verify package
|
|
178
|
+
twine check dist/*
|
|
179
|
+
|
|
180
|
+
# Upload to PyPI
|
|
181
|
+
twine upload dist/*
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
For TestPyPI first:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
twine upload --repository testpypi dist/*
|
|
188
|
+
pip install --index-url https://test.pypi.org/simple/ gunspec
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Development
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
cd packages/sdk-python
|
|
195
|
+
uv venv && source .venv/bin/activate
|
|
196
|
+
uv pip install -e ".[dev]"
|
|
197
|
+
|
|
198
|
+
# Run tests
|
|
199
|
+
python -m pytest
|
|
200
|
+
|
|
201
|
+
# Lint
|
|
202
|
+
ruff check src/
|
|
203
|
+
|
|
204
|
+
# Type check
|
|
205
|
+
mypy src/gunspec/
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
MIT
|
gunspec-0.1.0/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# gunspec
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the [GunSpec.io](https://gunspec.io) firearms specification database API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install gunspec
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from gunspec import GunSpec
|
|
15
|
+
|
|
16
|
+
# Reads GUNSPEC_API_KEY from environment automatically
|
|
17
|
+
client = GunSpec()
|
|
18
|
+
|
|
19
|
+
# List firearms
|
|
20
|
+
result = client.firearms.list({"category": "pistol", "manufacturer": "glock"})
|
|
21
|
+
for firearm in result.data:
|
|
22
|
+
print(firearm["name"], firearm["caliber"])
|
|
23
|
+
|
|
24
|
+
# Get a single firearm
|
|
25
|
+
result = client.firearms.get("glock-g17")
|
|
26
|
+
print(result.data["name"])
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Async Usage
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from gunspec import AsyncGunSpec
|
|
33
|
+
|
|
34
|
+
async with AsyncGunSpec() as client:
|
|
35
|
+
result = await client.firearms.list({"category": "rifle"})
|
|
36
|
+
for firearm in result.data:
|
|
37
|
+
print(firearm["name"])
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from gunspec import GunSpec, RetryConfig
|
|
44
|
+
|
|
45
|
+
# Reads GUNSPEC_API_KEY from env automatically
|
|
46
|
+
client = GunSpec()
|
|
47
|
+
|
|
48
|
+
# Or configure explicitly
|
|
49
|
+
client = GunSpec(
|
|
50
|
+
api_key="gs_...", # or set GUNSPEC_API_KEY env var
|
|
51
|
+
base_url="https://api.gunspec.io", # default
|
|
52
|
+
timeout=30.0, # 30s default
|
|
53
|
+
retry=RetryConfig(
|
|
54
|
+
max_retries=2, # default
|
|
55
|
+
initial_delay_s=0.5, # default
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Resources
|
|
61
|
+
|
|
62
|
+
| Resource | Methods |
|
|
63
|
+
|----------|---------|
|
|
64
|
+
| `client.firearms` | `list`, `get`, `search`, `compare`, `game_meta`, `action_types`, `filter_options`, `random`, `top`, `head_to_head`, `by_feature`, `by_action`, `by_material`, `by_designer`, `power_rating`, `timeline`, `by_conflict`, `get_variants`, `get_images`, `get_game_stats`, `get_dimensions`, `get_users`, `get_family_tree`, `get_similar`, `get_adoption_map`, `get_game_profile`, `get_silhouette`, `calculate`, `load`, `list_auto_paging` |
|
|
65
|
+
| `client.manufacturers` | `list`, `get`, `get_firearms`, `get_timeline`, `get_stats`, `list_auto_paging` |
|
|
66
|
+
| `client.calibers` | `list`, `get`, `compare`, `ballistics`, `get_firearms`, `get_parent_chain`, `get_family`, `get_ammunition`, `list_auto_paging` |
|
|
67
|
+
| `client.categories` | `list`, `get_firearms` |
|
|
68
|
+
| `client.stats` | `summary`, `production_status`, `field_coverage`, `popular_calibers`, `prolific_manufacturers`, `by_category`, `by_era`, `materials`, `adoption_by_country`, `adoption_by_type`, `action_types`, `feature_frequency`, `caliber_popularity_by_era` |
|
|
69
|
+
| `client.game` | `balance_report`, `tier_list`, `matchups`, `role_roster`, `stat_distribution` |
|
|
70
|
+
| `client.game_stats` | `list_versions`, `list_firearms`, `get_firearm` |
|
|
71
|
+
| `client.ammunition` | `list`, `get`, `get_bullet_svg`, `ballistics`, `list_auto_paging` |
|
|
72
|
+
| `client.countries` | `list`, `get_arsenal` |
|
|
73
|
+
| `client.conflicts` | `list` |
|
|
74
|
+
| `client.data_quality` | `coverage`, `confidence` |
|
|
75
|
+
| `client.favorites` | `list`, `add`, `remove` |
|
|
76
|
+
| `client.reports` | `create`, `list` |
|
|
77
|
+
| `client.support` | `create`, `list`, `get`, `reply` |
|
|
78
|
+
| `client.webhooks` | `list`, `create`, `get`, `update`, `delete`, `test` |
|
|
79
|
+
| `client.usage` | `get` |
|
|
80
|
+
|
|
81
|
+
## Auto-Pagination
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
# Sync
|
|
85
|
+
for firearm in client.firearms.list_auto_paging({"category": "rifle"}):
|
|
86
|
+
print(firearm["name"])
|
|
87
|
+
|
|
88
|
+
# Async
|
|
89
|
+
async for firearm in client.firearms.list_auto_paging({"category": "rifle"}):
|
|
90
|
+
print(firearm["name"])
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Error Handling
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from gunspec import (
|
|
97
|
+
GunSpec,
|
|
98
|
+
NotFoundError,
|
|
99
|
+
RateLimitError,
|
|
100
|
+
AuthenticationError,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
client = GunSpec()
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
result = client.firearms.get("nonexistent")
|
|
107
|
+
except NotFoundError as e:
|
|
108
|
+
print(f"Not found: {e.message}")
|
|
109
|
+
print(f"Request ID: {e.request_id}")
|
|
110
|
+
except RateLimitError as e:
|
|
111
|
+
print(f"Retry after: {e.retry_after}s")
|
|
112
|
+
except AuthenticationError:
|
|
113
|
+
print("Invalid API key")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Context Managers
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# Sync
|
|
120
|
+
with GunSpec() as client:
|
|
121
|
+
result = client.firearms.list()
|
|
122
|
+
|
|
123
|
+
# Async
|
|
124
|
+
async with AsyncGunSpec() as client:
|
|
125
|
+
result = await client.firearms.list()
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Requirements
|
|
129
|
+
|
|
130
|
+
- Python >= 3.9
|
|
131
|
+
- httpx >= 0.25
|
|
132
|
+
- pydantic >= 2
|
|
133
|
+
|
|
134
|
+
## Publishing
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
cd packages/sdk-python
|
|
138
|
+
|
|
139
|
+
# Install build tools
|
|
140
|
+
pip install build twine
|
|
141
|
+
|
|
142
|
+
# Build sdist and wheel
|
|
143
|
+
python -m build
|
|
144
|
+
|
|
145
|
+
# Verify package
|
|
146
|
+
twine check dist/*
|
|
147
|
+
|
|
148
|
+
# Upload to PyPI
|
|
149
|
+
twine upload dist/*
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
For TestPyPI first:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
twine upload --repository testpypi dist/*
|
|
156
|
+
pip install --index-url https://test.pypi.org/simple/ gunspec
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
cd packages/sdk-python
|
|
163
|
+
uv venv && source .venv/bin/activate
|
|
164
|
+
uv pip install -e ".[dev]"
|
|
165
|
+
|
|
166
|
+
# Run tests
|
|
167
|
+
python -m pytest
|
|
168
|
+
|
|
169
|
+
# Lint
|
|
170
|
+
ruff check src/
|
|
171
|
+
|
|
172
|
+
# Type check
|
|
173
|
+
mypy src/gunspec/
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gunspec"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python SDK for the GunSpec.io firearms specification API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "GunSpec.io" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["gunspec", "firearms", "api", "sdk", "specifications", "database"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Typing :: Typed",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"httpx>=0.25,<1",
|
|
30
|
+
"pydantic>=2,<3",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://gunspec.io"
|
|
35
|
+
Documentation = "https://gunspec.io/docs"
|
|
36
|
+
Repository = "https://github.com/buun-group/gunspec"
|
|
37
|
+
Issues = "https://github.com/buun-group/gunspec/issues"
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
dev = [
|
|
41
|
+
"pytest>=7",
|
|
42
|
+
"pytest-asyncio>=0.23",
|
|
43
|
+
"respx>=0.21",
|
|
44
|
+
"mypy>=1.0",
|
|
45
|
+
"ruff>=0.1",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[tool.hatch.build.targets.wheel]
|
|
49
|
+
packages = ["src/gunspec"]
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
asyncio_mode = "auto"
|
|
53
|
+
testpaths = ["tests"]
|
|
54
|
+
|
|
55
|
+
[tool.mypy]
|
|
56
|
+
python_version = "3.9"
|
|
57
|
+
strict = true
|
|
58
|
+
|
|
59
|
+
[tool.ruff]
|
|
60
|
+
target-version = "py39"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""GunSpec.io Python SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from gunspec._client import AsyncGunSpec, GunSpec
|
|
6
|
+
from gunspec._core._errors import (
|
|
7
|
+
APIError,
|
|
8
|
+
AuthenticationError,
|
|
9
|
+
BadRequestError,
|
|
10
|
+
ConnectError,
|
|
11
|
+
GunSpecError,
|
|
12
|
+
InternalServerError,
|
|
13
|
+
NotFoundError,
|
|
14
|
+
PermissionDeniedError,
|
|
15
|
+
RateLimitError,
|
|
16
|
+
RequestTimeoutError,
|
|
17
|
+
)
|
|
18
|
+
from gunspec._core._http_client import (
|
|
19
|
+
APIResponse,
|
|
20
|
+
HttpClientConfig,
|
|
21
|
+
PaginatedResponse,
|
|
22
|
+
PaginationMeta,
|
|
23
|
+
RateLimitInfo,
|
|
24
|
+
)
|
|
25
|
+
from gunspec._core._pagination import AsyncPage, SyncPage
|
|
26
|
+
from gunspec._core._retry import RetryConfig
|
|
27
|
+
from gunspec._version import __version__
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
# Client
|
|
31
|
+
"GunSpec",
|
|
32
|
+
"AsyncGunSpec",
|
|
33
|
+
# Version
|
|
34
|
+
"__version__",
|
|
35
|
+
# Config
|
|
36
|
+
"HttpClientConfig",
|
|
37
|
+
"RetryConfig",
|
|
38
|
+
# Response types
|
|
39
|
+
"APIResponse",
|
|
40
|
+
"PaginatedResponse",
|
|
41
|
+
"PaginationMeta",
|
|
42
|
+
"RateLimitInfo",
|
|
43
|
+
# Pagination
|
|
44
|
+
"SyncPage",
|
|
45
|
+
"AsyncPage",
|
|
46
|
+
# Errors
|
|
47
|
+
"GunSpecError",
|
|
48
|
+
"APIError",
|
|
49
|
+
"AuthenticationError",
|
|
50
|
+
"PermissionDeniedError",
|
|
51
|
+
"NotFoundError",
|
|
52
|
+
"BadRequestError",
|
|
53
|
+
"RateLimitError",
|
|
54
|
+
"InternalServerError",
|
|
55
|
+
"ConnectError",
|
|
56
|
+
"RequestTimeoutError",
|
|
57
|
+
]
|