vessel-api-python 1.3.0__py3-none-any.whl → 2.0.0__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.
- vessel_api_python/__init__.py +9 -64
- vessel_api_python/_client.py +0 -4
- vessel_api_python/_constants.py +1 -1
- vessel_api_python/_errors.py +49 -1
- vessel_api_python/_models.py +50 -396
- vessel_api_python/_services.py +2145 -351
- vessel_api_python/_transport.py +5 -2
- {vessel_api_python-1.3.0.dist-info → vessel_api_python-2.0.0.dist-info}/METADATA +80 -16
- vessel_api_python-2.0.0.dist-info/RECORD +13 -0
- {vessel_api_python-1.3.0.dist-info → vessel_api_python-2.0.0.dist-info}/WHEEL +1 -1
- vessel_api_python-1.3.0.dist-info/RECORD +0 -13
- {vessel_api_python-1.3.0.dist-info → vessel_api_python-2.0.0.dist-info}/licenses/LICENSE +0 -0
vessel_api_python/_transport.py
CHANGED
|
@@ -164,8 +164,11 @@ def _calc_backoff(attempt: int, response: httpx.Response) -> float:
|
|
|
164
164
|
pass
|
|
165
165
|
# Try HTTP-date format (RFC 7231 section 7.1.3).
|
|
166
166
|
try:
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
# Annotated because typeshed types parsedate_to_datetime as Any on
|
|
168
|
+
# Python 3.9, which propagates through the subtraction and makes the
|
|
169
|
+
# return Any. Without this, mypy passes on 3.12 and fails on 3.9.
|
|
170
|
+
dt: datetime.datetime = parsedate_to_datetime(retry_after)
|
|
171
|
+
delta: float = (dt - _utcnow()).total_seconds()
|
|
169
172
|
return max(0.0, min(delta, MAX_BACKOFF))
|
|
170
173
|
except (ValueError, TypeError):
|
|
171
174
|
pass
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: vessel-api-python
|
|
3
|
-
Version:
|
|
4
|
-
Summary: Python client for the Vessel Tracking API
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Python client for the Vessel Tracking API: maritime vessel tracking, port events, emissions, and nautical infrastructure.
|
|
5
5
|
Project-URL: Documentation, https://vesselapi.com/docs
|
|
6
6
|
Project-URL: Repository, https://github.com/vessel-api/vesselapi-python
|
|
7
7
|
Project-URL: Issues, https://github.com/vessel-api/vesselapi-python/issues
|
|
@@ -39,7 +39,7 @@ Description-Content-Type: text/markdown
|
|
|
39
39
|
[](https://pypi.org/project/vessel-api-python/)
|
|
40
40
|
[](LICENSE)
|
|
41
41
|
|
|
42
|
-
Python client for the [Vessel Tracking API](https://vesselapi.com)
|
|
42
|
+
Python client for the [Vessel Tracking API](https://vesselapi.com): maritime vessel tracking, port events, emissions, and nautical infrastructure.
|
|
43
43
|
|
|
44
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
45
|
|
|
@@ -91,15 +91,33 @@ asyncio.run(main())
|
|
|
91
91
|
|
|
92
92
|
| Service | Methods | Description |
|
|
93
93
|
|---------|---------|-------------|
|
|
94
|
-
| `vessels` | `get`, `position`, `casualties`, `
|
|
95
|
-
| `ports` | `get` | Port lookup by UN/LOCODE |
|
|
94
|
+
| `vessels` | `get`, `position`, `casualties`, `emissions`, `eta`, `positions` | Vessel details, positions, and records |
|
|
95
|
+
| `ports` | `get`, `inbound`, `inbound_all` | Port lookup by UN/LOCODE and inbound vessels |
|
|
96
96
|
| `port_events` | `list`, `by_port`, `by_ports`, `by_vessel`, `last_by_vessel`, `by_vessels` | Vessel arrival/departure events |
|
|
97
97
|
| `emissions` | `list` | EU MRV emissions data |
|
|
98
98
|
| `search` | `vessels`, `ports`, `dgps`, `light_aids`, `modus`, `radio_beacons` | Full-text search across entity types |
|
|
99
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
100
|
|
|
102
|
-
**
|
|
101
|
+
**33 methods total**, one per API endpoint, plus 28 auto-pagination iterators.
|
|
102
|
+
|
|
103
|
+
## Required Parameters
|
|
104
|
+
|
|
105
|
+
Parameters the API requires are keyword-only with no default, so leaving one out
|
|
106
|
+
raises `TypeError` at the call instead of returning HTTP 400 from the server:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
client.location.vessels_radius(latitude=51.9225, longitude=4.47917, radius=10000)
|
|
110
|
+
client.location.vessels_radius(latitude=51.9225) # TypeError: missing longitude, radius
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This covers the geo bounds on every `location` method (`lat_min`, `lat_max`,
|
|
114
|
+
`lon_min`, `lon_max` for bounding boxes; `latitude`, `longitude`, `radius` for
|
|
115
|
+
radius queries), `filter_name` on `search.dgps`, `search.light_aids`,
|
|
116
|
+
`search.modus` and `search.radio_beacons`, `filter_port_name` on
|
|
117
|
+
`port_events.by_ports`, `filter_vessel_name` on `port_events.by_vessels`, and
|
|
118
|
+
`filter_ids` on `vessels.positions`, along with the matching `all_*` iterators.
|
|
119
|
+
`filter_id_type` is required by the API but keeps its `"imo"` default, since the
|
|
120
|
+
SDK always sends it.
|
|
103
121
|
|
|
104
122
|
## Vessel Lookup & Location
|
|
105
123
|
|
|
@@ -108,16 +126,47 @@ asyncio.run(main())
|
|
|
108
126
|
vessel = client.vessels.get("9811000")
|
|
109
127
|
print(f"{vessel.vessel.name} ({vessel.vessel.vessel_type})")
|
|
110
128
|
|
|
111
|
-
# Get
|
|
112
|
-
|
|
129
|
+
# Get a vessel's latest stored AIS position. A vessel that exists may have no
|
|
130
|
+
# stored position, which raises VesselNotFoundError rather than returning empty.
|
|
131
|
+
pos = client.vessels.position("232003239", filter_id_type="mmsi")
|
|
113
132
|
print(f"Position: {pos.vessel_position.latitude}, {pos.vessel_position.longitude}")
|
|
114
133
|
|
|
134
|
+
# filter_sat=True falls back to satellite AIS when nothing is stored.
|
|
135
|
+
# ⚠️ Satellite lookups draw on a prepaid balance and are charged per call.
|
|
136
|
+
# Omit it unless you need that fallback.
|
|
137
|
+
|
|
115
138
|
# Find all vessels within 10 km of Rotterdam.
|
|
116
139
|
nearby = client.location.vessels_radius(latitude=51.9225, longitude=4.47917, radius=10000)
|
|
117
140
|
for v in nearby.vessels or []:
|
|
118
141
|
print(f"{v.vessel_name} at {v.latitude}, {v.longitude}")
|
|
119
142
|
```
|
|
120
143
|
|
|
144
|
+
## Search
|
|
145
|
+
|
|
146
|
+
`search.vessels` accepts `q`, a unified search across IMO, MMSI, ENI, callsign and
|
|
147
|
+
name. One value can return several vessels, and `_meta.matched_on` maps each result's
|
|
148
|
+
index to the fields it matched on.
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
res = client.search.vessels(q="4606770")
|
|
152
|
+
print(res.meta.matched_on) # {"0": ["eni"]}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Filters the API declares as repeatable take either one value or a list. A list is
|
|
156
|
+
sent as a repeated query parameter, so the values are OR-ed:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
# ?filter.flag=PA&filter.flag=LR&filter.vesselType=Container%20Ship
|
|
160
|
+
client.search.vessels(filter_flag=["PA", "LR"], filter_vessel_type="Container Ship")
|
|
161
|
+
|
|
162
|
+
client.search.ports(filter_country=["NL", "BE"], filter_size=["LARGE", "MEDIUM"])
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
These are `filter_flag` and `filter_vessel_type` on `search.vessels`;
|
|
166
|
+
`filter_country`, `filter_port_type`, `filter_size`, `filter_harbor_size` and
|
|
167
|
+
`filter_harbor_use` on `search.ports`; and `filter_ids` on `vessels.positions`,
|
|
168
|
+
which also accepts the comma-separated single-string form.
|
|
169
|
+
|
|
121
170
|
## Error Handling
|
|
122
171
|
|
|
123
172
|
All methods raise specific exception types on non-2xx responses:
|
|
@@ -131,7 +180,7 @@ except VesselAPIError as err:
|
|
|
131
180
|
if err.is_not_found:
|
|
132
181
|
print("Port not found")
|
|
133
182
|
elif err.is_rate_limited:
|
|
134
|
-
print("Rate limited
|
|
183
|
+
print("Rate limited, backing off")
|
|
135
184
|
elif err.is_auth_error:
|
|
136
185
|
print("Check API key")
|
|
137
186
|
print(err.status_code, err.message)
|
|
@@ -150,8 +199,14 @@ for vessel in client.search.all_vessels(filter_vessel_type="Tanker"):
|
|
|
150
199
|
async for vessel in client.search.all_vessels(filter_vessel_type="Tanker"):
|
|
151
200
|
print(vessel.name)
|
|
152
201
|
|
|
153
|
-
# Collect
|
|
202
|
+
# Collect every match at once. pagination_limit is the page size, not a total:
|
|
203
|
+
# .collect() walks to the end, so this is one request per page until exhausted.
|
|
154
204
|
vessels = client.search.all_vessels(filter_vessel_type="Tanker", pagination_limit=50).collect()
|
|
205
|
+
|
|
206
|
+
# To take a fixed number, stop the iterator yourself.
|
|
207
|
+
from itertools import islice
|
|
208
|
+
|
|
209
|
+
first_50 = list(islice(client.search.all_vessels(filter_vessel_type="Tanker"), 50))
|
|
155
210
|
```
|
|
156
211
|
|
|
157
212
|
## Configuration
|
|
@@ -170,15 +225,24 @@ Retries use exponential backoff with jitter on 429 and 5xx responses. The `Retry
|
|
|
170
225
|
|
|
171
226
|
## Documentation
|
|
172
227
|
|
|
173
|
-
- [API Documentation](https://vesselapi.com/docs)
|
|
174
|
-
- [API Explorer](https://vesselapi.com/api-reference)
|
|
175
|
-
- [Dashboard](https://dashboard.vesselapi.com)
|
|
228
|
+
- [API Documentation](https://vesselapi.com/docs): endpoint guides, request/response schemas, and usage examples
|
|
229
|
+
- [API Explorer](https://vesselapi.com/api-reference): interactive API reference
|
|
230
|
+
- [Dashboard](https://dashboard.vesselapi.com): manage API keys and monitor usage
|
|
176
231
|
|
|
177
232
|
## Contributing & Support
|
|
178
233
|
|
|
179
234
|
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).
|
|
180
235
|
|
|
181
|
-
For security vulnerabilities, **do not** open a public issue
|
|
236
|
+
For security vulnerabilities, **do not** open a public issue. Email security@vesselapi.com instead. See [SECURITY.md](SECURITY.md).
|
|
237
|
+
|
|
238
|
+
## Data Sources & Attribution
|
|
239
|
+
|
|
240
|
+
Emissions and casualty data: © European Union. Source: European Maritime Safety Agency
|
|
241
|
+
(EMSA): THETIS-MRV (EU MRV, Regulation (EU) 2015/757) and the European Marine Casualty
|
|
242
|
+
Information Platform (EMCIP). Reused under the European Commission reuse notice
|
|
243
|
+
(Commission Decision 2011/833/EU), which authorises reuse for commercial and
|
|
244
|
+
non-commercial purposes with acknowledgement of the source. Data may be transformed and
|
|
245
|
+
combined; EMSA does not endorse this service.
|
|
182
246
|
|
|
183
247
|
## License
|
|
184
248
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
vessel_api_python/__init__.py,sha256=-c0Rq1t5pDN4OY1w_9uNNeHjUI__kovOiyWvvU319jo,3114
|
|
2
|
+
vessel_api_python/_client.py,sha256=L7qkzUiATDpPlxWViEKicNpNx7D90gCohas56uCimgA,4919
|
|
3
|
+
vessel_api_python/_constants.py,sha256=Im6d9J9HSo5D-Rt4SVIQ35lqqGXIovSxhGsBhNqTVdU,244
|
|
4
|
+
vessel_api_python/_errors.py,sha256=DaiyCjYKJZTo6-6sOqAcJBdOeFaIYgWHE48nsHWGeGA,6414
|
|
5
|
+
vessel_api_python/_iterator.py,sha256=SkgsGSdxLrKtw-ad8fSUPaEDDJCamAKK0PrG_P8HX-4,3198
|
|
6
|
+
vessel_api_python/_models.py,sha256=rJnRaZZ9y-h3xYbn0e-7nRLm6Sr9bSkigLIC6jY_HW0,19739
|
|
7
|
+
vessel_api_python/_services.py,sha256=8f6yxKHvzDuIbrQCpN01wT_g4OsByWGHOIhKgDGeaQg,108285
|
|
8
|
+
vessel_api_python/_transport.py,sha256=pfRaJwkq_GYpA5Ev8wH7tBdlzN2ykgy29Ag1L3F5K4Y,6956
|
|
9
|
+
vessel_api_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
vessel_api_python-2.0.0.dist-info/METADATA,sha256=1HWjKevhtZDfUq9F1k4DNZoGZvtfaWnzsJw5dnPOVA0,10048
|
|
11
|
+
vessel_api_python-2.0.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
12
|
+
vessel_api_python-2.0.0.dist-info/licenses/LICENSE,sha256=zoj_abq99mj8cz-Bz71XCnwB-Qv3kU1VzVXeKEntuQU,1067
|
|
13
|
+
vessel_api_python-2.0.0.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
vessel_api_python/__init__.py,sha256=kmYpzbtVfaMHRXUBoom7JqZa5hCif3vGL8y-q5n4DrA,4599
|
|
2
|
-
vessel_api_python/_client.py,sha256=39yKlQ4W2TnE85sTtK7KlBzFF385Pl52I5ghyq575EA,5067
|
|
3
|
-
vessel_api_python/_constants.py,sha256=Cp_uNnK0RljiWlyPmkMrVFoQtF5GpXTggSCD1SPvcyk,244
|
|
4
|
-
vessel_api_python/_errors.py,sha256=pxDm36mbrviOoDRmJ-ogtlUIsyu-dHpC0jcs5f34WDU,4310
|
|
5
|
-
vessel_api_python/_iterator.py,sha256=SkgsGSdxLrKtw-ad8fSUPaEDDJCamAKK0PrG_P8HX-4,3198
|
|
6
|
-
vessel_api_python/_models.py,sha256=eawnhctWmvGK505EJzDyszTqXpI5ctRg73-uR6AVOck,30575
|
|
7
|
-
vessel_api_python/_services.py,sha256=PoRoHZP7PoqcUGGEaZNszm9_a1K_nTBQu_s5OaPCIqI,79094
|
|
8
|
-
vessel_api_python/_transport.py,sha256=_4s-65JMRwD2S435u0iuoLGH_GyLNaX8cP_uSh_u80I,6692
|
|
9
|
-
vessel_api_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
vessel_api_python-1.3.0.dist-info/METADATA,sha256=omcgGfIpL-dHECfAZqvoTmHqAUn6oKf14g0NoAULcHk,7019
|
|
11
|
-
vessel_api_python-1.3.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
12
|
-
vessel_api_python-1.3.0.dist-info/licenses/LICENSE,sha256=zoj_abq99mj8cz-Bz71XCnwB-Qv3kU1VzVXeKEntuQU,1067
|
|
13
|
-
vessel_api_python-1.3.0.dist-info/RECORD,,
|
|
File without changes
|