1+ #!/usr/bin/env python3
2+ import csv
3+ import psycopg2
4+ from psycopg2 .extras import execute_values
5+ from typing import Optional
6+ import argparse
7+
8+ '''
9+ Usage:
10+ python3 tools/import_stations.py \
11+ --csv stops.csv \
12+ --city Flensburg \
13+ --country DEU \
14+ --host localhost \
15+ --port 5432 \
16+ --db uranus \
17+ --user postgres \
18+ --password mysecretpassword
19+
20+ python3 tools/import_transport_station_gtfs_stops.py --csv /Volumes/RoaldMedia1/OpenData/Transport/GTFS/SH/stops.txt --city Flensburg --country DEU --host localhost --port 5432 --db oklab --user roaldchristesen --password ''
21+ '''
22+
23+ # --- your import function ---
24+ def import_transport_stations (
25+ csv_file_path : str ,
26+ city : Optional [str ] = None ,
27+ country : Optional [str ] = None ,
28+ db_config : dict = None
29+ ):
30+ if db_config is None :
31+ db_config = {
32+ "host" : "localhost" ,
33+ "database" : "uranus" ,
34+ "user" : "postgres" ,
35+ "password" : "" ,
36+ }
37+
38+ conn = psycopg2 .connect (** db_config )
39+ cur = conn .cursor ()
40+
41+ insert_sql = """
42+ INSERT INTO uranus.transport_station (
43+ name, geo_pos, gtfs_station_code, gtfs_location_type,
44+ city, country, gtfs_parent_station, gtfs_wheelchair_boarding, gtfs_zone_id
45+ ) VALUES %s
46+ ON CONFLICT (gtfs_station_code) DO UPDATE
47+ SET
48+ name = EXCLUDED.name,
49+ geo_pos = EXCLUDED.geo_pos,
50+ gtfs_location_type = EXCLUDED.gtfs_location_type,
51+ city = EXCLUDED.city,
52+ country = EXCLUDED.country,
53+ gtfs_parent_station = EXCLUDED.gtfs_parent_station,
54+ gtfs_wheelchair_boarding = EXCLUDED.gtfs_wheelchair_boarding,
55+ gtfs_zone_id = EXCLUDED.gtfs_zone_id
56+ """
57+
58+ values = []
59+
60+ with open (csv_file_path , newline = "" , encoding = "utf-8" ) as csvfile :
61+ reader = csv .DictReader (csvfile )
62+ for row in reader :
63+ stop_name = row .get ("stop_name" , "" ).strip ()
64+ stop_code = row .get ("stop_id" , "" ).strip () or None
65+ lat = row .get ("stop_lat" )
66+ lon = row .get ("stop_lon" )
67+ location_type = int (row .get ("location_type" , 0 ))
68+ parent_station = row .get ("parent_station" ) or None
69+ wheelchair_boarding = int (row .get ("wheelchair_boarding" , 0 ))
70+ zone_id = row .get ("zone_id" ) or None
71+
72+ try :
73+ lat_f = float (lat )
74+ lon_f = float (lon )
75+ except (TypeError , ValueError ):
76+ print (f"Skipping invalid row: { row } " )
77+ continue
78+
79+ point_wkt = f"SRID=4326;POINT({ lon_f } { lat_f } )"
80+
81+ values .append ((
82+ stop_name ,
83+ point_wkt ,
84+ stop_code ,
85+ location_type ,
86+ city ,
87+ country ,
88+ parent_station ,
89+ wheelchair_boarding ,
90+ zone_id
91+ ))
92+
93+ if not values :
94+ print ("No valid rows to insert." )
95+ cur .close ()
96+ conn .close ()
97+ return
98+
99+ execute_values (
100+ cur ,
101+ insert_sql ,
102+ values ,
103+ template = """(
104+ %s,
105+ ST_GeomFromText(%s),
106+ %s,
107+ %s,
108+ %s,
109+ %s,
110+ %s,
111+ %s,
112+ %s
113+ )"""
114+ )
115+
116+ conn .commit ()
117+ cur .close ()
118+ conn .close ()
119+ print (f"Imported { len (values )} transport stations successfully." )
120+
121+
122+ # --- CLI entry point ---
123+ if __name__ == "__main__" :
124+ parser = argparse .ArgumentParser (description = "Import GTFS stops into transport_station table" )
125+ parser .add_argument ("--csv" , required = True , help = "Path to the CSV file" )
126+ parser .add_argument ("--city" , default = None , help = "City name to assign" )
127+ parser .add_argument ("--country" , default = None , help = "Country code to assign" )
128+ parser .add_argument ("--host" , default = "localhost" , help = "PostgreSQL host" )
129+ parser .add_argument ("--port" , default = 5432 , type = int , help = "PostgreSQL port" )
130+ parser .add_argument ("--db" , required = True , help = "Database name" )
131+ parser .add_argument ("--user" , required = True , help = "Database user" )
132+ parser .add_argument ("--password" , required = True , help = "Database password" )
133+
134+ args = parser .parse_args ()
135+
136+ db_config = {
137+ "host" : args .host ,
138+ "port" : args .port ,
139+ "database" : args .db ,
140+ "user" : args .user ,
141+ "password" : args .password ,
142+ }
143+
144+ import_transport_stations (args .csv , args .city , args .country , db_config )
0 commit comments