ne-loader 0.3__tar.gz → 0.3.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ne-loader
3
- Version: 0.3
3
+ Version: 0.3.2
4
4
  Summary: A simple loader for Natural Earth map data.
5
5
  Author-email: Eric Tunn <erictunn@icloud.com>
6
6
  Project-URL: Homepage, https://github.com/erictunn/ne-loader
@@ -32,6 +32,16 @@ from ne_loader import map_loader
32
32
  world = map_loader.get_natural_earth('cultural', 'admin_0_countries')
33
33
  ```
34
34
 
35
+ Errors are raised by default. To return the caught exception instead:
36
+
37
+ ```python
38
+ result = map_loader.get_natural_earth(
39
+ 'cultural',
40
+ 'admin_0_countries',
41
+ error_mode='return',
42
+ )
43
+ ```
44
+
35
45
  ## CLI
36
46
 
37
47
  ```bash
@@ -47,7 +57,7 @@ export NATURAL_EARTH_CACHE_DIR="..."
47
57
  ## Tests
48
58
 
49
59
  ```bash
50
- python3 -m pytest tests/test_map_loader.py
60
+ python3 -m pytest tests
51
61
  ```
52
62
 
53
63
  ## License
@@ -20,6 +20,16 @@ from ne_loader import map_loader
20
20
  world = map_loader.get_natural_earth('cultural', 'admin_0_countries')
21
21
  ```
22
22
 
23
+ Errors are raised by default. To return the caught exception instead:
24
+
25
+ ```python
26
+ result = map_loader.get_natural_earth(
27
+ 'cultural',
28
+ 'admin_0_countries',
29
+ error_mode='return',
30
+ )
31
+ ```
32
+
23
33
  ## CLI
24
34
 
25
35
  ```bash
@@ -35,7 +45,7 @@ export NATURAL_EARTH_CACHE_DIR="..."
35
45
  ## Tests
36
46
 
37
47
  ```bash
38
- python3 -m pytest tests/test_map_loader.py
48
+ python3 -m pytest tests
39
49
  ```
40
50
 
41
51
  ## License
@@ -7,7 +7,7 @@ where = ["src"]
7
7
 
8
8
  [project]
9
9
  name = "ne-loader"
10
- version = "0.3"
10
+ version = "0.3.2"
11
11
  description = "A simple loader for Natural Earth map data."
12
12
  authors = [
13
13
  { name = "Eric Tunn", email = "erictunn@icloud.com" }
@@ -0,0 +1,4 @@
1
+ """Natural Earth Loader package.
2
+
3
+ See map_loader.py for public API entrypoint.
4
+ """
@@ -12,16 +12,20 @@ def main() -> None:
12
12
  parser: argparse.ArgumentParser = argparse.ArgumentParser(
13
13
  description="Download and load Natural Earth data."
14
14
  )
15
- parser.add_argument("category", choices=["cultural", "physical"], help="Data category")
15
+ parser.add_argument(
16
+ "category",
17
+ choices=["cultural", "physical"],
18
+ help="Data category",
19
+ )
16
20
  parser.add_argument("name", help="Dataset name (e.g., admin_0_countries)")
17
21
  parser.add_argument("--res", default="10m", help="Resolution (default: 10m)")
18
22
  parser.add_argument("--out", help="Output file to save as GeoJSON (optional)")
19
23
  args: argparse.Namespace = parser.parse_args()
20
24
 
21
25
  gdf: gpd.GeoDataFrame = map_loader.get_natural_earth(
22
- args.category,
23
- args.name,
24
- args.res,
26
+ category=args.category,
27
+ name=args.name,
28
+ res=args.res,
25
29
  )
26
30
  if args.out:
27
31
  gdf.to_file(args.out, driver="GeoJSON")
@@ -29,5 +33,6 @@ def main() -> None:
29
33
  else:
30
34
  print(gdf.head())
31
35
 
36
+
32
37
  if __name__ == "__main__":
33
38
  main()
@@ -1,6 +1,8 @@
1
1
  """Handles downloading and fetching of NE data."""
2
2
 
3
+ import contextlib
3
4
  import logging
5
+ import shutil
4
6
  import zipfile
5
7
  from pathlib import Path
6
8
  from typing import Literal, Optional, Union, overload
@@ -22,7 +24,7 @@ def build_ne_filename(name: str, res: str = "10m", suffix: str = ".zip") -> str:
22
24
  return f"ne_{res}_{name}{suffix}"
23
25
 
24
26
 
25
- def build_ne_url(category: str, name: str, res: str = "10m") -> str:
27
+ def build_ne_url(category: str, name: str, res: Resolution) -> str:
26
28
  """Build the download URL for a Natural Earth vector dataset."""
27
29
  return (
28
30
  f"https://naciscdn.org/naturalearth/{res}/{category}/"
@@ -30,17 +32,17 @@ def build_ne_url(category: str, name: str, res: str = "10m") -> str:
30
32
  )
31
33
 
32
34
 
33
- def build_ne_zip_path(data_dir: PathLike, name: str, res: str = "10m") -> Path:
35
+ def build_ne_zip_path(data_dir: PathLike, name: str, res: Resolution) -> Path:
34
36
  """Build the local cache path for a Natural Earth zip file."""
35
37
  return Path(data_dir) / build_ne_filename(name, res)
36
38
 
37
39
 
38
- def build_ne_extract_dir(data_dir: PathLike, name: str, res: str = "10m") -> Path:
40
+ def build_ne_extract_dir(data_dir: PathLike, name: str, res: Resolution) -> Path:
39
41
  """Build the local extraction directory for a Natural Earth dataset."""
40
42
  return Path(data_dir) / build_ne_filename(name, res, suffix="")
41
43
 
42
44
 
43
- def build_ne_shp_path(data_dir: PathLike, name: str, res: str = "10m") -> Path:
45
+ def build_ne_shp_path(data_dir: PathLike, name: str, res: Resolution) -> Path:
44
46
  """Build the local shapefile path for an extracted Natural Earth dataset."""
45
47
  extract_dir: Path = build_ne_extract_dir(data_dir, name, res)
46
48
  return extract_dir / build_ne_filename(name, res, suffix=".shp")
@@ -51,19 +53,9 @@ def get_natural_earth(
51
53
  category: str,
52
54
  name: str,
53
55
  res: Resolution = "10m",
56
+ *,
54
57
  dir_override: Optional[PathLike] = None,
55
- error_mode: Literal["raise"] = "raise",
56
- user_logger: Optional[logging.Logger] = None,
57
- ) -> gpd.GeoDataFrame: ...
58
-
59
-
60
- @overload
61
- def get_natural_earth(
62
- category: str,
63
- name: str,
64
- res: Resolution = "10m",
65
- dir_override: Optional[PathLike] = None,
66
- error_mode: Literal["ignore"] = "ignore",
58
+ error_mode: Literal["ignore"],
67
59
  user_logger: Optional[logging.Logger] = None,
68
60
  ) -> Optional[gpd.GeoDataFrame]: ...
69
61
 
@@ -73,10 +65,11 @@ def get_natural_earth(
73
65
  category: str,
74
66
  name: str,
75
67
  res: Resolution = "10m",
68
+ *,
76
69
  dir_override: Optional[PathLike] = None,
77
- error_mode: Literal["return"] = "return",
70
+ error_mode: Literal["raise"] = "raise",
78
71
  user_logger: Optional[logging.Logger] = None,
79
- ) -> Union[gpd.GeoDataFrame, Exception]: ...
72
+ ) -> gpd.GeoDataFrame: ...
80
73
 
81
74
 
82
75
  @overload
@@ -84,16 +77,18 @@ def get_natural_earth(
84
77
  category: str,
85
78
  name: str,
86
79
  res: Resolution = "10m",
80
+ *,
87
81
  dir_override: Optional[PathLike] = None,
88
- error_mode: ErrorMode = "raise",
82
+ error_mode: Literal["return"],
89
83
  user_logger: Optional[logging.Logger] = None,
90
- ) -> Union[gpd.GeoDataFrame, Exception, None]: ...
84
+ ) -> Union[gpd.GeoDataFrame, Exception]: ...
91
85
 
92
86
 
93
87
  def get_natural_earth(
94
88
  category: str,
95
89
  name: str,
96
90
  res: Resolution = "10m",
91
+ *,
97
92
  dir_override: Optional[PathLike] = None,
98
93
  error_mode: ErrorMode = "raise",
99
94
  user_logger: Optional[logging.Logger] = None,
@@ -107,6 +102,8 @@ def get_natural_earth(
107
102
  "admin_0_countries".
108
103
  res: Natural Earth resolution. "10m", "50m" and "110m" are accepted.
109
104
  However, not all datasets will have all 3 resolutions available.
105
+
106
+ Keyword Args:
110
107
  dir_override: Optional cache directory override. This takes precedence over the
111
108
  ``NATURAL_EARTH_CACHE_DIR`` environment variable.
112
109
  error_mode: Error handling mode. Default is raise. Upon error:
@@ -122,6 +119,7 @@ def get_natural_earth(
122
119
  logger = user_logger or fallback_logger
123
120
  try:
124
121
  validate_error_mode(error_mode)
122
+ validate_res(res)
125
123
 
126
124
  data_dir: Path = get_cache_dir(dir_override)
127
125
  data_dir.mkdir(parents=True, exist_ok=True)
@@ -143,10 +141,10 @@ def get_natural_earth(
143
141
 
144
142
  return gpd.read_file(shp_file)
145
143
  except Exception as error:
146
- logger.error(f"ne-loader: error caught fetching data with get_natural_earth():"\
147
- f"\n{error}")
148
- print(f"ne-loader: error caught fetching data with get_natural_earth():"\
149
- f"\n{error}")
144
+ logger.error(
145
+ "ne-loader: error caught fetching data with get_natural_earth():\n",
146
+ error,
147
+ )
150
148
  return error_handler(error, error_mode)
151
149
 
152
150
 
@@ -163,7 +161,7 @@ def _download_ne_data(
163
161
  if shp_file.exists():
164
162
  return
165
163
 
166
- print(f"ne-loader: Downloading {name} ({res})...")
164
+ logger.info(f"ne-loader: Downloading {name} ({res})...")
167
165
 
168
166
  try:
169
167
  response: requests.Response = requests.get(url, stream=True, timeout=10)
@@ -176,7 +174,6 @@ def _download_ne_data(
176
174
 
177
175
  with zipfile.ZipFile(zip_path, "r") as zip_ref:
178
176
  zip_ref.extractall(extract_dir)
179
- zip_path.unlink()
180
177
  return None
181
178
 
182
179
  except requests.exceptions.HTTPError as error:
@@ -186,7 +183,6 @@ def _download_ne_data(
186
183
  "This may cause an error when attempting to load the data.",
187
184
  error,
188
185
  )
189
- print(f"A HTTP error occurred while attempting to fetch data: {error}")
190
186
  raise
191
187
  except requests.exceptions.RequestException as error:
192
188
  logger.error(
@@ -195,5 +191,25 @@ def _download_ne_data(
195
191
  "This may cause an error when attempting to load the data.",
196
192
  error,
197
193
  )
198
- print(f"A request error occurred while attempting to fetch data: {error}")
199
194
  raise
195
+
196
+ finally:
197
+ with contextlib.suppress(FileNotFoundError):
198
+ zip_path.unlink()
199
+ if (not shp_file.exists() and
200
+ extract_dir.name == build_ne_filename(name, res, suffix="")):
201
+ shutil.rmtree(extract_dir, ignore_errors=True)
202
+
203
+ def validate_res(res: str) -> None:
204
+ """Validate the resolution against "10m", "50m", "110m".
205
+
206
+ Args:
207
+ res (Resolution): The resolution to be validated.
208
+
209
+ Raises:
210
+ ValueError: If res is invalid, raises ValueError.
211
+
212
+ """
213
+ if res not in ("10m", "50m", "110m"):
214
+ raise ValueError(f"Invalid resolution: {res}.\
215
+ \nResolution must be one of (\"10m\", \"50m\", \"110m\")")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ne-loader
3
- Version: 0.3
3
+ Version: 0.3.2
4
4
  Summary: A simple loader for Natural Earth map data.
5
5
  Author-email: Eric Tunn <erictunn@icloud.com>
6
6
  Project-URL: Homepage, https://github.com/erictunn/ne-loader
@@ -32,6 +32,16 @@ from ne_loader import map_loader
32
32
  world = map_loader.get_natural_earth('cultural', 'admin_0_countries')
33
33
  ```
34
34
 
35
+ Errors are raised by default. To return the caught exception instead:
36
+
37
+ ```python
38
+ result = map_loader.get_natural_earth(
39
+ 'cultural',
40
+ 'admin_0_countries',
41
+ error_mode='return',
42
+ )
43
+ ```
44
+
35
45
  ## CLI
36
46
 
37
47
  ```bash
@@ -47,7 +57,7 @@ export NATURAL_EARTH_CACHE_DIR="..."
47
57
  ## Tests
48
58
 
49
59
  ```bash
50
- python3 -m pytest tests/test_map_loader.py
60
+ python3 -m pytest tests
51
61
  ```
52
62
 
53
63
  ## License
@@ -1,12 +1,15 @@
1
1
  """Basic tests for map_loader.py constructors."""
2
2
 
3
3
  from pathlib import Path
4
+ import re
5
+ import pytest
4
6
 
5
7
  from ne_loader.map_loader import (
6
8
  build_ne_filename,
7
9
  build_ne_shp_path,
8
10
  build_ne_url,
9
11
  build_ne_zip_path,
12
+ validate_res
10
13
  )
11
14
 
12
15
 
@@ -45,3 +48,9 @@ def test_build_ne_shp_path() -> None:
45
48
  "/tmp/natural-earth-cache/ne_10m_admin_0_countries/"
46
49
  "ne_10m_admin_0_countries.shp"
47
50
  )
51
+
52
+ def test_validate_res() -> None:
53
+ """Tests that validate_res(res=kaboom) raises the correct ValueError."""
54
+ with pytest.raises(ValueError, match=re.escape(f"Invalid resolution: kaboom.\
55
+ \nResolution must be one of (\"10m\", \"50m\", \"110m\")")):
56
+ validate_res("kaboom")
@@ -1 +0,0 @@
1
- # Natural Earth Loader package
File without changes