Skip to content

Commit

Permalink
build: release on push to main; sdist, wheels and pypi publish (#26)
Browse files Browse the repository at this point in the history
* build: release on push to main; sdist, wheels and pypi publish

* build: use setup-micromamba with bash shell and pip

* test: mv input-data > data ; win-compatible paths in tests

* fix: catch TypeError in try/except for non-path `masks` in windows

* build: run all py versions in ubuntu; only latest in mac/win
  • Loading branch information
martibosch authored Aug 11, 2023
1 parent 5bf543f commit 8151caf
Show file tree
Hide file tree
Showing 14 changed files with 111 additions and 49 deletions.
91 changes: 69 additions & 22 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,78 @@ name: release

on:
push:
tags:
- "v*"
branches:
- main

jobs:
make_sdist:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: "3.11"

- name: install dependencies
run: |
python -m pip install --upgrade pip
pip install build twine
- name: build wheels and source tarball
run: |
python -m build --sdist
twine check --strict dist/*
- uses: actions/upload-artifact@v3
with:
path: dist/*.tar.gz

build_wheels:
name: wheel on ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2

- uses: pypa/cibuildwheel@v2

- name: Upload wheels
uses: actions/upload-artifact@v3
with:
path: wheelhouse/*.whl

publish_dev_build:
needs: [make_sdist, build_wheels]
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://pypi.org/p/pylandstats
permissions:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write

steps:
- uses: actions/checkout@v2

- uses: actions/download-artifact@v3
with:
name: artifact
path: dist

- name: publish to test pypi
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: true

release:
if: startsWith(github.event.ref, "refs/tags/v")
needs: [publish_dev_build]
name: create release
runs-on: ubuntu-latest
environment:
Expand All @@ -17,9 +84,6 @@ jobs:
id-token: write
# see https://github.com/softprops/action-gh-release/issues/236
contents: write
strategy:
matrix:
python-versions: ["3.10"]

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
Expand All @@ -39,23 +103,6 @@ jobs:
sinceTag: v0.1.0
output: RELEASE-CHANGELOG.md

- uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-versions }}

- name: install dependencies
run: |
python -m pip install --upgrade pip
pip install build twine
- name: build wheels and source tarball
run: |
python -m build
twine check --strict dist/*
- name: show temporary files
run: ls -l

- name: create github release
uses: softprops/action-gh-release@v1
with:
Expand Down
25 changes: 15 additions & 10 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,28 @@ jobs:
test:
strategy:
matrix:
python-versions: ["3.8", "3.9", "3.10", "3.11"]
os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest]
python-version: ["3.8", "3.9", "3.10", "3.11"]
include:
- miniforge-variant: Mambaforge
miniforge-version: 4.11.0-4
- os: macos-latest
python-version: "3.11"
- os: windows-latest
python-version: "3.11"

runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash -l {0}

steps:
- uses: actions/checkout@v2

- name: setup conda environment with mambaforge
uses: conda-incubator/setup-miniconda@v2
- uses: mamba-org/setup-micromamba@v1
with:
use-mamba: true
python-version: ${{ matrix.python-version }}
miniforge-variant: ${{ matrix.miniforge-variant }}
miniforge-version: ${{ matrix.miniforge-version }}
environment-name: test-env
create-args: >-
python=${{ matrix.python-version }}
pip
- name: install dependencies
run: pip install tox tox-gh-actions
Expand Down
5 changes: 4 additions & 1 deletion pylandstats/zonal.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,16 @@ def __init__(
elif not isinstance(masks, gpd.GeoDataFrame):
try:
masks = gpd.read_file(masks)
except AttributeError:
except (AttributeError, TypeError):
# AttributeError: 'list'/'numpy.ndarray' object has no
# attribute 'startswith'
# we assume that `masks` is a list-like of numpy
# arrays or a numpy array, in which case we rename the
# variable to `masks_arr` so that it is properly used
# below
# TypeError: in windows, fiona will try to read `masks` as a
# regular expression and raise a TypeError (see
# https://github.com/Toblerity/Fiona/blob/master/fiona/path.py)
masks_arr = masks

# at this point, `masks` can either be a GeoDataFrame (in
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
39 changes: 23 additions & 16 deletions tests/test_pylandstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
plt.switch_backend("agg") # only for testing purposes
geom_crs = "epsg:4326"

tests_dir = "tests"
tests_data_dir = path.join(tests_dir, "data")


class TestImports(unittest.TestCase):
def test_base_imports(self):
Expand All @@ -29,9 +32,11 @@ def test_geo_imports(self):

class TestLandscape(unittest.TestCase):
def setUp(self):
self.ls_arr = np.load("tests/input-data/ls250_06.npy", allow_pickle=True)
self.ls_arr = np.load(
path.join(tests_data_dir, "ls250_06.npy"), allow_pickle=True
)
self.ls = pls.Landscape(self.ls_arr, res=(250, 250))
self.landscape_fp = "tests/input-data/ls250_06.tif"
self.landscape_fp = path.join(tests_data_dir, "ls250_06.tif")

def test_io(self):
# test that if we provide a ndarray, we also need to provide the
Expand Down Expand Up @@ -330,7 +335,7 @@ def test_metrics_value_ranges(self):
# TODO: assert 0 < ls.interspersion_juxtaposition_index() <= 100

def test_transonic(self):
ls_arr = np.load("tests/input-data/ls250_06.npy", allow_pickle=True)
ls_arr = np.load(path.join(tests_data_dir, "ls250_06.npy"), allow_pickle=True)
ls = pls.Landscape(ls_arr, res=(250, 250))
adjacency_df = ls._adjacency_df
self.assertIsInstance(adjacency_df, pd.DataFrame)
Expand Down Expand Up @@ -367,17 +372,17 @@ def setUp(self):

self.landscapes = [
pls.Landscape(
np.load("tests/input-data/ls100_06.npy", allow_pickle=True),
np.load(path.join(tests_data_dir, "ls100_06.npy"), allow_pickle=True),
res=(100, 100),
),
pls.Landscape(
np.load("tests/input-data/ls250_06.npy", allow_pickle=True),
np.load(path.join(tests_data_dir, "ls250_06.npy"), allow_pickle=True),
res=(250, 250),
),
]
self.landscape_fps = [
"tests/input-data/ls100_06.tif",
"tests/input-data/ls250_06.tif",
path.join(tests_data_dir, "ls100_06.tif"),
path.join(tests_data_dir, "ls250_06.tif"),
]
self.attribute_name = "resolution"
self.attribute_values = [100, 250]
Expand Down Expand Up @@ -672,8 +677,8 @@ def setUp(self):
# between passing `Landscape` objects or filepaths is already tested
# in `TestMultiLandscape`
self.landscape_fps = [
"tests/input-data/ls250_06.tif",
"tests/input-data/ls250_12.tif",
path.join(tests_data_dir, "ls250_06.tif"),
path.join(tests_data_dir, "ls250_12.tif"),
]
self.dates = [2006, 2012]
self.inexistent_class_val = 999
Expand Down Expand Up @@ -774,21 +779,23 @@ def test_spatiotemporalanalysis_plot_metrics(self):

class TestZonaAlnalysis(unittest.TestCase):
def setUp(self):
self.masks_arr = np.load("tests/input-data/masks_arr.npy", allow_pickle=True)
self.masks_arr = np.load(
path.join(tests_data_dir, "masks_arr.npy"), allow_pickle=True
)
self.landscape = pls.Landscape(
np.load("tests/input-data/ls250_06.npy", allow_pickle=True),
np.load(path.join(tests_data_dir, "ls250_06.npy"), allow_pickle=True),
res=(250, 250),
)
self.landscape_fp = "tests/input-data/ls250_06.tif"
self.landscape_fp = path.join(tests_data_dir, "ls250_06.tif")
with rio.open(self.landscape_fp) as src:
self.landscape_transform = src.transform
self.landscape_crs = src.crs
self.masks_fp = "tests/input-data/gmb-lausanne.gpkg"
self.masks_fp = path.join(tests_data_dir, "gmb-lausanne.gpkg")
# for buffer analysis
self.geom = geometry.Point(6.6327025, 46.5218269)
self.buffer_dists = [10000, 15000, 20000]

self.tmp_dir = path.join("tests/tmp")
self.tmp_dir = path.join(tests_dir, "tmp")
os.mkdir(self.tmp_dir)

def tearDown(self):
Expand Down Expand Up @@ -1179,8 +1186,8 @@ def test_grid_init(self):
class TestSpatioTemporalBufferAnalysis(unittest.TestCase):
def setUp(self):
self.landscape_fps = [
"tests/input-data/ls250_06.tif",
"tests/input-data/ls250_12.tif",
path.join(tests_data_dir, "ls250_06.tif"),
path.join(tests_data_dir, "ls250_12.tif"),
]
self.dates = [2006, 2012]
self.base_mask = gpd.GeoSeries(
Expand Down

0 comments on commit 8151caf

Please sign in to comment.