Skip to main content

gtfs-blocks-to-transfers

Converts GTFS blocks, defined by setting trip.block_id into a series of trip-to-trip transfers (GTFS specification). Uses configurable heuristics to predict whether two trips are connected as in-seat transfers or as vehicle continuations only. This tool also validates predefined trip-to-trip transfers in transfers.txt.

Usage: ./convert.py <input feed> <directory for output>

Install

The easiest way to install the tool is to clone this repository, then run pip install -e .

If that doesn't work, try to run python3 manual_install.py.

Publishing

Package publishing is automated via GitHub Actions. Bump the version in pyproject.toml and merge to master to trigger publication to PyPI.

How it works

Throughout this tool, sets of service days are used to relate trips. They are defined in service_days.py, and are represented as a bitmap per service_id, with bit n set to 1 if that service operates on the nth day since the beginning of the feed. The term trip's service days refers to the service days for trip.service_id. If the first departure of a trip is after 24:00:00, the service days are stored as-if the trip began the next day between 00:00:00 and 23:59:59.

For each block defined in the feed, convert_blocks.py finds the most likely continuations for each trip, starting the search after the final arrival time of the trip. The program searches for a matching continuation for all of the trip's service days, greedily selecting continuation trips in order of wait time. Some days may remain unmatched if a configurable threshold is exceeded (config.TripToTripTransfers.max_wait_time). classify_transfers.py uses heuristics to assign transfer_type=4 (in-seat transfer) or transfer_type=5 to each continuation.

Generated transfers are combined with predefined transfers from transfers.txt in simplify_graph.py. If necessary, this step will split trips such that for any given from_trip_id, each of the potential to_trip_id, will operate on a disjoint set of service days. For example bus 50 could continue to bus 15 on Monday through Thursday, but continue to bus 20 on Fridays. Both generated and predefined transfers are validated to ensure they are unambiguous and conform to the specification.

simplify_export.py converts the continuation graph back to a series of transfers, resuing the feed's existing trip_ids and service_ids when an exact match can be found, or creating new entities if required. This step will preserve trip-to-trip transfers that don't represent vehicle continuations (e.g. transfer_type=2 used to estimate walk time between two vehicles).

Heuristics

An in-seat transfer is likely if:

  • Riders only need to wait a short time between trips.
  • The next trip begins at the same stop as the preceding trip ended, or the two stops are very close to each other.
  • The next trip goes a different destination than the preceding trip, or the two trips serve a loop route.

Riders probably won't be able to, or want to, to stay on board if:

  • The wait time aboard the bus is quite long.
  • The next trip is very similar to the preceding trip, but in reverse. We assess similarity by comparing the sequence of stop locations of the two trips using a modified Hausdorff metric.

You can adjust thresholds or entirely disable a heuristic in blocks_to_transfers/config.py. Configuration can also be provided as a JSON string with the --config argument.

Special continuations

Precise rules can also be added to enable or disable in-seat transfers for particular stops and routes within a feed.

A rule is a JSON object consisting of three parts:

  • match: A list of selectors.
  • op: The action to take on matching predicted continuations.
    • modify: Change the transfer_type.
    • More operations are planned in the future.
  • transfer_type: Only for modify operations. The new transfer_type to assign,
    • 4: in-seat transfer
    • 5: vehicle continuation only
    • (Transit's internal use) 104: in-seat transfer for trip planner only

The following selectors are supported:

  • All selectors will match any trip-to-trip transfers.
    • Example: {"all": true}
    • This selector may not be combined with any other selector.
  • Through selectors will match either the from_trip or the to_trip.
    • Example: {"through": {"route": "1", "stop": "Terminus Longueuil"}}
    • You can specify a route (route short name), a stop (stop name), or both.
    • This selector may not be combined with any other selector.
  • From selectors will match on the from_trip.
    • Example: {"from": {"route": "20", "last_stop": "Osachoff / White"}}
    • You can specify a route, a last_stop, or both.
  • To selectors will match on the to_trip.
    • Example: {"to": {"route": "5T", "first_stop": "Stewart Creek"}}
    • You can specify a route, a first_stop, or both.
  • From and to selectors can be combined to match a particular continuation between two trips].
    • Example: {"from": {"route": "124", "last_stop": "3rd / Pine"}, "to": {"route": "26", "first_stop": "3rd / Pine"}}

When a transfer matches multiple rules, the last rule wins. For transfers predicted from blocks, special continuation rules override all heuristics except max_wait_time. Rules never apply to predefined transfers specified using transfers.txt.

For example, to enable in-seat transfers only for routes 20 and 99 the following configuration can be set:

{
    "SpecialContinuations": [
        {
            "match": [
                {"all": true}
            ],
            "op": "modify",
            "transfer_type": 5
        },
        {
            "match": [
                {"through": {"route": "20"}},
                {"through": {"route": "99"}}
            ],
            "op": "modify"
            "transfer_type": 4
        }
    ]
} 

Advanced

  • simplify_linear.py: You probably don't want to enable this option, unless your system happens to have the same constraints described in this section. If enabled, trips will be split so that each trip has at most one incoming continuation, and at most one outgoing continuation. Where cycles exist (e.g. an automated people mover that serves trip 1 -> trip 2 -> trip 1 every day until the end of the feed), back edges are removed. Trips that decouple into multiple vehicles, or that are formed through the coupling of multiple vehicles are preserved as is.
  • Test cases can be found in the tests/ directory.
  • This program will run much faster using PyPy, a jitted interpreter for Python.

Metadata

Release files for gtfs-blocks-to-transfers 1.9.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gtfs-blocks-to-transfers 1.9.1
File Size Uploaded Provenance Actions
gtfs_blocks_to_transfers-1.9.1.tar.gz 23.8 kB With provenance Details for gtfs_blocks_to_transfers-1.9.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for gtfs-blocks-to-transfers 1.9.1
File Interpreter ABI Platform Actions
gtfs_blocks_to_transfers-1.9.1-py3-none-any.whl Python 3 none any Details for gtfs_blocks_to_transfers-1.9.1-py3-none-any.whl

Total release size: 50.1 kB

Release files / gtfs_blocks_to_transfers-1.9.1.tar.gz

Download URL gtfs_blocks_to_transfers-1.9.1.tar.gz
Size 23.8 kB
Tags Source
SHA-256 checksum
How to use checksums
6c136ca8a447e3feefa530e24e8c44a2a1827bb8a358a167b3242655bcfd319a
BLAKE2b-256 checksum
How to use checksums
4e90a6f8acbdd54e560bb83d9394df38b33f88278b5a0abcc7525c59685a8850
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / gtfs_blocks_to_transfers-1.9.1-py3-none-any.whl

Download URL gtfs_blocks_to_transfers-1.9.1-py3-none-any.whl
Size 26.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
10f23638d841707e1344bdc8c11fb0c51bec3da79ab38b41e7e006a067aea814
BLAKE2b-256 checksum
How to use checksums
47946eac9a6ff1fc5b738ea222e10030a0b9b78631f2ade5cae6331fa420215b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Security for gtfs-blocks-to-transfers 1.9.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for gtfs_blocks_to_transfers-1.9.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page