vessel-api-python 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.
- vessel_api_python-1.0.0/.github/workflows/ci.yml +46 -0
- vessel_api_python-1.0.0/.github/workflows/publish.yml +24 -0
- vessel_api_python-1.0.0/.gitignore +10 -0
- vessel_api_python-1.0.0/LICENSE +21 -0
- vessel_api_python-1.0.0/Makefile +21 -0
- vessel_api_python-1.0.0/PKG-INFO +168 -0
- vessel_api_python-1.0.0/README.md +134 -0
- vessel_api_python-1.0.0/SECURITY.md +11 -0
- vessel_api_python-1.0.0/examples/async_basic.py +49 -0
- vessel_api_python-1.0.0/examples/basic.py +67 -0
- vessel_api_python-1.0.0/openapi/swagger.json +5779 -0
- vessel_api_python-1.0.0/pyproject.toml +70 -0
- vessel_api_python-1.0.0/src/vessel_api_python/__init__.py +183 -0
- vessel_api_python-1.0.0/src/vessel_api_python/_client.py +163 -0
- vessel_api_python-1.0.0/src/vessel_api_python/_constants.py +8 -0
- vessel_api_python-1.0.0/src/vessel_api_python/_errors.py +137 -0
- vessel_api_python-1.0.0/src/vessel_api_python/_iterator.py +120 -0
- vessel_api_python-1.0.0/src/vessel_api_python/_models.py +887 -0
- vessel_api_python-1.0.0/src/vessel_api_python/_services.py +1180 -0
- vessel_api_python-1.0.0/src/vessel_api_python/_transport.py +185 -0
- vessel_api_python-1.0.0/src/vessel_api_python/py.typed +0 -0
- vessel_api_python-1.0.0/tests/__init__.py +0 -0
- vessel_api_python-1.0.0/tests/conftest.py +34 -0
- vessel_api_python-1.0.0/tests/test_client.py +102 -0
- vessel_api_python-1.0.0/tests/test_errors.py +136 -0
- vessel_api_python-1.0.0/tests/test_iterator.py +136 -0
- vessel_api_python-1.0.0/tests/test_services.py +125 -0
- vessel_api_python-1.0.0/tests/test_smoke.py +574 -0
- vessel_api_python-1.0.0/tests/test_transport.py +215 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
unit-tests:
|
|
12
|
+
name: Unit Tests (Python ${{ matrix.python-version }})
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.9", "3.12", "3.13"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- run: pip install -e ".[dev]"
|
|
25
|
+
- run: ruff check src/ tests/
|
|
26
|
+
- run: mypy src/vessel_api_python/
|
|
27
|
+
- run: pytest -v tests/
|
|
28
|
+
|
|
29
|
+
smoke-tests:
|
|
30
|
+
name: Smoke Tests
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
if: >-
|
|
33
|
+
github.event_name == 'workflow_dispatch' ||
|
|
34
|
+
github.event_name == 'push' ||
|
|
35
|
+
github.event.pull_request.head.repo.full_name == github.repository
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
|
|
39
|
+
- uses: actions/setup-python@v5
|
|
40
|
+
with:
|
|
41
|
+
python-version: "3.12"
|
|
42
|
+
|
|
43
|
+
- run: pip install -e ".[dev]"
|
|
44
|
+
- run: pytest -v -m smoke tests/
|
|
45
|
+
env:
|
|
46
|
+
VESSELAPI_API_KEY: ${{ secrets.VESSELAPI_API_KEY }}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
id-token: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
publish:
|
|
12
|
+
name: Build & Publish
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
|
|
21
|
+
- run: pip install build
|
|
22
|
+
- run: python -m build
|
|
23
|
+
|
|
24
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Vessel API
|
|
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.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.PHONY: all lint typecheck test fmt install smoke
|
|
2
|
+
|
|
3
|
+
all: fmt lint typecheck test
|
|
4
|
+
|
|
5
|
+
lint:
|
|
6
|
+
ruff check src/ tests/
|
|
7
|
+
|
|
8
|
+
typecheck:
|
|
9
|
+
mypy src/vesselapi/
|
|
10
|
+
|
|
11
|
+
test:
|
|
12
|
+
pytest -v tests/
|
|
13
|
+
|
|
14
|
+
fmt:
|
|
15
|
+
ruff format src/ tests/
|
|
16
|
+
|
|
17
|
+
install:
|
|
18
|
+
pip install -e ".[dev]"
|
|
19
|
+
|
|
20
|
+
smoke:
|
|
21
|
+
pytest -v -m smoke tests/
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vessel-api-python
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python client for the Vessel Tracking API — maritime vessel tracking, port events, emissions, and navigation data.
|
|
5
|
+
Project-URL: Documentation, https://vesselapi.com/docs
|
|
6
|
+
Project-URL: Repository, https://github.com/vessel-api/vesselapi-python
|
|
7
|
+
Project-URL: Issues, https://github.com/vessel-api/vesselapi-python/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/vessel-api/vesselapi-python/releases
|
|
9
|
+
Author-email: Vessel API <support@vesselapi.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ais,maritime,sdk,tracking,vessel,vesselapi
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
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: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: eval-type-backport>=0.2.0; python_version < '3.10'
|
|
25
|
+
Requires-Dist: httpx>=0.27
|
|
26
|
+
Requires-Dist: pydantic>=2.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# vesselapi-python
|
|
36
|
+
|
|
37
|
+
[](https://github.com/vessel-api/vesselapi-python/actions/workflows/ci.yml)
|
|
38
|
+
[](https://pypi.org/project/vessel-api-python/)
|
|
39
|
+
[](https://pypi.org/project/vessel-api-python/)
|
|
40
|
+
[](LICENSE)
|
|
41
|
+
|
|
42
|
+
Python client for the [Vessel Tracking API](https://vesselapi.com) — maritime vessel tracking, port events, emissions, and navigation data.
|
|
43
|
+
|
|
44
|
+
**Resources**: [Documentation](https://vesselapi.com/docs) | [API Explorer](https://vesselapi.com/api-reference) | [Dashboard](https://dashboard.vesselapi.com) | [Contact Support](mailto:support@vesselapi.com)
|
|
45
|
+
|
|
46
|
+
## Install
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install vessel-api-python
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Requires Python 3.9+.
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from vessel_api_python import VesselClient
|
|
58
|
+
|
|
59
|
+
client = VesselClient(api_key="your-api-key")
|
|
60
|
+
|
|
61
|
+
# Search for a vessel by name.
|
|
62
|
+
result = client.search.vessels(filter_name="Ever Given")
|
|
63
|
+
for v in result.vessels or []:
|
|
64
|
+
print(f"{v.name} (IMO {v.imo})")
|
|
65
|
+
|
|
66
|
+
# Get a port by UN/LOCODE.
|
|
67
|
+
port = client.ports.get("NLRTM")
|
|
68
|
+
print(port.port.name)
|
|
69
|
+
|
|
70
|
+
# Auto-paginate through port events.
|
|
71
|
+
for event in client.port_events.list_all(pagination_limit=10):
|
|
72
|
+
print(f"{event.event} at {event.timestamp}")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Async
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import asyncio
|
|
79
|
+
from vessel_api_python import AsyncVesselClient
|
|
80
|
+
|
|
81
|
+
async def main():
|
|
82
|
+
async with AsyncVesselClient(api_key="your-api-key") as client:
|
|
83
|
+
result = await client.search.vessels(filter_name="Ever Given")
|
|
84
|
+
async for event in client.port_events.list_all(pagination_limit=10):
|
|
85
|
+
print(f"{event.event} at {event.timestamp}")
|
|
86
|
+
|
|
87
|
+
asyncio.run(main())
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Available Services
|
|
91
|
+
|
|
92
|
+
| Service | Methods | Description |
|
|
93
|
+
|---------|---------|-------------|
|
|
94
|
+
| `vessels` | `get`, `position`, `casualties`, `classification`, `emissions`, `eta`, `inspections`, `inspection_detail`, `ownership`, `positions` | Vessel details, positions, and records |
|
|
95
|
+
| `ports` | `get` | Port lookup by UN/LOCODE |
|
|
96
|
+
| `port_events` | `list`, `by_port`, `by_ports`, `by_vessel`, `last_by_vessel`, `by_vessels` | Vessel arrival/departure events |
|
|
97
|
+
| `emissions` | `list` | EU MRV emissions data |
|
|
98
|
+
| `search` | `vessels`, `ports`, `dgps`, `light_aids`, `modus`, `radio_beacons` | Full-text search across entity types |
|
|
99
|
+
| `location` | `vessels_bounding_box`, `vessels_radius`, `ports_bounding_box`, `ports_radius`, `dgps_bounding_box`, `dgps_radius`, `light_aids_bounding_box`, `light_aids_radius`, `modus_bounding_box`, `modus_radius`, `radio_beacons_bounding_box`, `radio_beacons_radius` | Geo queries by bounding box or radius |
|
|
100
|
+
| `navtex` | `list` | NAVTEX maritime safety messages |
|
|
101
|
+
|
|
102
|
+
**37 methods total.**
|
|
103
|
+
|
|
104
|
+
## Error Handling
|
|
105
|
+
|
|
106
|
+
All methods raise specific exception types on non-2xx responses:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from vessel_api_python import VesselAPIError
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
client.ports.get("ZZZZZ")
|
|
113
|
+
except VesselAPIError as err:
|
|
114
|
+
if err.is_not_found:
|
|
115
|
+
print("Port not found")
|
|
116
|
+
elif err.is_rate_limited:
|
|
117
|
+
print("Rate limited — back off")
|
|
118
|
+
elif err.is_auth_error:
|
|
119
|
+
print("Check API key")
|
|
120
|
+
print(err.status_code, err.message)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Auto-Pagination
|
|
124
|
+
|
|
125
|
+
Every list endpoint has an `all_*` / `list_all` variant returning an iterator:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
# Sync
|
|
129
|
+
for vessel in client.search.all_vessels(filter_name="tanker"):
|
|
130
|
+
print(vessel.name)
|
|
131
|
+
|
|
132
|
+
# Async
|
|
133
|
+
async for vessel in client.search.all_vessels(filter_name="tanker"):
|
|
134
|
+
print(vessel.name)
|
|
135
|
+
|
|
136
|
+
# Collect all at once
|
|
137
|
+
vessels = client.search.all_vessels(filter_name="tanker").collect()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Configuration
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
client = VesselClient(
|
|
144
|
+
api_key="your-api-key",
|
|
145
|
+
base_url="https://custom-endpoint.example.com/v1",
|
|
146
|
+
timeout=60.0,
|
|
147
|
+
max_retries=5, # default: 3
|
|
148
|
+
user_agent="my-app/1.0",
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Retries use exponential backoff with jitter on 429 and 5xx responses. The `Retry-After` header is respected.
|
|
153
|
+
|
|
154
|
+
## Documentation
|
|
155
|
+
|
|
156
|
+
- [API Documentation](https://vesselapi.com/docs) — endpoint guides, request/response schemas, and usage examples
|
|
157
|
+
- [API Explorer](https://vesselapi.com/api-reference) — interactive API reference
|
|
158
|
+
- [Dashboard](https://dashboard.vesselapi.com) — manage API keys and monitor usage
|
|
159
|
+
|
|
160
|
+
## Contributing & Support
|
|
161
|
+
|
|
162
|
+
Found a bug, have a feature request, or need help? You're welcome to [open an issue](https://github.com/vessel-api/vesselapi-python/issues). For API-level bugs and feature requests, please use the [main VesselAPI repository](https://github.com/vessel-api/VesselApi/issues).
|
|
163
|
+
|
|
164
|
+
For security vulnerabilities, **do not** open a public issue — email security@vesselapi.com instead. See [SECURITY.md](SECURITY.md).
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# vesselapi-python
|
|
2
|
+
|
|
3
|
+
[](https://github.com/vessel-api/vesselapi-python/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/vessel-api-python/)
|
|
5
|
+
[](https://pypi.org/project/vessel-api-python/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
Python client for the [Vessel Tracking API](https://vesselapi.com) — maritime vessel tracking, port events, emissions, and navigation data.
|
|
9
|
+
|
|
10
|
+
**Resources**: [Documentation](https://vesselapi.com/docs) | [API Explorer](https://vesselapi.com/api-reference) | [Dashboard](https://dashboard.vesselapi.com) | [Contact Support](mailto:support@vesselapi.com)
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install vessel-api-python
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Requires Python 3.9+.
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from vessel_api_python import VesselClient
|
|
24
|
+
|
|
25
|
+
client = VesselClient(api_key="your-api-key")
|
|
26
|
+
|
|
27
|
+
# Search for a vessel by name.
|
|
28
|
+
result = client.search.vessels(filter_name="Ever Given")
|
|
29
|
+
for v in result.vessels or []:
|
|
30
|
+
print(f"{v.name} (IMO {v.imo})")
|
|
31
|
+
|
|
32
|
+
# Get a port by UN/LOCODE.
|
|
33
|
+
port = client.ports.get("NLRTM")
|
|
34
|
+
print(port.port.name)
|
|
35
|
+
|
|
36
|
+
# Auto-paginate through port events.
|
|
37
|
+
for event in client.port_events.list_all(pagination_limit=10):
|
|
38
|
+
print(f"{event.event} at {event.timestamp}")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Async
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import asyncio
|
|
45
|
+
from vessel_api_python import AsyncVesselClient
|
|
46
|
+
|
|
47
|
+
async def main():
|
|
48
|
+
async with AsyncVesselClient(api_key="your-api-key") as client:
|
|
49
|
+
result = await client.search.vessels(filter_name="Ever Given")
|
|
50
|
+
async for event in client.port_events.list_all(pagination_limit=10):
|
|
51
|
+
print(f"{event.event} at {event.timestamp}")
|
|
52
|
+
|
|
53
|
+
asyncio.run(main())
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Available Services
|
|
57
|
+
|
|
58
|
+
| Service | Methods | Description |
|
|
59
|
+
|---------|---------|-------------|
|
|
60
|
+
| `vessels` | `get`, `position`, `casualties`, `classification`, `emissions`, `eta`, `inspections`, `inspection_detail`, `ownership`, `positions` | Vessel details, positions, and records |
|
|
61
|
+
| `ports` | `get` | Port lookup by UN/LOCODE |
|
|
62
|
+
| `port_events` | `list`, `by_port`, `by_ports`, `by_vessel`, `last_by_vessel`, `by_vessels` | Vessel arrival/departure events |
|
|
63
|
+
| `emissions` | `list` | EU MRV emissions data |
|
|
64
|
+
| `search` | `vessels`, `ports`, `dgps`, `light_aids`, `modus`, `radio_beacons` | Full-text search across entity types |
|
|
65
|
+
| `location` | `vessels_bounding_box`, `vessels_radius`, `ports_bounding_box`, `ports_radius`, `dgps_bounding_box`, `dgps_radius`, `light_aids_bounding_box`, `light_aids_radius`, `modus_bounding_box`, `modus_radius`, `radio_beacons_bounding_box`, `radio_beacons_radius` | Geo queries by bounding box or radius |
|
|
66
|
+
| `navtex` | `list` | NAVTEX maritime safety messages |
|
|
67
|
+
|
|
68
|
+
**37 methods total.**
|
|
69
|
+
|
|
70
|
+
## Error Handling
|
|
71
|
+
|
|
72
|
+
All methods raise specific exception types on non-2xx responses:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from vessel_api_python import VesselAPIError
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
client.ports.get("ZZZZZ")
|
|
79
|
+
except VesselAPIError as err:
|
|
80
|
+
if err.is_not_found:
|
|
81
|
+
print("Port not found")
|
|
82
|
+
elif err.is_rate_limited:
|
|
83
|
+
print("Rate limited — back off")
|
|
84
|
+
elif err.is_auth_error:
|
|
85
|
+
print("Check API key")
|
|
86
|
+
print(err.status_code, err.message)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Auto-Pagination
|
|
90
|
+
|
|
91
|
+
Every list endpoint has an `all_*` / `list_all` variant returning an iterator:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
# Sync
|
|
95
|
+
for vessel in client.search.all_vessels(filter_name="tanker"):
|
|
96
|
+
print(vessel.name)
|
|
97
|
+
|
|
98
|
+
# Async
|
|
99
|
+
async for vessel in client.search.all_vessels(filter_name="tanker"):
|
|
100
|
+
print(vessel.name)
|
|
101
|
+
|
|
102
|
+
# Collect all at once
|
|
103
|
+
vessels = client.search.all_vessels(filter_name="tanker").collect()
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Configuration
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
client = VesselClient(
|
|
110
|
+
api_key="your-api-key",
|
|
111
|
+
base_url="https://custom-endpoint.example.com/v1",
|
|
112
|
+
timeout=60.0,
|
|
113
|
+
max_retries=5, # default: 3
|
|
114
|
+
user_agent="my-app/1.0",
|
|
115
|
+
)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Retries use exponential backoff with jitter on 429 and 5xx responses. The `Retry-After` header is respected.
|
|
119
|
+
|
|
120
|
+
## Documentation
|
|
121
|
+
|
|
122
|
+
- [API Documentation](https://vesselapi.com/docs) — endpoint guides, request/response schemas, and usage examples
|
|
123
|
+
- [API Explorer](https://vesselapi.com/api-reference) — interactive API reference
|
|
124
|
+
- [Dashboard](https://dashboard.vesselapi.com) — manage API keys and monitor usage
|
|
125
|
+
|
|
126
|
+
## Contributing & Support
|
|
127
|
+
|
|
128
|
+
Found a bug, have a feature request, or need help? You're welcome to [open an issue](https://github.com/vessel-api/vesselapi-python/issues). For API-level bugs and feature requests, please use the [main VesselAPI repository](https://github.com/vessel-api/VesselApi/issues).
|
|
129
|
+
|
|
130
|
+
For security vulnerabilities, **do not** open a public issue — email security@vesselapi.com instead. See [SECURITY.md](SECURITY.md).
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
This repository follows the security policy of the main VesselAPI project.
|
|
4
|
+
|
|
5
|
+
## Reporting a Vulnerability
|
|
6
|
+
|
|
7
|
+
**DO NOT** open a public GitHub issue for security vulnerabilities.
|
|
8
|
+
|
|
9
|
+
**Email:** security@vesselapi.com
|
|
10
|
+
|
|
11
|
+
For full details on reporting process, severity levels, scope, and safe harbor policy, see the [VesselAPI Security Policy](https://github.com/vessel-api/VesselApi/blob/master/SECURITY.md).
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Basic asynchronous usage of the Vessel API Python SDK."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from vesselapi import AsyncVesselClient, VesselAPIError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def main() -> None:
|
|
11
|
+
api_key = os.environ.get("VESSELAPI_API_KEY", "")
|
|
12
|
+
if not api_key:
|
|
13
|
+
print("VESSELAPI_API_KEY environment variable is required")
|
|
14
|
+
sys.exit(1)
|
|
15
|
+
|
|
16
|
+
async with AsyncVesselClient(api_key=api_key) as client:
|
|
17
|
+
# Search for vessels.
|
|
18
|
+
print("--- Search Vessels ---")
|
|
19
|
+
result = await client.search.vessels(filter_name="Ever Given")
|
|
20
|
+
for v in result.vessels or []:
|
|
21
|
+
print(f"Vessel: {v.name} (IMO: {v.imo})")
|
|
22
|
+
|
|
23
|
+
# Get a port.
|
|
24
|
+
print("\n--- Get Port ---")
|
|
25
|
+
port = await client.ports.get("NLRTM")
|
|
26
|
+
if port.port:
|
|
27
|
+
print(f"Port: {port.port.name} ({port.port.unlo_code})")
|
|
28
|
+
|
|
29
|
+
# Error handling.
|
|
30
|
+
print("\n--- Error Handling ---")
|
|
31
|
+
try:
|
|
32
|
+
await client.ports.get("ZZZZZ")
|
|
33
|
+
except VesselAPIError as err:
|
|
34
|
+
if err.is_not_found:
|
|
35
|
+
print(f"Port not found (status {err.status_code})")
|
|
36
|
+
|
|
37
|
+
# Auto-paginate (async).
|
|
38
|
+
print("\n--- Port Events (async paginated) ---")
|
|
39
|
+
count = 0
|
|
40
|
+
async for event in client.port_events.list_all(pagination_limit=10):
|
|
41
|
+
print(f"Event: {event.event} at {event.timestamp}")
|
|
42
|
+
count += 1
|
|
43
|
+
if count >= 25:
|
|
44
|
+
break
|
|
45
|
+
print(f"Total events shown: {count}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Basic synchronous usage of the Vessel API Python SDK."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from vesselapi import VesselClient, VesselAPIError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main() -> None:
|
|
10
|
+
api_key = os.environ.get("VESSELAPI_API_KEY", "")
|
|
11
|
+
if not api_key:
|
|
12
|
+
print("VESSELAPI_API_KEY environment variable is required")
|
|
13
|
+
sys.exit(1)
|
|
14
|
+
|
|
15
|
+
client = VesselClient(api_key=api_key)
|
|
16
|
+
|
|
17
|
+
# Search for vessels by name.
|
|
18
|
+
print("--- Search Vessels ---")
|
|
19
|
+
result = client.search.vessels(filter_name="Ever Given")
|
|
20
|
+
for v in result.vessels or []:
|
|
21
|
+
print(f"Vessel: {v.name} (IMO: {v.imo})")
|
|
22
|
+
|
|
23
|
+
# Search for vessels by flag.
|
|
24
|
+
print("\n--- Search Vessels by Flag ---")
|
|
25
|
+
flag_result = client.search.vessels(filter_flag="PA", filter_vessel_type="Container Ship", pagination_limit=5)
|
|
26
|
+
for v in flag_result.vessels or []:
|
|
27
|
+
print(f"Vessel: {v.name} (IMO: {v.imo}, Country: {v.country})")
|
|
28
|
+
|
|
29
|
+
# Search for ports by country.
|
|
30
|
+
print("\n--- Search Ports by Country ---")
|
|
31
|
+
port_search = client.search.ports(filter_country="NL", pagination_limit=5)
|
|
32
|
+
for p in port_search.ports or []:
|
|
33
|
+
print(f"Port: {p.name} ({p.unlo_code})")
|
|
34
|
+
|
|
35
|
+
# Get a port by UNLOCODE.
|
|
36
|
+
print("\n--- Get Port ---")
|
|
37
|
+
port = client.ports.get("NLRTM")
|
|
38
|
+
if port.port:
|
|
39
|
+
print(f"Port: {port.port.name} ({port.port.unlo_code})")
|
|
40
|
+
|
|
41
|
+
# Handle a not-found port gracefully.
|
|
42
|
+
print("\n--- Not Found Handling ---")
|
|
43
|
+
try:
|
|
44
|
+
client.ports.get("ZZZZZ")
|
|
45
|
+
except VesselAPIError as err:
|
|
46
|
+
if err.is_not_found:
|
|
47
|
+
print(f"Port ZZZZZ not found (status {err.status_code})")
|
|
48
|
+
elif err.is_rate_limited:
|
|
49
|
+
print("Rate limited — try again later")
|
|
50
|
+
else:
|
|
51
|
+
print(f"API error: {err.message} (status {err.status_code})")
|
|
52
|
+
|
|
53
|
+
# Auto-paginate through port events.
|
|
54
|
+
print("\n--- Port Events (paginated) ---")
|
|
55
|
+
count = 0
|
|
56
|
+
for event in client.port_events.list_all(pagination_limit=10):
|
|
57
|
+
print(f"Event: {event.event} at {event.timestamp}")
|
|
58
|
+
count += 1
|
|
59
|
+
if count >= 25:
|
|
60
|
+
break
|
|
61
|
+
print(f"Total events shown: {count}")
|
|
62
|
+
|
|
63
|
+
client.close()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
main()
|