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/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
- Find detailed routes between two points.
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 java.lang.NullPointerException:
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}, {self.request.fromLat}) "
150
- f"and destination ({self.request.toLon}, {self.request.toLat})",
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.transit_access_times,
218
- self.transit_egress_times,
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
- leg = min(
242
- [
243
- self.transit_egress_paths[transport_mode][
244
- state.back.stop
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
- for transport_mode in self.transit_egress_paths.keys()
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
- leg = min(
259
- [
260
- self.transit_access_paths[transport_mode][
261
- state.stop
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
- for transport_mode in self.transit_access_paths.keys()
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.transit_transfer_path(
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
- transit_paths.append(trip)
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 transit_access_paths(self):
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 transit_access_times(self):
410
- """Times to reached stops in the format required by
411
- McRaptorSuboptimalPathProfileRouter."""
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.transit_access_paths.items()
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 transit_egress_paths(self):
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 transit_egress_times(self):
471
- """Times to reached stops in the format required by
472
- McRaptorSuboptimalPathProfileRouter."""
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.transit_egress_paths.items()
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 transit_transfer_path(self, from_stop, to_stop):
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
- (from_stop, to_stop)
529
- ] = TransferLeg(TransportMode.WALK, street_segment)
569
+ transfer_path = self._transfer_paths[(from_stop, to_stop)] = (
570
+ TransferLeg(TransportMode.WALK, street_segment)
571
+ )
530
572
 
531
573
  return transfer_path
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env
2
+
3
+ """A placeholder for plugin-style sample data packages within the r5py.sampledata.* namespace."""
r5py/util/__init__.py CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  """Utility functions, e.g., starting a JVM, and accessing configuration."""
4
4
 
5
+ from . import environment # noqa: F401
6
+
5
7
  from .camel_to_snake_case import camel_to_snake_case
6
8
  from .config import Config
7
9
  from .contains_gtfs_data import contains_gtfs_data
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 = "https://github.com/conveyal/r5/releases/download/v6.9/r5-v6.9-all.jar"
21
- R5_JAR_SHA256 = "a7e1c5ff8786a9fb9191073b8f31a6933b862f44b9ff85b2c00a68c85491274d"
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 ValidatingRequestsSession() as session, session.get(
77
- R5_JAR_URL, R5_JAR_SHA256
78
- ) as response, open(r5_classpath, "wb") as jar:
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
- temp_dir = pathlib.Path(tempfile.mkdtemp(prefix=self.PACKAGE))
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
+ )
@@ -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)
@@ -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 containing a possible
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
- """Sends a GET request, tests checksum."""
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
- """Sends a POST request, tests checksum."""
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.1.dev0
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.8
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: doc
34
- Requires-Dist: contextily ; extra == 'doc'
35
- Requires-Dist: folium ; extra == 'doc'
36
- Requires-Dist: h3 ; extra == 'doc'
37
- Requires-Dist: mapclassify ; extra == 'doc'
38
- Requires-Dist: matplotlib ; extra == 'doc'
39
- Requires-Dist: myst-nb ; extra == 'doc'
40
- Requires-Dist: nbsphinx ; extra == 'doc'
41
- Requires-Dist: pybtex-apa7-style ; extra == 'doc'
42
- Requires-Dist: shapely ; extra == 'doc'
43
- Requires-Dist: sphinx ; extra == 'doc'
44
- Requires-Dist: sphinx-book-theme ; extra == 'doc'
45
- Requires-Dist: sphinx-design ; extra == 'doc'
46
- Requires-Dist: sphinxcontrib-bibtex ; extra == 'doc'
47
- Requires-Dist: sphinxcontrib-images ; extra == 'doc'
48
- Provides-Extra: test
49
- Requires-Dist: pytest ; extra == 'test'
50
- Requires-Dist: pytest-asyncio ; extra == 'test'
51
- Requires-Dist: pytest-cov ; extra == 'test'
52
- Requires-Dist: pytest-lazy-fixture ; extra == 'test'
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: setuptools (71.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5