r5py 0.1.1.dev2__py3-none-any.whl → 0.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of r5py might be problematic. Click here for more details.
- r5py/__init__.py +2 -1
- r5py/__main__.py +1 -14
- r5py/r5/__init__.py +14 -0
- r5py/r5/base_travel_time_matrix_computer.py +3 -4
- r5py/r5/detailed_itineraries_computer.py +6 -10
- r5py/r5/direct_leg.py +1 -3
- r5py/r5/regional_task.py +10 -7
- r5py/r5/street_layer.py +1 -0
- r5py/r5/transfer_leg.py +2 -6
- r5py/r5/transit_layer.py +2 -0
- r5py/r5/transit_leg.py +1 -5
- r5py/r5/transport_mode.py +5 -3
- r5py/r5/transport_network.py +16 -7
- r5py/r5/travel_time_matrix_computer.py +4 -15
- r5py/r5/trip.py +8 -4
- r5py/r5/trip_leg.py +44 -5
- r5py/r5/trip_planner.py +81 -39
- r5py/util/__init__.py +2 -0
- r5py/util/classpath.py +9 -5
- r5py/util/config.py +11 -2
- r5py/util/environment.py +34 -0
- r5py/util/good_enough_equidistant_crs.py +0 -1
- r5py/util/memory_footprint.py +3 -5
- r5py/util/sample_data_set.py +13 -5
- r5py/util/validating_requests_session.py +2 -2
- {r5py-0.1.1.dev2.dist-info → r5py-0.1.2.dist-info}/METADATA +7 -6
- r5py-0.1.2.dist-info/RECORD +43 -0
- {r5py-0.1.1.dev2.dist-info → r5py-0.1.2.dist-info}/WHEEL +1 -1
- r5py-0.1.1.dev2.dist-info/RECORD +0 -42
- {r5py-0.1.1.dev2.dist-info → r5py-0.1.2.dist-info}/LICENSE +0 -0
- {r5py-0.1.1.dev2.dist-info → r5py-0.1.2.dist-info}/top_level.txt +0 -0
r5py/__init__.py
CHANGED
r5py/__main__.py
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
"""A Python wrapper for the R5 routing analysis engine."""
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
from .util import Config
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def main():
|
|
11
|
-
config = Config()
|
|
12
|
-
arguments = config.get_arguments() # noqa F401
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if __name__ == "__main__":
|
|
16
|
-
main()
|
|
3
|
+
"""Python wrapper for the R5 routing analysis engine."""
|
r5py/r5/__init__.py
CHANGED
|
@@ -2,23 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
"""R5 classes."""
|
|
4
4
|
|
|
5
|
+
from .access_leg import AccessLeg
|
|
5
6
|
from .breakdown_stat import BreakdownStat
|
|
6
7
|
from .detailed_itineraries_computer import DetailedItinerariesComputer
|
|
8
|
+
from .direct_leg import DirectLeg
|
|
9
|
+
from .egress_leg import EgressLeg
|
|
7
10
|
from .regional_task import RegionalTask
|
|
8
11
|
from .scenario import Scenario
|
|
9
12
|
from .street_layer import StreetLayer
|
|
13
|
+
from .transfer_leg import TransferLeg
|
|
14
|
+
from .transit_leg import TransitLeg
|
|
10
15
|
from .transport_mode import TransportMode
|
|
11
16
|
from .transport_network import TransportNetwork
|
|
12
17
|
from .travel_time_matrix_computer import TravelTimeMatrixComputer
|
|
18
|
+
from .trip import Trip
|
|
19
|
+
from .trip_planner import TripPlanner
|
|
13
20
|
|
|
14
21
|
__all__ = [
|
|
22
|
+
"AccessLeg",
|
|
15
23
|
"BreakdownStat",
|
|
16
24
|
"DetailedItinerariesComputer",
|
|
25
|
+
"DirectLeg",
|
|
26
|
+
"EgressLeg",
|
|
17
27
|
"RegionalTask",
|
|
18
28
|
"Scenario",
|
|
19
29
|
"SpeedConfig",
|
|
20
30
|
"StreetLayer",
|
|
31
|
+
"TransferLeg",
|
|
32
|
+
"TransitLeg",
|
|
21
33
|
"TransportMode",
|
|
22
34
|
"TransportNetwork",
|
|
23
35
|
"TravelTimeMatrixComputer",
|
|
36
|
+
"Trip",
|
|
37
|
+
"TripPlanner",
|
|
24
38
|
]
|
|
@@ -91,6 +91,7 @@ class BaseTravelTimeMatrixComputer:
|
|
|
91
91
|
|
|
92
92
|
@property
|
|
93
93
|
def destinations(self):
|
|
94
|
+
"""The destinations of this travel time matrix (`geopandas.GeoDataFrame`)."""
|
|
94
95
|
return self._destinations
|
|
95
96
|
|
|
96
97
|
@destinations.setter
|
|
@@ -120,10 +121,7 @@ class BaseTravelTimeMatrixComputer:
|
|
|
120
121
|
return data_set.map(lambda x: numpy.nan if x == MAX_INT32 else x)
|
|
121
122
|
|
|
122
123
|
def _prepare_origins_destinations(self):
|
|
123
|
-
"""
|
|
124
|
-
Make sure we received enough information to route from origins to
|
|
125
|
-
destinations.
|
|
126
|
-
"""
|
|
124
|
+
"""Make sure we received enough information to route from origins to destinations."""
|
|
127
125
|
try:
|
|
128
126
|
self.origins
|
|
129
127
|
except AttributeError as exception:
|
|
@@ -165,6 +163,7 @@ class BaseTravelTimeMatrixComputer:
|
|
|
165
163
|
|
|
166
164
|
@property
|
|
167
165
|
def origins(self):
|
|
166
|
+
"""The origins of this travel time matrix (`geopandas.GeoDataFrame`)."""
|
|
168
167
|
return self._origins
|
|
169
168
|
|
|
170
169
|
@origins.setter
|
|
@@ -124,7 +124,6 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
124
124
|
route number or name), `geometry` (`shapely.LineString`)
|
|
125
125
|
TODO: Add description of output data frame columns and format
|
|
126
126
|
"""
|
|
127
|
-
|
|
128
127
|
self._prepare_origins_destinations()
|
|
129
128
|
|
|
130
129
|
# warn if public transport routes are requested, but R5 has been
|
|
@@ -150,11 +149,12 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
150
149
|
verbose=(10 * self.verbose), # joblib has a funny verbosity scale
|
|
151
150
|
n_jobs=self.NUM_THREADS,
|
|
152
151
|
) as parallel:
|
|
152
|
+
matrices = parallel(
|
|
153
|
+
joblib.delayed(self._travel_details_per_od_pair)(from_id, to_id)
|
|
154
|
+
for _, (from_id, to_id) in self.od_pairs.iterrows()
|
|
155
|
+
)
|
|
153
156
|
od_matrix = pandas.concat(
|
|
154
|
-
|
|
155
|
-
joblib.delayed(self._travel_details_per_od_pair)(from_id, to_id)
|
|
156
|
-
for _, (from_id, to_id) in self.od_pairs.iterrows()
|
|
157
|
-
),
|
|
157
|
+
[matrix.astype(matrices[0].dtypes) for matrix in matrices],
|
|
158
158
|
ignore_index=True,
|
|
159
159
|
)
|
|
160
160
|
|
|
@@ -162,11 +162,7 @@ class DetailedItinerariesComputer(BaseTravelTimeMatrixComputer):
|
|
|
162
162
|
return od_matrix
|
|
163
163
|
|
|
164
164
|
def _prepare_origins_destinations(self):
|
|
165
|
-
"""
|
|
166
|
-
Make sure we received enough information to route from origins to
|
|
167
|
-
destinations.
|
|
168
|
-
"""
|
|
169
|
-
|
|
165
|
+
"""Make sure we received enough information to route from origins to destinations."""
|
|
170
166
|
super()._prepare_origins_destinations()
|
|
171
167
|
|
|
172
168
|
if self.all_to_all:
|
r5py/r5/direct_leg.py
CHANGED
r5py/r5/regional_task.py
CHANGED
|
@@ -200,12 +200,16 @@ class RegionalTask:
|
|
|
200
200
|
# The value is a static property of com.conveyal.r5.analyst.cluster.PathResult;
|
|
201
201
|
# static properites of Java classes can be modified in a singleton kind of way
|
|
202
202
|
try:
|
|
203
|
-
|
|
204
|
-
com.conveyal.r5.analyst.cluster.PathResult.maxDestinations,
|
|
205
|
-
len(self.destinations) + 1,
|
|
206
|
-
)
|
|
203
|
+
num_destinations = len(self.destinations)
|
|
207
204
|
except AttributeError:
|
|
208
|
-
|
|
205
|
+
num_destinations = 0
|
|
206
|
+
if (
|
|
207
|
+
num_destinations
|
|
208
|
+
> com.conveyal.r5.analyst.cluster.PathResult.MAX_PATH_DESTINATIONS
|
|
209
|
+
):
|
|
210
|
+
com.conveyal.r5.analyst.cluster.PathResult.MAX_PATH_DESTINATIONS = (
|
|
211
|
+
num_destinations + 1
|
|
212
|
+
)
|
|
209
213
|
|
|
210
214
|
@property
|
|
211
215
|
def departure(self):
|
|
@@ -246,8 +250,7 @@ class RegionalTask:
|
|
|
246
250
|
|
|
247
251
|
@property
|
|
248
252
|
def departure_time_window(self):
|
|
249
|
-
"""Find public transport connections leaving within
|
|
250
|
-
``departure_time_window`` after ``departure`` (datetime.timedelta).
|
|
253
|
+
"""Find public transport connections leaving within ``departure_time_window`` after ``departure`` (datetime.timedelta).
|
|
251
254
|
|
|
252
255
|
**Note:** The value of ``departure_time_window`` should be set with some
|
|
253
256
|
caution. Specifically, setting values near or below the typical headways
|
r5py/r5/street_layer.py
CHANGED
r5py/r5/transfer_leg.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
"""Represent one leg of a trip, specifically transfers between public transport
|
|
5
|
-
vehicles."""
|
|
4
|
+
"""Represent one leg of a trip, specifically transfers between public transport vehicles."""
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
from .direct_leg import DirectLeg
|
|
@@ -12,7 +11,4 @@ __all__ = ["TransferLeg"]
|
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class TransferLeg(DirectLeg):
|
|
15
|
-
"""
|
|
16
|
-
Represent one leg of a trip, specifically transfers between public transport
|
|
17
|
-
vehicles.
|
|
18
|
-
"""
|
|
14
|
+
"""Represent one leg of a trip, specifically transfers between public transport vehicles."""
|
r5py/r5/transit_layer.py
CHANGED
|
@@ -90,10 +90,12 @@ class TransitLayer:
|
|
|
90
90
|
|
|
91
91
|
@functools.cached_property
|
|
92
92
|
def routes(self):
|
|
93
|
+
"""Return a list of GTFS routes."""
|
|
93
94
|
return list(self._transit_layer.routes)
|
|
94
95
|
|
|
95
96
|
@functools.cached_property
|
|
96
97
|
def trip_patterns(self):
|
|
98
|
+
"""Return a list of GTFS trip patterns."""
|
|
97
99
|
return list(self._transit_layer.tripPatterns)
|
|
98
100
|
|
|
99
101
|
|
r5py/r5/transit_leg.py
CHANGED
r5py/r5/transport_mode.py
CHANGED
|
@@ -68,6 +68,7 @@ class TransportMode(enum.Enum):
|
|
|
68
68
|
return None
|
|
69
69
|
|
|
70
70
|
def __add__(self, other):
|
|
71
|
+
"""Combine two transport modes."""
|
|
71
72
|
if isinstance(other, self.__class__):
|
|
72
73
|
return [self, other]
|
|
73
74
|
elif isinstance(other, list):
|
|
@@ -78,6 +79,7 @@ class TransportMode(enum.Enum):
|
|
|
78
79
|
)
|
|
79
80
|
|
|
80
81
|
def __radd__(self, other):
|
|
82
|
+
"""Combine two transport modes."""
|
|
81
83
|
if other == 0: # first iteration of sum()
|
|
82
84
|
return self
|
|
83
85
|
elif isinstance(other, list):
|
|
@@ -87,17 +89,17 @@ class TransportMode(enum.Enum):
|
|
|
87
89
|
|
|
88
90
|
@property
|
|
89
91
|
def is_leg_mode(self):
|
|
90
|
-
"""Can this TransportMode function as a LegMode
|
|
92
|
+
"""Can this TransportMode function as a LegMode?."""
|
|
91
93
|
return self.name in LEG_MODES
|
|
92
94
|
|
|
93
95
|
@property
|
|
94
96
|
def is_street_mode(self):
|
|
95
|
-
"""Can this TransportMode function as a StreetMode
|
|
97
|
+
"""Can this TransportMode function as a StreetMode?."""
|
|
96
98
|
return self.name in STREET_MODES
|
|
97
99
|
|
|
98
100
|
@property
|
|
99
101
|
def is_transit_mode(self):
|
|
100
|
-
"""Can this TransportMode function as a TransitMode
|
|
102
|
+
"""Can this TransportMode function as a TransitMode?."""
|
|
101
103
|
return self.name in TRANSIT_MODES
|
|
102
104
|
|
|
103
105
|
AIR = "AIR"
|
r5py/r5/transport_network.py
CHANGED
|
@@ -89,9 +89,7 @@ class TransportNetwork:
|
|
|
89
89
|
self._transport_network = transport_network
|
|
90
90
|
|
|
91
91
|
def __del__(self):
|
|
92
|
-
"""
|
|
93
|
-
Delete all temporary files upon destruction.
|
|
94
|
-
"""
|
|
92
|
+
"""Delete all temporary files upon destruction."""
|
|
95
93
|
MAX_TRIES = 10
|
|
96
94
|
|
|
97
95
|
# first, close the open osm_file,
|
|
@@ -110,13 +108,23 @@ class TransportNetwork:
|
|
|
110
108
|
del self.transit_layer
|
|
111
109
|
except AttributeError:
|
|
112
110
|
pass
|
|
113
|
-
|
|
111
|
+
try:
|
|
112
|
+
del self._transport_network
|
|
113
|
+
except AttributeError:
|
|
114
|
+
pass
|
|
114
115
|
|
|
115
|
-
time.sleep(0
|
|
116
|
-
|
|
116
|
+
time.sleep(1.0)
|
|
117
|
+
try:
|
|
118
|
+
jpype.java.lang.System.gc()
|
|
119
|
+
except jpype.JVMNotRunning:
|
|
120
|
+
pass
|
|
117
121
|
|
|
118
122
|
# then, try to delete all files in cache directory
|
|
119
|
-
|
|
123
|
+
try:
|
|
124
|
+
temporary_files = [child for child in self._cache_directory.iterdir()]
|
|
125
|
+
except FileNotFoundError: # deleted in the meantime/race condition
|
|
126
|
+
temporary_files = []
|
|
127
|
+
|
|
120
128
|
for _ in range(MAX_TRIES):
|
|
121
129
|
for temporary_file in temporary_files:
|
|
122
130
|
try:
|
|
@@ -206,6 +214,7 @@ class TransportNetwork:
|
|
|
206
214
|
|
|
207
215
|
@property
|
|
208
216
|
def extent(self):
|
|
217
|
+
"""The geographic area covered, as a `shapely.box`."""
|
|
209
218
|
# TODO: figure out how to get the extent of the GTFS schedule,
|
|
210
219
|
# then find the smaller extent of the two (or the larger one?)
|
|
211
220
|
return self.street_layer.extent
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import copy
|
|
6
6
|
|
|
7
|
-
import joblib
|
|
8
7
|
import pandas
|
|
9
8
|
|
|
10
9
|
from .base_travel_time_matrix_computer import BaseTravelTimeMatrixComputer
|
|
@@ -40,20 +39,10 @@ class TravelTimeMatrixComputer(BaseTravelTimeMatrixComputer):
|
|
|
40
39
|
self._prepare_origins_destinations()
|
|
41
40
|
self.request.destinations = self.destinations
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
verbose=(10 * self.verbose), # joblib has a funny verbosity scale
|
|
48
|
-
n_jobs=self.NUM_THREADS,
|
|
49
|
-
) as parallel:
|
|
50
|
-
od_matrix = pandas.concat(
|
|
51
|
-
parallel(
|
|
52
|
-
joblib.delayed(self._travel_times_per_origin)(from_id)
|
|
53
|
-
for from_id in self.origins.id
|
|
54
|
-
),
|
|
55
|
-
ignore_index=True,
|
|
56
|
-
)
|
|
42
|
+
od_matrix = pandas.concat(
|
|
43
|
+
[self._travel_times_per_origin(from_id) for from_id in self.origins.id],
|
|
44
|
+
ignore_index=True,
|
|
45
|
+
)
|
|
57
46
|
|
|
58
47
|
try:
|
|
59
48
|
od_matrix = od_matrix.to_crs(self._origins_crs)
|
r5py/r5/trip.py
CHANGED
|
@@ -15,9 +15,7 @@ __all__ = ["Trip"]
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class Trip:
|
|
18
|
-
"""
|
|
19
|
-
Represent one trip, consisting of one or more `TripLeg`s.
|
|
20
|
-
"""
|
|
18
|
+
"""Represent one trip, consisting of one or more `r5py.r5.TripLeg`."""
|
|
21
19
|
|
|
22
20
|
COLUMNS = [
|
|
23
21
|
"segment",
|
|
@@ -25,7 +23,7 @@ class Trip:
|
|
|
25
23
|
|
|
26
24
|
def __init__(self, legs=[]):
|
|
27
25
|
"""
|
|
28
|
-
Represent one trip, consisting of one of more `TripLeg
|
|
26
|
+
Represent one trip, consisting of one of more `r5py.r5.TripLeg`.
|
|
29
27
|
|
|
30
28
|
Arguments
|
|
31
29
|
=========
|
|
@@ -34,7 +32,13 @@ class Trip:
|
|
|
34
32
|
"""
|
|
35
33
|
self.legs = legs
|
|
36
34
|
|
|
35
|
+
def __eq__(self, other):
|
|
36
|
+
"""Check whether `self` and `other` are equal."""
|
|
37
|
+
if isinstance(other, self.__class__):
|
|
38
|
+
return self.legs == other.legs
|
|
39
|
+
|
|
37
40
|
def __repr__(self):
|
|
41
|
+
"""Return a string representation of `self`."""
|
|
38
42
|
legs = ", ".join([str(leg) for leg in self.legs])
|
|
39
43
|
return (
|
|
40
44
|
f"<{self.__class__.__name__}: "
|
r5py/r5/trip_leg.py
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
"""Represent one leg of a trip."""
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
import datetime
|
|
8
|
+
import numpy
|
|
9
|
+
import shapely
|
|
10
|
+
|
|
11
|
+
|
|
7
12
|
__all__ = ["TripLeg"]
|
|
8
13
|
|
|
9
14
|
|
|
@@ -28,12 +33,12 @@ class TripLeg:
|
|
|
28
33
|
def __init__(
|
|
29
34
|
self,
|
|
30
35
|
transport_mode=None,
|
|
31
|
-
departure_time=
|
|
36
|
+
departure_time=numpy.datetime64("NaT"),
|
|
32
37
|
distance=None,
|
|
33
|
-
travel_time=
|
|
34
|
-
wait_time=
|
|
38
|
+
travel_time=datetime.timedelta(seconds=0),
|
|
39
|
+
wait_time=datetime.timedelta(seconds=0),
|
|
35
40
|
route=None,
|
|
36
|
-
geometry=
|
|
41
|
+
geometry=shapely.LineString(),
|
|
37
42
|
):
|
|
38
43
|
"""
|
|
39
44
|
Represent one leg of a trip.
|
|
@@ -66,6 +71,7 @@ class TripLeg:
|
|
|
66
71
|
self.geometry = geometry
|
|
67
72
|
|
|
68
73
|
def __add__(self, other):
|
|
74
|
+
"""Trip-chain `other` to `self`."""
|
|
69
75
|
from .trip import Trip
|
|
70
76
|
|
|
71
77
|
if isinstance(other, self.__class__):
|
|
@@ -80,6 +86,7 @@ class TripLeg:
|
|
|
80
86
|
)
|
|
81
87
|
|
|
82
88
|
def __radd__(self, other):
|
|
89
|
+
"""Trip-chain `self` to `other`."""
|
|
83
90
|
from .trip import Trip
|
|
84
91
|
|
|
85
92
|
if other == 0: # first iteration of sum()
|
|
@@ -90,31 +97,43 @@ class TripLeg:
|
|
|
90
97
|
else:
|
|
91
98
|
return self.__add__(other)
|
|
92
99
|
|
|
100
|
+
def __eq__(self, other):
|
|
101
|
+
"""Check if `other` is an equal `TripLeg`."""
|
|
102
|
+
if isinstance(other, self.__class__):
|
|
103
|
+
return False not in [
|
|
104
|
+
self._are_columns_equal(other, column) for column in self.COLUMNS
|
|
105
|
+
]
|
|
106
|
+
|
|
93
107
|
def __gt__(self, other):
|
|
108
|
+
"""Check if `other` has a longer travel time."""
|
|
94
109
|
if isinstance(other, TripLeg):
|
|
95
110
|
return (self.travel_time + self.wait_time) > (
|
|
96
111
|
other.travel_time + other.wait_time
|
|
97
112
|
)
|
|
98
113
|
|
|
99
114
|
def __ge__(self, other):
|
|
115
|
+
"""Check if `other` has a longer or equal travel time."""
|
|
100
116
|
if isinstance(other, TripLeg):
|
|
101
117
|
return (self.travel_time + self.wait_time) >= (
|
|
102
118
|
other.travel_time + other.wait_time
|
|
103
119
|
)
|
|
104
120
|
|
|
105
121
|
def __lt__(self, other):
|
|
122
|
+
"""Check if `other` has a shorter travel time."""
|
|
106
123
|
if isinstance(other, TripLeg):
|
|
107
124
|
return (self.travel_time + self.wait_time) < (
|
|
108
125
|
other.travel_time + other.wait_time
|
|
109
126
|
)
|
|
110
127
|
|
|
111
128
|
def __le__(self, other):
|
|
129
|
+
"""Check if `other` has a shorter or equal travel time."""
|
|
112
130
|
if isinstance(other, TripLeg):
|
|
113
131
|
return (self.travel_time + self.wait_time) <= (
|
|
114
132
|
other.travel_time + other.wait_time
|
|
115
133
|
)
|
|
116
134
|
|
|
117
135
|
def __repr__(self):
|
|
136
|
+
"""Return a string representation."""
|
|
118
137
|
try:
|
|
119
138
|
first_point = self.geometry.coords[0]
|
|
120
139
|
last_point = self.geometry.coords[-1]
|
|
@@ -127,10 +146,30 @@ class TripLeg:
|
|
|
127
146
|
f"{first_point} -> {last_point}"
|
|
128
147
|
">"
|
|
129
148
|
)
|
|
130
|
-
except AttributeError:
|
|
149
|
+
except (AttributeError, IndexError):
|
|
131
150
|
_repr = f"<{self.__class__.__name__}>"
|
|
132
151
|
return _repr
|
|
133
152
|
|
|
153
|
+
def _are_columns_equal(self, other, column):
|
|
154
|
+
"""
|
|
155
|
+
Check if a column equals the same column of a different `Trip`.
|
|
156
|
+
|
|
157
|
+
Compare if attribute `column` of self equals attribute `column` of
|
|
158
|
+
other. Also True if both values are None or NaN or NaT.
|
|
159
|
+
"""
|
|
160
|
+
self_column = getattr(self, column)
|
|
161
|
+
other_column = getattr(other, column)
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
self_column == other_column
|
|
165
|
+
or (self_column is None and other_column is None)
|
|
166
|
+
or (self_column == numpy.nan and other_column == numpy.nan)
|
|
167
|
+
or (
|
|
168
|
+
self_column == numpy.datetime64("NaT")
|
|
169
|
+
and other_column == numpy.datetime64("NaT")
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
|
|
134
173
|
def as_table_row(self):
|
|
135
174
|
"""
|
|
136
175
|
Return a table row (list) of this trip leg’s details.
|
r5py/r5/trip_planner.py
CHANGED
|
@@ -43,9 +43,7 @@ ZERO_SECONDS = datetime.timedelta(seconds=0)
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
class TripPlanner:
|
|
46
|
-
"""
|
|
47
|
-
Find detailed routes between two points.
|
|
48
|
-
"""
|
|
46
|
+
"""Find detailed routes between two points."""
|
|
49
47
|
|
|
50
48
|
MAX_ACCESS_TIME = datetime.timedelta(hours=1)
|
|
51
49
|
MAX_EGRESS_TIME = MAX_ACCESS_TIME
|
|
@@ -72,7 +70,7 @@ class TripPlanner:
|
|
|
72
70
|
@property
|
|
73
71
|
def trips(self):
|
|
74
72
|
"""
|
|
75
|
-
|
|
73
|
+
Detailed routes between two points.
|
|
76
74
|
|
|
77
75
|
Returns
|
|
78
76
|
=======
|
|
@@ -84,6 +82,15 @@ class TripPlanner:
|
|
|
84
82
|
|
|
85
83
|
@property
|
|
86
84
|
def direct_paths(self):
|
|
85
|
+
"""
|
|
86
|
+
Detailed routes between two points using direct modes.
|
|
87
|
+
|
|
88
|
+
Returns
|
|
89
|
+
=======
|
|
90
|
+
list[r5py.r5.Trip]
|
|
91
|
+
Detailed routes that meet the requested parameters, using direct
|
|
92
|
+
modes (walking, cycling, driving).
|
|
93
|
+
"""
|
|
87
94
|
direct_paths = []
|
|
88
95
|
request = copy.copy(self.request)
|
|
89
96
|
|
|
@@ -143,11 +150,16 @@ class TripPlanner:
|
|
|
143
150
|
]
|
|
144
151
|
)
|
|
145
152
|
)
|
|
146
|
-
except
|
|
153
|
+
except (
|
|
154
|
+
java.lang.NullPointerException,
|
|
155
|
+
java.util.NoSuchElementException,
|
|
156
|
+
):
|
|
147
157
|
warnings.warn(
|
|
148
158
|
f"Could not find route between origin "
|
|
149
|
-
f"({self.request.fromLon},
|
|
150
|
-
f"
|
|
159
|
+
f"({self.request._regional_task.fromLon}, "
|
|
160
|
+
f"{self.request._regional_task.fromLat}) "
|
|
161
|
+
f"and destination ({self.request._regional_task.toLon}, "
|
|
162
|
+
f"{self.request._regional_task.toLat})",
|
|
151
163
|
RuntimeWarning,
|
|
152
164
|
)
|
|
153
165
|
return direct_paths
|
|
@@ -168,6 +180,15 @@ class TripPlanner:
|
|
|
168
180
|
|
|
169
181
|
@functools.cached_property
|
|
170
182
|
def transit_paths(self):
|
|
183
|
+
"""
|
|
184
|
+
Detailed routes between two points on public transport.
|
|
185
|
+
|
|
186
|
+
Returns
|
|
187
|
+
=======
|
|
188
|
+
list[r5py.r5.Trip]
|
|
189
|
+
Detailed routes that meet the requested parameters, on public
|
|
190
|
+
transport.
|
|
191
|
+
"""
|
|
171
192
|
transit_paths = []
|
|
172
193
|
|
|
173
194
|
# if any transit mode requested:
|
|
@@ -214,8 +235,8 @@ class TripPlanner:
|
|
|
214
235
|
com.conveyal.r5.profile.McRaptorSuboptimalPathProfileRouter(
|
|
215
236
|
self.transport_network,
|
|
216
237
|
request,
|
|
217
|
-
self.
|
|
218
|
-
self.
|
|
238
|
+
self._transit_access_times,
|
|
239
|
+
self._transit_egress_times,
|
|
219
240
|
list_supplier_callback,
|
|
220
241
|
None,
|
|
221
242
|
True,
|
|
@@ -234,18 +255,26 @@ class TripPlanner:
|
|
|
234
255
|
for state in list(states) # some departure times yield no results
|
|
235
256
|
}
|
|
236
257
|
|
|
258
|
+
# keep another cache layer of shortest access and egress legs
|
|
259
|
+
access_legs_by_stop = {}
|
|
260
|
+
egress_legs_by_stop = {}
|
|
261
|
+
|
|
237
262
|
for departure_time, state in final_states.items():
|
|
238
263
|
trip = Trip()
|
|
239
264
|
while state:
|
|
240
265
|
if state.stop == -1: # EgressLeg
|
|
241
|
-
|
|
242
|
-
[
|
|
243
|
-
|
|
244
|
-
|
|
266
|
+
try:
|
|
267
|
+
leg = egress_legs_by_stop[state.back.stop]
|
|
268
|
+
except KeyError:
|
|
269
|
+
leg = min(
|
|
270
|
+
[
|
|
271
|
+
self._transit_egress_paths[transport_mode][
|
|
272
|
+
state.back.stop
|
|
273
|
+
]
|
|
274
|
+
for transport_mode in self._transit_egress_paths.keys()
|
|
245
275
|
]
|
|
246
|
-
|
|
247
|
-
]
|
|
248
|
-
)
|
|
276
|
+
)
|
|
277
|
+
egress_legs_by_stop[state.back.stop] = leg
|
|
249
278
|
leg.wait_time = ZERO_SECONDS
|
|
250
279
|
leg.departure_time = (
|
|
251
280
|
midnight
|
|
@@ -255,14 +284,18 @@ class TripPlanner:
|
|
|
255
284
|
leg.arrival_time = leg.departure_time + leg.travel_time
|
|
256
285
|
|
|
257
286
|
elif state.back is None: # AccessLeg
|
|
258
|
-
|
|
259
|
-
[
|
|
260
|
-
|
|
261
|
-
|
|
287
|
+
try:
|
|
288
|
+
leg = access_legs_by_stop[state.stop]
|
|
289
|
+
except KeyError:
|
|
290
|
+
leg = min(
|
|
291
|
+
[
|
|
292
|
+
self._transit_access_paths[transport_mode][
|
|
293
|
+
state.stop
|
|
294
|
+
]
|
|
295
|
+
for transport_mode in self._transit_access_paths.keys()
|
|
262
296
|
]
|
|
263
|
-
|
|
264
|
-
]
|
|
265
|
-
)
|
|
297
|
+
)
|
|
298
|
+
access_legs_by_stop[state.stop] = leg
|
|
266
299
|
leg.wait_time = ZERO_SECONDS
|
|
267
300
|
leg.arrival_time = midnight + datetime.timedelta(
|
|
268
301
|
seconds=state.time
|
|
@@ -274,7 +307,7 @@ class TripPlanner:
|
|
|
274
307
|
departure_stop = state.back.stop
|
|
275
308
|
arrival_stop = state.stop
|
|
276
309
|
|
|
277
|
-
leg = self.
|
|
310
|
+
leg = self._transit_transfer_path(
|
|
278
311
|
departure_stop, arrival_stop
|
|
279
312
|
)
|
|
280
313
|
|
|
@@ -361,12 +394,14 @@ class TripPlanner:
|
|
|
361
394
|
trip = leg + trip
|
|
362
395
|
state = state.back
|
|
363
396
|
|
|
364
|
-
|
|
397
|
+
# R5 sometimes reports the same path more than once, skip duplicates
|
|
398
|
+
if trip not in transit_paths:
|
|
399
|
+
transit_paths.append(trip)
|
|
365
400
|
|
|
366
401
|
return transit_paths
|
|
367
402
|
|
|
368
403
|
@functools.cached_property
|
|
369
|
-
def
|
|
404
|
+
def _transit_access_paths(self):
|
|
370
405
|
access_paths = {}
|
|
371
406
|
|
|
372
407
|
request = copy.copy(self.request)
|
|
@@ -406,9 +441,12 @@ class TripPlanner:
|
|
|
406
441
|
return access_paths
|
|
407
442
|
|
|
408
443
|
@functools.cached_property
|
|
409
|
-
def
|
|
410
|
-
"""
|
|
411
|
-
|
|
444
|
+
def _transit_access_times(self):
|
|
445
|
+
"""
|
|
446
|
+
Times to reached stops.
|
|
447
|
+
|
|
448
|
+
In the format required by McRaptorSuboptimalPathProfileRouter.
|
|
449
|
+
"""
|
|
412
450
|
access_times = jpype.JObject(
|
|
413
451
|
{
|
|
414
452
|
com.conveyal.r5.api.util.LegMode
|
|
@@ -419,14 +457,14 @@ class TripPlanner:
|
|
|
419
457
|
for transfer_leg in reached_stops.values()
|
|
420
458
|
],
|
|
421
459
|
)
|
|
422
|
-
for mode, reached_stops in self.
|
|
460
|
+
for mode, reached_stops in self._transit_access_paths.items()
|
|
423
461
|
},
|
|
424
462
|
"java.util.Map<com.conveyal.r5.LegMode, gnu.trove.map.TIntIntMap>",
|
|
425
463
|
)
|
|
426
464
|
return access_times
|
|
427
465
|
|
|
428
466
|
@functools.cached_property
|
|
429
|
-
def
|
|
467
|
+
def _transit_egress_paths(self):
|
|
430
468
|
egress_paths = {}
|
|
431
469
|
|
|
432
470
|
request = copy.copy(self.request)
|
|
@@ -467,9 +505,12 @@ class TripPlanner:
|
|
|
467
505
|
return egress_paths
|
|
468
506
|
|
|
469
507
|
@functools.cached_property
|
|
470
|
-
def
|
|
471
|
-
"""
|
|
472
|
-
|
|
508
|
+
def _transit_egress_times(self):
|
|
509
|
+
"""
|
|
510
|
+
Times to reached stops.
|
|
511
|
+
|
|
512
|
+
In the format required by McRaptorSuboptimalPathProfileRouter.
|
|
513
|
+
"""
|
|
473
514
|
egress_times = jpype.JObject(
|
|
474
515
|
{
|
|
475
516
|
com.conveyal.r5.api.util.LegMode
|
|
@@ -480,13 +521,14 @@ class TripPlanner:
|
|
|
480
521
|
for transfer_leg in reached_stops.values()
|
|
481
522
|
],
|
|
482
523
|
)
|
|
483
|
-
for mode, reached_stops in self.
|
|
524
|
+
for mode, reached_stops in self._transit_egress_paths.items()
|
|
484
525
|
},
|
|
485
526
|
"java.util.Map<com.conveyal.r5.LegMode, gnu.trove.map.TIntIntMap>",
|
|
486
527
|
)
|
|
487
528
|
return egress_times
|
|
488
529
|
|
|
489
|
-
def
|
|
530
|
+
def _transit_transfer_path(self, from_stop, to_stop):
|
|
531
|
+
"""Find a transfer path between two transit stops."""
|
|
490
532
|
self._transfer_paths = {}
|
|
491
533
|
while True:
|
|
492
534
|
try:
|
|
@@ -524,8 +566,8 @@ class TripPlanner:
|
|
|
524
566
|
TransportMode.WALK,
|
|
525
567
|
)
|
|
526
568
|
|
|
527
|
-
transfer_path = self._transfer_paths[
|
|
528
|
-
(
|
|
529
|
-
|
|
569
|
+
transfer_path = self._transfer_paths[(from_stop, to_stop)] = (
|
|
570
|
+
TransferLeg(TransportMode.WALK, street_segment)
|
|
571
|
+
)
|
|
530
572
|
|
|
531
573
|
return transfer_path
|
r5py/util/__init__.py
CHANGED
r5py/util/classpath.py
CHANGED
|
@@ -17,8 +17,10 @@ from .warnings import R5pyWarning
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
# update these to use a newer R5 version if no R5 available locally
|
|
20
|
-
R5_JAR_URL =
|
|
21
|
-
|
|
20
|
+
R5_JAR_URL = (
|
|
21
|
+
"https://github.com/r5py/r5/releases/download/v7.1-r5py/r5-v7.1-r5py-all.jar"
|
|
22
|
+
)
|
|
23
|
+
R5_JAR_SHA256 = "cd697b50323fd99977c98039ea317698bcf5fbbdb12b59e3e094ae9443648db2"
|
|
22
24
|
# ---
|
|
23
25
|
|
|
24
26
|
|
|
@@ -73,9 +75,11 @@ def find_r5_classpath(arguments):
|
|
|
73
75
|
"Could not find R5 jar, trying to download it from upstream",
|
|
74
76
|
R5pyWarning,
|
|
75
77
|
)
|
|
76
|
-
with
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
with (
|
|
79
|
+
ValidatingRequestsSession() as session,
|
|
80
|
+
session.get(R5_JAR_URL, R5_JAR_SHA256) as response,
|
|
81
|
+
open(r5_classpath, "wb") as jar,
|
|
82
|
+
):
|
|
79
83
|
jar.write(response.content)
|
|
80
84
|
if arguments.verbose:
|
|
81
85
|
warnings.warn(
|
r5py/util/config.py
CHANGED
|
@@ -31,7 +31,6 @@ class Config:
|
|
|
31
31
|
|
|
32
32
|
def __init__(self):
|
|
33
33
|
"""Load configuration from config files or command line arguments."""
|
|
34
|
-
|
|
35
34
|
self.argparser.add(
|
|
36
35
|
"-v",
|
|
37
36
|
"--verbose",
|
|
@@ -40,6 +39,7 @@ class Config:
|
|
|
40
39
|
)
|
|
41
40
|
|
|
42
41
|
def __new__(cls):
|
|
42
|
+
"""Load configuration from config files or command line arguments."""
|
|
43
43
|
if cls._instance is None:
|
|
44
44
|
cls._instance = super(Config, cls).__new__(cls)
|
|
45
45
|
return cls._instance
|
|
@@ -55,6 +55,7 @@ class Config:
|
|
|
55
55
|
|
|
56
56
|
@property
|
|
57
57
|
def argparser(self):
|
|
58
|
+
"""Return a singleton instance of a `configargparse.ArgumentParser`."""
|
|
58
59
|
try:
|
|
59
60
|
argparser = configargparse.get_argument_parser(
|
|
60
61
|
prog=PACKAGE,
|
|
@@ -67,6 +68,7 @@ class Config:
|
|
|
67
68
|
|
|
68
69
|
@functools.cached_property
|
|
69
70
|
def CACHE_DIR(self):
|
|
71
|
+
"""Save persistent cache files into this directory."""
|
|
70
72
|
cache_dir = (
|
|
71
73
|
pathlib.Path(
|
|
72
74
|
os.environ.get("LOCALAPPDATA")
|
|
@@ -80,6 +82,7 @@ class Config:
|
|
|
80
82
|
|
|
81
83
|
@functools.cached_property
|
|
82
84
|
def CONFIG_FILES(self):
|
|
85
|
+
"""List locations of potential configuration files."""
|
|
83
86
|
config_files = [
|
|
84
87
|
pathlib.Path(f"/etc/{PACKAGE}.yml"),
|
|
85
88
|
pathlib.Path(
|
|
@@ -130,8 +133,14 @@ class Config:
|
|
|
130
133
|
|
|
131
134
|
@functools.cached_property
|
|
132
135
|
def TEMP_DIR(self):
|
|
136
|
+
"""
|
|
137
|
+
Save temporary files to this directory.
|
|
138
|
+
|
|
139
|
+
read-only property,
|
|
140
|
+
use command-line option `--temporary-directory` to change.
|
|
141
|
+
"""
|
|
133
142
|
parent_dir = self.arguments.temporary_directory
|
|
134
|
-
temp_dir = pathlib.Path(tempfile.mkdtemp(prefix=self.PACKAGE
|
|
143
|
+
temp_dir = pathlib.Path(tempfile.mkdtemp(prefix=self.PACKAGE, dir=parent_dir))
|
|
135
144
|
return temp_dir
|
|
136
145
|
|
|
137
146
|
PACKAGE = PACKAGE
|
r5py/util/environment.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
"""Normalise some environment variables that might not always get set."""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import pathlib
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# if a readthedocs runner uses a conda environment, it fails to
|
|
12
|
+
# properly initialise the JAVA_HOME and PROJ_LIB environment variables
|
|
13
|
+
#
|
|
14
|
+
# this might happen on other installation, so let’s keep this as general
|
|
15
|
+
# as possible.
|
|
16
|
+
#
|
|
17
|
+
# As readthedocs also does not export CONDA_PREFIX, we first reconstruct
|
|
18
|
+
# it from CONDA_ENVS_PATH and CONDA_DEFAULT_ENV
|
|
19
|
+
if (
|
|
20
|
+
"CONDA_PREFIX" not in os.environ
|
|
21
|
+
and "CONDA_DEFAULT_ENV" in os.environ
|
|
22
|
+
and "CONDA_ENVS_PATH" in os.environ
|
|
23
|
+
):
|
|
24
|
+
os.environ["CONDA_PREFIX"] = str(
|
|
25
|
+
pathlib.Path(os.environ["CONDA_ENVS_PATH"]) / os.environ["CONDA_DEFAULT_ENV"]
|
|
26
|
+
)
|
|
27
|
+
if "JAVA_HOME" not in os.environ and "CONDA_PREFIX" in os.environ:
|
|
28
|
+
os.environ["JAVA_HOME"] = str(
|
|
29
|
+
pathlib.Path(os.environ["CONDA_PREFIX"]) / "lib" / "jvm"
|
|
30
|
+
)
|
|
31
|
+
if "PROJ_LIB" not in os.environ and "CONDA_PREFIX" in os.environ:
|
|
32
|
+
os.environ["PROJ_LIB"] = str(
|
|
33
|
+
pathlib.Path(os.environ["CONDA_PREFIX"]) / "share" / "proj"
|
|
34
|
+
)
|
|
@@ -31,7 +31,6 @@ class GoodEnoughEquidistantCrs(pyproj.CRS):
|
|
|
31
31
|
The geographical extent for which to find an equidistant reference
|
|
32
32
|
system, in `EPSG:4326`
|
|
33
33
|
"""
|
|
34
|
-
|
|
35
34
|
if GoodEnoughEquidistantCrs._is_plausible_in_epsg4326(extent):
|
|
36
35
|
# default CRS in case we do not find any better match
|
|
37
36
|
crs = pyproj.CRS.from_epsg(3857)
|
r5py/util/memory_footprint.py
CHANGED
|
@@ -62,9 +62,9 @@ def _share_of_ram(share=0.8, leave_at_least=(2 * 1024**3)):
|
|
|
62
62
|
|
|
63
63
|
def _parse_value_and_unit(value_and_unit, max_unit_length=1):
|
|
64
64
|
"""
|
|
65
|
-
Extract value and unit from a string
|
|
66
|
-
(non-numeric) unit suffix.
|
|
65
|
+
Extract value and unit from a string.
|
|
67
66
|
|
|
67
|
+
The string is allowed to contain a (non-numeric) unit suffix.
|
|
68
68
|
For instance, input values of `'1M'` or `3.732G` would yield return
|
|
69
69
|
values `(1, 'M')` or `(3.732, 'G')`, respectively.
|
|
70
70
|
|
|
@@ -112,11 +112,10 @@ def _interpret_power_of_two_units(value, unit):
|
|
|
112
112
|
int:
|
|
113
113
|
interpreted value in bytes
|
|
114
114
|
"""
|
|
115
|
-
|
|
116
|
-
SUFFIXES = " KMGTPEZY"
|
|
117
115
|
# the position of each suffix in this string is the unit’s exponent
|
|
118
116
|
# over 1024.
|
|
119
117
|
# Compare https://en.wikipedia.org/wiki/ISO%2FIEC_80000#Part_13:_Information_science_and_technology
|
|
118
|
+
SUFFIXES = " KMGTPEZY"
|
|
120
119
|
|
|
121
120
|
if unit is None:
|
|
122
121
|
unit = " "
|
|
@@ -152,7 +151,6 @@ def _get_max_memory(max_memory):
|
|
|
152
151
|
int
|
|
153
152
|
Maximum amount of memory allocated for R5 in bytes.
|
|
154
153
|
"""
|
|
155
|
-
|
|
156
154
|
try:
|
|
157
155
|
value, unit = _parse_value_and_unit(max_memory)
|
|
158
156
|
except TypeError:
|
r5py/util/sample_data_set.py
CHANGED
|
@@ -25,6 +25,7 @@ class SampleDataSet(pathlib.Path):
|
|
|
25
25
|
_CACHE_DIR = pathlib.Path(config.CACHE_DIR) / "sampledata"
|
|
26
26
|
|
|
27
27
|
def __new__(cls, remote_url, sha256_checksum):
|
|
28
|
+
"""Define a data set that is downloaded and cached on demand."""
|
|
28
29
|
# pathlib.Path does everything in __new__, rather than __init__
|
|
29
30
|
cached_path = cls._CACHE_DIR / pathlib.Path(remote_url).name
|
|
30
31
|
return super().__new__(cls, cached_path)
|
|
@@ -40,10 +41,16 @@ class SampleDataSet(pathlib.Path):
|
|
|
40
41
|
sha256_checksum : str
|
|
41
42
|
checksum for this data set, using an SHA256 algorithm
|
|
42
43
|
"""
|
|
43
|
-
|
|
44
|
+
cached_path = self._CACHE_DIR / pathlib.Path(remote_url).name
|
|
45
|
+
|
|
46
|
+
try: # Python>=3.12
|
|
47
|
+
super().__init__(cached_path)
|
|
48
|
+
except TypeError:
|
|
49
|
+
super().__init__()
|
|
50
|
+
|
|
44
51
|
self.remote_url = remote_url
|
|
45
52
|
self.checksum = sha256_checksum
|
|
46
|
-
self.cached_path =
|
|
53
|
+
self.cached_path = cached_path
|
|
47
54
|
self._download_remote_file()
|
|
48
55
|
|
|
49
56
|
def _download_remote_file(self):
|
|
@@ -60,7 +67,8 @@ class SampleDataSet(pathlib.Path):
|
|
|
60
67
|
RuntimeWarning,
|
|
61
68
|
)
|
|
62
69
|
self.cached_path.parent.mkdir(exist_ok=True)
|
|
63
|
-
with
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
with (
|
|
71
|
+
ValidatingRequestsSession() as session,
|
|
72
|
+
session.get(self.remote_url, self.checksum) as response,
|
|
73
|
+
):
|
|
66
74
|
self.cached_path.write_bytes(response.content)
|
|
@@ -30,12 +30,12 @@ class ValidatingRequestsSession(requests.Session):
|
|
|
30
30
|
self._algorithm = checksum_algorithm
|
|
31
31
|
|
|
32
32
|
def get(self, url, checksum, **kwargs):
|
|
33
|
-
"""
|
|
33
|
+
"""Send a GET request, tests checksum."""
|
|
34
34
|
kwargs.setdefault("allow_redirects", True)
|
|
35
35
|
return self.request("GET", url, checksum, **kwargs)
|
|
36
36
|
|
|
37
37
|
def post(self, url, checksum, **kwargs):
|
|
38
|
-
"""
|
|
38
|
+
"""Send a POST request, tests checksum."""
|
|
39
39
|
return self.request("POST", url, checksum, **kwargs)
|
|
40
40
|
|
|
41
41
|
# delete, put, head don’t return data,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: r5py
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python wrapper for the R5 routing analysis engine
|
|
5
5
|
Author: Willem Klumpenhouwer, Marcus Sairava, Rafael Pereira, Henrikki Tenkanen
|
|
6
6
|
Author-email: Christoph Fink <christoph.fink@helsinki.fi>
|
|
@@ -41,8 +41,8 @@ Requires-Dist: matplotlib ; extra == 'docs'
|
|
|
41
41
|
Requires-Dist: myst-nb ; extra == 'docs'
|
|
42
42
|
Requires-Dist: nbsphinx ; extra == 'docs'
|
|
43
43
|
Requires-Dist: pybtex-apa7-style ; extra == 'docs'
|
|
44
|
-
Requires-Dist: r5py.sampledata.helsinki >=0.1.1
|
|
45
|
-
Requires-Dist: r5py.sampledata.sao-paulo >=0.1.1
|
|
44
|
+
Requires-Dist: r5py.sampledata.helsinki >=0.1.1 ; extra == 'docs'
|
|
45
|
+
Requires-Dist: r5py.sampledata.sao-paulo >=0.1.1 ; extra == 'docs'
|
|
46
46
|
Requires-Dist: shapely ; extra == 'docs'
|
|
47
47
|
Requires-Dist: sphinx ; extra == 'docs'
|
|
48
48
|
Requires-Dist: sphinx-book-theme ; extra == 'docs'
|
|
@@ -50,12 +50,13 @@ Requires-Dist: sphinx-design ; extra == 'docs'
|
|
|
50
50
|
Requires-Dist: sphinxcontrib-bibtex ; extra == 'docs'
|
|
51
51
|
Requires-Dist: sphinxcontrib-images ; extra == 'docs'
|
|
52
52
|
Provides-Extra: tests
|
|
53
|
+
Requires-Dist: pyarrow ; extra == 'tests'
|
|
53
54
|
Requires-Dist: pytest ; extra == 'tests'
|
|
54
55
|
Requires-Dist: pytest-asyncio ; extra == 'tests'
|
|
55
56
|
Requires-Dist: pytest-cov ; extra == 'tests'
|
|
56
|
-
Requires-Dist: pytest-lazy-
|
|
57
|
-
Requires-Dist: r5py.sampledata.helsinki >=0.1.1
|
|
58
|
-
Requires-Dist: r5py.sampledata.sao-paulo >=0.1.1
|
|
57
|
+
Requires-Dist: pytest-lazy-fixtures ; extra == 'tests'
|
|
58
|
+
Requires-Dist: r5py.sampledata.helsinki >=0.1.1 ; extra == 'tests'
|
|
59
|
+
Requires-Dist: r5py.sampledata.sao-paulo >=0.1.1 ; extra == 'tests'
|
|
59
60
|
|
|
60
61
|
<img class="r5py_logo" align="right" src="https://github.com/r5py/r5py/raw/main/docs/_static/images/r5py_blue.svg" alt="r5py logo" style="width:180px; max-width:30vW;">
|
|
61
62
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
r5py/__init__.py,sha256=CvtwufBhIEjDtiNGgSjbvb6mtHtmDAmzOmRYtdOm49M,414
|
|
2
|
+
r5py/__main__.py,sha256=Wvn0ChD7E-dCSZ8b8k_HhHG0KMOk0qMNFkijGuSH3-0,81
|
|
3
|
+
r5py/r5/__init__.py,sha256=xwk-xAck8osVgIW7sSML04c5JuB5y9a23Gym0G6cV4w,999
|
|
4
|
+
r5py/r5/access_leg.py,sha256=W3GfPEpqmWD1c4xipd6UcVIaBC-yb6srGCZV30E2dPY,293
|
|
5
|
+
r5py/r5/base_travel_time_matrix_computer.py,sha256=qxaNyw4AuzLfCi7Yll8M_Y37v6pCoZsQPEZ3WKLhpkc,6454
|
|
6
|
+
r5py/r5/breakdown_stat.py,sha256=ZQkWA0hXlcRH3KVgtxPSNHP0FUDri8MWqdFk8EUdDMU,533
|
|
7
|
+
r5py/r5/detailed_itineraries_computer.py,sha256=6PzypGs5bOJv_NJ2AIm77u7uECzhm6BCF0lUPKlCXrs,8525
|
|
8
|
+
r5py/r5/direct_leg.py,sha256=T7wX8puhOVIssCpflXthYs-G9OA8pasFbdz9p8k8teg,1054
|
|
9
|
+
r5py/r5/egress_leg.py,sha256=9rsCIcwlZUzoZE6q4imNY3VWpjJepO1IJvheVrlPi90,297
|
|
10
|
+
r5py/r5/regional_task.py,sha256=33PptFZziTPuwAlbBsyTqpAtl1K6HT9sjKLc_CxzRzY,23250
|
|
11
|
+
r5py/r5/scenario.py,sha256=nUNAlN3cO7E_b4sMpNqdL0FD7WQaQ49iIvh-k8l4YRM,763
|
|
12
|
+
r5py/r5/street_layer.py,sha256=iGlAWftzmwzaRUpXngis7prVuH3Oq8i-AXS8-pnVXMk,2259
|
|
13
|
+
r5py/r5/transfer_leg.py,sha256=_IpzQJAyW4hDPO5V4k-ZjIPd3uyxhHPa4U6_b8UbKt4,311
|
|
14
|
+
r5py/r5/transit_layer.py,sha256=Z2quvw19IqmB6eeCFbavYp8TFmo3YVWhlk0ifCWbDng,3023
|
|
15
|
+
r5py/r5/transit_leg.py,sha256=R0Qc9YLMEXYu51NIdo7Q0bdmpYIJf5irEDXWrW6pZWE,221
|
|
16
|
+
r5py/r5/transport_mode.py,sha256=zHSqXb0R4oyjTp069CzO69IgoCKt0nmOAwsSy272rGo,3675
|
|
17
|
+
r5py/r5/transport_network.py,sha256=d4PPBEBk3t2QbUI5KMS9zM-a4s4E4zEYOHIV6txCnYg,10777
|
|
18
|
+
r5py/r5/travel_time_matrix_computer.py,sha256=H_zsCfDlBX7LKJcTJZH92TY96P1nTCl9zDdCs78d7Wo,4463
|
|
19
|
+
r5py/r5/trip.py,sha256=ZsEshy4BflMHZQoq-LIFauvYbn4T7gLD-Aa91rV45m8,2854
|
|
20
|
+
r5py/r5/trip_leg.py,sha256=63DVgIYKc_X4nC7oYF6OMRkFeaL5kQy2zRnfkGX3ALc,5642
|
|
21
|
+
r5py/r5/trip_planner.py,sha256=hwarUMO29zw4-nPLbGtA6sxXUovNxVu8KBvo_Bkay54,22937
|
|
22
|
+
r5py/sampledata/_keep/__init__.py,sha256=Dd14TxWipq66sLK3ponMl09SbtzWoqmD-dhbTuS889M,114
|
|
23
|
+
r5py/util/__init__.py,sha256=S-agt-08twU7hFIH1_x_VjuNC-WHfP6844n0xM0E8t8,714
|
|
24
|
+
r5py/util/camel_to_snake_case.py,sha256=zj5F3PNBvsuS6vqN4USeeo8NI-3hnscGhwun0G95AK0,673
|
|
25
|
+
r5py/util/classpath.py,sha256=lqyoJaL2VI3Gu3s9sspKS8BDlmzH2dqA7k4VjJoNwdA,2773
|
|
26
|
+
r5py/util/config.py,sha256=TpT67KZoHj17USjmGgiyH7HKa757CFXVk5nnBEio8E0,4667
|
|
27
|
+
r5py/util/contains_gtfs_data.py,sha256=ooX4hfVDKK0aqX1MI46jSFZ7dZ6riyXaORrgF6PUFrk,1211
|
|
28
|
+
r5py/util/data_validation.py,sha256=H5Mcp2nS4vu5RKym20mPnGpl-8d0SDchzDRJBrrL6WE,1039
|
|
29
|
+
r5py/util/environment.py,sha256=cbSM8TKTuhbXsTIIB06pMtydBOiqLkitF2Lj2asVTho,1082
|
|
30
|
+
r5py/util/exceptions.py,sha256=r65XUg_AJ_bTw8ARNj7A2-GbFZlSTrOAjDynx1pSD2Y,1049
|
|
31
|
+
r5py/util/good_enough_equidistant_crs.py,sha256=1aqJLghNwcd2FbLfODcht_6pyOEqhsrE2KPaC3NLoek,2354
|
|
32
|
+
r5py/util/jvm.py,sha256=NCwoYLDznXydcIRAZl2kzUQA6D6NCvzjVG74pm6ioR0,5027
|
|
33
|
+
r5py/util/memory_footprint.py,sha256=p8efCUs4UXRg6P1GrRxVs71m7SpEw2mASoz6PVTRvgQ,4672
|
|
34
|
+
r5py/util/parse_int_date.py,sha256=JmnV8TwdUdUp3kSp2e73ZSxCbRyqv2FmQzNt0I_MsM0,667
|
|
35
|
+
r5py/util/sample_data_set.py,sha256=SRTFmhnhtwNCYtXRGPNKkh_lh3OEvgcyHS4Fz8N9uM8,2394
|
|
36
|
+
r5py/util/snake_to_camel_case.py,sha256=uJ5hTCVDUEmIxTyy4LGFTbpGC_rtnjDZVQ2vmVRTQ4k,485
|
|
37
|
+
r5py/util/validating_requests_session.py,sha256=sH5FgpS9eGax5DG2qA2GrGuiwgTJgh8tKsZ9OiXKmvk,1807
|
|
38
|
+
r5py/util/warnings.py,sha256=CvxKWKlNO_p3riB4SkNqbU5AGPsaY_3-OzqaBObE3B8,139
|
|
39
|
+
r5py-0.1.2.dist-info/LICENSE,sha256=VAnuGDX1TPylSN9G2xLa-urDpj_SQwn-qqs068dx4tk,51
|
|
40
|
+
r5py-0.1.2.dist-info/METADATA,sha256=8JDgZ6ZNX6a8hvLO7FPahfQxvN59DNz3hoTBHAw9suE,10015
|
|
41
|
+
r5py-0.1.2.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
|
|
42
|
+
r5py-0.1.2.dist-info/top_level.txt,sha256=fOH1R85dkNDOI7jkg-lIsl5CQIO4fE5X868K9dTqs9U,5
|
|
43
|
+
r5py-0.1.2.dist-info/RECORD,,
|
r5py-0.1.1.dev2.dist-info/RECORD
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
r5py/__init__.py,sha256=eWYsVlnfyYPcIveYA3jP_niDewEPlrWau81hem9WybM,418
|
|
2
|
-
r5py/__main__.py,sha256=5p_QWx8hsNbz34OwMKl9mY644bfqwXRFXkFSlTP06AM,239
|
|
3
|
-
r5py/r5/__init__.py,sha256=gq-1XbdrHE4v3XAvyV-Amod-Vcgp_c1Sbs13mgxOD08,643
|
|
4
|
-
r5py/r5/access_leg.py,sha256=W3GfPEpqmWD1c4xipd6UcVIaBC-yb6srGCZV30E2dPY,293
|
|
5
|
-
r5py/r5/base_travel_time_matrix_computer.py,sha256=lnyI70dIGq0e9E1cvLJfF17hIw8eG8Qnt8WfXOwNFBo,6313
|
|
6
|
-
r5py/r5/breakdown_stat.py,sha256=ZQkWA0hXlcRH3KVgtxPSNHP0FUDri8MWqdFk8EUdDMU,533
|
|
7
|
-
r5py/r5/detailed_itineraries_computer.py,sha256=kRV8OBpvdsgYHcNGQzBi6Y3WyAlPCTSQn0HrWoBqvus,8483
|
|
8
|
-
r5py/r5/direct_leg.py,sha256=opX575iuByoy8WORIsSvIgVqAwglBVCl15ZCo1pv_Mk,1064
|
|
9
|
-
r5py/r5/egress_leg.py,sha256=9rsCIcwlZUzoZE6q4imNY3VWpjJepO1IJvheVrlPi90,297
|
|
10
|
-
r5py/r5/regional_task.py,sha256=uzciavh9qWrMPYtixIdSR8hMxg4tyC98FnTYqpN4FME,23136
|
|
11
|
-
r5py/r5/scenario.py,sha256=nUNAlN3cO7E_b4sMpNqdL0FD7WQaQ49iIvh-k8l4YRM,763
|
|
12
|
-
r5py/r5/street_layer.py,sha256=aA8cBXvV60wH7WlEnwqbPXPpPxwQQsPPbW59HDUJrc0,2196
|
|
13
|
-
r5py/r5/transfer_leg.py,sha256=m_9t1Kr8pq5rmtJz4XZSvRpog4_WpMtF2nKeybJ0v8U,325
|
|
14
|
-
r5py/r5/transit_layer.py,sha256=znQcJmtFpqVcsvZziPDHxAcRS0OXvyn3JdWE_lXZv0A,2928
|
|
15
|
-
r5py/r5/transit_leg.py,sha256=zd8QnMiOHCw3hS6WO5uwegxROdwDpqNDqvZwVJ2MlKo,241
|
|
16
|
-
r5py/r5/transport_mode.py,sha256=YJj2CzZ0cz4hAu48udYtX8MnFuSx4he703xcP3BV_7I,3586
|
|
17
|
-
r5py/r5/transport_network.py,sha256=ZWKHEhRkmpy_lQLvMjjjRqp_8ciP5kea7263Y4WwhG0,10470
|
|
18
|
-
r5py/r5/travel_time_matrix_computer.py,sha256=ns4DnWXfyPpslwQlHGM5Vsmpdzvr8NF-hWaRgc8HYGc,4880
|
|
19
|
-
r5py/r5/trip.py,sha256=SvXXQdvkCZzXcAbLyxKjCEwdbft_Jt7SPmPDzdw0K9w,2617
|
|
20
|
-
r5py/r5/trip_leg.py,sha256=gto-VRo_AdUxdRDRlIey6f8jSZ021NI91BODTowp-wQ,4131
|
|
21
|
-
r5py/r5/trip_planner.py,sha256=298IvJioFz4uj1L8qXJE5Ehrqcy51IP_2FoQfo3GEDc,21293
|
|
22
|
-
r5py/sampledata/_keep/__init__.py,sha256=Dd14TxWipq66sLK3ponMl09SbtzWoqmD-dhbTuS889M,114
|
|
23
|
-
r5py/util/__init__.py,sha256=moUcR_oxpITt2vdNQxuej6haFywjA62UcUY4T5TMDns,673
|
|
24
|
-
r5py/util/camel_to_snake_case.py,sha256=zj5F3PNBvsuS6vqN4USeeo8NI-3hnscGhwun0G95AK0,673
|
|
25
|
-
r5py/util/classpath.py,sha256=os4UmHEs2GGk0jnHSD_1wJHEjmpYQU3VAb6T_iUdFEw,2724
|
|
26
|
-
r5py/util/config.py,sha256=M3eT4B2mB0CaFHQYn5DmtFTtSc4_RCK8fS3UuO7X2D8,4216
|
|
27
|
-
r5py/util/contains_gtfs_data.py,sha256=ooX4hfVDKK0aqX1MI46jSFZ7dZ6riyXaORrgF6PUFrk,1211
|
|
28
|
-
r5py/util/data_validation.py,sha256=H5Mcp2nS4vu5RKym20mPnGpl-8d0SDchzDRJBrrL6WE,1039
|
|
29
|
-
r5py/util/exceptions.py,sha256=r65XUg_AJ_bTw8ARNj7A2-GbFZlSTrOAjDynx1pSD2Y,1049
|
|
30
|
-
r5py/util/good_enough_equidistant_crs.py,sha256=VuzPGPTyL7T0Cl3SZba7atBTyyt9uUTLkq7JVMxjGsI,2355
|
|
31
|
-
r5py/util/jvm.py,sha256=NCwoYLDznXydcIRAZl2kzUQA6D6NCvzjVG74pm6ioR0,5027
|
|
32
|
-
r5py/util/memory_footprint.py,sha256=FlOLEAz7yI3YOv3wJe_tejJPh0y640QlDd0Z3Ce5i2s,4660
|
|
33
|
-
r5py/util/parse_int_date.py,sha256=JmnV8TwdUdUp3kSp2e73ZSxCbRyqv2FmQzNt0I_MsM0,667
|
|
34
|
-
r5py/util/sample_data_set.py,sha256=YQcDjcywria2hiR9A3cS8y3LmGsEAraQMDaGXFPg4JU,2165
|
|
35
|
-
r5py/util/snake_to_camel_case.py,sha256=uJ5hTCVDUEmIxTyy4LGFTbpGC_rtnjDZVQ2vmVRTQ4k,485
|
|
36
|
-
r5py/util/validating_requests_session.py,sha256=nkgOsZ_fbaP19R8l0ImZLFo5zUdw9-B289w0DEygtW0,1809
|
|
37
|
-
r5py/util/warnings.py,sha256=CvxKWKlNO_p3riB4SkNqbU5AGPsaY_3-OzqaBObE3B8,139
|
|
38
|
-
r5py-0.1.1.dev2.dist-info/LICENSE,sha256=VAnuGDX1TPylSN9G2xLa-urDpj_SQwn-qqs068dx4tk,51
|
|
39
|
-
r5py-0.1.1.dev2.dist-info/METADATA,sha256=ZFy_vU_mdoQtSMduASSOhF8uIIL0Yq2PG0KxnuBVnCY,9997
|
|
40
|
-
r5py-0.1.1.dev2.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
41
|
-
r5py-0.1.1.dev2.dist-info/top_level.txt,sha256=fOH1R85dkNDOI7jkg-lIsl5CQIO4fE5X868K9dTqs9U,5
|
|
42
|
-
r5py-0.1.1.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|