ne-loader 0.2.1__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.
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: ne-loader
3
+ Version: 0.2.1
4
+ Summary: A simple loader for Natural Earth map data.
5
+ Author-email: Eric Tunn <erictunn@icloud.com>
6
+ Project-URL: Homepage, https://github.com/erictunn/ne-loader
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: geopandas>=0.12
10
+ Requires-Dist: platformdirs>=4
11
+ Requires-Dist: requests>=2.25
12
+
13
+ # NE Loader
14
+
15
+ A simple, robust Python package to download and load Natural Earth map data using GeoPandas.
16
+
17
+ ## Features
18
+
19
+ - Download and cache Natural Earth datasets
20
+ - Load shapefiles as GeoDataFrames
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pip install ne-loader
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ```python
31
+ from ne_loader import map_loader
32
+ world = map_loader.get_natural_earth('cultural', 'admin_0_countries')
33
+ ```
34
+
35
+ ## CLI
36
+
37
+ ```bash
38
+ ne-loader --help
39
+ ```
40
+
41
+ To set an environment override for the NE data save path:
42
+
43
+ ```bash
44
+ export NATURAL_EARTH_CACHE_DIR="..."
45
+ ```
46
+
47
+ ## Tests
48
+
49
+ ```bash
50
+ python3 -m pytest tests/test_map_loader.py
51
+ ```
52
+
53
+ ## License
54
+
55
+ MIT
@@ -0,0 +1,43 @@
1
+ # NE Loader
2
+
3
+ A simple, robust Python package to download and load Natural Earth map data using GeoPandas.
4
+
5
+ ## Features
6
+
7
+ - Download and cache Natural Earth datasets
8
+ - Load shapefiles as GeoDataFrames
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ pip install ne-loader
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```python
19
+ from ne_loader import map_loader
20
+ world = map_loader.get_natural_earth('cultural', 'admin_0_countries')
21
+ ```
22
+
23
+ ## CLI
24
+
25
+ ```bash
26
+ ne-loader --help
27
+ ```
28
+
29
+ To set an environment override for the NE data save path:
30
+
31
+ ```bash
32
+ export NATURAL_EARTH_CACHE_DIR="..."
33
+ ```
34
+
35
+ ## Tests
36
+
37
+ ```bash
38
+ python3 -m pytest tests/test_map_loader.py
39
+ ```
40
+
41
+ ## License
42
+
43
+ MIT
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [tool.setuptools.packages.find]
6
+ where = ["src"]
7
+
8
+ [project]
9
+ name = "ne-loader"
10
+ version = "0.2.1"
11
+ description = "A simple loader for Natural Earth map data."
12
+ authors = [
13
+ { name = "Eric Tunn", email = "erictunn@icloud.com" }
14
+ ]
15
+ readme = "README.md"
16
+ license = { file = "LICENSE" }
17
+ requires-python = ">=3.8"
18
+ dependencies = [
19
+ "geopandas>=0.12",
20
+ "platformdirs>=4",
21
+ "requests>=2.25"
22
+ ]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/erictunn/ne-loader"
26
+
27
+ [project.scripts]
28
+ ne-loader = "ne_loader.cli:main"
29
+
30
+ [tool.ruff.lint]
31
+ select = [
32
+ "E",
33
+ "W",
34
+ "D",
35
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ # Natural Earth Loader package
@@ -0,0 +1,35 @@
1
+ """Resolve the cache directory used for downloaded Natural Earth data."""
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Optional, Union
6
+
7
+ from platformdirs import user_cache_dir
8
+
9
+
10
+ PathLike = Union[str, Path]
11
+
12
+
13
+ def get_cache_dir(path_override: Optional[PathLike] = None) -> Path:
14
+ """Return the directory used to cache Natural Earth downloads.
15
+
16
+ Cache directory in order of precedence:
17
+ 1. Explicit function argument 'path_override'
18
+ 2. ``NATURAL_EARTH_CACHE_DIR`` environment variable.
19
+ 3. Platform-specific user cache directory.
20
+
21
+ Args:
22
+ path_override: Optional cache directory
23
+ Returns:
24
+ A ``pathlib.Path`` pointing to the cache directory.
25
+
26
+ """
27
+ if path_override:
28
+ return Path(path_override).expanduser()
29
+
30
+ env_path: Optional[str] = os.getenv("NATURAL_EARTH_CACHE_DIR")
31
+ if env_path:
32
+ return Path(env_path).expanduser()
33
+
34
+ default_cache_dir: str = user_cache_dir(appname="ne-loader", appauthor="erictunn")
35
+ return Path(default_cache_dir)
@@ -0,0 +1,33 @@
1
+ """Provides basic command line functionality."""
2
+
3
+ import argparse
4
+
5
+ import geopandas as gpd
6
+
7
+ from . import map_loader
8
+
9
+
10
+ def main() -> None:
11
+ """Run the Natural Earth loader command-line interface."""
12
+ parser: argparse.ArgumentParser = argparse.ArgumentParser(
13
+ description="Download and load Natural Earth data."
14
+ )
15
+ parser.add_argument("category", choices=["cultural", "physical"], help="Data category")
16
+ parser.add_argument("name", help="Dataset name (e.g., admin_0_countries)")
17
+ parser.add_argument("--res", default="10m", help="Resolution (default: 10m)")
18
+ parser.add_argument("--out", help="Output file to save as GeoJSON (optional)")
19
+ args: argparse.Namespace = parser.parse_args()
20
+
21
+ gdf: gpd.GeoDataFrame = map_loader.get_natural_earth(
22
+ args.category,
23
+ args.name,
24
+ args.res,
25
+ )
26
+ if args.out:
27
+ gdf.to_file(args.out, driver="GeoJSON")
28
+ print(f"Saved to {args.out}")
29
+ else:
30
+ print(gdf.head())
31
+
32
+ if __name__ == "__main__":
33
+ main()
@@ -0,0 +1,129 @@
1
+ """Handles downloading and fetching of NE data."""
2
+
3
+ import logging
4
+ import zipfile
5
+ from pathlib import Path
6
+ from typing import Optional
7
+
8
+ import geopandas as gpd
9
+ import requests
10
+
11
+ from .cacher import PathLike, get_cache_dir
12
+
13
+
14
+ def build_ne_filename(name: str, res: str = "10m", suffix: str = ".zip") -> str:
15
+ """Build a Natural Earth dataset filename."""
16
+ return f"ne_{res}_{name}{suffix}"
17
+
18
+
19
+ def build_ne_url(category: str, name: str, res: str = "10m") -> str:
20
+ """Build the download URL for a Natural Earth vector dataset."""
21
+ return (
22
+ f"https://naciscdn.org/naturalearth/{res}/{category}/"
23
+ f"{build_ne_filename(name, res)}"
24
+ )
25
+
26
+
27
+ def build_ne_zip_path(data_dir: PathLike, name: str, res: str = "10m") -> Path:
28
+ """Build the local cache path for a Natural Earth zip file."""
29
+ return Path(data_dir) / build_ne_filename(name, res)
30
+
31
+
32
+ def build_ne_extract_dir(data_dir: PathLike, name: str, res: str = "10m") -> Path:
33
+ """Build the local extraction directory for a Natural Earth dataset."""
34
+ return Path(data_dir) / build_ne_filename(name, res, suffix="")
35
+
36
+
37
+ def build_ne_shp_path(data_dir: PathLike, name: str, res: str = "10m") -> Path:
38
+ """Build the local shapefile path for an extracted Natural Earth dataset."""
39
+ extract_dir: Path = build_ne_extract_dir(data_dir, name, res)
40
+ return extract_dir / build_ne_filename(name, res, suffix=".shp")
41
+
42
+
43
+ def get_natural_earth(
44
+ category: str,
45
+ name: str,
46
+ res: str = "10m",
47
+ dir_override: Optional[PathLike] = None,
48
+ ) -> gpd.GeoDataFrame:
49
+ """Download, cache, and load a Natural Earth vector dataset.
50
+
51
+ Args:
52
+ category: Natural Earth data category, e.g. "cultural" or
53
+ "physical".
54
+ name: Dataset name without the ``ne_{res}_`` prefix, e.g.
55
+ "admin_0_countries".
56
+ res: Natural Earth resolution. "10m", "50m" and "110m" are accepted.
57
+ However, not all datasets will have all 3 resolutions available.
58
+ dir_override: Optional cache directory override. This takes precedence over the
59
+ ``NATURAL_EARTH_CACHE_DIR`` environment variable.
60
+
61
+ Returns:
62
+ A GeoPandas ``GeoDataFrame`` loaded from the cached shapefile.
63
+
64
+ """
65
+ logger: logging.Logger = logging.getLogger(__name__)
66
+
67
+ data_dir: Path = get_cache_dir(dir_override)
68
+ data_dir.mkdir(parents=True, exist_ok=True)
69
+
70
+ url: str = build_ne_url(category, name, res)
71
+ zip_path: Path = build_ne_zip_path(data_dir, name, res)
72
+ extract_dir: Path = build_ne_extract_dir(data_dir, name, res)
73
+ shp_file: Path = build_ne_shp_path(data_dir, name, res)
74
+
75
+ _download_ne_data(
76
+ url=url,
77
+ extract_dir=extract_dir,
78
+ name=name,
79
+ res=res,
80
+ zip_path=zip_path,
81
+ shp_file=shp_file,
82
+ logger=logger,
83
+ )
84
+
85
+ return gpd.read_file(shp_file)
86
+
87
+
88
+ def _download_ne_data(
89
+ url: str,
90
+ extract_dir: Path,
91
+ name: str,
92
+ res: str,
93
+ zip_path: Path,
94
+ shp_file: Path,
95
+ logger: logging.Logger,
96
+ ) -> None:
97
+ """Download and extract a dataset when the expected shapefile is absent."""
98
+ if shp_file.exists():
99
+ return
100
+
101
+ print(f"Downloading {name} ({res})...")
102
+
103
+ try:
104
+ response: requests.Response = requests.get(url, stream=True, timeout=10)
105
+ response.raise_for_status()
106
+
107
+ with zip_path.open("wb") as zip_file:
108
+ chunk: bytes
109
+ for chunk in response.iter_content(chunk_size=8192):
110
+ zip_file.write(chunk)
111
+
112
+ with zipfile.ZipFile(zip_path, "r") as zip_ref:
113
+ zip_ref.extractall(extract_dir)
114
+ zip_path.unlink()
115
+
116
+ except requests.exceptions.HTTPError as error:
117
+ logger.error(
118
+ "A HTTP error occurred while attempting to fetch data: %s\n"
119
+ "This may cause an error when attempting to load the data.",
120
+ error,
121
+ )
122
+ print(f"A HTTP error occurred while attempting to fetch data: {error}")
123
+ except requests.exceptions.RequestException as error:
124
+ logger.error(
125
+ "A request error occurred while attempting to fetch data: %s\n"
126
+ "This may cause an error when attempting to load the data.",
127
+ error,
128
+ )
129
+ print(f"A request error occurred while attempting to fetch data: {error}")
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: ne-loader
3
+ Version: 0.2.1
4
+ Summary: A simple loader for Natural Earth map data.
5
+ Author-email: Eric Tunn <erictunn@icloud.com>
6
+ Project-URL: Homepage, https://github.com/erictunn/ne-loader
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: geopandas>=0.12
10
+ Requires-Dist: platformdirs>=4
11
+ Requires-Dist: requests>=2.25
12
+
13
+ # NE Loader
14
+
15
+ A simple, robust Python package to download and load Natural Earth map data using GeoPandas.
16
+
17
+ ## Features
18
+
19
+ - Download and cache Natural Earth datasets
20
+ - Load shapefiles as GeoDataFrames
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pip install ne-loader
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ```python
31
+ from ne_loader import map_loader
32
+ world = map_loader.get_natural_earth('cultural', 'admin_0_countries')
33
+ ```
34
+
35
+ ## CLI
36
+
37
+ ```bash
38
+ ne-loader --help
39
+ ```
40
+
41
+ To set an environment override for the NE data save path:
42
+
43
+ ```bash
44
+ export NATURAL_EARTH_CACHE_DIR="..."
45
+ ```
46
+
47
+ ## Tests
48
+
49
+ ```bash
50
+ python3 -m pytest tests/test_map_loader.py
51
+ ```
52
+
53
+ ## License
54
+
55
+ MIT
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/ne_loader/__init__.py
4
+ src/ne_loader/cacher.py
5
+ src/ne_loader/cli.py
6
+ src/ne_loader/map_loader.py
7
+ src/ne_loader.egg-info/PKG-INFO
8
+ src/ne_loader.egg-info/SOURCES.txt
9
+ src/ne_loader.egg-info/dependency_links.txt
10
+ src/ne_loader.egg-info/entry_points.txt
11
+ src/ne_loader.egg-info/requires.txt
12
+ src/ne_loader.egg-info/top_level.txt
13
+ tests/test_map_loader.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ne-loader = ne_loader.cli:main
@@ -0,0 +1,3 @@
1
+ geopandas>=0.12
2
+ platformdirs>=4
3
+ requests>=2.25
@@ -0,0 +1 @@
1
+ ne_loader
@@ -0,0 +1,47 @@
1
+ """Basic tests for map_loader.py constructors."""
2
+
3
+ from pathlib import Path
4
+
5
+ from ne_loader.map_loader import (
6
+ build_ne_filename,
7
+ build_ne_shp_path,
8
+ build_ne_url,
9
+ build_ne_zip_path,
10
+ )
11
+
12
+
13
+ def test_build_ne_url() -> None:
14
+ """Tests that the Natural Earth website URL is built correctly."""
15
+ assert (
16
+ build_ne_url("cultural", "admin_0_countries", "10m")
17
+ == "https://naciscdn.org/naturalearth/10m/cultural/"
18
+ "ne_10m_admin_0_countries.zip"
19
+ )
20
+
21
+
22
+ def test_build_ne_zip_path() -> None:
23
+ """Tests that the cache zip path builds correctly."""
24
+ assert build_ne_zip_path(
25
+ Path("/tmp/natural-earth-cache"),
26
+ "admin_0_countries",
27
+ "10m",
28
+ ) == Path("/tmp/natural-earth-cache/ne_10m_admin_0_countries.zip")
29
+
30
+
31
+ def test_build_ne_filename() -> None:
32
+ """Tests that the Natural Earth data zip file name is built correctly."""
33
+ assert build_ne_filename("admin_0_countries", "10m") == (
34
+ "ne_10m_admin_0_countries.zip"
35
+ )
36
+
37
+
38
+ def test_build_ne_shp_path() -> None:
39
+ """Tests that the path to the .shp file containing NE data is built correctly."""
40
+ assert build_ne_shp_path(
41
+ Path("/tmp/natural-earth-cache"),
42
+ "admin_0_countries",
43
+ "10m",
44
+ ) == Path(
45
+ "/tmp/natural-earth-cache/ne_10m_admin_0_countries/"
46
+ "ne_10m_admin_0_countries.shp"
47
+ )