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

Fixed some functions in StandardTripsCreator #126

Merged
merged 1 commit into from
Mar 1, 2018
Merged

Fixed some functions in StandardTripsCreator #126

merged 1 commit into from
Mar 1, 2018

Conversation

ialokim
Copy link
Contributor

@ialokim ialokim commented Feb 15, 2018

While working on the countrywide NicaraguaCreator, I've found some issues with the current TripsCreator implementation. See the inline comments for the specific issues.

Copy link
Contributor Author

@ialokim ialokim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my inline comments.

@@ -88,7 +88,8 @@ def _prepare_trips(self, feed, schedule, itinerary):
if input_fr == itinerary.fr and input_to == itinerary.to:
trip_services = trip["services"]
for service in trip_services:
services.append(service)
if service not in services:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent the case when the itineraries in the Schedule are split by some reason, do not double the services.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should they be split. Sorry I lack of context here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are in some cases of the Nicaraguan timetable.json because of the generation by easy-timetable-generator. But anyway, why shouldn't it be supported?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't understand it. Can you explain concretely why they should be split. Sorry for asking this stupid question, I just didn't get it, yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm referring to the case when there are two or more dict items inside the line's list for the same line, which present different times but using the same service period. See this example:

    "lines": {
        "E-MAN-EST": [
            {
                "exeptions": [],
                "from": "Mercado Mayoreo",
                "services": [
                    "Mo-Su"
                ],
                "stations": [
                    "Mercado Mayoreo",
                    "COTRAN Sur"
                ],
                "times": [
                    [
                        "05:45",
                        "08:15"
                    ],
                    [
                        "08:15",
                        "10:45"
                    ],
                    [
                        "09:15",
                        "11:45"
                    ],
                    [
                        "10:45",
                        "13:15"
                    ],
                    [
                        "11:45",
                        "14:15"
                    ]
                ],
                "to": "COTRAN Sur"
            },
            {
                "exeptions": [],
                "from": "Mercado Mayoreo",
                "services": [
                    "Mo-Su"
                ],
                "stations": [
                    "Mercado Mayoreo",
                    "COTRAN Sur"
                ],
                "times": [
                    [
                        "13:15",
                        "15:45"
                    ],
                    [
                        "15:15",
                        "17:45"
                    ],
                    [
                        "13:45",
                        "16:15"
                    ],
                    [
                        "15:45",
                        "18:15"
                    ]
                ],
                "to": "COTRAN Sur"
            },
            ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. I think this (edge) case is kind of an inconsistency in the standard schedule format and I personally would rather require a clean input format. But I guess if you and @Skippern are in favour of supporting it, there is a deeper reason I still can't see.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But shouldn't then the two dicts not been merged? As far as I see, now the second one (and all that follow) would be just discarded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now the second one (and all that follow) would be just discarded

To clear it up a bit, I'll explain what happened before and what should happen IMHO:

  • Before this PR, the services variable contained the following after iterating over the two (or more) dicts for one line: [Mo-Su, Mo-Su]. So in line 98 and more specifically in line 112, it would append the times from both dicts twice to the trips variable with the same service period Mo-Su.
  • With this change, the service variable would only contain the following: [Mo-Su] and the trips would be getting doubled.

This code isn't about the whole dict that would be discarded, but only preventing the doubling of a service period.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I got it. Thanks!

@@ -125,14 +126,31 @@ def _verify_data(self, schedule, line, itinerary):
str(line.route_id) + ")")
print(" " + itinerary.osm_url)
print(" " + line.osm_url)
return True
return False
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure, but shouldn't it return False when there's an error?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it looks like this should be False, indeed.


# Check if time information in schedule can be found for
# the itinerary
if itinerary.route_id not in schedule['lines']:
print(" Warning: Route not found in schedule.")
print("Warning: Route not found in schedule.")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to keep it as in the other cases.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

return False

# Check if from and to tags are valid and same one as first and last itinerary.stop
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This explains well the added check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to have this check. However I suggest to reword the comment. Maybe to

Check if from and to tags are valid and correspond to the actual name of the first and last stop of the itinerary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed accordingly.

@@ -166,16 +184,16 @@ def _add_itinerary_trips(self, feed, itinerary, line, trip_builder,
gtfs_trip = route.AddTrip(feed, headsign=itinerary.to,
service_period=trip_builder['service_period'])
trips_count += 1
search_idx = 0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent problems in itineraries where a stop (or a stop_name) is served twice, so that it doesn't pick the same time information twice (this would give "high-speed services" for the transitfeed validator), I've introduced the index from where it should search for the next time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested with Managua and it is the same result. Generally checked the code and looks good.

except ValueError:
pass

# Make sure the last stop of itinerary will keep being the last stop in GTFS
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To solve same problem described above.

@@ -217,10 +255,10 @@ def _add_itinerary_trips(self, feed, itinerary, line, trip_builder,
else:
try:
gtfs_trip.AddStopTime(gtfs_stop)
except ValueError:
print("Warning: Could not add first a stop to trip.")
except transitfeed.problems.OtherProblem:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It never throws ValueError, but OtherProblem.

print(" " + itinerary_stop.name +
" - " + itinerary_stop.osm_id)
" - " + itinerary_stop.osm_url)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to give more and consistent information

for trip in schedule['lines'][itinerary.route_id]:
trip_services = trip["services"]
if (trip["from"] == itinerary.fr and
trip["to"] == itinerary.to and
service in trip_services):
times = trip["times"]
for time in trip["times"]:
times.append(time)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to not loose times (overriding them).

@@ -323,4 +362,5 @@ def _load_scheduled_stops(self, schedule, itinerary, service):
"to"] == itinerary.to and service in trip_services):
for stop in trip["stations"]:
stops.append(stop)
break
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to not duplicate stops.

Copy link
Contributor

@xamanu xamanu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested it with Managua, had some minor questions. Looks good. Thanks for improving the standard trips creator!!

@@ -88,7 +88,8 @@ def _prepare_trips(self, feed, schedule, itinerary):
if input_fr == itinerary.fr and input_to == itinerary.to:
trip_services = trip["services"]
for service in trip_services:
services.append(service)
if service not in services:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should they be split. Sorry I lack of context here.

@@ -125,14 +126,31 @@ def _verify_data(self, schedule, line, itinerary):
str(line.route_id) + ")")
print(" " + itinerary.osm_url)
print(" " + line.osm_url)
return True
return False
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it looks like this should be False, indeed.


# Check if time information in schedule can be found for
# the itinerary
if itinerary.route_id not in schedule['lines']:
print(" Warning: Route not found in schedule.")
print("Warning: Route not found in schedule.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

return False

# Check if from and to tags are valid and same one as first and last itinerary.stop
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to have this check. However I suggest to reword the comment. Maybe to

Check if from and to tags are valid and correspond to the actual name of the first and last stop of the itinerary.

@@ -166,16 +184,16 @@ def _add_itinerary_trips(self, feed, itinerary, line, trip_builder,
gtfs_trip = route.AddTrip(feed, headsign=itinerary.to,
service_period=trip_builder['service_period'])
trips_count += 1
search_idx = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested with Managua and it is the same result. Generally checked the code and looks good.

@ialokim
Copy link
Contributor Author

ialokim commented Feb 26, 2018

Tested it with Managua

As Estelí and Managua are currently the only regions that use the standard creator's implementation (please correct me if I am wrong), I think this is ready to be merged too.

@Skippern
Copy link

Skippern commented Feb 27, 2018 via email

Copy link
Contributor

@xamanu xamanu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. I'm very happy with these improvements to the standard trips creator. It is great to see that a generic solution, which is used by several cities will improve it all together. Thanks a lot for this!

@grote
Copy link
Owner

grote commented Mar 1, 2018

Maybe let's get reviews from others whose creators rely on this?

@xamanu
Copy link
Contributor

xamanu commented Mar 1, 2018

So far I think only the Nicaraguan providers rely on the standard trips creator.

@grote grote merged commit bc7aaa8 into grote:master Mar 1, 2018
@ialokim ialokim deleted the trips-creator-fixes branch March 3, 2018 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants