r5py 0.1.1.dev0__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 +4 -5
- r5py/r5/detailed_itineraries_computer.py +6 -10
- r5py/r5/direct_leg.py +1 -3
- r5py/r5/regional_task.py +44 -38
- 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 +26 -11
- 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/sampledata/_keep/__init__.py +3 -0
- r5py/util/__init__.py +2 -0
- r5py/util/classpath.py +9 -5
- r5py/util/config.py +21 -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 +74 -0
- r5py/util/validating_requests_session.py +2 -2
- {r5py-0.1.1.dev0.dist-info → r5py-0.1.2.dist-info}/METADATA +30 -23
- r5py-0.1.2.dist-info/RECORD +43 -0
- {r5py-0.1.1.dev0.dist-info → r5py-0.1.2.dist-info}/WHEEL +1 -1
- r5py/util/data_set.py +0 -74
- r5py-0.1.1.dev0.dist-info/RECORD +0 -41
- {r5py-0.1.1.dev0.dist-info → r5py-0.1.2.dist-info}/LICENSE +0 -0
- {r5py-0.1.1.dev0.dist-info → r5py-0.1.2.dist-info}/top_level.txt +0 -0
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,7 +133,23 @@ class Config:
|
|
|
130
133
|
|
|
131
134
|
@functools.cached_property
|
|
132
135
|
def TEMP_DIR(self):
|
|
133
|
-
|
|
136
|
+
"""
|
|
137
|
+
Save temporary files to this directory.
|
|
138
|
+
|
|
139
|
+
read-only property,
|
|
140
|
+
use command-line option `--temporary-directory` to change.
|
|
141
|
+
"""
|
|
142
|
+
parent_dir = self.arguments.temporary_directory
|
|
143
|
+
temp_dir = pathlib.Path(tempfile.mkdtemp(prefix=self.PACKAGE, dir=parent_dir))
|
|
134
144
|
return temp_dir
|
|
135
145
|
|
|
136
146
|
PACKAGE = PACKAGE
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
Config().argparser.add(
|
|
150
|
+
"-t",
|
|
151
|
+
"--temporary-directory",
|
|
152
|
+
help="Directory for temporary files, overrides system default",
|
|
153
|
+
default=None,
|
|
154
|
+
type=pathlib.Path,
|
|
155
|
+
)
|
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:
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
"""A remote data set that is downloaded on demand."""
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
import hashlib
|
|
8
|
+
import pathlib
|
|
9
|
+
import warnings
|
|
10
|
+
|
|
11
|
+
from .config import Config
|
|
12
|
+
from .validating_requests_session import ValidatingRequestsSession
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
config = Config()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SampleDataSet(pathlib.Path):
|
|
19
|
+
"""Data set that is downloaded and cached as needed."""
|
|
20
|
+
|
|
21
|
+
# decide which kind of pathlib.Path we are (Windows, Unix, ...)
|
|
22
|
+
# cf. https://stackoverflow.com/a/66613346/463864
|
|
23
|
+
_flavour = type(pathlib.Path())._flavour
|
|
24
|
+
|
|
25
|
+
_CACHE_DIR = pathlib.Path(config.CACHE_DIR) / "sampledata"
|
|
26
|
+
|
|
27
|
+
def __new__(cls, remote_url, sha256_checksum):
|
|
28
|
+
"""Define a data set that is downloaded and cached on demand."""
|
|
29
|
+
# pathlib.Path does everything in __new__, rather than __init__
|
|
30
|
+
cached_path = cls._CACHE_DIR / pathlib.Path(remote_url).name
|
|
31
|
+
return super().__new__(cls, cached_path)
|
|
32
|
+
|
|
33
|
+
def __init__(self, remote_url, sha256_checksum, *args, **kwargs):
|
|
34
|
+
"""
|
|
35
|
+
Define a data set that is downloaded and cached on demand.
|
|
36
|
+
|
|
37
|
+
Arguments
|
|
38
|
+
---------
|
|
39
|
+
remote_url : str
|
|
40
|
+
source URL for this data set
|
|
41
|
+
sha256_checksum : str
|
|
42
|
+
checksum for this data set, using an SHA256 algorithm
|
|
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
|
+
|
|
51
|
+
self.remote_url = remote_url
|
|
52
|
+
self.checksum = sha256_checksum
|
|
53
|
+
self.cached_path = cached_path
|
|
54
|
+
self._download_remote_file()
|
|
55
|
+
|
|
56
|
+
def _download_remote_file(self):
|
|
57
|
+
try:
|
|
58
|
+
assert (
|
|
59
|
+
hashlib.sha256(self.cached_path.read_bytes()).hexdigest()
|
|
60
|
+
== self.checksum
|
|
61
|
+
)
|
|
62
|
+
except (AssertionError, FileNotFoundError):
|
|
63
|
+
if config.arguments.verbose:
|
|
64
|
+
warnings.warn(
|
|
65
|
+
f"First access to {pathlib.Path(self.remote_url).name}, "
|
|
66
|
+
"downloading remote file to local cache",
|
|
67
|
+
RuntimeWarning,
|
|
68
|
+
)
|
|
69
|
+
self.cached_path.parent.mkdir(exist_ok=True)
|
|
70
|
+
with (
|
|
71
|
+
ValidatingRequestsSession() as session,
|
|
72
|
+
session.get(self.remote_url, self.checksum) as response,
|
|
73
|
+
):
|
|
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>
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
14
14
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Classifier: Operating System :: OS Independent
|
|
17
|
-
Requires-Python: >=3.
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
18
|
Description-Content-Type: text/markdown
|
|
19
19
|
License-File: LICENSE
|
|
20
20
|
Requires-Dist: ConfigArgParse
|
|
@@ -25,31 +25,38 @@ Requires-Dist: importlib-resources
|
|
|
25
25
|
Requires-Dist: joblib
|
|
26
26
|
Requires-Dist: jpype1
|
|
27
27
|
Requires-Dist: numpy
|
|
28
|
-
Requires-Dist: pandas
|
|
28
|
+
Requires-Dist: pandas >=2.1.0
|
|
29
29
|
Requires-Dist: psutil
|
|
30
30
|
Requires-Dist: pyproj
|
|
31
31
|
Requires-Dist: requests
|
|
32
32
|
Requires-Dist: shapely >=2.0
|
|
33
|
-
Provides-Extra:
|
|
34
|
-
Requires-Dist: contextily ; extra == '
|
|
35
|
-
Requires-Dist: folium ; extra == '
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
Requires-Dist:
|
|
41
|
-
Requires-Dist:
|
|
42
|
-
Requires-Dist:
|
|
43
|
-
Requires-Dist:
|
|
44
|
-
Requires-Dist:
|
|
45
|
-
Requires-Dist:
|
|
46
|
-
Requires-Dist:
|
|
47
|
-
Requires-Dist:
|
|
48
|
-
|
|
49
|
-
Requires-Dist:
|
|
50
|
-
Requires-Dist:
|
|
51
|
-
Requires-Dist:
|
|
52
|
-
|
|
33
|
+
Provides-Extra: docs
|
|
34
|
+
Requires-Dist: contextily ; extra == 'docs'
|
|
35
|
+
Requires-Dist: folium ; extra == 'docs'
|
|
36
|
+
Requires-Dist: GitPython ; extra == 'docs'
|
|
37
|
+
Requires-Dist: h3 >=4.0.0b2 ; extra == 'docs'
|
|
38
|
+
Requires-Dist: jupyterlab-myst ; extra == 'docs'
|
|
39
|
+
Requires-Dist: mapclassify ; extra == 'docs'
|
|
40
|
+
Requires-Dist: matplotlib ; extra == 'docs'
|
|
41
|
+
Requires-Dist: myst-nb ; extra == 'docs'
|
|
42
|
+
Requires-Dist: nbsphinx ; extra == 'docs'
|
|
43
|
+
Requires-Dist: pybtex-apa7-style ; extra == 'docs'
|
|
44
|
+
Requires-Dist: r5py.sampledata.helsinki >=0.1.1 ; extra == 'docs'
|
|
45
|
+
Requires-Dist: r5py.sampledata.sao-paulo >=0.1.1 ; extra == 'docs'
|
|
46
|
+
Requires-Dist: shapely ; extra == 'docs'
|
|
47
|
+
Requires-Dist: sphinx ; extra == 'docs'
|
|
48
|
+
Requires-Dist: sphinx-book-theme ; extra == 'docs'
|
|
49
|
+
Requires-Dist: sphinx-design ; extra == 'docs'
|
|
50
|
+
Requires-Dist: sphinxcontrib-bibtex ; extra == 'docs'
|
|
51
|
+
Requires-Dist: sphinxcontrib-images ; extra == 'docs'
|
|
52
|
+
Provides-Extra: tests
|
|
53
|
+
Requires-Dist: pyarrow ; extra == 'tests'
|
|
54
|
+
Requires-Dist: pytest ; extra == 'tests'
|
|
55
|
+
Requires-Dist: pytest-asyncio ; extra == 'tests'
|
|
56
|
+
Requires-Dist: pytest-cov ; extra == 'tests'
|
|
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'
|
|
53
60
|
|
|
54
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;">
|
|
55
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,,
|