Skip to content

Data Models

Roadway

Tables

Datamodels for Roadway Network Tables.

This module contains the datamodels used to validate the format and types of Roadway Network tables.

Includes:

  • RoadLinksTable
  • RoadNodesTable
  • RoadShapesTable
  • ExplodedScopedLinkPropertyTable

ExplodedScopedLinkPropertyTable

Bases: DataFrameModel

Datamodel used to validate an exploded links_df by scope.

Source code in network_wrangler/models/roadway/tables.py
class ExplodedScopedLinkPropertyTable(DataFrameModel):
    """Datamodel used to validate an exploded links_df by scope."""

    model_link_id: Series[int]
    category: Series[Any]
    timespan: Series[list[str]]
    start_time: Series[dt.datetime]
    end_time: Series[dt.datetime]
    scoped: Series[Any] = pa.Field(default=None, nullable=True)

    class Config:
        """Config for ExplodedScopedLinkPropertySchema."""

        name = "ExplodedScopedLinkPropertySchema"
        coerce = True

Config

Config for ExplodedScopedLinkPropertySchema.

Source code in network_wrangler/models/roadway/tables.py
class Config:
    """Config for ExplodedScopedLinkPropertySchema."""

    name = "ExplodedScopedLinkPropertySchema"
    coerce = True

RoadLinksTable

Bases: DataFrameModel

Datamodel used to validate if links_df is of correct format and types.

Attributes:

Name Type Description
model_link_id int

Unique identifier for the link.

A int

model_node_id of the link’s start node. Foreign key to road_nodes.

B int

model_node_id of the link’s end node. Foreign key to road_nodes.

geometry GeoSeries

Warning: this attribute is controlled by wrangler and should not be explicitly user-edited. Simple A→B geometry of the link.

name str

Name of the link.

rail_only bool

If the link is only for rail. Default is False.

bus_only bool

If the link is only for buses. Default is False.

drive_access bool

If the link allows driving. Default is True.

bike_access bool

If the link allows biking. Default is True.

walk_access bool

If the link allows walking. Default is True.

truck_access bool

If the link allows trucks. Default is True.

distance float

Length of the link.

roadway str

Type of roadway per OSM definitions. Default is “road”.

projects str

Warning: this attribute is controlled by wrangler and should not be explicitly user-edited. Comma-separated list of project names applied to the link. Default is “”.

managed int

Warning: this attribute is controlled by wrangler and should not be explicitly user-edited. Indicator for the type of managed lane facility. Values can be:

  • 0 indicating no managed lane on this link.
  • 1 indicates that there is a managed lane on the link (std network) or that the link is a managed lane (model network).
  • -1 indicates that there is a parallel managed lane derived from this link (model network).
shape_id str

Identifier referencing the primary key of the shapes table. Default is None.

lanes int

Default number of lanes on the link. Default is 1.

sc_lanes Optional[list[dict]]

List of scoped link values for the number of lanes. Default is None. Example: [{'timespan':['12:00':'15:00'], 'value': 3},{'timespan':['15:00':'19:00'], 'value': 2}].

price float

Default price to use the link. Default is 0.

sc_price Optional[list[dict]]

List of scoped link values for the price. Default is None. Example: [{'timespan':['15:00':'19:00'],'category': 'sov', 'value': 2.5}].

ref Optional[str]

Reference numbers for link referring to a route or exit number per the OSM definition. Default is None.

access Optional[Any]

User-defined method to note access restrictions for the link. Default is None.

ML_projects Optional[str]

Warning: this attribute is controlled by wrangler and should not be explicitly user-edited. Comma-separated list of project names applied to the managed lane. Default is “”.

ML_lanes Optional[int]

Default number of lanes on the managed lane. Default is None.

ML_price Optional[float]

Default price to use the managed lane. Default is 0.

ML_access Optional[Any]

User-defined method to note access restrictions for the managed lane. Default is None.

ML_access_point Optional[bool]

If the link is an access point for the managed lane. Default is False.

ML_egress_point Optional[bool]

If the link is an egress point for the managed lane. Default is False.

sc_ML_lanes Optional[list[dict]]

List of scoped link values for the number of lanes on the managed lane. Default is None.

sc_ML_price Optional[list[dict]]

List of scoped link values for the price of the managed lane. Default is None.

sc_ML_access Optional[list[dict]]

List of scoped link values for the access restrictions of the managed lane. Default is None.

ML_geometry Optional[GeoSeries]

Warning: this attribute is controlled by wrangler and should not be explicitly user-edited. Simple A→B geometry of the managed lane. Default is None.

ML_shape_id Optional[str]

Identifier referencing the primary key of the shapes table for the managed lane. Default is None.

osm_link_id Optional[str]

Identifier referencing the OSM link ID. Default is “”.

GP_A Optional[int]

Warning: this attribute is controlled by wrangler and should not be explicitly user-edited. Identifier referencing the primary key of the associated general purpose link start node for a managed lane link in a model network. Default is None.

GP_B Optional[int]

Warning: this attribute is controlled by wrangler and should not be explicitly user-edited. Identifier referencing the primary key of the associated general purpose link end node for a managed lane link in a model network. Default is None.

User Defined Properties

Additional properites may be defined and are assumed to have the same definition of OpenStreetMap if they have overlapping property names.

Properties for parallel managed lanes

Properties for parallel managed lanes are prefixed with ML_. (Almost) any property, including an ad-hoc one, can be made to apply to a parallel managed lane by applying the prefix ML_, e.g. ML_lanes

Warning

The following properties should not be assigned an ML_ prefix by the user because they are assigned one within networkwrangler:

  • name
  • A
  • B
  • model_link_id
Time- or category-dependent properties

The following properties can be time-dependent, category-dependent, or both by adding sc_. The “plain” property without the prefix becomes the default when no scoped property applies.

Property # of Lanes Price
Default value lanes price
Time- and/or category-dependent value sc_lanes sc_price
Default value for managed lane ML_lanes ML_price
Time- and/or category-dependent value for managed lane sc_ML_lanes sc_ML_price
previous format for scoped properties

Some previous tooling was developed around a previous method for serializing scoped properties. In order to retain compatability with this format:

  • load_roadway_from_dir(), read_links(), and associated functions will “sniff” the network for the old format and apply the converter function translate_links_df_v0_to_v1()
  • write_links() has an boolean attribute to convert_complex_properties_to_single_field which can also be invoked from write_roadway() as convert_complex_link_properties_to_single_field.
Defining time-dependent properties

Time-dependent properties are defined as a list of dictionaries with timespans and values.

  • Timespans must be defined as a list of HH:MM or HH:MM:SS using a 24-hour clock: ('06:00':'09:00').
  • Timespans must not intersect.

Time-dependent property

$3 peak-period pricing

# default price
'price' = 0
'sc_price':
[
    {
        'time':['06:00':'09:00'],
        'value': 3
    },
    {
        'timespan':['16:00':'19:00'],
        'value': 3,
    }
]
Defining time- and category-dependent properties

Properties co-dependent on time- and category are defined as a list of dictionaries with value, category and time defined.

time- and category-dependent property

A pricing strategy which only applies in peak period for trucks and sovs:

# default price
"price": 0
# price scoped by time of day
"sc_price":
[
    {
        'timespan':['06:00':'09:00'],
        'category': ('sov','truck'),
        'value': 3
    },
    {
        'timespan':['16:00':'19:00'],
        'category': ('sov','truck'),
        'value': 3,
    }
]

Tip

There is no limit on other, user-defined properties being listed as time-dependent or time- and category-dependent.

User-defined variable by time of day

Define a variable access to represent which categories can access the network and vary it by time of day.

#access
{
    # default value for access
    'access': ('any'),
    # scoped value for access
    'sc_access': [
        {
            'timespan':['06:00':'09:00'],
            'value': ('no-trucks')
        },
        {
            'timespan':['16:00':'19:00'],
            'value': ('hov2','hov3','trucks')
        }
    ]
}
Source code in network_wrangler/models/roadway/tables.py
class RoadLinksTable(DataFrameModel):
    """Datamodel used to validate if links_df is of correct format and types.

    Attributes:
        model_link_id (int): Unique identifier for the link.
        A (int): `model_node_id` of the link's start node. Foreign key to `road_nodes`.
        B (int): `model_node_id` of the link's end node. Foreign key to `road_nodes`.
        geometry (GeoSeries): **Warning**: this attribute is controlled by wrangler and should not be explicitly user-edited.
            Simple A-->B geometry of the link.
        name (str): Name of the link.
        rail_only (bool): If the link is only for rail. Default is False.
        bus_only (bool): If the link is only for buses. Default is False.
        drive_access (bool): If the link allows driving. Default is True.
        bike_access (bool): If the link allows biking. Default is True.
        walk_access (bool): If the link allows walking. Default is True.
        truck_access (bool): If the link allows trucks. Default is True.
        distance (float): Length of the link.
        roadway (str): Type of roadway per [OSM definitions](https://wiki.openstreetmap.org/wiki/Key:highway#Roads).
            Default is "road".
        projects (str): **Warning**: this attribute is controlled by wrangler and should not be explicitly user-edited.
            Comma-separated list of project names applied to the link. Default is "".
        managed (int): **Warning**: this attribute is controlled by wrangler and should not be explicitly user-edited.
            Indicator for the type of managed lane facility. Values can be:

            - 0 indicating no managed lane on this link.
            - 1 indicates that there is a managed lane on the link (std network) or that the link is a
                managed lane (model network).
            - -1 indicates that there is a parallel managed lane derived from this link (model network).
        shape_id (str): Identifier referencing the primary key of the shapes table. Default is None.
        lanes (int): Default number of lanes on the link. Default is 1.
        sc_lanes (Optional[list[dict]]: List of scoped link values for the number of lanes. Default is None.
            Example: `[{'timespan':['12:00':'15:00'], 'value': 3},{'timespan':['15:00':'19:00'], 'value': 2}]`.

        price (float): Default price to use the link. Default is 0.
        sc_price (Optional[list[dict]]): List of scoped link values for the price. Default is None.
            Example: `[{'timespan':['15:00':'19:00'],'category': 'sov', 'value': 2.5}]`.
        ref (Optional[str]): Reference numbers for link referring to a route or exit number per the
            [OSM definition](https://wiki.openstreetmap.org/wiki/Key:ref). Default is None.
        access (Optional[Any]): User-defined method to note access restrictions for the link. Default is None.
        ML_projects (Optional[str]): **Warning**: this attribute is controlled by wrangler and should not be explicitly user-edited.
            Comma-separated list of project names applied to the managed lane. Default is "".
        ML_lanes (Optional[int]): Default number of lanes on the managed lane. Default is None.
        ML_price (Optional[float]): Default price to use the managed lane. Default is 0.
        ML_access (Optional[Any]): User-defined method to note access restrictions for the managed lane. Default is None.
        ML_access_point (Optional[bool]): If the link is an access point for the managed lane. Default is False.
        ML_egress_point (Optional[bool]): If the link is an egress point for the managed lane. Default is False.
        sc_ML_lanes (Optional[list[dict]]): List of scoped link values for the number of lanes on the managed lane.
            Default is None.
        sc_ML_price (Optional[list[dict]]): List of scoped link values for the price of the managed lane. Default is None.
        sc_ML_access (Optional[list[dict]]): List of scoped link values for the access restrictions of the managed lane.
            Default is None.
        ML_geometry (Optional[GeoSeries]): **Warning**: this attribute is controlled by wrangler and should not be explicitly user-edited.
            Simple A-->B geometry of the managed lane. Default is None.
        ML_shape_id (Optional[str]): Identifier referencing the primary key of the shapes table for the managed lane.
            Default is None.
        osm_link_id (Optional[str]): Identifier referencing the OSM link ID. Default is "".
        GP_A (Optional[int]): **Warning**: this attribute is controlled by wrangler and should not be explicitly user-edited.
            Identifier referencing the primary key of the associated general purpose link start node for
            a managed lane link in a model network. Default is None.
        GP_B (Optional[int]): **Warning**: this attribute is controlled by wrangler and should not be explicitly user-edited.
            Identifier referencing the primary key of the associated general purpose link end node for
            a managed lane link in a model network. Default is None.

    !!! tip "User Defined Properties"

        Additional properites may be defined and are assumed to have the same definition of OpenStreetMap if they
        have overlapping property names.

    ### Properties for parallel managed lanes

    Properties for parallel managed lanes are prefixed with `ML_`. (Almost) any property,
    including an ad-hoc one, can be made to apply to a parallel managed lane by applying
    the prefix `ML_`, e.g. `ML_lanes`

    !!! warning

        The following properties should **not** be assigned an `ML_` prefix by the user
        because they are assigned one within networkwrangler:

        - `name`
        - `A`
        - `B`
        - `model_link_id`

    ### Time- or category-dependent properties

    The following properties can be time-dependent, category-dependent, or both by adding `sc_`.
    The "plain" property without the prefix becomes the default when no scoped property applies.

    | Property | # of Lanes | Price |
    | -----------| ----------------- | ---------------- |
    | Default value | `lanes` | `price` |
    | Time- and/or category-dependent value | `sc_lanes` | `sc_price` |
    | Default value for managed lane | `ML_lanes` | `ML_price` |
    | Time- and/or category-dependent value for managed lane | `sc_ML_lanes` | `sc_ML_price` |


    ??? note "previous format for scoped properties"

        Some previous tooling was developed around a previous method for serializing scoped properties.  In order to retain compatability with this format:

        - `load_roadway_from_dir()`, `read_links()`, and associated functions will "sniff" the network for the old format and apply the converter function `translate_links_df_v0_to_v1()`
        - `write_links()` has an boolean attribute to `convert_complex_properties_to_single_field` which can also be invoked from `write_roadway()` as `convert_complex_link_properties_to_single_field`.

    #### Defining time-dependent properties

    Time-dependent properties are defined as a list of dictionaries with timespans and values.

    - Timespans must be defined as a list of HH:MM or HH:MM:SS using a 24-hour clock: `('06:00':'09:00')`.
    - Timespans must not intersect.

    !!! example  "Time-dependent property"

        $3 peak-period pricing

        ```python
        # default price
        'price' = 0
        'sc_price':
        [
            {
                'time':['06:00':'09:00'],
                'value': 3
            },
            {
                'timespan':['16:00':'19:00'],
                'value': 3,
            }
        ]
        ```

    #### Defining time- and category-dependent properties

    Properties co-dependent on time- and category are defined as a list of dictionaries with value, category and time defined.

    !!! example "time- and category-dependent property"

        A pricing strategy which only applies in peak period for trucks and sovs:

        ```python
        # default price
        "price": 0
        # price scoped by time of day
        "sc_price":
        [
            {
                'timespan':['06:00':'09:00'],
                'category': ('sov','truck'),
                'value': 3
            },
            {
                'timespan':['16:00':'19:00'],
                'category': ('sov','truck'),
                'value': 3,
            }
        ]
        ```

    !!! tip

        There is no limit on other, user-defined properties being listed as time-dependent or time- and category-dependent.

    !!! example "User-defined variable by time of day"

        Define a variable `access` to represent which categories can access the network and vary it by time of day.

        ```python
        #access
        {
            # default value for access
            'access': ('any'),
            # scoped value for access
            'sc_access': [
                {
                    'timespan':['06:00':'09:00'],
                    'value': ('no-trucks')
                },
                {
                    'timespan':['16:00':'19:00'],
                    'value': ('hov2','hov3','trucks')
                }
            ]
        }
        ```
    """

    model_link_id: Series[int] = pa.Field(coerce=True, unique=True)
    model_link_id_idx: Optional[Series[int]] = pa.Field(coerce=True, unique=True)
    A: Series[int] = pa.Field(nullable=False, coerce=True)
    B: Series[int] = pa.Field(nullable=False, coerce=True)
    geometry: GeoSeries = pa.Field(nullable=False)
    name: Series[str] = pa.Field(nullable=False, default="unknown")
    rail_only: Series[bool] = pa.Field(coerce=True, nullable=False, default=False)
    bus_only: Series[bool] = pa.Field(coerce=True, nullable=False, default=False)
    drive_access: Series[bool] = pa.Field(coerce=True, nullable=False, default=True)
    bike_access: Series[bool] = pa.Field(coerce=True, nullable=False, default=True)
    walk_access: Series[bool] = pa.Field(coerce=True, nullable=False, default=True)
    distance: Series[float] = pa.Field(coerce=True, nullable=False)

    roadway: Series[str] = pa.Field(nullable=False, default="road")
    projects: Series[str] = pa.Field(coerce=True, default="")
    managed: Series[int] = pa.Field(coerce=True, nullable=False, default=0)

    shape_id: Series[str] = pa.Field(coerce=True, nullable=True)
    lanes: Series[int] = pa.Field(coerce=True, nullable=False)
    price: Series[float] = pa.Field(coerce=True, nullable=False, default=0)

    # Optional Fields
    ref: Optional[Series[str]] = pa.Field(coerce=True, nullable=True, default=None)
    access: Optional[Series[Any]] = pa.Field(coerce=True, nullable=True, default=None)

    sc_lanes: Optional[Series[object]] = pa.Field(coerce=True, nullable=True, default=None)
    sc_price: Optional[Series[object]] = pa.Field(coerce=True, nullable=True, default=None)

    ML_projects: Series[str] = pa.Field(coerce=True, default="")
    ML_lanes: Optional[Series[Int64]] = pa.Field(coerce=True, nullable=True, default=None)
    ML_price: Optional[Series[float]] = pa.Field(coerce=True, nullable=True, default=0)
    ML_access: Optional[Series[Any]] = pa.Field(coerce=True, nullable=True, default=True)
    ML_access_point: Optional[Series[bool]] = pa.Field(
        coerce=True,
        default=False,
    )
    ML_egress_point: Optional[Series[bool]] = pa.Field(
        coerce=True,
        default=False,
    )
    sc_ML_lanes: Optional[Series[object]] = pa.Field(
        coerce=True,
        nullable=True,
        default=None,
    )
    sc_ML_price: Optional[Series[object]] = pa.Field(
        coerce=True,
        nullable=True,
        default=None,
    )
    sc_ML_access: Optional[Series[object]] = pa.Field(
        coerce=True,
        nullable=True,
        default=None,
    )

    ML_geometry: Optional[GeoSeries] = pa.Field(nullable=True, coerce=True, default=None)
    ML_shape_id: Optional[Series[str]] = pa.Field(nullable=True, coerce=True, default=None)

    truck_access: Optional[Series[bool]] = pa.Field(coerce=True, nullable=True, default=True)
    osm_link_id: Series[str] = pa.Field(coerce=True, nullable=True, default="")
    # todo this should be List[dict] but ranch output something else so had to have it be Any.
    locationReferences: Optional[Series[Any]] = pa.Field(
        coerce=True,
        nullable=True,
        default="",
    )

    GP_A: Optional[Series[Int64]] = pa.Field(coerce=True, nullable=True, default=None)
    GP_B: Optional[Series[Int64]] = pa.Field(coerce=True, nullable=True, default=None)

    class Config:
        """Config for RoadLinksTable."""

        add_missing_columns = True
        coerce = True
        unique: ClassVar[list[str]] = ["A", "B"]

    @pa.check("sc_*", regex=True, element_wise=True)
    def check_scoped_fields(cls, scoped_value: Series) -> Series[bool]:
        """Checks that all fields starting with 'sc_' or 'sc_ML_' are valid ScopedLinkValueList.

        Custom check to validate fields starting with 'sc_' or 'sc_ML_'
        against a ScopedLinkValueItem model, handling both mandatory and optional fields.
        """
        if scoped_value is None or (not isinstance(scoped_value, list) and pd.isna(scoped_value)):
            return True
        return validate_pyd(scoped_value, ScopedLinkValueList)

Config

Config for RoadLinksTable.

Source code in network_wrangler/models/roadway/tables.py
class Config:
    """Config for RoadLinksTable."""

    add_missing_columns = True
    coerce = True
    unique: ClassVar[list[str]] = ["A", "B"]

check_scoped_fields(scoped_value)

Checks that all fields starting with ‘sc_’ or ‘sc_ML_’ are valid ScopedLinkValueList.

Custom check to validate fields starting with ‘sc_’ or ‘sc_ML_’ against a ScopedLinkValueItem model, handling both mandatory and optional fields.

Source code in network_wrangler/models/roadway/tables.py
@pa.check("sc_*", regex=True, element_wise=True)
def check_scoped_fields(cls, scoped_value: Series) -> Series[bool]:
    """Checks that all fields starting with 'sc_' or 'sc_ML_' are valid ScopedLinkValueList.

    Custom check to validate fields starting with 'sc_' or 'sc_ML_'
    against a ScopedLinkValueItem model, handling both mandatory and optional fields.
    """
    if scoped_value is None or (not isinstance(scoped_value, list) and pd.isna(scoped_value)):
        return True
    return validate_pyd(scoped_value, ScopedLinkValueList)

RoadNodesTable

Bases: DataFrameModel

Datamodel used to validate if links_df is of correct format and types.

Must have a record for each node used by the links table and by the transit shapes, stop_times, and stops tables.

Attributes:

Name Type Description
model_node_id int

Unique identifier for the node.

osm_node_id Optional[str]

Reference to open street map node id. Used for querying. Not guaranteed to be unique.

X float

Longitude of the node in WGS84. Must be in the range of -180 to 180.

Y float

Latitude of the node in WGS84. Must be in the range of -90 to 90.

geometry GeoSeries

Warning: this attribute is controlled by wrangler and should not be explicitly user-edited.

Source code in network_wrangler/models/roadway/tables.py
class RoadNodesTable(DataFrameModel):
    """Datamodel used to validate if links_df is of correct format and types.

    Must have a record for each node used by the `links` table and by the transit `shapes`, `stop_times`, and `stops` tables.

    Attributes:
        model_node_id (int): Unique identifier for the node.
        osm_node_id (Optional[str]): Reference to open street map node id. Used for querying. Not guaranteed to be unique.
        X (float): Longitude of the node in WGS84. Must be in the range of -180 to 180.
        Y (float): Latitude of the node in WGS84. Must be in the range of -90 to 90.
        geometry (GeoSeries): **Warning**: this attribute is controlled by wrangler and should not be explicitly user-edited.
    """

    model_node_id: Series[int] = pa.Field(coerce=True, unique=True, nullable=False)
    model_node_idx: Optional[Series[int]] = pa.Field(coerce=True, unique=True, nullable=False)
    X: Series[float] = pa.Field(coerce=True, nullable=False)
    Y: Series[float] = pa.Field(coerce=True, nullable=False)
    geometry: GeoSeries

    # optional fields
    osm_node_id: Series[str] = pa.Field(
        coerce=True,
        nullable=True,
        default="",
    )
    projects: Series[str] = pa.Field(coerce=True, default="")
    inboundReferenceIds: Optional[Series[list[str]]] = pa.Field(coerce=True, nullable=True)
    outboundReferenceIds: Optional[Series[list[str]]] = pa.Field(coerce=True, nullable=True)

    class Config:
        """Config for RoadNodesTable."""

        add_missing_columns = True
        coerce = True
        _pk: ClassVar[TablePrimaryKeys] = ["model_node_id"]

Config

Config for RoadNodesTable.

Source code in network_wrangler/models/roadway/tables.py
class Config:
    """Config for RoadNodesTable."""

    add_missing_columns = True
    coerce = True
    _pk: ClassVar[TablePrimaryKeys] = ["model_node_id"]

RoadShapesTable

Bases: DataFrameModel

Datamodel used to validate if shapes_df is of correct format and types.

Should have a record for each shape_id referenced in links table.

Attributes:

Name Type Description
shape_id str

Unique identifier for the shape.

geometry GeoSeries

Warning: this attribute is controlled by wrangler and should not be explicitly user-edited. Geometry of the shape.

ref_shape_id Optional[str]

Reference to another shape_id that it may have been created from. Default is None.

Source code in network_wrangler/models/roadway/tables.py
class RoadShapesTable(DataFrameModel):
    """Datamodel used to validate if shapes_df is of correct format and types.

    Should have a record for each `shape_id` referenced in `links` table.

    Attributes:
        shape_id (str): Unique identifier for the shape.
        geometry (GeoSeries): **Warning**: this attribute is controlled by wrangler and should not be explicitly user-edited.
            Geometry of the shape.
        ref_shape_id (Optional[str]): Reference to another `shape_id` that it may
            have been created from. Default is None.
    """

    shape_id: Series[str] = pa.Field(unique=True)
    shape_id_idx: Optional[Series[int]] = pa.Field(unique=True)

    geometry: GeoSeries = pa.Field()
    ref_shape_id: Optional[Series] = pa.Field(nullable=True)

    class Config:
        """Config for RoadShapesTable."""

        coerce = True
        _pk: ClassVar[TablePrimaryKeys] = ["shape_id"]

Config

Config for RoadShapesTable.

Source code in network_wrangler/models/roadway/tables.py
class Config:
    """Config for RoadShapesTable."""

    coerce = True
    _pk: ClassVar[TablePrimaryKeys] = ["shape_id"]

Types

Complex roadway types defined using Pydantic models to facilitation validation.

LocationReferences = conlist(LocationReference, min_length=2) module-attribute

List of at least two LocationReferences which define a path.

LocationReference

Bases: BaseModel

SharedStreets-defined object for location reference.

Source code in network_wrangler/models/roadway/types.py
class LocationReference(BaseModel):
    """SharedStreets-defined object for location reference."""

    sequence: PositiveInt
    point: LatLongCoordinates
    bearing: float = Field(None, ge=-360, le=360)
    distanceToNextRef: NonNegativeFloat
    intersectionId: str

ScopedLinkValueItem

Bases: RecordModel

Define the value of a link property for a particular timespan or category.

Attributes:

Name Type Description
`category` str

Category or link user that this scoped value applies to, ex: HOV2, truck, etc. Categories are user-defined with the exception of any which is reserved as the default category. Default is DEFAULT_CATEGORY, which is all.

`timespan` list[TimeString]

timespan of the link property as defined as a list of two HH:MM(:SS) strings. Default is DEFAULT_TIMESPAN, which is ["00:00", "24:00"].

`value` Union[float, int, str]

Value of the link property for the given category and timespan.

Conflicting or matching scopes are not allowed in a list of ScopedLinkValueItems:

  • matching: a scope that could be applied for a given category/timespan combination. This includes the default scopes as well as scopes that are contained within the given category AND timespan combination.
  • overlapping: a scope that fully or partially overlaps a given category OR timespan combination. This includes the default scopes, all matching scopes and all scopes where at least one minute of timespan or one category overlap.
  • conflicting: a scope that is overlapping but not matching for a given category/timespan.

NOTE: Default scope values of category: any and timespan:["00:00", "24:00"] are not considered conflicting, but are applied to residual scopes.

Source code in network_wrangler/models/roadway/types.py
class ScopedLinkValueItem(RecordModel):
    """Define the value of a link property for a particular timespan or category.

    Attributes:
        `category` (str): Category or link user that this scoped value applies to, ex: `HOV2`,
            `truck`, etc.  Categories are user-defined with the exception of `any` which is
            reserved as the default category. Default is `DEFAULT_CATEGORY`, which is `all`.
        `timespan` (list[TimeString]): timespan of the link property as defined as a list of
            two HH:MM(:SS) strings. Default is `DEFAULT_TIMESPAN`, which is `["00:00", "24:00"]`.
        `value` (Union[float, int, str]): Value of the link property for the given category and
            timespan.

    Conflicting or matching scopes are not allowed in a list of ScopedLinkValueItems:

    - `matching`: a scope that could be applied for a given category/timespan combination. This includes the default scopes as well as scopes that are contained within the given category AND timespan combination.
    - `overlapping`: a scope that fully or partially overlaps a given category OR timespan combination.  This includes the default scopes, all `matching` scopes and all scopes where at least one minute of timespan or one category overlap.
    - `conflicting`: a scope that is overlapping but not matching for a given category/timespan.

    NOTE: Default scope values of `category: any` and `timespan:["00:00", "24:00"]` are **not** considered conflicting, but are applied to residual scopes.
    """

    require_any_of: ClassVar[AnyOf] = [["category", "timespan"]]
    model_config = ConfigDict(extra="forbid")
    category: Optional[Union[str, int]] = Field(default=DEFAULT_CATEGORY)
    timespan: Optional[list[TimeString]] = Field(default=DEFAULT_TIMESPAN)
    value: Union[int, float, str]

    @property
    def timespan_dt(self) -> list[list[datetime]]:
        """Convert timespan to list of datetime objects."""
        return str_to_time_list(self.timespan)

timespan_dt: list[list[datetime]] property

Convert timespan to list of datetime objects.

ScopedLinkValueList

Bases: RootListMixin, RootModel

List of non-conflicting ScopedLinkValueItems.

Source code in network_wrangler/models/roadway/types.py
class ScopedLinkValueList(RootListMixin, RootModel):
    """List of non-conflicting ScopedLinkValueItems."""

    root: list[ScopedLinkValueItem]

    def overlapping_timespans(self, timespan: Timespan):
        """Identify overlapping timespans in the list."""
        timespan_dt = str_to_time_list(timespan)
        return [i for i in self if dt_overlaps(i.timespan_dt, timespan_dt)]

    @model_validator(mode="after")
    def check_conflicting_scopes(self):
        """Check for conflicting scopes in the list."""
        conflicts = []
        for i in self:
            if i.timespan == DEFAULT_TIMESPAN:
                continue
            overlapping_ts_i = self.overlapping_timespans(i.timespan)
            for j in overlapping_ts_i:
                if j == i:
                    continue
                if j.category == i.category:
                    conflicts.append((i, j))
        if conflicts:
            msg = "Conflicting scopes in ScopedLinkValueList:\n"
            WranglerLogger.error(msg + f" Conflicts: \n{conflicts}")
            raise ScopeLinkValueError(msg)

        return self

check_conflicting_scopes()

Check for conflicting scopes in the list.

Source code in network_wrangler/models/roadway/types.py
@model_validator(mode="after")
def check_conflicting_scopes(self):
    """Check for conflicting scopes in the list."""
    conflicts = []
    for i in self:
        if i.timespan == DEFAULT_TIMESPAN:
            continue
        overlapping_ts_i = self.overlapping_timespans(i.timespan)
        for j in overlapping_ts_i:
            if j == i:
                continue
            if j.category == i.category:
                conflicts.append((i, j))
    if conflicts:
        msg = "Conflicting scopes in ScopedLinkValueList:\n"
        WranglerLogger.error(msg + f" Conflicts: \n{conflicts}")
        raise ScopeLinkValueError(msg)

    return self

overlapping_timespans(timespan)

Identify overlapping timespans in the list.

Source code in network_wrangler/models/roadway/types.py
def overlapping_timespans(self, timespan: Timespan):
    """Identify overlapping timespans in the list."""
    timespan_dt = str_to_time_list(timespan)
    return [i for i in self if dt_overlaps(i.timespan_dt, timespan_dt)]

Transit

Main functionality for GTFS tables including Feed object.

Feed

Bases: DBModelMixin

Wrapper class around Wrangler flavored GTFS feed.

Most functionality derives from mixin class DBModelMixin which provides:

  • validation of tables to schemas when setting a table attribute (e.g. self.trips = trips_df)
  • validation of fks when setting a table attribute (e.g. self.trips = trips_df)
  • hashing and deep copy functionality
  • overload of eq to apply only to tables in table_names.
  • convenience methods for accessing tables

Attributes:

Name Type Description
table_names list[str]

list of table names in GTFS feed.

tables list[DataFrame]

: list tables as dataframes.

stop_times DataFrame[WranglerStopTimesTable]

: stop_times dataframe with roadway node_ids

stops DataFrame[WranglerStopsTable]

stops dataframe

shapes(DataFrame[WranglerShapesTable]) DataFrame[WranglerStopsTable]

shapes dataframe

trips DataFrame[WranglerTripsTable]

trips dataframe

frequencies DataFrame[WranglerFrequenciesTable]

frequencies dataframe

routes DataFrame[RoutesTable]

route dataframe

agencies Optional[DataFrame[AgenciesTable]]

agencies dataframe

net Optional[TransitNetwork]

TransitNetwork object

Source code in network_wrangler/transit/feed/feed.py
class Feed(DBModelMixin):
    """Wrapper class around Wrangler flavored GTFS feed.

    Most functionality derives from mixin class DBModelMixin which provides:

    - validation of tables to schemas when setting a table attribute (e.g. self.trips = trips_df)
    - validation of fks when setting a table attribute (e.g. self.trips = trips_df)
    - hashing and deep copy functionality
    - overload of __eq__ to apply only to tables in table_names.
    - convenience methods for accessing tables

    Attributes:
        table_names (list[str]): list of table names in GTFS feed.
        tables (list[DataFrame]):: list tables as dataframes.
        stop_times (DataFrame[WranglerStopTimesTable]):: stop_times dataframe with roadway node_ids
        stops (DataFrame[WranglerStopsTable]):stops dataframe
        shapes(DataFrame[WranglerShapesTable]): shapes dataframe
        trips (DataFrame[WranglerTripsTable]): trips dataframe
        frequencies (DataFrame[WranglerFrequenciesTable]): frequencies dataframe
        routes (DataFrame[RoutesTable]): route dataframe
        agencies (Optional[DataFrame[AgenciesTable]]): agencies dataframe
        net (Optional[TransitNetwork]): TransitNetwork object
    """

    # the ordering here matters because the stops need to be added before stop_times if
    # stop times needs to be converted
    _table_models: ClassVar[dict] = {
        "agencies": AgenciesTable,
        "frequencies": WranglerFrequenciesTable,
        "routes": RoutesTable,
        "shapes": WranglerShapesTable,
        "stops": WranglerStopsTable,
        "trips": WranglerTripsTable,
        "stop_times": WranglerStopTimesTable,
    }

    # Define the converters if the table needs to be converted to a Wrangler table.
    # Format: "table_name": converter_function
    _converters: ClassVar[dict[str, Callable]] = {}

    table_names: ClassVar[list[str]] = [
        "frequencies",
        "routes",
        "shapes",
        "stops",
        "trips",
        "stop_times",
    ]

    optional_table_names: ClassVar[list[str]] = ["agencies"]

    def __init__(self, **kwargs):
        """Create a Feed object from a dictionary of DataFrames representing a GTFS feed.

        Args:
            kwargs: A dictionary containing DataFrames representing the tables of a GTFS feed.
        """
        self._net = None
        self.feed_path: Path = None
        self.initialize_tables(**kwargs)

        # Set extra provided attributes but just FYI in logger.
        extra_attr = {k: v for k, v in kwargs.items() if k not in self.table_names}
        if extra_attr:
            WranglerLogger.info(f"Adding additional attributes to Feed: {extra_attr.keys()}")
        for k, v in extra_attr:
            self.__setattr__(k, v)

    def set_by_id(
        self,
        table_name: str,
        set_df: pd.DataFrame,
        id_property: str = "index",
        properties: Optional[list[str]] = None,
    ):
        """Set one or more property values based on an ID property for a given table.

        Args:
            table_name (str): Name of the table to modify.
            set_df (pd.DataFrame): DataFrame with columns `<id_property>` and `value` containing
                values to set for the specified property where `<id_property>` is unique.
            id_property: Property to use as ID to set by. Defaults to "index".
            properties: List of properties to set which are in set_df. If not specified, will set
                all properties.
        """
        if not set_df[id_property].is_unique:
            msg = f"{id_property} must be unique in set_df."
            _dupes = set_df[id_property][set_df[id_property].duplicated()]
            WranglerLogger.error(msg + f"Found duplicates: {_dupes.sum()}")

            raise ValueError(msg)
        table_df = self.get_table(table_name)
        updated_df = update_df_by_col_value(table_df, set_df, id_property, properties=properties)
        self.__dict__[table_name] = updated_df

__init__(**kwargs)

Create a Feed object from a dictionary of DataFrames representing a GTFS feed.

Parameters:

Name Type Description Default
kwargs

A dictionary containing DataFrames representing the tables of a GTFS feed.

{}
Source code in network_wrangler/transit/feed/feed.py
def __init__(self, **kwargs):
    """Create a Feed object from a dictionary of DataFrames representing a GTFS feed.

    Args:
        kwargs: A dictionary containing DataFrames representing the tables of a GTFS feed.
    """
    self._net = None
    self.feed_path: Path = None
    self.initialize_tables(**kwargs)

    # Set extra provided attributes but just FYI in logger.
    extra_attr = {k: v for k, v in kwargs.items() if k not in self.table_names}
    if extra_attr:
        WranglerLogger.info(f"Adding additional attributes to Feed: {extra_attr.keys()}")
    for k, v in extra_attr:
        self.__setattr__(k, v)

set_by_id(table_name, set_df, id_property='index', properties=None)

Set one or more property values based on an ID property for a given table.

Parameters:

Name Type Description Default
table_name str

Name of the table to modify.

required
set_df DataFrame

DataFrame with columns <id_property> and value containing values to set for the specified property where <id_property> is unique.

required
id_property str

Property to use as ID to set by. Defaults to “index”.

'index'
properties Optional[list[str]]

List of properties to set which are in set_df. If not specified, will set all properties.

None
Source code in network_wrangler/transit/feed/feed.py
def set_by_id(
    self,
    table_name: str,
    set_df: pd.DataFrame,
    id_property: str = "index",
    properties: Optional[list[str]] = None,
):
    """Set one or more property values based on an ID property for a given table.

    Args:
        table_name (str): Name of the table to modify.
        set_df (pd.DataFrame): DataFrame with columns `<id_property>` and `value` containing
            values to set for the specified property where `<id_property>` is unique.
        id_property: Property to use as ID to set by. Defaults to "index".
        properties: List of properties to set which are in set_df. If not specified, will set
            all properties.
    """
    if not set_df[id_property].is_unique:
        msg = f"{id_property} must be unique in set_df."
        _dupes = set_df[id_property][set_df[id_property].duplicated()]
        WranglerLogger.error(msg + f"Found duplicates: {_dupes.sum()}")

        raise ValueError(msg)
    table_df = self.get_table(table_name)
    updated_df = update_df_by_col_value(table_df, set_df, id_property, properties=properties)
    self.__dict__[table_name] = updated_df

merge_shapes_to_stop_times(stop_times, shapes, trips)

Add shape_id and shape_pt_sequence to stop_times dataframe.

Parameters:

Name Type Description Default
stop_times DataFrame[WranglerStopTimesTable]

stop_times dataframe to add shape_id and shape_pt_sequence to.

required
shapes DataFrame[WranglerShapesTable]

shapes dataframe to add to stop_times.

required
trips DataFrame[WranglerTripsTable]

trips dataframe to link stop_times to shapes

required

Returns:

Type Description
DataFrame[WranglerStopTimesTable]

stop_times dataframe with shape_id and shape_pt_sequence added.

Source code in network_wrangler/transit/feed/feed.py
def merge_shapes_to_stop_times(
    stop_times: DataFrame[WranglerStopTimesTable],
    shapes: DataFrame[WranglerShapesTable],
    trips: DataFrame[WranglerTripsTable],
) -> DataFrame[WranglerStopTimesTable]:
    """Add shape_id and shape_pt_sequence to stop_times dataframe.

    Args:
        stop_times: stop_times dataframe to add shape_id and shape_pt_sequence to.
        shapes: shapes dataframe to add to stop_times.
        trips: trips dataframe to link stop_times to shapes

    Returns:
        stop_times dataframe with shape_id and shape_pt_sequence added.
    """
    stop_times_w_shape_id = stop_times.merge(
        trips[["trip_id", "shape_id"]], on="trip_id", how="left"
    )

    stop_times_w_shapes = stop_times_w_shape_id.merge(
        shapes,
        how="left",
        left_on=["shape_id", "stop_id"],
        right_on=["shape_id", "shape_model_node_id"],
    )
    stop_times_w_shapes = stop_times_w_shapes.drop(columns=["shape_model_node_id"])
    return stop_times_w_shapes

stop_count_by_trip(stop_times)

Returns dataframe with trip_id and stop_count from stop_times.

Source code in network_wrangler/transit/feed/feed.py
def stop_count_by_trip(
    stop_times: DataFrame[WranglerStopTimesTable],
) -> pd.DataFrame:
    """Returns dataframe with trip_id and stop_count from stop_times."""
    stops_count = stop_times.groupby("trip_id").size()
    return stops_count.reset_index(name="stop_count")

Pure GTFS Tables

Models for when you want to use vanilla (non wrangler) GTFS.

BikesAllowed

Bases: IntEnum

Indicates whether bicycles are allowed.

Source code in network_wrangler/models/gtfs/types.py
class BikesAllowed(IntEnum):
    """Indicates whether bicycles are allowed."""

    NO_INFORMATION = 0
    ALLOWED = 1
    NOT_ALLOWED = 2

DirectionID

Bases: IntEnum

Indicates the direction of travel for a trip.

Source code in network_wrangler/models/gtfs/types.py
class DirectionID(IntEnum):
    """Indicates the direction of travel for a trip."""

    OUTBOUND = 0
    INBOUND = 1

LocationType

Bases: IntEnum

Indicates the type of node the stop record represents.

Full documentation: https://gtfs.org/schedule/reference/#stopstxt

Source code in network_wrangler/models/gtfs/types.py
class LocationType(IntEnum):
    """Indicates the type of node the stop record represents.

    Full documentation: https://gtfs.org/schedule/reference/#stopstxt
    """

    STOP_PLATFORM = 0
    STATION = 1
    ENTRANCE_EXIT = 2
    GENERIC_NODE = 3
    BOARDING_AREA = 4

MockPaModel

Mock model for when Pandera is not installed.

Source code in network_wrangler/models/gtfs/__init__.py
class MockPaModel:
    """Mock model for when Pandera is not installed."""

    def __init__(self, **kwargs):
        """Mock modle initiation."""
        for key, value in kwargs.items():
            setattr(self, key, value)

__init__(**kwargs)

Mock modle initiation.

Source code in network_wrangler/models/gtfs/__init__.py
def __init__(self, **kwargs):
    """Mock modle initiation."""
    for key, value in kwargs.items():
        setattr(self, key, value)

PickupDropoffType

Bases: IntEnum

Indicates the pickup method for passengers at a stop.

Full documentation: https://gtfs.org/schedule/reference

Source code in network_wrangler/models/gtfs/types.py
class PickupDropoffType(IntEnum):
    """Indicates the pickup method for passengers at a stop.

    Full documentation: https://gtfs.org/schedule/reference
    """

    REGULAR = 0
    NONE = 1
    PHONE_AGENCY = 2
    COORDINATE_WITH_DRIVER = 3

RouteType

Bases: IntEnum

Indicates the type of transportation used on a route.

Full documentation: https://gtfs.org/schedule/reference

Source code in network_wrangler/models/gtfs/types.py
class RouteType(IntEnum):
    """Indicates the type of transportation used on a route.

    Full documentation: https://gtfs.org/schedule/reference
    """

    TRAM = 0
    SUBWAY = 1
    RAIL = 2
    BUS = 3
    FERRY = 4
    CABLE_TRAM = 5
    AERIAL_LIFT = 6
    FUNICULAR = 7
    TROLLEYBUS = 11
    MONORAIL = 12

TimepointType

Bases: IntEnum

Indicates whether the specified time is exact or approximate.

Full documentation: https://gtfs.org/schedule/reference

Source code in network_wrangler/models/gtfs/types.py
class TimepointType(IntEnum):
    """Indicates whether the specified time is exact or approximate.

    Full documentation: https://gtfs.org/schedule/reference
    """

    APPROXIMATE = 0
    EXACT = 1

WheelchairAccessible

Bases: IntEnum

Indicates whether the trip is wheelchair accessible.

Full documentation: https://gtfs.org/schedule/reference

Source code in network_wrangler/models/gtfs/types.py
class WheelchairAccessible(IntEnum):
    """Indicates whether the trip is wheelchair accessible.

    Full documentation: https://gtfs.org/schedule/reference
    """

    NO_INFORMATION = 0
    POSSIBLE = 1
    NOT_POSSIBLE = 2

Project Cards

Projects

Bases: RecordModel

Requirements for describing roadway deletion project card (e.g. to delete).

Source code in network_wrangler/models/projects/roadway_changes.py
class RoadwayDeletion(RecordModel):
    """Requirements for describing roadway deletion project card (e.g. to delete)."""

    require_any_of: ClassVar[AnyOf] = [["links", "nodes"]]
    model_config = ConfigDict(extra="forbid")

    links: Optional[SelectLinksDict] = None
    nodes: Optional[SelectNodesDict] = None
    clean_shapes: bool = False
    clean_nodes: bool = False

    @field_validator("links")
    @classmethod
    def set_to_all_modes(cls, links: Optional[SelectLinksDict] = None):
        """Set the search mode to 'any' if not specified explicitly."""
        if links is not None and links.modes == DEFAULT_SEARCH_MODES:
            links.modes = DEFAULT_DELETE_MODES
        return links

set_to_all_modes(links=None) classmethod

Set the search mode to ‘any’ if not specified explicitly.

Source code in network_wrangler/models/projects/roadway_changes.py
@field_validator("links")
@classmethod
def set_to_all_modes(cls, links: Optional[SelectLinksDict] = None):
    """Set the search mode to 'any' if not specified explicitly."""
    if links is not None and links.modes == DEFAULT_SEARCH_MODES:
        links.modes = DEFAULT_DELETE_MODES
    return links

Bases: RecordModel

Value for setting property value for a time of day and category.

Source code in network_wrangler/models/projects/roadway_changes.py
class RoadPropertyChange(RecordModel):
    """Value for setting property value for a time of day and category."""

    model_config = ConfigDict(extra="forbid", exclude_none=True)

    existing: Optional[Any] = None
    change: Optional[Union[int, float]] = None
    set: Optional[Any] = None
    scoped: Optional[Union[None, ScopedPropertySetList]] = None
    overwrite_scoped: Optional[Literal["conflicting", "all", "error"]] = None
    existing_value_conflict: Optional[Literal["error", "warn", "skip"]] = None

    require_one_of: ClassVar[OneOf] = [
        ["change", "set"],
    ]

    _examples: ClassVar[list] = [
        {"set": 1},
        {"existing": 2, "change": -1},
        {
            "set": 0,
            "scoped": [
                {"timespan": ["6:00", "9:00"], "value": 2.0},
                {"timespan": ["9:00", "15:00"], "value": 4.0},
            ],
        },
        {
            "set": 0,
            "scoped": [
                {
                    "categories": ["hov3", "hov2"],
                    "timespan": ["6:00", "9:00"],
                    "value": 2.0,
                },
                {"category": "truck", "timespan": ["6:00", "9:00"], "value": 4.0},
            ],
        },
        {
            "set": 0,
            "scoped": [
                {"categories": ["hov3", "hov2"], "value": 2.0},
                {"category": "truck", "value": 4.0},
            ],
        },
    ]

Roadway Selections

Data models for selecting roadway facilities in a project card.

RoadwaySelectionFormatError

Bases: Exception

Raised when there is an issue with the format of a selection.

Source code in network_wrangler/models/projects/roadway_selection.py
class RoadwaySelectionFormatError(Exception):
    """Raised when there is an issue with the format of a selection."""

SelectFacility

Bases: RecordModel

Roadway Facility Selection.

Source code in network_wrangler/models/projects/roadway_selection.py
class SelectFacility(RecordModel):
    """Roadway Facility Selection."""

    require_one_of: ClassVar[OneOf] = [
        ["links", "nodes", ["links", "from", "to"]],
    ]
    model_config = ConfigDict(extra="forbid")

    links: Optional[SelectLinksDict] = None
    nodes: Optional[SelectNodesDict] = None
    from_: Annotated[Optional[SelectNodeDict], Field(None, alias="from")]
    to: Optional[SelectNodeDict] = None

    _examples: ClassVar[list[dict]] = [
        {
            "links": {"name": ["Main Street"]},
            "from": {"model_node_id": 1},
            "to": {"model_node_id": 2},
        },
        {"nodes": {"osm_node_id": ["1", "2", "3"]}},
        {"nodes": {"model_node_id": [1, 2, 3]}},
        {"links": {"model_link_id": [1, 2, 3]}},
    ]

SelectLinksDict

Bases: RecordModel

requirements for describing links in the facility section of a project card.

Examples:

    {'name': ['Main St'], 'modes': ['drive']}
    {'osm_link_id': ['123456789']}
    {'model_link_id': [123456789], 'modes': ['walk']}
    {'all': 'True', 'modes': ['transit']}
    {'all': 'True', name': ['Main St']}
Source code in network_wrangler/models/projects/roadway_selection.py
class SelectLinksDict(RecordModel):
    """requirements for describing links in the `facility` section of a project card.

    Examples:
    ```python
        {'name': ['Main St'], 'modes': ['drive']}
        {'osm_link_id': ['123456789']}
        {'model_link_id': [123456789], 'modes': ['walk']}
        {'all': 'True', 'modes': ['transit']}
        {'all': 'True', name': ['Main St']}
    ```

    """

    require_conflicts: ClassVar[ConflictsWith] = [
        ["all", "osm_link_id"],
        ["all", "model_link_id"],
        ["all", "name"],
        ["all", "ref"],
        ["osm_link_id", "model_link_id"],
        ["osm_link_id", "name"],
        ["model_link_id", "name"],
    ]
    require_any_of: ClassVar[AnyOf] = [["name", "ref", "osm_link_id", "model_link_id", "all"]]

    model_config = ConfigDict(extra="allow")

    all: Optional[bool] = False
    name: Annotated[Optional[list[str]], Field(None, min_length=1)]
    ref: Annotated[Optional[list[str]], Field(None, min_length=1)]
    osm_link_id: Annotated[Optional[list[str]], Field(None, min_length=1)]
    model_link_id: Annotated[Optional[list[int]], Field(None, min_length=1)]
    modes: list[str] = DEFAULT_SEARCH_MODES
    ignore_missing: Optional[bool] = True

    _examples: ClassVar[list[dict]] = [
        {"name": ["Main St"], "modes": ["drive"]},
        {"osm_link_id": ["123456789"]},
        {"model_link_id": [123456789], "modes": ["walk"]},
        {"all": "True", "modes": ["transit"]},
    ]

SelectNodeDict

Bases: RecordModel

Selection of a single roadway node in the facility section of a project card.

Source code in network_wrangler/models/projects/roadway_selection.py
class SelectNodeDict(RecordModel):
    """Selection of a single roadway node in the `facility` section of a project card."""

    require_one_of: ClassVar[OneOf] = [["osm_node_id", "model_node_id"]]
    model_config = ConfigDict(extra="allow")

    osm_node_id: Optional[str] = None
    model_node_id: Optional[int] = None

    _examples: ClassVar[list[dict]] = [{"osm_node_id": "12345"}, {"model_node_id": 67890}]

SelectNodesDict

Bases: RecordModel

Requirements for describing multiple nodes of a project card (e.g. to delete).

Source code in network_wrangler/models/projects/roadway_selection.py
class SelectNodesDict(RecordModel):
    """Requirements for describing multiple nodes of a project card (e.g. to delete)."""

    require_any_of: ClassVar[AnyOf] = [["osm_node_id", "model_node_id"]]
    model_config = ConfigDict(extra="forbid")

    all: Optional[bool] = False
    osm_node_id: Annotated[Optional[list[str]], Field(None, min_length=1)]
    model_node_id: Annotated[Optional[list[int]], Field(min_length=1)]
    ignore_missing: Optional[bool] = True

    _examples: ClassVar[list[dict]] = [
        {"osm_node_id": ["12345", "67890"], "model_node_id": [12345, 67890]},
        {"osm_node_id": ["12345", "67890"]},
        {"model_node_id": [12345, 67890]},
    ]

Transit Selections

Data Models for selecting transit trips, nodes, links, and routes.

SelectRouteProperties

Bases: RecordModel

Selection properties for transit routes.

Source code in network_wrangler/models/projects/transit_selection.py
class SelectRouteProperties(RecordModel):
    """Selection properties for transit routes."""

    route_short_name: Annotated[Optional[list[ForcedStr]], Field(None, min_length=1)]
    route_long_name: Annotated[Optional[list[ForcedStr]], Field(None, min_length=1)]
    agency_id: Annotated[Optional[list[ForcedStr]], Field(None, min_length=1)]
    route_type: Annotated[Optional[list[int]], Field(None, min_length=1)]

    model_config = ConfigDict(
        extra="allow",
        validate_assignment=True,
        exclude_none=True,
        protected_namespaces=(),
    )

Bases: RecordModel

Requirements for describing multiple transit links of a project card.

Source code in network_wrangler/models/projects/transit_selection.py
class SelectTransitLinks(RecordModel):
    """Requirements for describing multiple transit links of a project card."""

    require_one_of: ClassVar[OneOf] = [
        ["ab_nodes", "model_link_id"],
    ]

    model_link_id: Annotated[Optional[list[int]], Field(min_length=1)] = None
    ab_nodes: Annotated[Optional[list[TransitABNodesModel]], Field(min_length=1)] = None
    require: Optional[SelectionRequire] = "any"

    model_config = ConfigDict(
        extra="forbid",
        validate_assignment=True,
        exclude_none=True,
        protected_namespaces=(),
    )
    _examples: ClassVar[list[dict]] = [
        {
            "ab_nodes": [{"A": "75520", "B": "66380"}, {"A": "66380", "B": "75520"}],
            "type": "any",
        },
        {
            "model_link_id": [123, 321],
            "type": "all",
        },
    ]

SelectTransitNodes

Bases: RecordModel

Requirements for describing multiple transit nodes of a project card (e.g. to delete).

Source code in network_wrangler/models/projects/transit_selection.py
class SelectTransitNodes(RecordModel):
    """Requirements for describing multiple transit nodes of a project card (e.g. to delete)."""

    require_any_of: ClassVar[AnyOf] = [
        [
            "model_node_id",
            # "gtfs_stop_id", TODO Not implemented
        ]
    ]

    # gtfs_stop_id: Annotated[Optional[List[ForcedStr]], Field(None, min_length=1)] TODO Not implemented
    model_node_id: Annotated[list[int], Field(min_length=1)]
    require: Optional[SelectionRequire] = "any"

    model_config = ConfigDict(
        extra="forbid",
        validate_assignment=True,
        exclude_none=True,
        protected_namespaces=(),
    )

    _examples: ClassVar[list[dict]] = [
        # {"gtfstop_id": ["stop1", "stop2"], "require": "any"},  TODO Not implemented
        {"model_node_id": [1, 2], "require": "all"},
    ]

SelectTransitTrips

Bases: RecordModel

Selection properties for transit trips.

Source code in network_wrangler/models/projects/transit_selection.py
class SelectTransitTrips(RecordModel):
    """Selection properties for transit trips."""

    trip_properties: Optional[SelectTripProperties] = None
    route_properties: Optional[SelectRouteProperties] = None
    timespans: Annotated[Optional[list[TimespanString]], Field(None, min_length=1)]
    nodes: Optional[SelectTransitNodes] = None
    links: Optional[SelectTransitLinks] = None

    model_config = ConfigDict(
        extra="forbid",
        validate_assignment=True,
        exclude_none=True,
        protected_namespaces=(),
    )

SelectTripProperties

Bases: RecordModel

Selection properties for transit trips.

Source code in network_wrangler/models/projects/transit_selection.py
class SelectTripProperties(RecordModel):
    """Selection properties for transit trips."""

    trip_id: Annotated[Optional[list[ForcedStr]], Field(None, min_length=1)]
    shape_id: Annotated[Optional[list[ForcedStr]], Field(None, min_length=1)]
    direction_id: Annotated[Optional[int], Field(None)]
    service_id: Annotated[Optional[list[ForcedStr]], Field(None, min_length=1)]
    route_id: Annotated[Optional[list[ForcedStr]], Field(None, min_length=1)]
    trip_short_name: Annotated[Optional[list[ForcedStr]], Field(None, min_length=1)]

    model_config = ConfigDict(
        extra="allow",
        validate_assignment=True,
        exclude_none=True,
        protected_namespaces=(),
    )

TransitABNodesModel

Bases: RecordModel

Single transit link model.

Source code in network_wrangler/models/projects/transit_selection.py
class TransitABNodesModel(RecordModel):
    """Single transit link model."""

    A: Optional[int] = None  # model_node_id
    B: Optional[int] = None  # model_node_id

    model_config = ConfigDict(
        extra="forbid",
        validate_assignment=True,
        exclude_none=True,
        protected_namespaces=(),
    )