Skip to content

Commit

Permalink
Merge pull request #492 from VorTECHsa/feat-voyage-filters
Browse files Browse the repository at this point in the history
Include missing voyage filters
  • Loading branch information
migueluzcategui committed Apr 22, 2024
2 parents e4d3f35 + 78077f9 commit e5982f7
Show file tree
Hide file tree
Showing 16 changed files with 379 additions and 136 deletions.
100 changes: 100 additions & 0 deletions tests/endpoints/test_voyages_search_enriched.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from tests.testcases import TestCaseUsingRealAPI
from vortexasdk import VoyagesSearchEnriched
from vortexasdk.api.shared_types import VoyageDateRangeActivity

rotterdam = "68faf65af1345067f11dc6723b8da32f00e304a6f33c000118fccd81947deb4e"

Expand Down Expand Up @@ -135,3 +136,102 @@ def test_has_ship_to_ship_param(self):
)

assert len(res) > 0

def test_departure_mode_with_first_load(self):
start = datetime(2022, 4, 26)
end = datetime(2022, 4, 26, 23, 59)

res = (
VoyagesSearchEnriched()
.search(
time_min=start,
time_max=end,
origins=rotterdam,
voyage_date_range_activity=VoyageDateRangeActivity.DEPARTURES.value,
origin_behaviour="first_load",
)
.to_list()
)

assert len(res) > 0

def test_reduced_events_fetching_only_cargo_events(self):
start = datetime(2022, 4, 26)
end = datetime(2022, 4, 26, 23, 59)

res = (
VoyagesSearchEnriched()
.search(
time_min=start,
time_max=end,
origins=rotterdam,
voyage_status=["laden"],
event_types=["cargo"],
)
.to_list()
)

invalid_events = [
event
for event in res[0].events
if event is not None
and (event.event_type == "vessel" or event.event_type == "status")
]

assert len(res) > 0
assert len(res[0].events) > 0
assert len(invalid_events) == 0

def test_reduced_events_fetching_only_vessel_events(self):
start = datetime(2022, 4, 26)
end = datetime(2022, 4, 26, 23, 59)

res = (
VoyagesSearchEnriched()
.search(
time_min=start,
time_max=end,
origins=rotterdam,
voyage_status=["laden"],
event_types=["vessel"],
)
.to_list()
)

invalid_events = [
event
for event in res[0].events
if event is not None
and (event.event_type == "cargo" or event.event_type == "status")
]

assert len(res) > 0
assert len(res[0].events) > 0
assert len(invalid_events) == 0

def test_reduced_events_fetching_only_status_events(self):
start = datetime(2022, 4, 26)
end = datetime(2022, 4, 26, 23, 59)

res = (
VoyagesSearchEnriched()
.search(
time_min=start,
time_max=end,
origins=rotterdam,
voyage_status=["laden"],
event_types=["status"],
)
.to_list()
)

invalid_events = [
event
for event in res[0].events
if event is not None
and (event.event_type == "cargo" or event.event_type == "vessel")
]

assert len(res) > 0
assert len(res[0].events) > 0
assert len(invalid_events) == 0
56 changes: 55 additions & 1 deletion tests/endpoints/test_voyages_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from tests.testcases import TestCaseUsingRealAPI
from vortexasdk.endpoints.geographies import Geographies
from vortexasdk.api.shared_types import VoyageDateRangeActivity

rotterdam = "68faf65af1345067f11dc6723b8da32f00e304a6f33c000118fccd81947deb4e"

Expand All @@ -11,13 +12,66 @@ class TestVoyagesTimeseries(TestCaseUsingRealAPI):
def test_search_returns_all_days(self):
start = datetime(2021, 6, 17)
end = datetime(2021, 6, 21)
numbers_of_days_between_start_and_end = 4

df = (
VoyagesTimeseries()
.search(time_min=start, time_max=end, origins=rotterdam)
.to_df()
)
assert len(df) == 5
assert len(df) == numbers_of_days_between_start_and_end

def test_search_arrivals(self):
start = datetime(2021, 6, 17)
end = datetime(2021, 6, 21)
numbers_of_days_between_start_and_end = 4

df = (
VoyagesTimeseries()
.search(
time_min=start,
time_max=end,
origins=rotterdam,
voyage_date_range_activity=VoyageDateRangeActivity.ARRIVALS.value,
)
.to_df()
)
assert len(df) >= numbers_of_days_between_start_and_end

def test_search_departures(self):
start = datetime(2021, 6, 17)
end = datetime(2021, 6, 21)
numbers_of_days_between_start_and_end = 4

df = (
VoyagesTimeseries()
.search(
time_min=start,
time_max=end,
origins=rotterdam,
voyage_date_range_activity=VoyageDateRangeActivity.DEPARTURES.value,
)
.to_df()
)
assert len(df) >= numbers_of_days_between_start_and_end

def test_search_departures_with_last_discharge_behaviour(self):
start = datetime(2021, 6, 17)
end = datetime(2021, 6, 21)
numbers_of_days_between_start_and_end = 4

df = (
VoyagesTimeseries()
.search(
time_min=start,
time_max=end,
origins=rotterdam,
voyage_date_range_activity=VoyageDateRangeActivity.DEPARTURES.value,
destination_behaviour="last_discharge",
)
.to_df()
)
assert len(df) >= numbers_of_days_between_start_and_end

def test_from_description(self):
start = datetime(2022, 4, 26)
Expand Down
8 changes: 7 additions & 1 deletion vortexasdk/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,18 @@
IDName,
IDNameLayer,
ISODate,
VoyageDateRangeActivity,
OriginBehaviour,
DestinationBehaviour,
)
from vortexasdk.api.storage_terminal import StorageTerminal
from vortexasdk.api.vessel import Vessel, VesselEntity
from vortexasdk.api.eia_forecast import EIAForecast
from vortexasdk.api.vessel_availability import VesselAvailability
from vortexasdk.api.voyages import CongestionBreakdownItem
from vortexasdk.api.voyages import (
CongestionBreakdownItem,
VoyagesVesselEntity,
)
from vortexasdk.api.aggregation_breakdown_item import AggregationBreakdownItem
from vortexasdk.api.fixture import Fixture
from vortexasdk.api.vessel_summary import VesselSummary
Expand Down
17 changes: 17 additions & 0 deletions vortexasdk/api/shared_types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from abc import ABC
from enum import Enum
from pydantic import BaseModel
from datetime import datetime
from typing import List, Optional, Union
Expand Down Expand Up @@ -176,3 +177,19 @@ class VesselClassEntry(BaseModel):
id: Optional[str] = None
layer: Optional[str] = None
label: Optional[str] = None


class VoyageDateRangeActivity(Enum):
ACTIVE = "active"
DEPARTURES = "departures"
ARRIVALS = "arrivals"


class OriginBehaviour(Enum):
ANY_LOAD = "any_load"
FIRST_LOAD = "first_load"


class DestinationBehaviour(Enum):
ANY_LOAD = "any_discharge"
LAST_DISCHARGE = "last_discharge"
1 change: 0 additions & 1 deletion vortexasdk/api/voyages.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from typing_extensions import Literal
from vortexasdk.api.id import ID


from vortexasdk.api.shared_types import (
EntityWithListLayer,
EntityWithSingleLayer,
Expand Down
24 changes: 23 additions & 1 deletion vortexasdk/endpoints/voyages_congestion_breakdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@
from typing import Any, Dict, List, Union

from vortexasdk.api import ID
from vortexasdk.api.shared_types import Tag, to_ISODate
from vortexasdk.api.shared_types import (
Tag,
to_ISODate,
VoyageDateRangeActivity,
OriginBehaviour,
DestinationBehaviour,
)
from vortexasdk.endpoints.endpoints import VOYAGES_CONGESTION_BREAKDOWN
from vortexasdk.endpoints.voyages_congestion_breakdown_result import (
CongestionBreakdownResult,
Expand Down Expand Up @@ -83,6 +89,10 @@ def search(
vessel_risk_level_excluded: Union[str, List[str]] = None,
has_ship_to_ship: str = None,
has_charterer: str = None,
intra_movements: str = None,
voyage_date_range_activity: VoyageDateRangeActivity = None,
origin_behaviour: OriginBehaviour = None,
destination_behaviour: DestinationBehaviour = None,
) -> CongestionBreakdownResult:
"""
Expand Down Expand Up @@ -210,6 +220,14 @@ def search(
order_direction: Determines the direction of sorting. ‘asc’ for ascending, ‘desc’ for
descending.
voyage_date_range_activity: Filter to determine how the voyages should be counted. Must be one of [`active`, `departures`, `arrivals`]
origin_behaviour: The origin behaviour determines which departure mode the `voyage_date_range_activity` should count, must be one of [`first_load`, `any_load`].
destination_behaviour: The destination behaviour determines which arrival mode the voyage_date_range_activity should count, must be one of [last_discharge, any_discharge].
intra_movements: Filter movements based on whether the vessel started and ended in the same country, or geographical layer.
# Returns
`CongestionBreakdownResult`
Expand Down Expand Up @@ -310,6 +328,10 @@ def search(
),
"order": order,
"order_direction": order_direction,
"voyage_date_range_activity": voyage_date_range_activity,
"origin_behaviour": origin_behaviour,
"destination_behaviour": destination_behaviour,
"intra_movements": intra_movements,
}

response = super().search_with_client(**api_params)
Expand Down
20 changes: 19 additions & 1 deletion vortexasdk/endpoints/voyages_geography_breakdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@
from typing import Any, Dict, List, Union

from vortexasdk.api import ID
from vortexasdk.api.shared_types import Tag, to_ISODate
from vortexasdk.api.shared_types import (
Tag,
to_ISODate,
VoyageDateRangeActivity,
OriginBehaviour,
DestinationBehaviour,
)

from vortexasdk.endpoints.endpoints import VOYAGES_BREAKDOWN
from vortexasdk.endpoints.voyages_breakdown_result import (
Expand Down Expand Up @@ -114,6 +120,9 @@ def search(
time_charterer: Union[ID, List[ID]] = None,
time_charterer_excluded: Union[ID, List[ID]] = None,
intra_movements: str = None,
voyage_date_range_activity: VoyageDateRangeActivity = None,
origin_behaviour: OriginBehaviour = None,
destination_behaviour: DestinationBehaviour = None,
) -> VoyagesBreakdownResult:
"""
Expand Down Expand Up @@ -251,6 +260,12 @@ def search(
intra_movements: Filter movements based on whether the vessel started and ended in the same country, or geographical layer.
voyage_date_range_activity: Filter to determine how the voyages should be counted. Must be one of [`active`, `departures`, `arrivals`]
origin_behaviour: The origin behaviour determines which departure mode the `voyage_date_range_activity` should count, must be one of [`first_load`, `any_load`].
destination_behaviour: The destination behaviour determines which arrival mode the voyage_date_range_activity should count, must be one of [last_discharge, any_discharge].
# Returns
`BreakdownResult`
Expand Down Expand Up @@ -371,6 +386,9 @@ def search(
"vessel_risk_level_excluded": convert_to_list(
vessel_risk_level_excluded
),
"voyage_date_range_activity": voyage_date_range_activity,
"origin_behaviour": origin_behaviour,
"destination_behaviour": destination_behaviour,
}

response = super().search_with_client(**api_params)
Expand Down
23 changes: 21 additions & 2 deletions vortexasdk/endpoints/voyages_product_breakdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@
from typing import Any, Dict, List, Union

from vortexasdk.api import ID
from vortexasdk.api.shared_types import Tag, to_ISODate
from vortexasdk.api.shared_types import (
Tag,
to_ISODate,
VoyageDateRangeActivity,
OriginBehaviour,
DestinationBehaviour,
)

from vortexasdk.endpoints.endpoints import VOYAGES_BREAKDOWN
from vortexasdk.endpoints.voyages_breakdown_result import (
Expand All @@ -17,8 +23,9 @@
from vortexasdk.operations import Search
from vortexasdk.utils import convert_to_list


# noinspection PyUnresolvedReferences


class VoyagesProductBreakdown(Search):
"""
VoyagesProductBreakdown class has an optional _second_breakdown_ property.
Expand Down Expand Up @@ -113,6 +120,9 @@ def search(
time_charterer: Union[ID, List[ID]] = None,
time_charterer_excluded: Union[ID, List[ID]] = None,
intra_movements: str = None,
voyage_date_range_activity: VoyageDateRangeActivity = None,
origin_behaviour: OriginBehaviour = None,
destination_behaviour: DestinationBehaviour = None,
) -> VoyagesBreakdownResult:
"""
Expand Down Expand Up @@ -250,6 +260,12 @@ def search(
intra_movements: Filter movements based on whether the vessel started and ended in the same country, or geographical layer.
voyage_date_range_activity: Filter to determine how the voyages should be counted. Must be one of [`active`, `departures`, `arrivals`]
origin_behaviour: The origin behaviour determines which departure mode the `voyage_date_range_activity` should count, must be one of [`first_load`, `any_load`].
destination_behaviour: The destination behaviour determines which arrival mode the voyage_date_range_activity should count, must be one of [last_discharge, any_discharge].
# Returns
`BreakdownResult`
Expand Down Expand Up @@ -373,6 +389,9 @@ def search(
"vessel_risk_level_excluded": convert_to_list(
vessel_risk_level_excluded
),
"voyage_date_range_activity": voyage_date_range_activity,
"origin_behaviour": origin_behaviour,
"destination_behaviour": destination_behaviour,
}

response = super().search_with_client(**api_params)
Expand Down

0 comments on commit e5982f7

Please sign in to comment.