r5py 0.1.1.dev2__py3-none-any.whl → 1.0.0__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.

Files changed (38) hide show
  1. r5py/__init__.py +8 -1
  2. r5py/__main__.py +1 -14
  3. r5py/r5/__init__.py +20 -2
  4. r5py/r5/{base_travel_time_matrix_computer.py → base_travel_time_matrix.py} +28 -8
  5. r5py/r5/{detailed_itineraries_computer.py → detailed_itineraries.py} +82 -20
  6. r5py/r5/direct_leg.py +1 -3
  7. r5py/r5/isochrones.py +351 -0
  8. r5py/r5/regional_task.py +12 -9
  9. r5py/r5/street_layer.py +8 -3
  10. r5py/r5/street_segment.py +41 -0
  11. r5py/r5/transfer_leg.py +2 -6
  12. r5py/r5/transit_layer.py +6 -0
  13. r5py/r5/transit_leg.py +1 -5
  14. r5py/r5/transport_mode.py +5 -3
  15. r5py/r5/transport_network.py +60 -138
  16. r5py/r5/travel_time_matrix.py +209 -0
  17. r5py/r5/trip.py +13 -8
  18. r5py/r5/trip_leg.py +76 -15
  19. r5py/r5/trip_planner.py +109 -54
  20. r5py/util/__init__.py +8 -0
  21. r5py/util/classpath.py +9 -5
  22. r5py/util/config.py +32 -7
  23. r5py/util/environment.py +34 -0
  24. r5py/util/file_digest.py +42 -0
  25. r5py/util/good_enough_equidistant_crs.py +8 -4
  26. r5py/util/memory_footprint.py +3 -5
  27. r5py/util/sample_data_set.py +17 -6
  28. r5py/util/spatially_clustered_geodataframe.py +78 -0
  29. r5py/util/validating_requests_session.py +2 -2
  30. r5py/util/working_copy.py +44 -0
  31. {r5py-0.1.1.dev2.dist-info → r5py-1.0.0.dist-info}/METADATA +34 -33
  32. r5py-1.0.0.dist-info/RECORD +47 -0
  33. {r5py-0.1.1.dev2.dist-info → r5py-1.0.0.dist-info}/WHEEL +1 -1
  34. r5py/r5/travel_time_matrix_computer.py +0 -134
  35. r5py/sampledata/_keep/__init__.py +0 -3
  36. r5py-0.1.1.dev2.dist-info/RECORD +0 -42
  37. {r5py-0.1.1.dev2.dist-info → r5py-1.0.0.dist-info}/LICENSE +0 -0
  38. {r5py-0.1.1.dev2.dist-info → r5py-1.0.0.dist-info}/top_level.txt +0 -0
r5py/util/config.py CHANGED
@@ -2,23 +2,25 @@
2
2
 
3
3
  """Handle configuration options and command line options."""
4
4
 
5
+ import datetime
5
6
  import functools
7
+ import importlib.resources
6
8
  import os
7
9
  import pathlib
8
10
  import sys
9
11
  import tempfile
10
12
 
11
13
  import configargparse
12
- import importlib_resources
13
14
 
14
15
 
15
16
  __all__ = ["Config"]
16
17
 
17
18
 
18
19
  PACKAGE = __package__.split(".")[0]
19
- CONFIG_FILE_TEMPLATE = importlib_resources.files(f"{PACKAGE}.util").joinpath(
20
+ CONFIG_FILE_TEMPLATE = importlib.resources.files(f"{PACKAGE}.util").joinpath(
20
21
  f"{PACKAGE}.yml.template"
21
22
  )
23
+ CACHE_MAX_AGE = datetime.timedelta(weeks=2)
22
24
 
23
25
  if "HOME" not in os.environ: # e.g., testing environment or container
24
26
  os.environ["HOME"] = "."
@@ -31,7 +33,6 @@ class Config:
31
33
 
32
34
  def __init__(self):
33
35
  """Load configuration from config files or command line arguments."""
34
-
35
36
  self.argparser.add(
36
37
  "-v",
37
38
  "--verbose",
@@ -40,6 +41,7 @@ class Config:
40
41
  )
41
42
 
42
43
  def __new__(cls):
44
+ """Load configuration from config files or command line arguments."""
43
45
  if cls._instance is None:
44
46
  cls._instance = super(Config, cls).__new__(cls)
45
47
  return cls._instance
@@ -55,6 +57,7 @@ class Config:
55
57
 
56
58
  @property
57
59
  def argparser(self):
60
+ """Return a singleton instance of a `configargparse.ArgumentParser`."""
58
61
  try:
59
62
  argparser = configargparse.get_argument_parser(
60
63
  prog=PACKAGE,
@@ -67,25 +70,41 @@ class Config:
67
70
 
68
71
  @functools.cached_property
69
72
  def CACHE_DIR(self):
73
+ """Save persistent cache files into this directory."""
70
74
  cache_dir = (
71
75
  pathlib.Path(
72
76
  os.environ.get("LOCALAPPDATA")
73
77
  or os.environ.get("XDG_CACHE_HOME")
74
- or (pathlib.Path(os.environ["HOME"]) / ".cache")
78
+ or (pathlib.Path(os.environ.get("HOME")) / ".cache")
75
79
  )
76
80
  / PACKAGE
77
81
  )
78
82
  cache_dir.mkdir(parents=True, exist_ok=True)
83
+
84
+ # clean old files to keep cache dir from growing too much
85
+ cache_treshold = (datetime.datetime.now() - CACHE_MAX_AGE).timestamp()
86
+ for cached_file in cache_dir.glob("**/*"):
87
+ try:
88
+ *_, atime, mtime, _ = cached_file.stat()
89
+ assert max(atime, mtime) > cache_treshold
90
+ except (
91
+ AssertionError, # expired
92
+ FileNotFoundError, # broken symlink
93
+ PermissionError,
94
+ ):
95
+ cached_file.unlink()
96
+
79
97
  return cache_dir
80
98
 
81
99
  @functools.cached_property
82
100
  def CONFIG_FILES(self):
101
+ """List locations of potential configuration files."""
83
102
  config_files = [
84
103
  pathlib.Path(f"/etc/{PACKAGE}.yml"),
85
104
  pathlib.Path(
86
105
  os.environ.get("APPDATA")
87
106
  or os.environ.get("XDG_CONFIG_HOME")
88
- or (pathlib.Path(os.environ["HOME"]) / ".config")
107
+ or (pathlib.Path(os.environ.get("HOME")) / ".config")
89
108
  )
90
109
  / f"{PACKAGE}.yml",
91
110
  ]
@@ -113,7 +132,7 @@ class Config:
113
132
  try:
114
133
  destination_path.parent.mkdir(parents=True, exist_ok=True)
115
134
 
116
- with importlib_resources.as_file(CONFIG_FILE_TEMPLATE) as template:
135
+ with importlib.resources.as_file(CONFIG_FILE_TEMPLATE) as template:
117
136
  destination_path.write_text(template.read_text())
118
137
 
119
138
  except (
@@ -130,8 +149,14 @@ class Config:
130
149
 
131
150
  @functools.cached_property
132
151
  def TEMP_DIR(self):
152
+ """
153
+ Save temporary files to this directory.
154
+
155
+ read-only property,
156
+ use command-line option `--temporary-directory` to change.
157
+ """
133
158
  parent_dir = self.arguments.temporary_directory
134
- temp_dir = pathlib.Path(tempfile.mkdtemp(prefix=self.PACKAGE), dir=parent_dir)
159
+ temp_dir = pathlib.Path(tempfile.mkdtemp(prefix=self.PACKAGE, dir=parent_dir))
135
160
  return temp_dir
136
161
 
137
162
  PACKAGE = PACKAGE
@@ -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
+ )
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """Create a hash sum of a file."""
4
+
5
+
6
+ import hashlib
7
+ import pathlib
8
+
9
+
10
+ __all__ = ["FileDigest"]
11
+
12
+
13
+ BUFFER_SIZE = 64 * 1024
14
+
15
+
16
+ class FileDigest(str):
17
+ """Create a hash sum of a file."""
18
+
19
+ def __new__(cls, input_file, digest="blake2s"):
20
+ """
21
+ Create a hash sum of a file.
22
+
23
+ Arguments
24
+ ---------
25
+ input_file : pathlib.Path | str
26
+ for which file to compute a hash digest
27
+ digest : str | func
28
+ name of hash algorithm (s.
29
+ https://docs.python.org/3/library/hashlib.html) or function that
30
+ returns a hash sum
31
+ """
32
+ input_file = pathlib.Path(input_file)
33
+ try:
34
+ with input_file.open("rb") as f:
35
+ hashdigest = hashlib.file_digest(f, digest)
36
+ except AttributeError: # Python<=3.10
37
+ hashdigest = hashlib.new(digest)
38
+ with input_file.open("rb") as f:
39
+ while data := f.read(BUFFER_SIZE):
40
+ hashdigest.update(data)
41
+
42
+ return hashdigest.hexdigest()
@@ -10,6 +10,11 @@ import shapely
10
10
  from .exceptions import UnexpectedCrsError
11
11
 
12
12
 
13
+ FALLBACK_CRS = 3857
14
+ DATUM_NAME = "WGS 84"
15
+ VERY_SMALL_BUFFER_SIZE = 0.001
16
+
17
+
13
18
  class GoodEnoughEquidistantCrs(pyproj.CRS):
14
19
  """
15
20
  Find the most appropriate UTM reference system for the current extent.
@@ -31,16 +36,15 @@ class GoodEnoughEquidistantCrs(pyproj.CRS):
31
36
  The geographical extent for which to find an equidistant reference
32
37
  system, in `EPSG:4326`
33
38
  """
34
-
35
39
  if GoodEnoughEquidistantCrs._is_plausible_in_epsg4326(extent):
36
40
  # default CRS in case we do not find any better match
37
- crs = pyproj.CRS.from_epsg(3857)
41
+ crs = pyproj.CRS.from_epsg(FALLBACK_CRS)
38
42
 
39
43
  # buffer extent (so everything is a polygon)
40
- extent = extent.buffer(0.1)
44
+ extent = extent.buffer(VERY_SMALL_BUFFER_SIZE)
41
45
 
42
46
  crsinfo = pyproj.database.query_utm_crs_info(
43
- datum_name="WGS 84",
47
+ datum_name=DATUM_NAME,
44
48
  area_of_interest=pyproj.aoi.AreaOfInterest(*extent.bounds),
45
49
  )
46
50
  for candidate_crs in crsinfo:
@@ -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:
@@ -20,11 +20,15 @@ class SampleDataSet(pathlib.Path):
20
20
 
21
21
  # decide which kind of pathlib.Path we are (Windows, Unix, ...)
22
22
  # cf. https://stackoverflow.com/a/66613346/463864
23
- _flavour = type(pathlib.Path())._flavour
23
+ try:
24
+ _flavour = type(pathlib.Path())._flavour
25
+ except AttributeError: # Python>=3.13
26
+ pass
24
27
 
25
28
  _CACHE_DIR = pathlib.Path(config.CACHE_DIR) / "sampledata"
26
29
 
27
30
  def __new__(cls, remote_url, sha256_checksum):
31
+ """Define a data set that is downloaded and cached on demand."""
28
32
  # pathlib.Path does everything in __new__, rather than __init__
29
33
  cached_path = cls._CACHE_DIR / pathlib.Path(remote_url).name
30
34
  return super().__new__(cls, cached_path)
@@ -40,10 +44,16 @@ class SampleDataSet(pathlib.Path):
40
44
  sha256_checksum : str
41
45
  checksum for this data set, using an SHA256 algorithm
42
46
  """
43
- super().__init__()
47
+ cached_path = self._CACHE_DIR / pathlib.Path(remote_url).name
48
+
49
+ try: # Python>=3.12
50
+ super().__init__(cached_path)
51
+ except TypeError:
52
+ super().__init__()
53
+
44
54
  self.remote_url = remote_url
45
55
  self.checksum = sha256_checksum
46
- self.cached_path = self._CACHE_DIR / pathlib.Path(remote_url).name
56
+ self.cached_path = cached_path
47
57
  self._download_remote_file()
48
58
 
49
59
  def _download_remote_file(self):
@@ -60,7 +70,8 @@ class SampleDataSet(pathlib.Path):
60
70
  RuntimeWarning,
61
71
  )
62
72
  self.cached_path.parent.mkdir(exist_ok=True)
63
- with ValidatingRequestsSession() as session, session.get(
64
- self.remote_url, self.checksum
65
- ) as response:
73
+ with (
74
+ ValidatingRequestsSession() as session,
75
+ session.get(self.remote_url, self.checksum) as response,
76
+ ):
66
77
  self.cached_path.write_bytes(response.content)
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env python3
2
+
3
+
4
+ """Assign a cluster label column to a point-geometry GeoDataFrame."""
5
+
6
+
7
+ import warnings
8
+
9
+ import geopandas
10
+ import numpy
11
+ import shapely
12
+ import sklearn.cluster
13
+
14
+ from .good_enough_equidistant_crs import GoodEnoughEquidistantCrs
15
+
16
+
17
+ __all__ = ["SpatiallyClusteredGeoDataFrame"]
18
+
19
+
20
+ class SpatiallyClusteredGeoDataFrame(geopandas.GeoDataFrame):
21
+ """Assign a cluster label column to a point-geometry GeoDataFrame."""
22
+
23
+ def __init__(self, data, *args, eps=200.0, min_cluster_size=3, **kwargs):
24
+ """
25
+ Assign a cluster label column to a point-geometry GeoDataFrame.
26
+
27
+ Arguments:
28
+ ----------
29
+ data : geopandas.GeoDataFrame
30
+ input data set
31
+ eps : int | float
32
+ EPS parameter to a DBSCAN cluster algorithm, the maximum
33
+ intra-cluster distance between two points
34
+ *args, **kwargs: passed to geopandas.GeoDataFrame.__init__()
35
+ """
36
+ geopandas.GeoDataFrame.__init__(self, *args, **kwargs)
37
+
38
+ EQUIDISTANT_CRS = GoodEnoughEquidistantCrs(
39
+ shapely.box(*data.to_crs("EPSG:4326").geometry.total_bounds)
40
+ )
41
+
42
+ # loosely based on:
43
+ # https://github.com/geopandas/scipy2018-geospatial-data/blob/master/08-clustering.ipynb
44
+
45
+ coordinates = numpy.vstack(
46
+ data.to_crs(EQUIDISTANT_CRS)["geometry"]
47
+ .apply(lambda geometry: numpy.hstack(geometry.xy))
48
+ .values
49
+ )
50
+
51
+ with warnings.catch_warnings():
52
+ warnings.filterwarnings(
53
+ "ignore",
54
+ "Could not find the number of physical cores",
55
+ category=UserWarning,
56
+ )
57
+ data["cluster"] = (
58
+ sklearn.cluster.DBSCAN(
59
+ eps=eps,
60
+ min_samples=min_cluster_size,
61
+ n_jobs=-1,
62
+ )
63
+ .fit(coordinates)
64
+ .labels_
65
+ )
66
+
67
+ with warnings.catch_warnings():
68
+ warnings.filterwarnings(
69
+ "ignore",
70
+ message=(
71
+ "You are adding a column named 'geometry' to a GeoDataFrame "
72
+ "constructed without an active geometry column"
73
+ ),
74
+ category=FutureWarning,
75
+ )
76
+ for column in data.columns:
77
+ self[column] = data[column]
78
+ self.set_geometry("geometry")
@@ -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,
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """Create a copy or link of an input file in a cache directory."""
4
+
5
+
6
+ import filelock
7
+ import pathlib
8
+ import shutil
9
+
10
+ from .config import Config
11
+
12
+
13
+ __all__ = ["WorkingCopy"]
14
+
15
+
16
+ class WorkingCopy(pathlib.Path):
17
+ """Create a copy or link of an input file in a cache directory."""
18
+
19
+ def __new__(cls, path):
20
+ """
21
+ Create a copy or link of an input file in a cache directory.
22
+
23
+ This exists because R5 creates temporary files in the directory of input
24
+ files. This can not only be annoying clutter, but also create problems
25
+ of concurrency, performance, etc., for instance, when the data comes
26
+ from a shared network drive or a read-only file system.
27
+
28
+ Arguments
29
+ ---------
30
+ path : str or pathlib.Path
31
+ The file to create a copy or link of in a cache directory
32
+ """
33
+ # try to first create a symbolic link, if that fails (e.g., on Windows),
34
+ # copy the file to a cache directory
35
+ path = pathlib.Path(path).absolute()
36
+ destination = pathlib.Path(Config().CACHE_DIR / path.name).absolute()
37
+
38
+ with filelock.FileLock(destination.parent / f"{destination.name}.lock"):
39
+ if not destination.exists():
40
+ try:
41
+ destination.symlink_to(path)
42
+ except OSError:
43
+ shutil.copyfile(f"{path}", f"{destination}")
44
+ return destination
@@ -1,9 +1,8 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: r5py
3
- Version: 0.1.1.dev2
3
+ Version: 1.0.0
4
4
  Summary: Python wrapper for the R5 routing analysis engine
5
- Author: Willem Klumpenhouwer, Marcus Sairava, Rafael Pereira, Henrikki Tenkanen
6
- Author-email: Christoph Fink <christoph.fink@helsinki.fi>
5
+ Author: Christoph Fink, Willem Klumpenhouwer, Marcus Sairava, Rafael Pereira, Henrikki Tenkanen
7
6
  License: GPL-3.0-or-later or MIT
8
7
  Project-URL: Documentation, https://r5py.readthedocs.org/
9
8
  Project-URL: Repository, https://github.com/r5py/r5py.git
@@ -19,43 +18,45 @@ Description-Content-Type: text/markdown
19
18
  License-File: LICENSE
20
19
  Requires-Dist: ConfigArgParse
21
20
  Requires-Dist: filelock
22
- Requires-Dist: fiona
21
+ Requires-Dist: geohexgrid
23
22
  Requires-Dist: geopandas
24
- Requires-Dist: importlib-resources
25
23
  Requires-Dist: joblib
26
24
  Requires-Dist: jpype1
27
25
  Requires-Dist: numpy
28
- Requires-Dist: pandas >=2.1.0
26
+ Requires-Dist: pandas>=2.1.0
29
27
  Requires-Dist: psutil
30
28
  Requires-Dist: pyproj
31
29
  Requires-Dist: requests
32
- Requires-Dist: shapely >=2.0
30
+ Requires-Dist: scikit-learn
31
+ Requires-Dist: shapely>=2.0
32
+ Requires-Dist: simplification
33
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.dev2 ; extra == 'docs'
45
- Requires-Dist: r5py.sampledata.sao-paulo >=0.1.1.dev2 ; 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'
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
52
  Provides-Extra: tests
53
- Requires-Dist: pytest ; extra == 'tests'
54
- Requires-Dist: pytest-asyncio ; extra == 'tests'
55
- Requires-Dist: pytest-cov ; extra == 'tests'
56
- Requires-Dist: pytest-lazy-fixture ; extra == 'tests'
57
- Requires-Dist: r5py.sampledata.helsinki >=0.1.1.dev2 ; extra == 'tests'
58
- Requires-Dist: r5py.sampledata.sao-paulo >=0.1.1.dev2 ; extra == 'tests'
53
+ Requires-Dist: pyarrow; extra == "tests"
54
+ Requires-Dist: pytest; extra == "tests"
55
+ Requires-Dist: pytest-cov; extra == "tests"
56
+ Requires-Dist: pytest-lazy-fixtures; extra == "tests"
57
+ Requires-Dist: r5py.sampledata.helsinki>=0.1.1; extra == "tests"
58
+ Requires-Dist: r5py.sampledata.sao_paulo>=0.1.1; extra == "tests"
59
+ Requires-Dist: typing-extensions; 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
 
@@ -155,7 +156,7 @@ your project better.
155
156
  <!-- (2) other links -->
156
157
  [conda-create-env-from-yml]: https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-from-an-environment-yml-file
157
158
  [conveyal]: https://www.conveyal.com/
158
- [env-file]: https://github.com/r5py/r5py/blob/main/ci/r5py_distro.yaml
159
+ [env-file]: https://github.com/r5py/r5py/blob/main/ci/r5py.yaml
159
160
  [geopandas]: https://geopandas.org/
160
161
  [r5-github]: https://github.com/conveyal/r5/
161
162
  [r5r-github]: https://github.com/ipeaGIT/r5r/
@@ -0,0 +1,47 @@
1
+ r5py/__init__.py,sha256=j6T-4NRTg_w9P_RloJOBLuc1L2ZnERHJzsqbeM5M-cc,546
2
+ r5py/__main__.py,sha256=Wvn0ChD7E-dCSZ8b8k_HhHG0KMOk0qMNFkijGuSH3-0,81
3
+ r5py/r5/__init__.py,sha256=6IQpvStxKeNxflizfRWh05USpdM18KBSB3UZ8Z_cGY4,1124
4
+ r5py/r5/access_leg.py,sha256=W3GfPEpqmWD1c4xipd6UcVIaBC-yb6srGCZV30E2dPY,293
5
+ r5py/r5/base_travel_time_matrix.py,sha256=Vl82Wkk2iANNy6L3r937yXNnQ9lmMOErGT_-fQnb1Ms,6978
6
+ r5py/r5/breakdown_stat.py,sha256=ZQkWA0hXlcRH3KVgtxPSNHP0FUDri8MWqdFk8EUdDMU,533
7
+ r5py/r5/detailed_itineraries.py,sha256=Oo8JnF5jM2FsYFR1ma9r4y3evOmU7itDYs5M4vbqrZo,11245
8
+ r5py/r5/direct_leg.py,sha256=T7wX8puhOVIssCpflXthYs-G9OA8pasFbdz9p8k8teg,1054
9
+ r5py/r5/egress_leg.py,sha256=9rsCIcwlZUzoZE6q4imNY3VWpjJepO1IJvheVrlPi90,297
10
+ r5py/r5/isochrones.py,sha256=NNpV3Df4NeLdDksGERkb2Eos33ziMBGEeaWyCKPt5P8,12974
11
+ r5py/r5/regional_task.py,sha256=wTNx2NT3-GCEvDyz0e-_YYkVWtpE66dg2IlXTA1gI-4,23234
12
+ r5py/r5/scenario.py,sha256=nUNAlN3cO7E_b4sMpNqdL0FD7WQaQ49iIvh-k8l4YRM,763
13
+ r5py/r5/street_layer.py,sha256=2AWhIE0-aTNGQenX6bF1xv5bmhR_LV0CgqM4BKgVYfk,2329
14
+ r5py/r5/street_segment.py,sha256=0O0QV8Eyfss-xHJShKGSQV1IusZfTrrxzu_AWl3KACo,1109
15
+ r5py/r5/transfer_leg.py,sha256=_IpzQJAyW4hDPO5V4k-ZjIPd3uyxhHPa4U6_b8UbKt4,311
16
+ r5py/r5/transit_layer.py,sha256=vVo_o10yDCzpujOQ99xdzmznwVjAbANjdDflQy2QOpI,3223
17
+ r5py/r5/transit_leg.py,sha256=R0Qc9YLMEXYu51NIdo7Q0bdmpYIJf5irEDXWrW6pZWE,221
18
+ r5py/r5/transport_mode.py,sha256=zHSqXb0R4oyjTp069CzO69IgoCKt0nmOAwsSy272rGo,3675
19
+ r5py/r5/transport_network.py,sha256=wy7jsIqcladee6FdUiOu0kJgMhGYymtJpfyjX9RRnNU,7925
20
+ r5py/r5/travel_time_matrix.py,sha256=Z_ErylB8mMD_eO2BogV3K_OFdYFVCcmIPmcMe7GGRiU,8003
21
+ r5py/r5/trip.py,sha256=AqhlhgYaGRL5jVzV08BhsqgWxe8f4wAb5HMP8HIGwc8,2944
22
+ r5py/r5/trip_leg.py,sha256=9E4vZpBEJCXIVqAXWJvnPloC-upEASKhFnjiuen8i8A,6495
23
+ r5py/r5/trip_planner.py,sha256=QM3kSx-EC1VWtmReMtwxzG0CdbtlRi3-PpLxOAoHGrA,23754
24
+ r5py/util/__init__.py,sha256=3iqzebRt7RE1TMzzuGNzyXca0SBcBx1rHLs8eW3ijo4,940
25
+ r5py/util/camel_to_snake_case.py,sha256=zj5F3PNBvsuS6vqN4USeeo8NI-3hnscGhwun0G95AK0,673
26
+ r5py/util/classpath.py,sha256=b16xL94pDxTpc0vrf68R1nvZHnHqZXGcFJaN36eW3wc,2773
27
+ r5py/util/config.py,sha256=5jz42iUaftgBfJ2HNnktZw5oXIPE2ytl3Nxt2RjjDoM,5267
28
+ r5py/util/contains_gtfs_data.py,sha256=ooX4hfVDKK0aqX1MI46jSFZ7dZ6riyXaORrgF6PUFrk,1211
29
+ r5py/util/data_validation.py,sha256=H5Mcp2nS4vu5RKym20mPnGpl-8d0SDchzDRJBrrL6WE,1039
30
+ r5py/util/environment.py,sha256=cbSM8TKTuhbXsTIIB06pMtydBOiqLkitF2Lj2asVTho,1082
31
+ r5py/util/exceptions.py,sha256=r65XUg_AJ_bTw8ARNj7A2-GbFZlSTrOAjDynx1pSD2Y,1049
32
+ r5py/util/file_digest.py,sha256=95UbaxbTZLa54j1CupsKria028xZ8f6ueZsTupnjlYE,1061
33
+ r5py/util/good_enough_equidistant_crs.py,sha256=7FX3Ly3qegSV_YRA4OFk49LC29xUyTte1Gc5qOEi_9E,2458
34
+ r5py/util/jvm.py,sha256=NCwoYLDznXydcIRAZl2kzUQA6D6NCvzjVG74pm6ioR0,5027
35
+ r5py/util/memory_footprint.py,sha256=p8efCUs4UXRg6P1GrRxVs71m7SpEw2mASoz6PVTRvgQ,4672
36
+ r5py/util/parse_int_date.py,sha256=JmnV8TwdUdUp3kSp2e73ZSxCbRyqv2FmQzNt0I_MsM0,667
37
+ r5py/util/sample_data_set.py,sha256=aqUCx6drWD-WbCauewO4EzgOGnFr35mAZt-YHlqb92k,2463
38
+ r5py/util/snake_to_camel_case.py,sha256=uJ5hTCVDUEmIxTyy4LGFTbpGC_rtnjDZVQ2vmVRTQ4k,485
39
+ r5py/util/spatially_clustered_geodataframe.py,sha256=FxG8V3SSeK-PuCep565p1b3TNcl8oCkY764tk1L0sKM,2410
40
+ r5py/util/validating_requests_session.py,sha256=sH5FgpS9eGax5DG2qA2GrGuiwgTJgh8tKsZ9OiXKmvk,1807
41
+ r5py/util/warnings.py,sha256=CvxKWKlNO_p3riB4SkNqbU5AGPsaY_3-OzqaBObE3B8,139
42
+ r5py/util/working_copy.py,sha256=sbLbRCi39LtC-0tXxvh2y7ZN2D15chbhleCZXzHAFSc,1432
43
+ r5py-1.0.0.dist-info/LICENSE,sha256=VAnuGDX1TPylSN9G2xLa-urDpj_SQwn-qqs068dx4tk,51
44
+ r5py-1.0.0.dist-info/METADATA,sha256=yWDmg1mjGHQHj4SveWnYfuI4E3TWvo43Gug4L1hwFno,9965
45
+ r5py-1.0.0.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
46
+ r5py-1.0.0.dist-info/top_level.txt,sha256=fOH1R85dkNDOI7jkg-lIsl5CQIO4fE5X868K9dTqs9U,5
47
+ r5py-1.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: setuptools (76.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5