Skip to content

Package Documentation

Port Expenses API Package.

Classes:

Name Description
PortExpensesAPI

Represents Signal's Port Expenses API.

Operation

Enumeration of all possible operations.

OperationStatus

Enumeration of all possible operations statuses.

EstimationStatus

Enumeration of all possible estimation statuses.

ItalianAnchorageDues

Enumeration of all possible italian anchorage dues.

PortExpenses

The fees to be payed to port authorities.

Port

A maritime facility where vessels can dock.

VesselType

A vessel type.

PortFilter

A filter used to find specific ports.

EstimationStatus

Bases: Enum

An enumeration of all possible estimation statuses.

Source code in signal_ocean/port_expenses/enums.py
28
29
30
31
32
33
@unique
class EstimationStatus(Enum):
    """An enumeration of all possible estimation statuses."""
    PRIORITY_TO_FORMULAS = 0
    PRIORITY_TO_ESTIMATES = 1
    NO_ESTIMATES = 2

ItalianAnchorageDues

Bases: Enum

An enumeration of all possible italian anchorage dues.

Source code in signal_ocean/port_expenses/enums.py
20
21
22
23
24
25
@unique
class ItalianAnchorageDues(Enum):
    """An enumeration of all possible italian anchorage dues."""
    NONE = 0
    MONTHLY = 1
    YEARLY = 2

Operation

Bases: Enum

An enumeration of all possible operations.

Source code in signal_ocean/port_expenses/enums.py
 6
 7
 8
 9
10
@unique
class Operation(Enum):
    """An enumeration of all possible operations."""
    LOAD = 0
    DISCHARGE = 1

OperationStatus

Bases: Enum

An enumeration of all possible operations statuses.

Source code in signal_ocean/port_expenses/enums.py
13
14
15
16
17
@unique
class OperationStatus(Enum):
    """An enumeration of all possible operations statuses."""
    BALLAST = 0
    LADEN = 1

Port dataclass

A maritime facility where vessels can dock.

Attributes:

Name Type Description
id int

ID of the port.

name str

Name of the port.

Source code in signal_ocean/port_expenses/models.py
47
48
49
50
51
52
53
54
55
56
57
@dataclass(frozen=True)
class Port:
    """A maritime facility where vessels can dock.

    Attributes:
        id: ID of the port.
        name: Name of the port.
    """

    id: int
    name: str

PortExpenses dataclass

The fees for port's facilities and services.

Attributes:

Name Type Description
port_id int

Port ID

towage int

Towage

port_dues int

Port dues

pilotage int

Pilotage

agency_fees int

Agency fees

other int

Other

suez_dues int

Suez dues

total_cost int

Total cost

miscellaneous_dues int

Mischellaneous dues

is_estimated bool

Flag for estimation

canal_dues int

Canal dues

berth_dues int

Berth dues

lighthouse_dues int

Lighthouse dues

mooring_unmooring int

Mooring-unmooring

quay_dues int

Quay dues

anchorage_dues int

Anchorage dues

Source code in signal_ocean/port_expenses/models.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@dataclass(frozen=True)
class PortExpenses:
    """The fees for port's facilities and services.

    Attributes:
        port_id: Port ID
        towage: Towage
        port_dues: Port dues
        pilotage: Pilotage
        agency_fees: Agency fees
        other: Other
        suez_dues: Suez dues
        total_cost: Total cost
        miscellaneous_dues: Mischellaneous dues
        is_estimated: Flag for estimation
        canal_dues: Canal dues
        berth_dues: Berth dues
        lighthouse_dues: Lighthouse dues
        mooring_unmooring: Mooring-unmooring
        quay_dues: Quay dues
        anchorage_dues: Anchorage dues
    """

    port_id: int
    towage: int
    port_dues: int
    pilotage: int
    agency_fees: int
    other: int
    suez_dues: int
    total_cost: int
    miscellaneous_dues: int
    is_estimated: bool
    canal_dues: int
    berth_dues: int
    lighthouse_dues: int
    mooring_unmooring: int
    quay_dues: int
    anchorage_dues: int

PortExpensesAPI

Represents Signal's Port Expenses API.

Source code in signal_ocean/port_expenses/port_expenses_api.py
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
class PortExpensesAPI:
    """Represents Signal's Port Expenses API."""

    def __init__(self, connection: Optional[Connection] = None):
        """Initializes the Port Expenses API.

        Args:
            connection: API connection configuration. If not provided, the
                default connection method is used.
        """
        self.__connection = connection or Connection()

    def get_port_expenses(
        self, imo: int, port_id: int,
            vessel_type_id: Optional[int] = None,
            estimated_time_of_berth: Optional[datetime] = None,
            estimated_time_of_sail: Optional[datetime] = None,
            operation: Optional[Operation] = None,
            italian_anchorage_dues: Optional[ItalianAnchorageDues] = None,
            cargo_type: Optional[str] = None,
            operation_status: Optional[OperationStatus] = None,
            utc_date: Optional[datetime] = None,
            historical_tce: Optional[bool] = None,
            estimation_status: Optional[EstimationStatus] = None
    ) -> Optional[PortExpenses]:
        """Retrieves port expenses.

        Args:
            imo: The vessel's IMO number.
            port_id: ID of the port to retrieve the expenses for.
            vessel_type_id: Vessel type ID.
            estimated_time_of_berth: Estimated time of berth.
            estimated_time_of_sail: Estimated time of sail.
            operation: Operation type.
            italian_anchorage_dues: Italian anchorage dues.
            cargo_type: Cargo type.
            operation_status: Operation status.
            utc_date: UTC date.
            historical_tce: Flag for Historical TCE.
            estimation_status: Estimation status.

        Returns:
            The port expenses or None if a port with given ID does not exist or
            a vessel with the given IMO number does not exist.
        """
        query_dict = {
            "imo": '{}'.format(imo),
            "portId": '{}'.format(port_id)
        }

        if vessel_type_id is not None:
            query_dict["vesselTypeId"] = '{}'.format(vessel_type_id)
        if estimated_time_of_berth is not None:
            query_dict["estimatedTimeOfBerth"] = \
                estimated_time_of_berth.isoformat()
        if estimated_time_of_sail is not None:
            query_dict["estimatedTimeOfSail"] = \
                estimated_time_of_sail.isoformat()
        if operation is not None:
            query_dict["operation"] = '{}'.format(operation.value)
        if italian_anchorage_dues is not None:
            query_dict["italianAnchorageDues"] = \
                '{}'.format(italian_anchorage_dues.value)
        if cargo_type is not None:
            query_dict["cargoType"] = '{}'.format(cargo_type)
        if operation_status is not None:
            query_dict["operationStatus"] = '{}'.format(operation_status.value)
        if utc_date is not None:
            query_dict["utcDate"] = utc_date.isoformat()
        if historical_tce is not None:
            query_dict["historicalTce"] = '{}'.format(historical_tce)
        if estimation_status is not None:
            query_dict["estimationStatus"] = \
                '{}'.format(estimation_status.value)

        query_string: QueryString = query_dict
        response = self.__connection._make_post_request(
            "port-expenses/api/v1/Port", query_string
        )
        response.raise_for_status()
        response_json = response.json()
        return_object = parse_port_expenses(response_json) \
            if response_json else None

        return return_object

    def get_port_model_vessel_expenses(
        self, port_id: int, vessel_type_id: int,
            formula_calculation_date: datetime, vessel_class_id: int = 0,
            operation_status: OperationStatus = OperationStatus.BALLAST,
            historical_tce: bool = False,
            estimation_status: EstimationStatus =
            EstimationStatus.PRIORITY_TO_FORMULAS) -> Optional[PortExpenses]:
        """Retrieves model vessel port expenses.

        Args:
            port_id: ID of the port to retrieve the expenses for.
            vessel_type_id: Vessel type ID.
            formula_calculation_date: Formula calculation date.
            vessel_class_id: Vessel class ID.
            operation_status: Operation status.
            historical_tce: Flag for historical TCE.
            estimation_status: Estimation status.

        Returns:
            The port expenses for model vessel or None if a port with given ID
            does not exist or a vessel type with the given ID number does not
            exist.
        """
        query_string: QueryString = {
            "portId": '{}'.format(port_id),
            "vesselTypeId": '{}'.format(vessel_type_id),
            "formulaCalculationDate": formula_calculation_date.isoformat(),
            "vesselClassId": '{}'.format(vessel_class_id),
            "operationStatus": '{}'.format(operation_status.value),
            "historicalTce": '{}'.format(historical_tce),
            "estimationStatus": '{}'.format(estimation_status.value)
        }

        response = self.__connection._make_post_request(
            "port-expenses/api/v1/PortModelVessel", query_string
        )
        response.raise_for_status()
        response_json = response.json()
        return_object = parse_port_expenses(response_json) \
            if response_json else None

        return return_object

    def get_required_formula_parameters(
        self, port_id: int, vessel_type_id: int,
            calculation_date: Optional[datetime] = None
    ) -> List[str]:
        """Retrieves required formula parameters.

        Args:
            port_id: ID of the port to retrieve the expenses for.
            vessel_type_id: Vessel type ID.
            calculation_date: Calculation date.

        Returns:
            List of required port expenses formula calculation parameters.
        """
        query_dict = {
            "portId": '{}'.format(port_id),
            "vesselTypeId": '{}'.format(vessel_type_id),
        }

        if calculation_date is not None:
            query_dict["calculationDate"] = calculation_date.isoformat()

        query_string: QueryString = query_dict
        response = self.__connection._make_post_request(
            "port-expenses/api/v1/RequiredFormulaParameters", query_string
        )
        response.raise_for_status()
        response_json = response.json()

        return cast(List[str], response_json)

    def get_vessel_types(self) -> Tuple[VesselType, ...]:
        """Retrieves all available vessel types.

        Returns:
            A tuple of all available vessel types.
        """
        vessel_types = tuple(VesselType(vessel_type.value, vessel_type.name)
                             for vessel_type in VesselTypeEnum)
        return vessel_types

    def get_ports(
        self, port_filter: Optional[PortFilter] = None
    ) -> Tuple[Port, ...]:
        """Retrieves available ports.

        Args:
            port_filter: A filter used to find specific ports. If not
                specified, returns all available ports.

        Returns:
            A tuple of available ports that match the filter.
        """
        query_dict = {
            "date": datetime.now().isoformat()
        }

        query_string: QueryString = query_dict

        available_ports: List[Port] = []
        for vessel_type in VesselTypeEnum:
            response = self.__connection._make_get_request(
                f"port-expenses/api/v1/AvailablePorts/{vessel_type.value}",
                query_string
            )
            response.raise_for_status()
            response_json = response.json()
            available_ports += parse_ports(response_json)

        port_filter = port_filter or PortFilter()

        return tuple(port_filter._apply(available_ports))

__init__(connection=None)

Initializes the Port Expenses API.

Parameters:

Name Type Description Default
connection Optional[Connection]

API connection configuration. If not provided, the default connection method is used.

None
Source code in signal_ocean/port_expenses/port_expenses_api.py
18
19
20
21
22
23
24
25
def __init__(self, connection: Optional[Connection] = None):
    """Initializes the Port Expenses API.

    Args:
        connection: API connection configuration. If not provided, the
            default connection method is used.
    """
    self.__connection = connection or Connection()

get_port_expenses(imo, port_id, vessel_type_id=None, estimated_time_of_berth=None, estimated_time_of_sail=None, operation=None, italian_anchorage_dues=None, cargo_type=None, operation_status=None, utc_date=None, historical_tce=None, estimation_status=None)

Retrieves port expenses.

Parameters:

Name Type Description Default
imo int

The vessel's IMO number.

required
port_id int

ID of the port to retrieve the expenses for.

required
vessel_type_id Optional[int]

Vessel type ID.

None
estimated_time_of_berth Optional[datetime]

Estimated time of berth.

None
estimated_time_of_sail Optional[datetime]

Estimated time of sail.

None
operation Optional[Operation]

Operation type.

None
italian_anchorage_dues Optional[ItalianAnchorageDues]

Italian anchorage dues.

None
cargo_type Optional[str]

Cargo type.

None
operation_status Optional[OperationStatus]

Operation status.

None
utc_date Optional[datetime]

UTC date.

None
historical_tce Optional[bool]

Flag for Historical TCE.

None
estimation_status Optional[EstimationStatus]

Estimation status.

None

Returns:

Type Description
Optional[PortExpenses]

The port expenses or None if a port with given ID does not exist or

Optional[PortExpenses]

a vessel with the given IMO number does not exist.

Source code in signal_ocean/port_expenses/port_expenses_api.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
def get_port_expenses(
    self, imo: int, port_id: int,
        vessel_type_id: Optional[int] = None,
        estimated_time_of_berth: Optional[datetime] = None,
        estimated_time_of_sail: Optional[datetime] = None,
        operation: Optional[Operation] = None,
        italian_anchorage_dues: Optional[ItalianAnchorageDues] = None,
        cargo_type: Optional[str] = None,
        operation_status: Optional[OperationStatus] = None,
        utc_date: Optional[datetime] = None,
        historical_tce: Optional[bool] = None,
        estimation_status: Optional[EstimationStatus] = None
) -> Optional[PortExpenses]:
    """Retrieves port expenses.

    Args:
        imo: The vessel's IMO number.
        port_id: ID of the port to retrieve the expenses for.
        vessel_type_id: Vessel type ID.
        estimated_time_of_berth: Estimated time of berth.
        estimated_time_of_sail: Estimated time of sail.
        operation: Operation type.
        italian_anchorage_dues: Italian anchorage dues.
        cargo_type: Cargo type.
        operation_status: Operation status.
        utc_date: UTC date.
        historical_tce: Flag for Historical TCE.
        estimation_status: Estimation status.

    Returns:
        The port expenses or None if a port with given ID does not exist or
        a vessel with the given IMO number does not exist.
    """
    query_dict = {
        "imo": '{}'.format(imo),
        "portId": '{}'.format(port_id)
    }

    if vessel_type_id is not None:
        query_dict["vesselTypeId"] = '{}'.format(vessel_type_id)
    if estimated_time_of_berth is not None:
        query_dict["estimatedTimeOfBerth"] = \
            estimated_time_of_berth.isoformat()
    if estimated_time_of_sail is not None:
        query_dict["estimatedTimeOfSail"] = \
            estimated_time_of_sail.isoformat()
    if operation is not None:
        query_dict["operation"] = '{}'.format(operation.value)
    if italian_anchorage_dues is not None:
        query_dict["italianAnchorageDues"] = \
            '{}'.format(italian_anchorage_dues.value)
    if cargo_type is not None:
        query_dict["cargoType"] = '{}'.format(cargo_type)
    if operation_status is not None:
        query_dict["operationStatus"] = '{}'.format(operation_status.value)
    if utc_date is not None:
        query_dict["utcDate"] = utc_date.isoformat()
    if historical_tce is not None:
        query_dict["historicalTce"] = '{}'.format(historical_tce)
    if estimation_status is not None:
        query_dict["estimationStatus"] = \
            '{}'.format(estimation_status.value)

    query_string: QueryString = query_dict
    response = self.__connection._make_post_request(
        "port-expenses/api/v1/Port", query_string
    )
    response.raise_for_status()
    response_json = response.json()
    return_object = parse_port_expenses(response_json) \
        if response_json else None

    return return_object

get_port_model_vessel_expenses(port_id, vessel_type_id, formula_calculation_date, vessel_class_id=0, operation_status=OperationStatus.BALLAST, historical_tce=False, estimation_status=EstimationStatus.PRIORITY_TO_FORMULAS)

Retrieves model vessel port expenses.

Parameters:

Name Type Description Default
port_id int

ID of the port to retrieve the expenses for.

required
vessel_type_id int

Vessel type ID.

required
formula_calculation_date datetime

Formula calculation date.

required
vessel_class_id int

Vessel class ID.

0
operation_status OperationStatus

Operation status.

BALLAST
historical_tce bool

Flag for historical TCE.

False
estimation_status EstimationStatus

Estimation status.

PRIORITY_TO_FORMULAS

Returns:

Type Description
Optional[PortExpenses]

The port expenses for model vessel or None if a port with given ID

Optional[PortExpenses]

does not exist or a vessel type with the given ID number does not

Optional[PortExpenses]

exist.

Source code in signal_ocean/port_expenses/port_expenses_api.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def get_port_model_vessel_expenses(
    self, port_id: int, vessel_type_id: int,
        formula_calculation_date: datetime, vessel_class_id: int = 0,
        operation_status: OperationStatus = OperationStatus.BALLAST,
        historical_tce: bool = False,
        estimation_status: EstimationStatus =
        EstimationStatus.PRIORITY_TO_FORMULAS) -> Optional[PortExpenses]:
    """Retrieves model vessel port expenses.

    Args:
        port_id: ID of the port to retrieve the expenses for.
        vessel_type_id: Vessel type ID.
        formula_calculation_date: Formula calculation date.
        vessel_class_id: Vessel class ID.
        operation_status: Operation status.
        historical_tce: Flag for historical TCE.
        estimation_status: Estimation status.

    Returns:
        The port expenses for model vessel or None if a port with given ID
        does not exist or a vessel type with the given ID number does not
        exist.
    """
    query_string: QueryString = {
        "portId": '{}'.format(port_id),
        "vesselTypeId": '{}'.format(vessel_type_id),
        "formulaCalculationDate": formula_calculation_date.isoformat(),
        "vesselClassId": '{}'.format(vessel_class_id),
        "operationStatus": '{}'.format(operation_status.value),
        "historicalTce": '{}'.format(historical_tce),
        "estimationStatus": '{}'.format(estimation_status.value)
    }

    response = self.__connection._make_post_request(
        "port-expenses/api/v1/PortModelVessel", query_string
    )
    response.raise_for_status()
    response_json = response.json()
    return_object = parse_port_expenses(response_json) \
        if response_json else None

    return return_object

get_ports(port_filter=None)

Retrieves available ports.

Parameters:

Name Type Description Default
port_filter Optional[PortFilter]

A filter used to find specific ports. If not specified, returns all available ports.

None

Returns:

Type Description
Tuple[Port, ...]

A tuple of available ports that match the filter.

Source code in signal_ocean/port_expenses/port_expenses_api.py
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
def get_ports(
    self, port_filter: Optional[PortFilter] = None
) -> Tuple[Port, ...]:
    """Retrieves available ports.

    Args:
        port_filter: A filter used to find specific ports. If not
            specified, returns all available ports.

    Returns:
        A tuple of available ports that match the filter.
    """
    query_dict = {
        "date": datetime.now().isoformat()
    }

    query_string: QueryString = query_dict

    available_ports: List[Port] = []
    for vessel_type in VesselTypeEnum:
        response = self.__connection._make_get_request(
            f"port-expenses/api/v1/AvailablePorts/{vessel_type.value}",
            query_string
        )
        response.raise_for_status()
        response_json = response.json()
        available_ports += parse_ports(response_json)

    port_filter = port_filter or PortFilter()

    return tuple(port_filter._apply(available_ports))

get_required_formula_parameters(port_id, vessel_type_id, calculation_date=None)

Retrieves required formula parameters.

Parameters:

Name Type Description Default
port_id int

ID of the port to retrieve the expenses for.

required
vessel_type_id int

Vessel type ID.

required
calculation_date Optional[datetime]

Calculation date.

None

Returns:

Type Description
List[str]

List of required port expenses formula calculation parameters.

Source code in signal_ocean/port_expenses/port_expenses_api.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
def get_required_formula_parameters(
    self, port_id: int, vessel_type_id: int,
        calculation_date: Optional[datetime] = None
) -> List[str]:
    """Retrieves required formula parameters.

    Args:
        port_id: ID of the port to retrieve the expenses for.
        vessel_type_id: Vessel type ID.
        calculation_date: Calculation date.

    Returns:
        List of required port expenses formula calculation parameters.
    """
    query_dict = {
        "portId": '{}'.format(port_id),
        "vesselTypeId": '{}'.format(vessel_type_id),
    }

    if calculation_date is not None:
        query_dict["calculationDate"] = calculation_date.isoformat()

    query_string: QueryString = query_dict
    response = self.__connection._make_post_request(
        "port-expenses/api/v1/RequiredFormulaParameters", query_string
    )
    response.raise_for_status()
    response_json = response.json()

    return cast(List[str], response_json)

get_vessel_types()

Retrieves all available vessel types.

Returns:

Type Description
Tuple[VesselType, ...]

A tuple of all available vessel types.

Source code in signal_ocean/port_expenses/port_expenses_api.py
175
176
177
178
179
180
181
182
183
def get_vessel_types(self) -> Tuple[VesselType, ...]:
    """Retrieves all available vessel types.

    Returns:
        A tuple of all available vessel types.
    """
    vessel_types = tuple(VesselType(vessel_type.value, vessel_type.name)
                         for vessel_type in VesselTypeEnum)
    return vessel_types

PortFilter dataclass

A filter used to find specific ports.

Attributes:

Name Type Description
name_like Optional[str]

Used to find ports by name. When specified, ports whose names partially match (contain) the attribute's value will be returned. Matching is case-insensitive.

Source code in signal_ocean/port_expenses/port_filter.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@dataclass(eq=False)
class PortFilter:
    """A filter used to find specific ports.

    Attributes:
        name_like: Used to find ports by name. When specified, ports whose
            names partially match (contain) the attribute's value will be
            returned. Matching is case-insensitive.
    """

    name_like: Optional[str] = None

    def _apply(self, ports: Iterable[Port]) -> Iterable[Port]:
        return filter(self.__does_port_match, ports)

    def __does_port_match(self, port: Port) -> bool:
        return not self.name_like or contains_caseless(
            self.name_like, port.name
        )

VesselType dataclass

A vessel type.

Attributes:

Name Type Description
id int

The vessel type id, e.g. 1 -> Tanker, 3 -> Dry, 4 -> Containers, 5 -> LNG (Liquified Natural gas), 6-> LPG (Liquified Petroleum Gas).

name str

The vessel type name, e.g. Tanker, Dry, Containers, LNG (Liquified Natural gas), LPG (Liquified Petroleum Gas).

Source code in signal_ocean/port_expenses/models.py
60
61
62
63
64
65
66
67
68
69
70
71
72
73
@dataclass(frozen=True)
class VesselType:
    """A vessel type.

    Attributes:
        id: The vessel type id, e.g. 1 -> Tanker, 3 -> Dry, 4 -> Containers,
            5 -> LNG (Liquified Natural gas),
            6-> LPG (Liquified Petroleum Gas).
        name: The vessel type name, e.g. Tanker, Dry, Containers,
            LNG (Liquified Natural gas), LPG (Liquified Petroleum Gas).
    """

    id: int
    name: str