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.
- ne_loader-0.2.1/PKG-INFO +55 -0
- ne_loader-0.2.1/README.md +43 -0
- ne_loader-0.2.1/pyproject.toml +35 -0
- ne_loader-0.2.1/setup.cfg +4 -0
- ne_loader-0.2.1/src/ne_loader/__init__.py +1 -0
- ne_loader-0.2.1/src/ne_loader/cacher.py +35 -0
- ne_loader-0.2.1/src/ne_loader/cli.py +33 -0
- ne_loader-0.2.1/src/ne_loader/map_loader.py +129 -0
- ne_loader-0.2.1/src/ne_loader.egg-info/PKG-INFO +55 -0
- ne_loader-0.2.1/src/ne_loader.egg-info/SOURCES.txt +13 -0
- ne_loader-0.2.1/src/ne_loader.egg-info/dependency_links.txt +1 -0
- ne_loader-0.2.1/src/ne_loader.egg-info/entry_points.txt +2 -0
- ne_loader-0.2.1/src/ne_loader.egg-info/requires.txt +3 -0
- ne_loader-0.2.1/src/ne_loader.egg-info/top_level.txt +1 -0
- ne_loader-0.2.1/tests/test_map_loader.py +47 -0
ne_loader-0.2.1/PKG-INFO
ADDED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
1
|
+
|
|
@@ -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
|
+
)
|