Skip to content

Commit f334af6

Browse files
authored
Merge branch 'master' into ids
2 parents f527126 + d291e01 commit f334af6

File tree

20 files changed

+901
-341
lines changed

20 files changed

+901
-341
lines changed

.github/workflows/unittests.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,18 @@
1919
strategy:
2020
matrix:
2121
os: ['ubuntu-latest']
22-
environment-file: [ci/37-minimal.yaml, ci/37.yaml, ci/38.yaml, ci/39.yaml, ci/310.yaml]
22+
environment-file: [
23+
ci/38.yaml,
24+
ci/39.yaml,
25+
ci/310.yaml,
26+
ci/310_shapely_dev.yaml
27+
]
2328
include:
2429
- environment-file: ci/310.yaml
2530
os: macos-latest
2631
- environment-file: ci/310.yaml
2732
os: windows-latest
33+
fail-fast: false
2834

2935
steps:
3036
- name: checkout repo
@@ -35,6 +41,7 @@
3541
with:
3642
environment-file: ${{ matrix.environment-file }}
3743
micromamba-version: 'latest'
44+
channel-priority: 'flexible'
3845

3946
- name: run tests - bash
4047
shell: bash -l {0}

.pre-commit-config.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
2-
- repo: https://github.com/psf/black
3-
rev: 21.12b0
4-
hooks:
5-
- id: black
6-
language_version: python3.9
2+
- repo: https://github.com/psf/black
3+
rev: 22.10.0
4+
hooks:
5+
- id: black
6+
language_version: python3

ci/37.yaml renamed to ci/310_shapely_dev.yaml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
name: test
22
channels:
33
- conda-forge
4+
- conda-forge/label/shapely_dev
45
dependencies:
5-
- python=3.7
6+
- python=3.10
67
- platformdirs
78
- beautifulsoup4
89
- jinja2
@@ -15,11 +16,18 @@ dependencies:
1516
- pytest
1617
- pytest-cov
1718
- pytest-xdist
18-
- networkx=2.7
1919
# optional
20-
- geopandas>=0.7.0
20+
- geopandas>=0.12.0
2121
- joblib
22+
- networkx
2223
- numba
2324
- packaging
25+
- shapely>=2.0b1
2426
- xarray
2527
- zstd
28+
# for docs build action (this env only)
29+
- nbsphinx
30+
- numpydoc
31+
- sphinx
32+
- sphinxcontrib-bibtex
33+
- sphinx_bootstrap_theme

ci/37-minimal.yaml

Lines changed: 0 additions & 17 deletions
This file was deleted.

examples.ipynb

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": 46,
5+
"execution_count": 1,
66
"metadata": {},
77
"outputs": [],
88
"source": [
@@ -11,7 +11,7 @@
1111
},
1212
{
1313
"cell_type": "code",
14-
"execution_count": 47,
14+
"execution_count": 2,
1515
"metadata": {},
1616
"outputs": [],
1717
"source": [
@@ -25,7 +25,7 @@
2525
},
2626
{
2727
"cell_type": "code",
28-
"execution_count": 48,
28+
"execution_count": 3,
2929
"metadata": {},
3030
"outputs": [],
3131
"source": [
@@ -83,7 +83,7 @@
8383
},
8484
{
8585
"cell_type": "code",
86-
"execution_count": 71,
86+
"execution_count": 4,
8787
"metadata": {},
8888
"outputs": [],
8989
"source": [
@@ -126,28 +126,41 @@
126126
},
127127
{
128128
"cell_type": "code",
129-
"execution_count": 72,
129+
"execution_count": 5,
130130
"metadata": {},
131-
"outputs": [],
131+
"outputs": [
132+
{
133+
"ename": "FileNotFoundError",
134+
"evalue": "[Errno 2] No such file or directory: 'libpysal/examples/examples.json'",
135+
"output_type": "error",
136+
"traceback": [
137+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
138+
"\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
139+
"Input \u001b[0;32mIn [5]\u001b[0m, in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[38;5;28;43mopen\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mlibpysal/examples/examples.json\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mr\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m efile:\n\u001b[1;32m 2\u001b[0m examples \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mload(efile)\n",
140+
"\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'libpysal/examples/examples.json'"
141+
]
142+
}
143+
],
132144
"source": [
133145
"with open('libpysal/examples/examples.json', 'r') as efile:\n",
134146
" examples = json.load(efile)"
135147
]
136148
},
137149
{
138150
"cell_type": "code",
139-
"execution_count": 73,
151+
"execution_count": 6,
140152
"metadata": {},
141153
"outputs": [
142154
{
143-
"data": {
144-
"text/plain": [
145-
"dict_keys(['nat', 'south', 'rio', 'mexico', 'baltimore'])"
146-
]
147-
},
148-
"execution_count": 73,
149-
"metadata": {},
150-
"output_type": "execute_result"
155+
"ename": "NameError",
156+
"evalue": "name 'examples' is not defined",
157+
"output_type": "error",
158+
"traceback": [
159+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
160+
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
161+
"Input \u001b[0;32mIn [6]\u001b[0m, in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mexamples\u001b[49m\u001b[38;5;241m.\u001b[39mkeys()\n",
162+
"\u001b[0;31mNameError\u001b[0m: name 'examples' is not defined"
163+
]
151164
}
152165
],
153166
"source": [
@@ -555,7 +568,7 @@
555568
],
556569
"metadata": {
557570
"kernelspec": {
558-
"display_name": "Python 3",
571+
"display_name": "Python 3 (ipykernel)",
559572
"language": "python",
560573
"name": "python3"
561574
},
@@ -569,9 +582,9 @@
569582
"name": "python",
570583
"nbconvert_exporter": "python",
571584
"pygments_lexer": "ipython3",
572-
"version": "3.7.3"
585+
"version": "3.10.6"
573586
}
574587
},
575588
"nbformat": 4,
576-
"nbformat_minor": 2
589+
"nbformat_minor": 4
577590
}

libpysal/examples/__init__.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
1-
""" The :mod:`libpysal.examples` module includes a number of small built-in
2-
example datasets as well as functions to fetch larger datasets.
1+
"""The :mod:`libpysal.examples` module provides example datasets.
2+
3+
The datasets consist of two sets, built-ins which are installed with
4+
this module and remotes that can be downloaded.
5+
6+
This module provides functionality for working with these example datasets.
37
"""
48

59

610
import pandas as pd
711
from .base import example_manager
812
from .remotes import datasets as remote_datasets
913
from .builtin import datasets as builtin_datasets
14+
from typing import Union
1015

1116

12-
from typing import Union
17+
available_datasets = builtin_datasets.copy()
18+
available_datasets.update(remote_datasets.datasets)
1319

14-
__all__ = ["get_path", "available", "explain", "fetch_all"]
20+
__all__ = ["get_path", "available", "explain", "fetch_all",
21+
"get_url", "load_example", "summary"]
22+
23+
example_manager.add_examples(available_datasets)
1524

16-
example_manager.add_examples(builtin_datasets)
1725

1826
def fetch_all():
19-
"""Fetch and install all remote datasets
20-
"""
27+
"""Fetch and install all remote datasets."""
2128
datasets = remote_datasets.datasets
2229
names = list(datasets.keys())
2330
names.sort()
@@ -32,35 +39,36 @@ def fetch_all():
3239

3340
def available() -> pd.DataFrame:
3441
"""Return a dataframe with available datasets."""
35-
fetch_all()
36-
3742
return example_manager.available()
3843

3944

4045
def explain(name: str) -> str:
4146
"""Explain a dataset by name."""
42-
4347
return example_manager.explain(name)
4448

4549

50+
def get_url(name: str) -> str:
51+
"""Get url for remote dataset."""
52+
return example_manager.get_remote_url(name)
53+
54+
4655
def load_example(example_name: str) -> Union[base.Example, builtin.LocalExample]:
4756
"""Load example dataset instance."""
4857
example = example_manager.load(example_name)
49-
50-
if example is None:
51-
fetch_all() # refresh remotes
52-
example = example_manager.load(example_name)
53-
5458
return example
5559

5660

5761
def get_path(file_name: str) -> str:
5862
"""Get the path for a file by searching installed datasets."""
59-
6063
installed = example_manager.get_installed_names()
6164
for name in installed:
6265
example = example_manager.datasets[name]
6366
pth = example.get_path(file_name, verbose=False)
6467
if pth:
6568
return pth
6669
print("{} is not a file in any installed dataset.".format(file_name))
70+
71+
72+
def summary():
73+
"""Summary of datasets."""
74+
example_manager.summary()

libpysal/examples/base.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
import io
99
import os
1010
import webbrowser
11-
from os import environ, makedirs
12-
from os.path import exists, expanduser, join
1311
from platformdirs import user_data_dir
1412
import zipfile
1513
import requests
@@ -35,9 +33,9 @@ def get_data_home():
3533

3634
appname = "pysal"
3735
appauthor = "pysal"
38-
data_home = user_data_dir(appname, appauthor)
39-
if not exists(data_home):
40-
makedirs(data_home, exist_ok=True)
36+
data_home = user_data_dir(appname, appauthor)
37+
if not os.path.exists(data_home):
38+
os.makedirs(data_home, exist_ok=True)
4139
return data_home
4240

4341

@@ -122,7 +120,9 @@ class Example:
122120
123121
"""
124122

125-
def __init__(self, name, description, n, k, download_url, explain_url):
123+
def __init__(self, name, description, n, k, download_url,
124+
explain_url):
125+
"""Initialze Example."""
126126
self.name = name
127127
self.description = description
128128
self.n = n
@@ -134,12 +134,10 @@ def __init__(self, name, description, n, k, download_url, explain_url):
134134

135135
def get_local_path(self, path=get_data_home()) -> str:
136136
"""Get the local path for example."""
137-
138-
return join(path, self.root)
137+
return os.path.join(path, self.root)
139138

140139
def get_path(self, file_name, verbose=True) -> Union[str, None]:
141140
"""Get the path for local file."""
142-
143141
file_list = self.get_file_list()
144142
for file_path in file_list:
145143
base_name = os.path.basename(file_path)
@@ -151,7 +149,6 @@ def get_path(self, file_name, verbose=True) -> Union[str, None]:
151149

152150
def downloaded(self) -> bool:
153151
"""Check if the example has already been installed."""
154-
155152
path = self.get_local_path()
156153
if os.path.isdir(path):
157154
self.installed = True
@@ -180,7 +177,7 @@ def download(self, path=get_data_home()):
180177
if not self.downloaded():
181178
request = requests.get(self.download_url)
182179
archive = zipfile.ZipFile(io.BytesIO(request.content))
183-
target = join(path, self.root)
180+
target = os.path.join(path, self.root)
184181
print("Downloading {} to {}".format(self.name, target))
185182
archive.extractall(path=target)
186183
self.zipfile = archive
@@ -213,8 +210,8 @@ def load(self, file_name) -> io.FileIO:
213210
class Examples:
214211
"""Manager for pysal example datasets."""
215212

216-
def __init__(self):
217-
self.datasets = {}
213+
def __init__(self, datasets={}):
214+
self.datasets = datasets
218215

219216
def add_examples(self, examples):
220217
"""Add examples to the set of datasets available."""
@@ -273,5 +270,23 @@ def get_installed_names(self) -> list:
273270
ds = self.datasets
274271
return [name for name in ds if ds[name].installed]
275272

273+
def get_remote_url(self, name):
274+
if name in self.datasets:
275+
try:
276+
return self.datasets[name].download_url
277+
except:
278+
print(f'{name} is a built-in dataset, no url.')
279+
else:
280+
print(f'{name} is not an available dataset.')
281+
282+
283+
def summary(self):
284+
"""Report on datasets."""
285+
available = self.available()
286+
n = available.shape[0]
287+
n_installed = available.Installed.sum()
288+
n_remote = n - n_installed
289+
print(f'{n} datasets available, {n_installed} installed, {n_remote} remote.')
290+
276291

277292
example_manager = Examples()

0 commit comments

Comments
 (0)