Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ repos:
rev: 22.3.0
hooks:
- id: black
language_version: python3.9.0
language_version: python3.9.19
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this because I'm using an Apple ARM chip and cannot install Python 3.9.0. Not sure what's the best approach here since many other docs & requirements all list Python 3.9.0 🤔

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v1.2.3
hooks:
Expand Down
8 changes: 1 addition & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,7 @@ Now you're ready to create a new branch, add a feature or fix a bug, then send u

### Note about Apple ARM-based chips

To run the SDK on an Apple ARM chip, upgrade your Python version to 3.9 or higher and use the latest version of pip. This works for the SDK version 0.41.0 or higher.

The set up is almost identical as above except one command; to create a virtual environment for Python 3.8 you should run:

```bash
python -m venv venv
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command is the same as the one above so I'm not sure why this is here lol

```
To run the SDK on an Apple ARM chip, use Python version 3.9.19 and use the latest version of pip. This works for the SDK version 0.41.0 or higher.

## Contributing Code

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pip3 install vortexasdk

The SDK requires Python version 3.9. See [Setup FAQ](https://vortechsa.github.io/python-sdk/faq_setup/) for more details.

To install the SDK on an Apple ARM-based machine, use Python versions 3.9 and use the latest version of pip. This is supported in the SDK versions 1.0.0 or higher.
To install the SDK on an Apple ARM-based machine, use Python versions 3.9.19 and use the latest version of pip. This is supported in the SDK versions 1.0.0 or higher.

## Authentication

Expand Down
14 changes: 13 additions & 1 deletion tests/api/examples/cargo_movements.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@
"id": "9d52ede1cff0421a8cd7283b0171afe8d23f519dca5f4e489734522f9cdf804c",
"splinter_timestamp": "2019-10-20T16:41:49+0000"
}
]
],
"trades": [
{
"type": "shipper",
"id": "c9f70607e743e82428ea24cd32f6e403c6ced09078eacfe3d6c175347a9ab508",
"label": "NAYARA ENERGY"
},
{
"type": "consignee",
"id": "5b3fcbc1bd2efec8999bd37d128a7e2132ebd9acf5a1a6fd8d6d2ba234c13938",
"label": "RELIANCE"
}
]
}
]
18 changes: 18 additions & 0 deletions tests/api/test_cargo_movement.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,18 @@ class TestCargoMovement(TestCase):
"splinter_timestamp": "2019-10-20T16:41:49+0000",
}
],
"trades": [
{
"type": "shipper",
"id": "c9f70607e743e82428ea24cd32f6e403c6ced09078eacfe3d6c175347a9ab508",
"label": "NAYARA ENERGY",
},
{
"type": "consignee",
"id": "5b3fcbc1bd2efec8999bd37d128a7e2132ebd9acf5a1a6fd8d6d2ba234c13938",
"label": "RELIANCE",
},
],
}

cm = CargoMovement.model_validate(dictionary)
Expand Down Expand Up @@ -179,6 +191,12 @@ def test_convert_to_flat_dict(self) -> None:
"vessels.0.voyage_id": "401f0e74fc42401248a484aca2e9955dea885378796f7f4d0bc8e92c35ea270a",
"parent_ids.0.id": "9d52ede1cff0421a8cd7283b0171afe8d23f519dca5f4e489734522f9cdf804c",
"parent_ids.0.splinter_timestamp": "2019-10-20T16:41:49+0000",
"trades.0.type": "shipper",
"trades.0.id": "c9f70607e743e82428ea24cd32f6e403c6ced09078eacfe3d6c175347a9ab508",
"trades.0.label": "NAYARA ENERGY",
"trades.1.type": "consignee",
"trades.1.id": "5b3fcbc1bd2efec8999bd37d128a7e2132ebd9acf5a1a6fd8d6d2ba234c13938",
"trades.1.label": "RELIANCE",
}

assert flat == expected
2 changes: 1 addition & 1 deletion tests/endpoints/test_canal_transit_timeseries_real.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def test_canal_timeseries_with_filtering(self):
nonLng = CanalTransitTimeseries().search(
time_min=datetime(2023, 9, 5),
time_max=datetime(2023, 9, 7),
exclude_filter_vessel_classes=["lng"],
exclude_vessel_classes=["lng"],
metric="count_of_vessels",
timeseries_activity="started_waiting",
)
Expand Down
48 changes: 48 additions & 0 deletions tests/endpoints/test_cargo_movements_real.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,51 @@ def test_get_single_cargo_movement_with_unit_param(self):

assert cmT["quantity"] != cmB["quantity"]
assert cmT["quantity"] != cmCBM["quantity"]

def test_filter_by_shipper_and_consignee(self):
cms = CargoMovements().search(
filter_activity="loading_start",
filter_time_min=datetime(2025, 6, 8),
filter_time_max=datetime(2025, 6, 10),
filter_shipper="7b3c9abe7a56425f27bfcd227426ff6a8bc68357cbbb775d7c6c3d0df9bb2f2c",
filter_consignee="5b3fcbc1bd2efec8999bd37d128a7e2132ebd9acf5a1a6fd8d6d2ba234c13938",
)

for i, cm in enumerate(cms):
assert "trades" in cm
assert cm["trades"]

for trade in cm["trades"]:
if trade["type"] == "shipper":
assert (
trade["id"]
== "7b3c9abe7a56425f27bfcd227426ff6a8bc68357cbbb775d7c6c3d0df9bb2f2c"
)
elif trade["type"] == "consignee":
assert (
trade["id"]
== "5b3fcbc1bd2efec8999bd37d128a7e2132ebd9acf5a1a6fd8d6d2ba234c13938"
)

def test_filter_exclude_shipper_and_consignee(self):
cms = CargoMovements().search(
filter_activity="loading_start",
filter_time_min=datetime(2025, 6, 8),
filter_time_max=datetime(2025, 6, 10),
exclude_shipper="7b3c9abe7a56425f27bfcd227426ff6a8bc68357cbbb775d7c6c3d0df9bb2f2c",
exclude_consignee="5b3fcbc1bd2efec8999bd37d128a7e2132ebd9acf5a1a6fd8d6d2ba234c13938",
)

for i, cm in enumerate(cms):
if "trades" in cm and cm["trades"]:
for trade in cm["trades"]:
if trade["type"] == "shipper":
assert (
trade["id"]
!= "7b3c9abe7a56425f27bfcd227426ff6a8bc68357cbbb775d7c6c3d0df9bb2f2c"
)
elif trade["type"] == "consignee":
assert (
trade["id"]
!= "5b3fcbc1bd2efec8999bd37d128a7e2132ebd9acf5a1a6fd8d6d2ba234c13938"
)
7 changes: 7 additions & 0 deletions vortexasdk/api/cargo_movement.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ class CargoMovementProductEntry(BaseModel):
label: Optional[str] = None


class CargoMovementTradeEntry(BaseModel):
type: Literal["load", "discharge", "shipper", "consignee"]
id: Optional[ID] = None
label: Optional[str] = None


class CargoMovement(BaseModel):
"""

Expand Down Expand Up @@ -171,3 +177,4 @@ class CargoMovement(BaseModel):
]
]
] = None
trades: Optional[List[CargoMovementTradeEntry]] = None
46 changes: 21 additions & 25 deletions vortexasdk/endpoints/canal_transit.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,13 @@ def search(
filter_canal: Optional[str] = None,
filter_direction: Optional[str] = None,
filter_lock: Optional[str] = None,
exclude_filter_vessels: Optional[Union[ID, List[ID]]] = None,
exclude_filter_vessel_classes: Optional[Union[ID, List[ID]]] = None,
exclude_filter_products: Optional[Union[ID, List[ID]]] = None,
exclude_filter_origin: Optional[Union[ID, List[ID]]] = None,
exclude_filter_destination: Optional[Union[ID, List[ID]]] = None,
exclude_filter_charterer: Optional[Union[ID, List[ID]]] = None,
exclude_filter_effective_controller: Optional[
Union[ID, List[ID]]
] = None,
exclude_vessels: Optional[Union[ID, List[ID]]] = None,
exclude_vessel_classes: Optional[Union[ID, List[ID]]] = None,
exclude_products: Optional[Union[ID, List[ID]]] = None,
exclude_origin: Optional[Union[ID, List[ID]]] = None,
exclude_destination: Optional[Union[ID, List[ID]]] = None,
exclude_charterer: Optional[Union[ID, List[ID]]] = None,
exclude_effective_controller: Optional[Union[ID, List[ID]]] = None,
) -> CanalTransitResult:
"""

Expand Down Expand Up @@ -121,36 +119,34 @@ def search(

updated_since: The UTC date of last record update time,

exclude_filter_vessels: A vessel ID, or list of vessel IDs to exclude,
exclude_vessels: A vessel ID, or list of vessel IDs to exclude,

exclude_filter_vessel_classes: A vessel class, or list of vessel classes to exclude,
exclude_vessel_classes: A vessel class, or list of vessel classes to exclude,

exclude_filter_products: A product ID, or list of product IDs to exclude,
exclude_products: A product ID, or list of product IDs to exclude,

exclude_filter_origin: A geography ID, or list of geography IDs to exclude,
exclude_origin: A geography ID, or list of geography IDs to exclude,

exclude_filter_destination: A geography ID, or list of geography IDs to exclude,
exclude_destination: A geography ID, or list of geography IDs to exclude,

exclude_filter_charterer: A charterer ID, or list of charterer IDs to exclude,
exclude_charterer: A charterer ID, or list of charterer IDs to exclude,

exclude_filter_effective_controller: A effective controller ID, or list of IDs to exclude,
exclude_effective_controller: A effective controller ID, or list of IDs to exclude,

# Returns
`CanalTransitResults`, containing all the canal transit records matching the given search terms.

"""

exclude_params: Dict[str, Any] = {
"filter_origin": convert_to_list(exclude_filter_origin),
"filter_destination": convert_to_list(exclude_filter_destination),
"filter_products": convert_to_list(exclude_filter_products),
"filter_vessels": convert_to_list(exclude_filter_vessels),
"filter_vessel_classes": convert_to_list(
exclude_filter_vessel_classes
),
"filter_charterers": convert_to_list(exclude_filter_charterer),
"filter_origin": convert_to_list(exclude_origin),
"filter_destination": convert_to_list(exclude_destination),
"filter_products": convert_to_list(exclude_products),
"filter_vessels": convert_to_list(exclude_vessels),
"filter_vessel_classes": convert_to_list(exclude_vessel_classes),
"filter_charterers": convert_to_list(exclude_charterer),
"filter_effective_controllers": convert_to_list(
exclude_filter_effective_controller
exclude_effective_controller
),
}

Expand Down
46 changes: 21 additions & 25 deletions vortexasdk/endpoints/canal_transit_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,13 @@ def search(
timeseries_activity: str = "started_waiting",
metric: str = "count_of_vessels",
timeseries_frequency: str = "day",
exclude_filter_vessels: Optional[Union[ID, List[ID]]] = None,
exclude_filter_vessel_classes: Optional[Union[ID, List[ID]]] = None,
exclude_filter_products: Optional[Union[ID, List[ID]]] = None,
exclude_filter_origin: Optional[Union[ID, List[ID]]] = None,
exclude_filter_destination: Optional[Union[ID, List[ID]]] = None,
exclude_filter_charterer: Optional[Union[ID, List[ID]]] = None,
exclude_filter_effective_controller: Optional[
Union[ID, List[ID]]
] = None,
exclude_vessels: Optional[Union[ID, List[ID]]] = None,
exclude_vessel_classes: Optional[Union[ID, List[ID]]] = None,
exclude_products: Optional[Union[ID, List[ID]]] = None,
exclude_origin: Optional[Union[ID, List[ID]]] = None,
exclude_destination: Optional[Union[ID, List[ID]]] = None,
exclude_charterer: Optional[Union[ID, List[ID]]] = None,
exclude_effective_controller: Optional[Union[ID, List[ID]]] = None,
) -> TimeSeriesResult:
"""

Expand Down Expand Up @@ -132,36 +130,34 @@ def search(

timeseries_frequency: Frequency denoting the granularity of the time series. Must be one of [`'day'`, `'week'`]

exclude_filter_vessels: A vessel ID, or list of vessel IDs to exclude,
exclude_vessels: A vessel ID, or list of vessel IDs to exclude,

exclude_filter_vessel_classes: A vessel class, or list of vessel classes to exclude,
exclude_vessel_classes: A vessel class, or list of vessel classes to exclude,

exclude_filter_products: A product ID, or list of product IDs to exclude,
exclude_products: A product ID, or list of product IDs to exclude,

exclude_filter_origin: A geography ID, or list of geography IDs to exclude,
exclude_origin: A geography ID, or list of geography IDs to exclude,

exclude_filter_destination: A geography ID, or list of geography IDs to exclude,
exclude_destination: A geography ID, or list of geography IDs to exclude,

exclude_filter_charterer: A charterer ID, or list of charterer IDs to exclude,
exclude_charterer: A charterer ID, or list of charterer IDs to exclude,

exclude_filter_effective_controller: A effective controller ID, or list of IDs to exclude,
exclude_effective_controller: A effective controller ID, or list of IDs to exclude,

# Returns
`CanalTransitTimeseries`

"""

exclude_params: Dict[str, Any] = {
"filter_origin": convert_to_list(exclude_filter_origin),
"filter_destination": convert_to_list(exclude_filter_destination),
"filter_products": convert_to_list(exclude_filter_products),
"filter_vessels": convert_to_list(exclude_filter_vessels),
"filter_vessel_classes": convert_to_list(
exclude_filter_vessel_classes
),
"filter_charterers": convert_to_list(exclude_filter_charterer),
"filter_origin": convert_to_list(exclude_origin),
"filter_destination": convert_to_list(exclude_destination),
"filter_products": convert_to_list(exclude_products),
"filter_vessels": convert_to_list(exclude_vessels),
"filter_vessel_classes": convert_to_list(exclude_vessel_classes),
"filter_charterers": convert_to_list(exclude_charterer),
"filter_effective_controllers": convert_to_list(
exclude_filter_effective_controller
exclude_effective_controller
),
}

Expand Down
34 changes: 23 additions & 11 deletions vortexasdk/endpoints/cargo_movements.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def search(
filter_vessel_owners: Optional[Union[ID, List[ID]]] = None,
filter_time_charterers: Optional[Union[ID, List[ID]]] = None,
filter_effective_controllers: Optional[Union[ID, List[ID]]] = None,
filter_shipper: Optional[Union[ID, List[ID]]] = None,
filter_consignee: Optional[Union[ID, List[ID]]] = None,
filter_products: Optional[Union[ID, List[ID]]] = None,
filter_vessels: Optional[Union[ID, List[ID]]] = None,
filter_vessel_classes: Optional[Union[str, List[str]]] = None,
Expand All @@ -70,8 +72,10 @@ def search(
exclude_charterers: Optional[Union[ID, List[ID]]] = None,
exclude_owners: Optional[Union[ID, List[ID]]] = None,
exclude_effective_controllers: Optional[Union[ID, List[ID]]] = None,
exclude_filter_vessel_owners: Optional[Union[ID, List[ID]]] = None,
exclude_filter_time_charterers: Optional[Union[ID, List[ID]]] = None,
exclude_vessel_owners: Optional[Union[ID, List[ID]]] = None,
exclude_time_charterers: Optional[Union[ID, List[ID]]] = None,
exclude_shipper: Optional[Union[ID, List[ID]]] = None,
exclude_consignee: Optional[Union[ID, List[ID]]] = None,
exclude_vessel_flags: Optional[Union[ID, List[ID]]] = None,
exclude_vessel_ice_class: Optional[Union[ID, List[ID]]] = None,
exclude_vessel_propulsion: Optional[Union[ID, List[ID]]] = None,
Expand Down Expand Up @@ -107,6 +111,10 @@ def search(

filter_time_charterers: An time charterer ID, or list of time charterers IDs to filter on.

filter_shipper: A shipper ID, or list of shipper IDs to filter on.

filter_consignee: A consignee ID, or list of consignee IDs to filter on.

filter_products: A product ID, or list of product IDs to filter on.

filter_vessels: A vessel ID, or list of vessel IDs to filter on.
Expand Down Expand Up @@ -143,11 +151,15 @@ def search(

exclude_charterers: A charterer ID, or list of charterer IDs to exclude.

exclude_filter_effective_controllers: An effective controller ID, or list of effective controller IDs to exclude.
exclude_effective_controllers: An effective controller ID, or list of effective controller IDs to exclude.

exclude_vessel_owners: An vessel owner ID, or list of vessel owners IDs to exclude.

exclude_filter_vessel_owners: An vessel owner ID, or list of vessel owners IDs to filter on.
exclude_time_charterers: An time charterer ID, or list of time charterers IDs to exclude.

exclude_filter_time_charterers: An time charterer ID, or list of time charterers IDs to filter on.
exclude_shipper: A shipper ID, or list of shipper IDs to exclude.

exclude_consignee: A consignee ID, or list of consignee IDs to exclude.

exclude_vessel_flags: A geography ID, or list of geography IDs to exclude.

Expand Down Expand Up @@ -249,12 +261,10 @@ def search(
"filter_effective_controllers": convert_to_list(
exclude_effective_controllers
),
"filter_vessel_owners": convert_to_list(
exclude_filter_vessel_owners
),
"filter_time_charterers": convert_to_list(
exclude_filter_time_charterers
),
"filter_shipper": convert_to_list(exclude_shipper),
"filter_consignee": convert_to_list(exclude_consignee),
"filter_vessel_owners": convert_to_list(exclude_vessel_owners),
"filter_time_charterers": convert_to_list(exclude_time_charterers),
"filter_vessel_flags": convert_to_list(exclude_vessel_flags),
"filter_vessel_ice_class": convert_to_list(
exclude_vessel_ice_class
Expand All @@ -276,6 +286,8 @@ def search(
),
"filter_vessel_owners": convert_to_list(filter_vessel_owners),
"filter_time_charterers": convert_to_list(filter_time_charterers),
"filter_shipper": convert_to_list(filter_shipper),
"filter_consignee": convert_to_list(filter_consignee),
"filter_products": convert_to_list(filter_products),
"filter_vessels": convert_to_list(filter_vessels),
"filter_vessel_classes": convert_to_list(filter_vessel_classes),
Expand Down
3 changes: 3 additions & 0 deletions vortexasdk/endpoints/cargo_movements_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,9 @@ def to_df(
'parent_ids.0.splinter_timestamp',
'parent_ids.1.id',
'parent_ids.1.splinter_timestamp',
'trades.0.type',
'trades.0.id',
'trades.0.label'
]
```

Expand Down
Loading
Loading