Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2nd iteration on GTFS adaptation #961

Merged
merged 8 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
authors = ["Hove <core@hove.com>", "Guillaume Pinot <texitoi@texitoi.eu>"]
name = "transit_model"
version = "0.67.0"
version = "0.68.0"
license = "AGPL-3.0-only"
description = "Transit data management"
repository = "https://github.com/hove-io/transit_model"
Expand Down Expand Up @@ -39,7 +39,7 @@ parser = []
[dependencies]
anyhow = "1"
chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }
chrono-tz = { version = "0.9", features = ["serde"] }
chrono-tz = { version = "0.10", features = ["serde"] }
csv = "1"
derivative = "2"
geo = "0.28"
Expand Down
8 changes: 6 additions & 2 deletions gtfs2netexfr/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use tracing_subscriber::{
layer::SubscriberExt as _,
util::SubscriberInitExt as _,
};
use transit_model::{configuration, Result};
use transit_model::{configuration, objects::VehicleJourneyScheduleType, Model, Result};

lazy_static::lazy_static! {
pub static ref GIT_VERSION: String = transit_model::binary_full_version(env!("CARGO_PKG_VERSION"));
Expand Down Expand Up @@ -115,7 +115,11 @@ fn run(opt: Opt) -> Result<()> {
..Default::default()
};

let model = transit_model::gtfs::Reader::new(configuration).parse(opt.input)?;
let mut collections =
transit_model::gtfs::Reader::new(configuration).parse_collections(opt.input)?;
collections
.filter_by_vj_schedule_types(vec![VehicleJourneyScheduleType::ArrivalDepartureTimesOnly])?;
let model = Model::new(collections)?;

let mut config = transit_model::netex_france::WriteConfiguration::new(opt.participant)
.current_datetime(opt.current_datetime);
Expand Down
6 changes: 3 additions & 3 deletions ntfs2gtfs/tests/fixtures/output/stop_times.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
trip_id,arrival_time,departure_time,stop_id,stop_sequence,pickup_type,drop_off_type,local_zone_id,stop_headsign,timepoint
trip:1,09:00:00,09:00:00,stop:point:1,0,0,1,,,1
trip:1,09:10:00,09:10:00,stop:point:2,2,1,0,,,1
trip_id,arrival_time,departure_time,start_pickup_drop_off_window,end_pickup_drop_off_window,stop_id,stop_sequence,pickup_type,drop_off_type,local_zone_id,stop_headsign,timepoint,pickup_booking_rule_id,drop_off_booking_rule_id
trip:1,09:00:00,09:00:00,,,stop:point:1,0,0,1,,,1,,
trip:1,09:10:00,09:10:00,,,stop:point:2,2,1,0,,,1,,
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
agency_id,agency_name,agency_url,agency_timezone,agency_lang,agency_phone,agency_email,agency_fare_url
MFDI:1061,Vélizy Vallées,http://www.navitia.io/,Europe/Paris,,,,
MFDI:1071,Roissy Ouest,http://www.navitia.io/,Europe/Paris,,,,
MFDI:1062,Saint Germain Boucles de Seine,http://www.navitia.io/,Europe/Paris,,,,
MFDI:Operator_100,RATP,http://www.navitia.io/,Europe/Paris,,,,
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
id,booking_type,message,phone_number,info_url,booking_url
MFDI:10,0,"Bus de soirée : Le service fonctionne sans réservation, il suffit d'indiquer l'arrêt de descente au conducteur",,,
MFDI:11,0,24h/24 et 7j/7,01 74 37 24 77,https://www.fileo.com/se-deplacer/reserver-votre-fileo/,https://www.fileo.com/tad
MFDI:12,0,,,,
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
route_id,agency_id,route_short_name,route_long_name,route_desc,route_type,route_url,route_color,route_text_color,route_sort_order
MFDI:C01376,MFDI:Operator_100,6,6,,1,,6ECA97,000000,
MFDI:C02060,MFDI:1071,Filéo RS,Filéo Roissy Sud - Villeparisis et Mitry (sur réservation),,3,,4890CD,FFFFFF,
MFDI:C02491,MFDI:1062,Soir,Soir Saint-Germain-en-Laye,,3,,652C8F,FFFFFF,
MFDI:C02513,MFDI:1061,Soir,Soir Versailles-Chantiers,,3,,640082,FFFFFF,
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
object_id,object_system,object_code
MFDI:22167,source,FR::Quay:22167:FR1
MFDI:22173,source,FR::Quay:22173:FR1
MFDI:22073,source,FR::Quay:22073:FR1
MFDI:41403,source,FR::Quay:41403:FR1
MFDI:463194,source,FR::Quay:463194:FR1
MFDI:463042,source,FR::Quay:463042:FR1
MFDI:426813,source,FR::Quay:426813:FR1
MFDI:426214,source,FR::Quay:426214:FR1
MFDI:477725,source,FR::Quay:477725:FR1
MFDI:34582,source,FR::Quay:34582:FR1
MFDI:38175,source,FR::Quay:38175:FR1
MFDI:461909,source,FR::Quay:461909:FR1
MFDI:18995,source,FR::Quay:18995:FR1
MFDI:34605,source,FR::Quay:34605:FR1
MFDI:34744,source,FR::Quay:34744:FR1
MFDI:11584,source,FR::Quay:11584:FR1
MFDI:14081,source,FR::Quay:14081:FR1
MFDI:20324,source,FR::Quay:20324:FR1
MFDI:20312,source,FR::Quay:20312:FR1
MFDI:485179,source,FR::Quay:485179:FR1
MFDI:461827,source,FR::multimodalStopPlace:461827:FR1
MFDI:426072,source,FR::multimodalStopPlace:426072:FR1
MFDI:71639,source,FR::multimodalStopPlace:71639:FR1
MFDI:71673,source,FR::multimodalStopPlace:71673:FR1
MFDI:64589,source,FR::multimodalStopPlace:64589:FR1
MFDI:63880,source,FR::multimodalStopPlace:63880:FR1
MFDI:71026,source,FR::multimodalStopPlace:71026:FR1
MFDI:64509,source,FR::multimodalStopPlace:64509:FR1
MFDI:64485,source,FR::multimodalStopPlace:64485:FR1
MFDI:63534,source,FR::multimodalStopPlace:63534:FR1
MFDI:63529,source,FR::multimodalStopPlace:63529:FR1
MFDI:63438,source,FR::multimodalStopPlace:63438:FR1
MFDI:73556,source,FR::multimodalStopPlace:73556:FR1
MFDI:73596,source,FR::multimodalStopPlace:73596:FR1
MFDI:73591,source,FR::multimodalStopPlace:73591:FR1
MFDI:71347,source,FR::multimodalStopPlace:71347:FR1
MFDI:73486,source,FR::multimodalStopPlace:73486:FR1
MFDI:71199,source,FR::multimodalStopPlace:71199:FR1
MFDI:480959,source,FR::multimodalStopPlace:480959:FR1
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
trip_id,arrival_time,departure_time,start_pickup_drop_off_window,end_pickup_drop_off_window,stop_id,stop_sequence,pickup_type,drop_off_type,local_zone_id,stop_headsign,timepoint,pickup_booking_rule_id,drop_off_booking_rule_id
MFDI:KVVB:158023-C02513-1638-260,22:30:00,22:31:00,,,MFDI:485179,0,0,1,,,1,,
MFDI:KVVB:158023-C02513-1638-260,22:33:00,22:34:00,,,MFDI:426214,1,0,0,,,1,,
MFDI:KVVB:158023-C02513-1638-260,,,22:36:00,22:55:00,MFDI:20312,12,1,2,,,0,MFDI:10,MFDI:10
MFDI:KVVB:158023-C02513-1638-260,,,22:36:00,22:55:00,MFDI:20324,24,1,2,,,0,MFDI:10,MFDI:10
MFDI:KVVB:158023-C02513-1638-260,,,22:36:00,22:55:00,MFDI:11584,32,1,2,,,0,MFDI:10,MFDI:10
MFDI:BOUCLE_DE_LYS:149996-C02491-18777678,,,23:15:00,23:48:00,MFDI:34605,0,2,1,,,0,MFDI:12,MFDI:12
MFDI:BOUCLE_DE_LYS:149996-C02491-18777678,,,23:15:00,23:48:00,MFDI:34744,1,2,2,,,0,MFDI:12,MFDI:12
MFDI:BOUCLE_DE_LYS:149996-C02491-18777678,,,23:15:00,23:48:00,MFDI:14081,15,2,2,,,0,MFDI:12,MFDI:12
MFDI:BOUCLE_DE_LYS:149996-C02491-18777678,,,23:15:00,23:48:00,MFDI:34582,25,2,2,,,0,MFDI:12,MFDI:12
MFDI:BOUCLE_DE_LYS:149996-C02491-18777678,,,23:15:00,23:48:00,MFDI:461909,35,1,2,,,0,MFDI:12,MFDI:12
MFDI:KRO6:153358-C02060-680-260,26:39:00,26:39:00,,,MFDI:477725,0,2,1,,,1,MFDI:11,MFDI:11
MFDI:KRO6:153358-C02060-680-260,26:40:00,26:40:00,,,MFDI:38175,1,2,2,,,1,MFDI:11,MFDI:11
MFDI:KRO6:153358-C02060-680-260,26:52:00,26:52:00,,,MFDI:18995,17,2,2,,,1,MFDI:11,MFDI:11
MFDI:KRO6:153358-C02060-680-260,27:06:00,27:06:00,,,MFDI:41403,32,2,2,,,1,MFDI:11,MFDI:11
MFDI:KRO6:153358-C02060-680-260,27:15:00,27:15:00,,,MFDI:426813,37,1,2,,,1,MFDI:11,MFDI:11
MFDI:RATP:153912-C01376-COU_RATP_5086613_2991428_116,10:30:00,10:30:00,,,MFDI:22073,0,0,1,,,1,,
MFDI:RATP:153912-C01376-COU_RATP_5086613_2991428_116,10:31:00,10:31:00,,,MFDI:22167,1,0,0,,,1,,
MFDI:RATP:153912-C01376-COU_RATP_5086613_2991428_116,10:43:00,10:43:00,,,MFDI:22173,11,0,0,,,1,,
MFDI:RATP:153912-C01376-COU_RATP_5086613_2991428_116,10:54:00,10:54:00,,,MFDI:463194,20,0,0,,,1,,
MFDI:RATP:153912-C01376-COU_RATP_5086613_2991428_116,11:03:00,11:03:00,,,MFDI:463042,27,1,0,,,1,,
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
stop_id,stop_code,stop_name,stop_desc,stop_lon,stop_lat,zone_id,stop_url,location_type,parent_station,stop_timezone,level_id,wheelchair_boarding,platform_code
MFDI:22167,,Picpus,,2.401248269453829,48.84501767720269,1,,0,MFDI:71639,Europe/Paris,,2,
MFDI:22173,,Glacière,,2.3434974927179884,48.831170235245835,1,,0,MFDI:71026,Europe/Paris,,2,
MFDI:22073,,Nation,,2.3958598043279085,48.84789550545761,1,,0,MFDI:71673,Europe/Paris,,2,
MFDI:41403,,Cargo Centre,,2.526990016633599,48.99817129747993,5,,0,MFDI:73591,Europe/Paris,,1,
MFDI:463194,,La Motte-Picquet - Grenelle,,2.298957096977008,48.848765448122315,1,,0,MFDI:71199,Europe/Paris,,2,
MFDI:463042,,Charles de Gaulle - Etoile,,2.2947520493673434,48.87371127132366,1,,0,MFDI:71347,Europe/Paris,,2,
MFDI:426813,,Gare de Roissypole - Aéroport CDG1 Terminal 3 (C4),,2.559069276593061,49.010290004685544,,,0,MFDI:73596,Europe/Paris,,2,
MFDI:426214,,La Logeraie,,2.1359934967138585,48.766289059613705,4,,0,MFDI:63529,Europe/Paris,,1,
MFDI:477725,,Verdi,,2.577391101137773,48.961194121418,4,,0,MFDI:480959,Europe/Paris,,2,
MFDI:34582,,Fourqueux,,2.0804267048554177,48.89058561987773,,,0,MFDI:64509,Europe/Paris,,1,
MFDI:38175,,Parmentier,,2.561581492140883,48.947693512717194,4,,0,MFDI:73486,Europe/Paris,,2,
MFDI:461909,,Gare de Saint-Germain-en-Laye,,2.094588526727687,48.898931576292874,,,0,MFDI:64589,Europe/Paris,,1,
MFDI:18995,,Croix l'Aumône,,2.524710804326184,48.96497157469924,4,,0,MFDI:73556,Europe/Paris,,2,
MFDI:34605,,Gare de Saint-Germain-en-Laye,,2.0939283750483924,48.89924135453759,,,0,MFDI:64589,Europe/Paris,,1,
MFDI:34744,,République,,2.0927460449808457,48.89812620815719,,,0,MFDI:426072,Europe/Paris,,1,
MFDI:11584,,Porte Jaune,,2.229129261380777,48.76610796421317,4,,0,MFDI:63534,Europe/Paris,,1,
MFDI:14081,,Victor Hugo,,2.063504165681303,48.886623198199004,,,0,MFDI:64485,Europe/Paris,,2,
MFDI:20324,,Clos Normand,,2.186312472329811,48.75818767629223,4,,0,MFDI:63438,Europe/Paris,,1,
MFDI:20312,,Les Tilleuls,,2.1615499577506054,48.76517599148135,4,,0,MFDI:461827,Europe/Paris,,2,
MFDI:485179,,Gare routière de Versailles Chantiers - Quai G,,2.1340608589561016,48.795848498088226,4,,0,MFDI:63880,Europe/Paris,,1,
MFDI:461827,,Les Tilleuls,,2.1613451720416506,48.76521952597488,,,1,,,,0,
MFDI:426072,,République / Rue de la Salle,,2.092660713832334,48.89762192758876,,,1,,,,0,
MFDI:71639,,Picpus,,2.402166806721031,48.845125696754025,,,1,,,,0,
MFDI:71673,,Nation,,2.3963316057344417,48.848927647042316,,,1,,,,0,
MFDI:64589,,Saint-Germain-en-Laye,,2.0951814549394174,48.899349756253876,,,1,,,,0,
MFDI:63880,,Versailles Chantiers,,2.134652391388478,48.79588875952142,,,1,,,,0,
MFDI:71026,,Glacière,,2.3438687884909264,48.8308934672617,,,1,,,,0,
MFDI:64509,,Fourqueux,,2.080767458510045,48.89098395203159,,,1,,,,0,
MFDI:64485,,Victor Hugo,,2.063504165681303,48.886623198199004,,,1,,,,0,
MFDI:63534,,Porte Jaune,,2.2291546111332714,48.766234048830825,,,1,,,,0,
MFDI:63529,,La Logeraie,,2.1363481054691924,48.76623765829017,,,1,,,,0,
MFDI:63438,,Clos Normand,,2.1861969917891195,48.758177894949306,,,1,,,,0,
MFDI:73556,,Croix l'Aumône,,2.524833265434999,48.965021518604,,,1,,,,0,
MFDI:73596,,Roissy Aéroport CDG 1 (Terminal 3) (Tremblay-en-France),,2.5601295519817535,49.01033329803776,,,1,,,,0,
MFDI:73591,,Cargo Centre,,2.5261341855607036,48.998356758085166,,,1,,,,0,
MFDI:71347,,Charles de Gaulle - Etoile,,2.2946168784613463,48.87362503818625,,,1,,,,0,
MFDI:73486,,Parmentier / Saint Vincent de Paul,,2.5608350156242676,48.94635987507931,,,1,,,,0,
MFDI:71199,,La Motte-Picquet - Grenelle,,2.2984077121284154,48.84918377697637,,,1,,,,0,
MFDI:480959,,Verdi,,2.577391101137773,48.961194121418,,,1,,,,0,
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from_stop_id,to_stop_id,transfer_type,min_transfer_time
MFDI:34744,MFDI:461909,2,206
MFDI:34744,MFDI:34605,2,192
MFDI:34605,MFDI:34744,2,192
MFDI:461909,MFDI:34744,2,206
MFDI:461909,MFDI:34605,2,62
MFDI:34605,MFDI:461909,2,62
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
route_id,service_id,trip_id,trip_headsign,trip_short_name,direction_id,block_id,shape_id,wheelchair_accessible,bikes_allowed
MFDI:C02513,MFDI:1000,MFDI:KVVB:158023-C02513-1638-260,Porte Jaune,,1,,,0,0
MFDI:C02491,MFDI:1,MFDI:BOUCLE_DE_LYS:149996-C02491-18777678,Gare de St-Germain-en-Laye - Gare Routière,,0,,,0,0
MFDI:C02060,MFDI:1000,MFDI:KRO6:153358-C02060-680-260,Gare de Roissypole Aéroport CDG 1,,1,,,0,0
MFDI:C01376,MFDI:1,MFDI:RATP:153912-C01376-COU_RATP_5086613_2991428_116,Charles de Gaulle-Etoile,,1,,,2,0
18 changes: 18 additions & 0 deletions ntfs2gtfs/tests/ntfs2gtfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,21 @@ fn test_ntfs2gtfs_with_fare_urls_and_deeplinks() {
"./tests/fixtures/output_gtfs_with_fare_url_deeplinks",
);
}

#[test]
fn test_ntfs2gtfs_with_pickup_drop_off_windows_stoptimes() {
let output_dir = TempDir::new().expect("create temp dir failed");
Command::cargo_bin("ntfs2gtfs")
.expect("Failed to find binary 'ntfs2gtfs'")
.arg("--input")
.arg("../tests/fixtures/pickup_drop_off_windows/input_ntfs")
.arg("--output")
.arg(output_dir.path().to_str().unwrap())
.assert()
.success();
compare_output_dir_with_expected(
output_dir,
None,
"./tests/fixtures/output_gtfs_pickup_drop_off_windows",
);
}
4 changes: 3 additions & 1 deletion ntfs2netexfr/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use tracing_subscriber::{
layer::SubscriberExt as _,
util::SubscriberInitExt as _,
};
use transit_model::{Model, Result};
use transit_model::{objects::VehicleJourneyScheduleType, Model, Result};

lazy_static::lazy_static! {
pub static ref GIT_VERSION: String = transit_model::binary_full_version(env!("CARGO_PKG_VERSION"));
Expand Down Expand Up @@ -91,6 +91,8 @@ fn run(opt: Opt) -> Result<()> {

let mut collections = transit_model::ntfs::read_collections(opt.input)?;
collections.remove_route_points();
collections
.filter_by_vj_schedule_types(vec![VehicleJourneyScheduleType::ArrivalDepartureTimesOnly])?;
let model = Model::new(collections)?;

let mut config = transit_model::netex_france::WriteConfiguration::new(opt.participant)
Expand Down
23 changes: 23 additions & 0 deletions ntfs2netexfr/tests/ntfs2netexfr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use assert_cmd::prelude::*;
use std::process::Command;
use tempfile::TempDir;
use transit_model::test_utils::*;

#[test]
fn test_ntfs2netexfr() {
Expand Down Expand Up @@ -78,3 +79,25 @@ fn test_ntfs2netexfr_create_foobar() {
.success();
assert!(netexfr_foobar.join("arrets.xml").is_file());
}

#[test]
fn test_ntfs2netexfr_with_pickup_drop_off_windows_stoptimes() {
let output_dir = TempDir::new().expect("create temp dir failed");
Command::cargo_bin("ntfs2netexfr")
.expect("Failed to find binary 'ntfs2netexfr'")
.arg("--input")
.arg("../tests/fixtures/pickup_drop_off_windows/input_ntfs")
.arg("--output")
.arg(output_dir.path().to_str().unwrap())
.arg("--participant")
.arg("Participant")
.arg("--current-datetime")
.arg("2024-04-03T17:19:00Z")
.assert()
.success();
compare_output_dir_with_expected(
output_dir,
Some(vec!["lignes.xml"]),
"../tests/fixtures/netex_france/output_netexfr_pickup_drop_off_windows",
);
}
37 changes: 37 additions & 0 deletions src/gtfs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ struct StopTime {
trip_id: String,
arrival_time: Option<Time>,
departure_time: Option<Time>,
start_pickup_drop_off_window: Option<Time>,
end_pickup_drop_off_window: Option<Time>,
#[serde(deserialize_with = "de_without_slashes")]
stop_id: String,
stop_sequence: u32,
Expand All @@ -222,6 +224,40 @@ struct StopTime {
default = "default_true_bool"
)]
timepoint: bool,
pickup_booking_rule_id: Option<String>,
drop_off_booking_rule_id: Option<String>,
}

#[derive(Derivative, Serialize)]
#[derivative(Default)]
enum BookingType {
#[derivative(Default)]
#[serde(rename = "0")]
RealTime,
}

#[derive(Derivative, Serialize)]
#[derivative(Default)]
struct BookingRule {
id: String,
booking_type: BookingType,
message: Option<String>,
phone_number: Option<String>,
info_url: Option<String>,
booking_url: Option<String>,
}

impl<'a> From<&'a objects::BookingRule> for BookingRule {
fn from(obj: &objects::BookingRule) -> BookingRule {
BookingRule {
id: obj.id.clone(),
message: obj.message.clone(),
phone_number: obj.phone.clone(),
info_url: obj.info_url.clone(),
booking_url: obj.booking_url.clone(),
..Default::default()
}
}
}

#[derive(Serialize, Deserialize, Debug, Derivative, PartialEq, Clone)]
Expand Down Expand Up @@ -705,6 +741,7 @@ pub fn write<P: AsRef<Path>>(model: Model, path: P, extend_route_type: bool) ->
&model.stop_points,
&model.stop_time_headsigns,
)?;
write::write_booking_rules(path, &model.booking_rules)?;
write::write_shapes(path, &model.geometries)?;
write_collection_with_id(path, "pathways.txt", &model.pathways)?;
write_collection_with_id(path, "levels.txt", &model.levels)?;
Expand Down
Loading