diff --git a/transport_accessibility/api/io.py b/transport_accessibility/api/io.py new file mode 100644 index 0000000..5298216 --- /dev/null +++ b/transport_accessibility/api/io.py @@ -0,0 +1,79 @@ +import csv +import io +import os +from pt_map.models import * +import pt_map +import pt_map.class_names +from django.db import models +import inspect +import datetime +import sys + +def csv_queryset(q: models.query.QuerySet) -> str: + fields = [field.name for field in q.model._meta.fields] + result = io.StringIO() + csv_writer = csv.DictWriter(result, fields) + csv_writer.writeheader() + + for model in q: + row = {} + for field_name in fields: + field = model._meta.get_field(field_name) + value = model.__getattribute__(field.name) + if value is None: + continue + if isinstance(field, models.DateField): + row[field.name] = value.strftime("%Y%m%d") + elif isinstance(field, models.ForeignKey): + row[field.name] = value.pk if not model == Shape else value.shape_id + elif isinstance(field, models.ManyToManyField): + row[field.name] = value.all().first().__getattribute__(field.name) + elif isinstance(field, models.BooleanField): + row[field.name] = int(value) + else: + row[field.name] = value + csv_writer.writerow(row) + return result.getvalue() + +def models_csv(path: str) -> list[models.Model]: + assume_compliance = True + if assume_compliance: + os.chdir(path) + feed = None + order = [] + for m in [*pt_map.class_names.fks.values(), *pt_map.class_names.mtm.values(), *[m for _,m in inspect.getmembers(pt_map.models, inspect.isclass)]]: + if m not in order: + order.append(m) + for m in order: + if os.path.exists(pt_map.class_names.file_names[m]): + with open(pt_map.class_names.file_names[m], 'r') as f: + csvreader = csv.DictReader(f) + mtm = {} + for row in csvreader: + for field in [field for field in m._meta.fields if field.name in csvreader.fieldnames]: + if not row[field.name]: + del row[field.name] + continue + if isinstance(field, models.ForeignKey): + row[field.name] = pt_map.class_names.fks[field.name].objects.get(pk=f"{feed.pk}_{row[field.name]}") + elif isinstance(field, models.DateField): + row[field.name] = datetime.datetime.fromisoformat(row[field.name]) + elif (field.primary_key and feed) or field.name == 'service_id': + row[field.name] = f"{feed.pk}_{row[field.name]}" + for field in m._meta.many_to_many: + mtm[field.name] = pt_map.class_names.mtm[field.name].objects.filter(**{field.name: row[field.name]}) + del row[field.name] + if feed: + row['feed_info_id'] = feed + if m == pt_map.models.Shape: + row['shape_id'] = f"{feed.pk}_{row['shape_id']}" + obj = m.objects.create(**row) + for name, value in mtm.items(): + getattr(obj, name).set(value) + if not feed: + feed = obj + + + + + diff --git a/transport_accessibility/pt_map/bridge.py b/transport_accessibility/pt_map/bridge.py index 30286c6..5747fe2 100644 --- a/transport_accessibility/pt_map/bridge.py +++ b/transport_accessibility/pt_map/bridge.py @@ -234,6 +234,7 @@ def db_to_gtfs(q: list[django.db.models.query.QuerySet], folder_path: str = ""): object containing the queried data """ dfs = {reversed_file_mapping[m.model.__name__]: (pd.DataFrame(list(m.values())) if m else pd.DataFrame()) for m in q} + dfs = {key: dfs[key].astype({col: pd.Timestamp for col in dfs[key].columns if isinstance(getattr(getattr(pt_map.models, {v:k for k,v in reversed_file_mapping.items()}[key]), col), django.db.models.DateField)}) for key in dfs.keys()} g = pt_map.gtfs.GTFS(folder_path, dfs) g.validate() return g diff --git a/transport_accessibility/pt_map/class_names.py b/transport_accessibility/pt_map/class_names.py index a32cc0e..34a30c3 100644 --- a/transport_accessibility/pt_map/class_names.py +++ b/transport_accessibility/pt_map/class_names.py @@ -139,6 +139,40 @@ pt_map.models.Shape: "shapes", ] + +file_names = { + pt_map.models.Agency: "agency.txt", + pt_map.models.Stop: "stops.txt", + pt_map.models.Route: "routes.txt", + pt_map.models.Trip: "trips.txt", + pt_map.models.StopTime: "stop_times.txt", + pt_map.models.Calendar: "calendar.txt", + pt_map.models.CalendarDate: "calendar_dates.txt", + pt_map.models.FareAttribute: "fare_attributes.txt", + pt_map.models.FareRule: "fare_rules.txt", + pt_map.models.Timeframe: "timeframes.txt", + pt_map.models.FareMedium: "fare_media.txt", + pt_map.models.FareProduct: "fare_products.txt", + pt_map.models.FareLegRule: "fare_leg_rules.txt", + pt_map.models.FareTransferRule: "fare_transfer_rules.txt", + pt_map.models.Area: "areas.txt", + pt_map.models.StopArea: "stop_areas.txt", + pt_map.models.Network: "networks.txt", + pt_map.models.RouteNetwork: "route_networks.txt", + pt_map.models.Shape: "shapes.txt", + pt_map.models.Frequency: "frequencies.txt", + pt_map.models.Transfer: "transfers.txt", + pt_map.models.Pathway: "pathways.txt", + pt_map.models.Level: "levels.txt", + pt_map.models.LocationGroup: "location_groups.txt", + pt_map.models.LocationGroupStop: "location_group_stops.txt", + pt_map.models.LocationsGeojson: "locations.geojson", + pt_map.models.BookingRule: "booking_rules.txt", + pt_map.models.Translation: "translations.txt", + pt_map.models.FeedInfo: "feed_info.txt", + pt_map.models.Attribution: "attributions.txt", +} + reversed_file_mapping = { "Agency": "agency", "Stop": "stops", @@ -276,4 +310,35 @@ foreign_keys = [ (pt_map.models.FareTransferRule, [(pt_map.models.FeedInfo, 'feed_info_id'),(pt_map.models.FareProduct, 'fare_product_id'), ]), ] +mtm = { + 'shape_id': pt_map.models.Shape, + 'from_timeframe_group_id': pt_map.models.Timeframe, + 'to_timeframe_group_id': pt_map.models.Timeframe, + } + +fks = { + 'feed_info_id_id': pt_map.models.FeedInfo, + 'parent_station': pt_map.models.Stop, + 'level_id': pt_map.models.Level, + 'agency_id': pt_map.models.Agency, + 'route_id': pt_map.models.Route, + 'trip_id': pt_map.models.Trip, + 'stop_id': pt_map.models.Stop, + 'location_group_id': pt_map.models.LocationGroup, + 'location_id': pt_map.models.LocationsGeojson, + 'fare_id': pt_map.models.FareAttribute, + 'from_stop_id': pt_map.models.Stop, + 'to_stop_id': pt_map.models.Stop, + 'from_route_id': pt_map.models.Route, + 'to_route_id': pt_map.models.Route, + 'from_trip_id': pt_map.models.Trip, + 'to_trip_id': pt_map.models.Trip, + 'network_id': pt_map.models.Network, + 'area_id': pt_map.models.Area, + 'from_area_id': pt_map.models.Area, + 'to_area_id': pt_map.models.Area, + 'fare_product_id': pt_map.models.FareProduct, + } + + fk_dict = {fk[0]: fk[1] for fk in foreign_keys} diff --git a/transport_accessibility/pt_map/gtfs.py b/transport_accessibility/pt_map/gtfs.py index 16f8e07..132300b 100644 --- a/transport_accessibility/pt_map/gtfs.py +++ b/transport_accessibility/pt_map/gtfs.py @@ -405,12 +405,13 @@ class GTFS: os.mkdir(path) for name in self.get_files(): df = getattr(self, name).data + df = df.astype({col: 'int8' for col in df.columns if df[col].dtype == 'bool'}) fpath = f"{path}/{name}.txt" if name == 'locations_geojson': fpath = f"{path}/{name}.geojson" df.to_json(fpath) else: - df.to_csv(fpath, index=False) + df.to_csv(fpath, date_format='%Y%m%d', index=False) def validate(self): """ diff --git a/transport_accessibility/pt_map/migrations/0004_remove_trip_shape_id_trip_shape_id.py b/transport_accessibility/pt_map/migrations/0004_remove_trip_shape_id_trip_shape_id.py new file mode 100644 index 0000000..8f3ac1f --- /dev/null +++ b/transport_accessibility/pt_map/migrations/0004_remove_trip_shape_id_trip_shape_id.py @@ -0,0 +1,22 @@ +# Generated by Django 5.0.6 on 2024-06-22 09:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pt_map', '0003_faretransferrule_feed_info_id'), + ] + + operations = [ + migrations.RemoveField( + model_name='trip', + name='shape_id', + ), + migrations.AddField( + model_name='trip', + name='shape_id', + field=models.ManyToManyField(blank=True, related_name='shape', to='pt_map.shape'), + ), + ] diff --git a/transport_accessibility/pt_map/migrations/0005_alter_trip_shape_id.py b/transport_accessibility/pt_map/migrations/0005_alter_trip_shape_id.py new file mode 100644 index 0000000..1135047 --- /dev/null +++ b/transport_accessibility/pt_map/migrations/0005_alter_trip_shape_id.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.6 on 2024-06-22 09:40 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pt_map', '0004_remove_trip_shape_id_trip_shape_id'), + ] + + operations = [ + migrations.AlterField( + model_name='trip', + name='shape_id', + field=models.ManyToManyField(blank=True, related_name='trips', to='pt_map.shape'), + ), + ] diff --git a/transport_accessibility/pt_map/migrations/0006_alter_bookingrule_end_time_and_more.py b/transport_accessibility/pt_map/migrations/0006_alter_bookingrule_end_time_and_more.py new file mode 100644 index 0000000..96f8f9e --- /dev/null +++ b/transport_accessibility/pt_map/migrations/0006_alter_bookingrule_end_time_and_more.py @@ -0,0 +1,53 @@ +# Generated by Django 5.0.6 on 2024-06-23 20:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pt_map', '0005_alter_trip_shape_id'), + ] + + operations = [ + migrations.AlterField( + model_name='bookingrule', + name='end_time', + field=models.CharField(blank=True, max_length=7, null=True), + ), + migrations.AlterField( + model_name='bookingrule', + name='start_time', + field=models.CharField(blank=True, max_length=7, null=True), + ), + migrations.AlterField( + model_name='frequency', + name='end_time', + field=models.CharField(max_length=7), + ), + migrations.AlterField( + model_name='frequency', + name='start_time', + field=models.CharField(max_length=7), + ), + migrations.AlterField( + model_name='stoptime', + name='arrival_time', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AlterField( + model_name='stoptime', + name='departure_time', + field=models.CharField(blank=True, max_length=7, null=True), + ), + migrations.AlterField( + model_name='timeframe', + name='end_time', + field=models.CharField(max_length=7), + ), + migrations.AlterField( + model_name='timeframe', + name='start_time', + field=models.CharField(max_length=7), + ), + ] diff --git a/transport_accessibility/pt_map/migrations/0007_alter_bookingrule_end_time_and_more.py b/transport_accessibility/pt_map/migrations/0007_alter_bookingrule_end_time_and_more.py new file mode 100644 index 0000000..5fc6351 --- /dev/null +++ b/transport_accessibility/pt_map/migrations/0007_alter_bookingrule_end_time_and_more.py @@ -0,0 +1,48 @@ +# Generated by Django 5.0.6 on 2024-06-23 21:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pt_map', '0006_alter_bookingrule_end_time_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='bookingrule', + name='end_time', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AlterField( + model_name='bookingrule', + name='start_time', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AlterField( + model_name='frequency', + name='end_time', + field=models.CharField(max_length=255), + ), + migrations.AlterField( + model_name='frequency', + name='start_time', + field=models.CharField(max_length=255), + ), + migrations.AlterField( + model_name='stoptime', + name='departure_time', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AlterField( + model_name='timeframe', + name='end_time', + field=models.CharField(max_length=255), + ), + migrations.AlterField( + model_name='timeframe', + name='start_time', + field=models.CharField(max_length=255), + ), + ] diff --git a/transport_accessibility/pt_map/migrations/0008_alter_timeframe_service_id_alter_trip_service_id.py b/transport_accessibility/pt_map/migrations/0008_alter_timeframe_service_id_alter_trip_service_id.py new file mode 100644 index 0000000..035f58a --- /dev/null +++ b/transport_accessibility/pt_map/migrations/0008_alter_timeframe_service_id_alter_trip_service_id.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.6 on 2024-06-23 23:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pt_map', '0007_alter_bookingrule_end_time_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='timeframe', + name='service_id', + field=models.CharField(max_length=255), + ), + migrations.AlterField( + model_name='trip', + name='service_id', + field=models.CharField(max_length=255), + ), + ] diff --git a/transport_accessibility/pt_map/model_test_fields.py b/transport_accessibility/pt_map/model_test_fields.py new file mode 100644 index 0000000..b41de97 --- /dev/null +++ b/transport_accessibility/pt_map/model_test_fields.py @@ -0,0 +1,600 @@ +""" +Constants defining requirements of model fields. +To be used to decide wether a test should run or fail and which tests to run to test for self-preserved integrity. +""" +from pt_map.models import * + +field_requirements = \ +[ + { + "model": Agency, + "fields": [ + { + "name": "agency_id", + "type": "pk", + "required": "true", + }, + { + "name": "agency_name", + "type": "str", + "required": "true", + }, + { + "name": "agency_url", + "type": "url", + "required": "true", + }, + { + "name": "agency_timezone", + "type": "timezone", + "required": "true", + }, + { + "name": "agency_lang", + "type": "langcode", + "required": "false", + }, + { + "name": "agency_phone", + "type": "telephone", + "required": "false", + }, + { + "name": "agency_email", + "type": "email", + "required": "false", + }, + ], + }, + { + "model": "Stop", + "fields": [ + { + "name": "stop_id", + "type": "pk", + "required": "true", + }, + { + "name": "stop_code", + "type": "str", + "required": "false", + }, + { + "name": "stop_name", + "type": "str", + "required": "true", + }, + { + "name": "stop_desc", + "type": "str", + "required": "false", + }, + { + "name": "stop_lat", + "type": "float", + "required": "if", + "required_if": ["location_type", [0,1,2]], + }, + { + "name": "stop_lon", + "type": "float", + "required": "if", + "required_if": ["location_type", [0,1,2]], + }, + { + "name": "zone_id", + "type": "str", + "required": "false", + }, + { + "name": "stop_url", + "type": "url", + "required": "false", + }, + { + "name": "location_type", + "type": "int", + "required": "true", + }, + { + "name": "parent_station", + "type": "fk", + "required": "if", + "required_if": ["location_type", [2,3,4]], + "forbidden_if": ["location_type", [1]], + }, + { + "name": "stop_timezone", + "type": "timezone", + "required": "false", + }, + { + "name": "wheelchair_boarding", + "type": "int", + "required": "false", + }, + ], + }, + { + "model": "Stop", + "fields": [ + { + "name": "stop_id", + "type": "pk", + "required": "true", + }, + { + "name": "stop_code", + "type": "str", + "required": "false", + }, + { + "name": "stop_name", + "type": "str", + "required": "true", + }, + { + "name": "stop_desc", + "type": "str", + "required": "false", + }, + { + "name": "stop_lat", + "type": "float", + "required": "true", + }, + { + "name": "stop_lon", + "type": "float", + "required": "true", + }, + { + "name": "zone_id", + "type": "str", + "required": "false", + }, + { + "name": "stop_url", + "type": "url", + "required": "false", + }, + { + "name": "location_type", + "type": "int", + "required": "true", + }, + { + "name": "parent_station", + "type": "str", + "required": "false", + }, + { + "name": "stop_timezone", + "type": "timezone", + "required": "false", + }, + { + "name": "wheelchair_boarding", + "type": "int", + "required": "false", + }, + ], + }, + { + "model": "Route", + "fields": [ + { + "name": "route_id", + "type": "pk", + "required": "true", + }, + { + "name": "route_short_name", + "type": "str", + "required": "false", + }, + { + "name": "route_long_name", + "type": "str", + "required": "true", + }, + { + "name": "route_desc", + "type": "str", + "required": "false", + }, + { + "name": "route_type", + "type": "int", + "required": "true", + }, + { + "name": "route_url", + "type": "url", + "required": "false", + }, + { + "name": "route_color", + "type": "str", + "required": "false", + }, + { + "name": "route_text_color", + "type": "str", + "required": "false", + } + ], + }, + { + "model": "Trip", + "fields": [ + { + "name": "trip_id", + "type": "pk", + "required": "true", + }, + { + "name": "route_id", + "type": "fk", + "required": "true", + }, + { + "name": "service_id", + "type": "fk", + "required": "true", + }, + { + "name": "trip_headsign", + "type": "str", + "required": "true", + }, + { + "name": "trip_short_name", + "type": "str", + "required": "false", + }, + { + "name": "direction_id", + "type": "int", + "required": "true", + }, + { + "name": "block_id", + "type": "str", + "required": "false", + }, + { + "name": "shape_id", + "type": "fk", + "required": "true", + }, + ], + }, + { + "model": "StopTime", + "fields": [ + { + "name": "trip_id", + "type": "fk", + "required": "true", + }, + { + "name": "arrival_time", + "type": "time", + "required": "true", + }, + { + "name": "departure_time", + "type": "time", + "required": "true", + }, + { + "name": "stop_id", + "type": "fk", + "required": "true", + }, + { + "name": "stop_sequence", + "type": "int", + "required": "true", + }, + { + "name": "pickup_type", + "type": "int", + "required": "true", + }, + { + "name": "drop_off_type", + "type": "int", + "required": "true", + }, + { + "name": "shape_dist_traveled", + "type": "float", + "required": "false", + }, + { + "name": "timepoint", + "type": "int", + "required": "false", + }, + ], + }, + { + "model": "Calendar", + "fields": [ + { + "name": "service_id", + "type": "pk", + "required": "true", + }, + { + "name": "monday", + "type": "int", + "required": "true", + }, + { + "name": "tuesday", + "type": "int", + "required": "true", + }, + { + "name": "wednesday", + "type": "int", + "required": "true", + }, + { + "name": "thursday", + "type": "int", + "required": "true", + }, + { + "name": "friday", + "type": "int", + "required": "true", + }, + { + "name": "saturday", + "type": "int", + "required": "true", + }, + { + "name": "sunday", + "type": "int", + "required": "true", + }, + { + "name": "start_date", + "type": "date", + "required": "true", + }, + { + "name": "end_date", + "type": "date", + "required": "true", + }, + ], + }, + { + "model": "CalendarDates", + "fields": [ + { + "name": "service_id", + "type": "fk", + "required": "true", + }, + { + "name": "date", + "type": "date", + "required": "true", + }, + { + "name": "exception_type", + "type": "int", + "required": "true", + }, + ], + }, + { + "model": "FareAttributes", + "fields": [ + { + "name": "fare_id", + "type": "pk", + "required": "true", + }, + { + "name": "price", + "type": "float", + "required": "true", + }, + { + "name": "currency_type", + "type": "str", + "required": "true", + }, + { + "name": "payment_method", + "type": "int", + "required": "true", + }, + { + "name": "transfers", + "type": "int", + "required": "true", + }, + { + "name": "transfer_duration", + "type": "int", + "required": "true", + }, + ], + }, + { + "model": "FareRules", + "fields": [ + { + "name": "fare_id", + "type": "fk", + "required": "true", + }, + { + "name": "route_id", + "type": "fk", + "required": "true", + }, + { + "name": "origin_id", + "type": "fk", + "required": "true", + }, + { + "name": "destination_id", + "type": "fk", + "required": "true", + }, + { + "name": "contains_id", + "type": "fk", + "required": "false", + }, + ], + }, + { + "model": "FareZones", + "fields": [ + { + "name": "fare_zone_id", + "type": "pk", + "required": "true", + }, + { + "name": "zone_id", + "type": "str", + "required": "true", + }, + ], + }, + { + "model": "Shape", + "fields": [ + { + "name": "shape_id", + "type": "pk", + "required": "true", + }, + { + "name": "shape_pt_lat", + "type": "float", + "required": "true", + }, + { + "name": "shape_pt_lon", + "type": "float", + "required": "true", + }, + { + "name": "shape_pt_sequence", + "type": "int", + "required": "true", + }, + { + "name": "shape_dist_traveled", + "type": "float", + "required": "true", + }, + ], + }, + { + "model": "Frequencies", + "fields": [ + { + "name": "trip_id", + "type": "fk", + "required": "true", + }, + { + "name": "start_time", + "type": "time", + "required": "true", + }, + { + "name": "end_time", + "type": "time", + "required": "true", + }, + { + "name": "headway_secs", + "type": "int", + "required": "true", + }, + { + "name": "exact_times", + "type": "int", + "required": "true", + }, + ], + }, + { + "model": "Transfers", + "fields": [ + { + "name": "from_stop_id", + "type": "fk", + "required": "true", + }, + { + "name": "to_stop_id", + "type": "fk", + "required": "true", + }, + { + "name": "transfer_type", + "type": "int", + "required": "true", + }, + { + "name": "min_transfer_time", + "type": "int", + "required": "true", + }, + ], + }, + { + "model": "FeedInfo", + "fields": [ + { + "name": "feed_publisher_name", + "type": "str", + "required": "true", + }, + { + "name": "feed_publisher_url", + "type": "url", + "required": "true", + }, + { + "name": "feed_lang", + "type": "langcode", + "required": "true", + }, + { + "name": "feed_start_date", + "type": "date", + "required": "true", + }, + { + "name": "feed_end_date", + "type": "date", + "required": "false", + }, + { + "name": "feed_version", + "type": "str", + "required": "true", + }, + ], + }, + +] + diff --git a/transport_accessibility/pt_map/models.py b/transport_accessibility/pt_map/models.py index d97a262..9d3cd89 100644 --- a/transport_accessibility/pt_map/models.py +++ b/transport_accessibility/pt_map/models.py @@ -139,12 +139,12 @@ class Trip(models.Model): """ trip_id = models.CharField(max_length=255, primary_key=True) route_id = models.ForeignKey(Route, on_delete=models.CASCADE) - service_id = models.IntegerField() + service_id = models.CharField(max_length=255) trip_headsign = models.CharField(max_length=255, blank=True, null=True) trip_short_name = models.CharField(max_length=255, blank=True, null=True) direction_id = models.IntegerField(blank=True, null=True) block_id = models.CharField(max_length=255, blank=True, null=True) - shape_id = models.ForeignKey(Shape, on_delete=models.CASCADE, blank=True) + shape_id = models.ManyToManyField(Shape, related_name='trips', blank=True) wheelchair_accessible = models.IntegerField(blank=True, null=True) bikes_allowed = models.IntegerField(blank=True, null=True) @@ -191,8 +191,8 @@ class StopTime(models.Model): """ stop_time_id = models.BigAutoField(primary_key=True) trip_id = models.ForeignKey(Trip, on_delete=models.CASCADE) - arrival_time = models.TimeField(blank=True, null=True) - departure_time = models.TimeField(blank=True, null=True) + arrival_time = models.CharField(max_length=255, blank=True, null=True) + departure_time = models.CharField(max_length=255, blank=True, null=True) stop_id = models.ForeignKey(Stop, on_delete=models.CASCADE) location_group_id = models.ForeignKey(LocationGroup, on_delete=models.SET_NULL, blank=True, null=True) location_id = models.ForeignKey(LocationsGeojson, on_delete=models.SET_NULL, blank=True, null=True) @@ -238,8 +238,8 @@ class Frequency(models.Model): """ frequency_id = models.BigAutoField(primary_key=True) trip_id = models.ForeignKey(Trip, on_delete=models.CASCADE) - start_time = models.TimeField() - end_time = models.TimeField() + start_time = models.CharField(max_length=255) + end_time = models.CharField(max_length=255) headway_secs = models.IntegerField() exact_times = models.IntegerField(blank=True, null=True) feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE) @@ -286,8 +286,8 @@ class BookingRule(models.Model): """ booking_rule_id = models.CharField(max_length=255, primary_key=True) trip_id = models.ForeignKey(Trip, on_delete=models.CASCADE) - start_time = models.TimeField(blank=True, null=True) - end_time = models.TimeField(blank=True, null=True) + start_time = models.CharField(max_length=255, blank=True, null=True) + end_time = models.CharField(max_length=255, blank=True, null=True) booking_type = models.CharField(max_length=255) rule_criteria = models.TextField(blank=True, null=True) booking_rule_instructions = models.TextField(blank=True, null=True) @@ -390,11 +390,11 @@ class Timeframe(models.Model): Represents timeframe.txt from the GTFS Reference. """ timeframe_group_id = models.CharField(max_length=255,primary_key=True) - service_id = models.IntegerField() + service_id = models.CharField(max_length=255) start_date = models.DateField() end_date = models.DateField() - start_time = models.TimeField() - end_time = models.TimeField() + start_time = models.CharField(max_length=255) + end_time = models.CharField(max_length=255) feed_info_id = models.ForeignKey(FeedInfo, on_delete=models.CASCADE) class FareLegRule(models.Model): diff --git a/transport_accessibility/pt_map/tests.py b/transport_accessibility/pt_map/tests.py index bccdb2f..9c306e2 100644 --- a/transport_accessibility/pt_map/tests.py +++ b/transport_accessibility/pt_map/tests.py @@ -1,3 +1,26 @@ from django.test import TestCase +from pt_map.models import Agency, FeedInfo, Level, Stop, Route, Shape, Calendar, CalendarDate, LocationGroup, LocationGroupStop, LocationsGeojson, Trip, StopArea, StopTime, FareAttribute, FareLegRule, FareMedium, FareProduct, FareTransferRule, FareRule, Frequency, Transfer, Pathway, BookingRule, Translation, Attribution, Network, RouteNetwork, Area, Timeframe +from datetime import date, datetime # Create your tests here. +class FeedInfoTestCase(TestCase): + def setUp(self): + FeedInfo.objects.create(feed_publisher_name="All fields", feed_publisher_url='example.com', feed_lang='pl', default_lang='pl', feed_start_date=datetime(2024, 1, 1), feed_end_date=datetime.now(), feed_version='1.0', feed_contact_email='me@example.com', feed_contact_url='example.com') + def test_ok(self): + FeedInfo.objects.get(feed_publisher_name="All fields") + FeedInfo.objects.get(feed_publisher_url='example.com') + FeedInfo.objects.get(feed_lang='pl') + FeedInfo.objects.get(default_lang='pl') + FeedInfo.objects.get(feed_start_date=datetime(2024, 1, 1)) + FeedInfo.objects.get(feed_end_date=datetime.now()) + FeedInfo.objects.get(feed_version='1.0') + FeedInfo.objects.get(feed_contact_email='me@example.com') + FeedInfo.objects.get(feed_contact_email='me@example.com') + + +class AgencyTestCase(TestCase): + def setUp(self): + FeedInfo.objects.create(feed_publisher_name="All fields", feed_publisher_url='example.com', feed_lang='pl', default_lang='pl', feed_start_date=datetime(2024, 1, 1), feed_end_date=datetime.now(), feed_version='1.0', feed_contact_email='me@example.com', feed_contact_url='example.com') + Agency.objects.create(agency_name='test', agency_url='example.com', agency_timezone='Europe/Berlin', agency_lang='pl', agency_phone='0123456574', agency_fare_url='example.com', agency_email='me@example.com', feed_info_id=FeedInfo.objects.get(feed_publisher_name="All fields")) + def test_ok(self): + print(Agency.objects.get(agency_name='test').feed_info_id.feed_id) diff --git a/transport_accessibility/test.py b/transport_accessibility/test.py new file mode 100644 index 0000000..56efe13 --- /dev/null +++ b/transport_accessibility/test.py @@ -0,0 +1,10 @@ +import pt_map.models +import api.io +import inspect +#api.io.models_csv("/home/johannes/Downloads/torun") +q = [m.objects.all() for _,m in inspect.getmembers(pt_map.models, inspect.isclass)] +for s in q: + f = f"/home/johannes/Downloads/test3/{pt_map.class_names.case_swap[s.model._meta.object_name]}.txt" + with open(f, 'w') as file: + file.write(api.io.csv_queryset(s)) +quit()