Skip to content

Commit f1f45f6

Browse files
PatBall1cursoragent
andcommitted
Modernise packaging for PyPI publication
- Replace setup.py with pyproject.toml (PEP 621) - Add __version__ and graceful detectron2 import check to __init__.py - Add MANIFEST.in to prune report/notebooks from sdist - Add GitHub Actions publish workflow (trusted publishing) - Update README install instructions with clear 3-step process - Add PyPI badge Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 1af7f9f commit f1f45f6

6 files changed

Lines changed: 276 additions & 54 deletions

File tree

.github/workflows/publish.yml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
# Allow manual trigger for testing with TestPyPI
8+
workflow_dispatch:
9+
inputs:
10+
target:
11+
description: "Publish target"
12+
required: true
13+
default: "testpypi"
14+
type: choice
15+
options:
16+
- testpypi
17+
- pypi
18+
19+
permissions:
20+
contents: read
21+
22+
jobs:
23+
build:
24+
name: Build distribution
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v4
28+
29+
- name: Set up Python
30+
uses: actions/setup-python@v5
31+
with:
32+
python-version: "3.12"
33+
34+
- name: Install build tools
35+
run: python -m pip install --upgrade pip build
36+
37+
- name: Build sdist and wheel
38+
run: python -m build
39+
40+
- name: Upload distribution artifacts
41+
uses: actions/upload-artifact@v4
42+
with:
43+
name: dist
44+
path: dist/
45+
46+
publish-testpypi:
47+
name: Publish to TestPyPI
48+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'testpypi'
49+
needs: build
50+
runs-on: ubuntu-latest
51+
environment: testpypi
52+
permissions:
53+
id-token: write # trusted publishing
54+
steps:
55+
- name: Download distribution artifacts
56+
uses: actions/download-artifact@v4
57+
with:
58+
name: dist
59+
path: dist/
60+
61+
- name: Publish to TestPyPI
62+
uses: pypa/gh-action-pypi-publish@release/v1
63+
with:
64+
repository-url: https://test.pypi.org/legacy/
65+
66+
publish-pypi:
67+
name: Publish to PyPI
68+
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'pypi')
69+
needs: build
70+
runs-on: ubuntu-latest
71+
environment: pypi
72+
permissions:
73+
id-token: write # trusted publishing
74+
steps:
75+
- name: Download distribution artifacts
76+
uses: actions/download-artifact@v4
77+
with:
78+
name: dist
79+
path: dist/
80+
81+
- name: Publish to PyPI
82+
uses: pypa/gh-action-pypi-publish@release/v1

MANIFEST.in

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
include LICENSE
2+
include README.md
3+
include pyproject.toml
4+
recursive-include detectree2 *.py *.geojson *.jpg
5+
6+
# Exclude non-package directories from sdist
7+
prune report
8+
prune notebooks
9+
prune docker
10+
prune docs
11+
prune model_garden
12+
prune .devcontainer
13+
prune .setup_scripts
14+
prune .github

README.md

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
</p>
55

66

7-
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Detectree CI](https://github.com/patball1/detectree2/actions/workflows/python-ci.yml/badge.svg)](https://github.com/patball1/detectree2/actions/workflows/python-ci.yml) [![PEP8](https://img.shields.io/badge/code%20style-pep8-orange.svg)](https://www.python.org/dev/peps/pep-0008/) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17367058.svg)](https://doi.org/10.5281/zenodo.17367058) [![Open in Spaces](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/spaces/forestmap-ai/Detectree2)
7+
[![PyPI](https://img.shields.io/pypi/v/detectree2.svg)](https://pypi.org/project/detectree2/) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Detectree CI](https://github.com/patball1/detectree2/actions/workflows/python-ci.yml/badge.svg)](https://github.com/patball1/detectree2/actions/workflows/python-ci.yml) [![PEP8](https://img.shields.io/badge/code%20style-pep8-orange.svg)](https://www.python.org/dev/peps/pep-0008/) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17367058.svg)](https://doi.org/10.5281/zenodo.17367058) [![Open in Spaces](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/spaces/forestmap-ai/Detectree2)
88

99

1010
<!-- <a href="https://github.com/hhatto/autopep8"><img alt="Code style: autopep8" src="https://img.shields.io/badge/code%20style-autopep8-000000.svg"></a> -->
@@ -56,25 +56,46 @@ Tree Crown Detection and Delineation in a Temperate Deciduous Forest from UAV RG
5656
## Requirements
5757

5858
- Python 3.8+
59-
- [gdal](https://gdal.org/download.html) geospatial libraries
60-
- [PyTorch ≥ 1.8 and torchvision](https://pytorch.org/get-started/previous-versions/) versions that match
61-
- For training models GPU access (with CUDA) is recommended
62-
63-
e.g.
64-
```pip3 install torch torchvision torchaudio```
59+
- [GDAL](https://gdal.org/download.html) geospatial libraries
60+
- [PyTorch >= 1.8 and torchvision](https://pytorch.org/get-started/previous-versions/) (matching versions)
61+
- [Detectron2](https://github.com/facebookresearch/detectron2) (Facebook's object detection library)
62+
- For training models, GPU access (with CUDA) is recommended
6563

6664
## Installation
6765

68-
### pip
66+
### Step 1: Install PyTorch
67+
68+
Follow the [official instructions](https://pytorch.org/get-started) to install PyTorch with the appropriate CUDA version for your system:
69+
70+
```bash
71+
# Example: CPU-only
72+
pip install torch torchvision torchaudio
73+
74+
# Example: CUDA 12.4
75+
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
76+
```
6977

70-
```pip install git+https://github.com/PatBall1/detectree2.git```
78+
### Step 2: Install Detectron2
7179

72-
Currently works on Google Colab (Pro version recommended). May struggle on clusters if geospatial libraries are not configured.
73-
See [Installation Instructions](https://patball1.github.io/detectree2/installation.html) if you are having trouble.
80+
```bash
81+
pip install 'git+https://github.com/facebookresearch/detectron2.git'
82+
```
7483

75-
### conda
84+
### Step 3: Install detectree2
85+
86+
```bash
87+
pip install detectree2
88+
```
89+
90+
Or install from source for development:
91+
92+
```bash
93+
git clone https://github.com/PatBall1/detectree2.git
94+
cd detectree2
95+
pip install -e ".[dev,test]"
96+
```
7697

77-
*Under development*
98+
> **Note:** If you have trouble with geospatial dependencies (GDAL, rasterio, fiona), using conda to install them first is recommended: `conda install -c conda-forge gdal rasterio fiona`. See [Installation Instructions](https://patball1.github.io/detectree2/installation.html) for more details.
7899
79100
## Getting started
80101

@@ -172,8 +193,7 @@ Here is an example image of the predictions made by Detectree2.
172193
│ ├── requirements.txt
173194
│ ├── dev-requirements.txt
174195
│ └── test-requirements.txt
175-
├── setup.cfg # Lint/format config used by CI
176-
├── setup.py
196+
├── pyproject.toml # Package config, deps, tool settings
177197
└── .setup_scripts/ # Helper scripts for local tooling
178198
```
179199

detectree2/__init__.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""detectree2: Automatic tree crown delineation using Mask R-CNN.
2+
3+
Requires `Detectron2 <https://github.com/facebookresearch/detectron2>`_
4+
and `PyTorch <https://pytorch.org>`_ to be installed separately.
5+
6+
Install PyTorch first (see https://pytorch.org/get-started), then::
7+
8+
pip install 'git+https://github.com/facebookresearch/detectron2.git'
9+
pip install detectree2
10+
"""
11+
12+
__version__ = "2.1.1"
13+
14+
15+
def _check_detectron2() -> None:
16+
"""Verify that detectron2 is importable and give a helpful error if not."""
17+
try:
18+
import detectron2 # noqa: F401
19+
except ImportError:
20+
raise ImportError(
21+
"\n"
22+
"detectree2 requires Facebook's Detectron2, which must be installed separately.\n"
23+
"\n"
24+
" 1. Install PyTorch first: https://pytorch.org/get-started\n"
25+
" 2. Then install Detectron2:\n"
26+
" pip install 'git+https://github.com/facebookresearch/detectron2.git'\n"
27+
"\n"
28+
"See: https://detectron2.readthedocs.io/en/latest/tutorials/install.html\n"
29+
) from None
30+
31+
32+
_check_detectron2()

pyproject.toml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
[build-system]
2+
requires = ["setuptools>=68.0", "setuptools-scm>=8.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "detectree2"
7+
version = "2.1.1"
8+
description = "Automatic tree crown delineation in aerial RGB imagery based on Mask R-CNN."
9+
readme = "README.md"
10+
license = {text = "MIT"}
11+
requires-python = ">=3.8"
12+
authors = [
13+
{name = "James G. C. Ball", email = "ball.jgc@gmail.com"},
14+
]
15+
keywords = ["tree-crown", "remote-sensing", "instance-segmentation", "Mask-RCNN", "detectron2"]
16+
classifiers = [
17+
"Development Status :: 5 - Production/Stable",
18+
"Intended Audience :: Science/Research",
19+
"License :: OSI Approved :: MIT License",
20+
"Operating System :: OS Independent",
21+
"Programming Language :: Python :: 3",
22+
"Programming Language :: Python :: 3.8",
23+
"Programming Language :: Python :: 3.9",
24+
"Programming Language :: Python :: 3.10",
25+
"Programming Language :: Python :: 3.11",
26+
"Programming Language :: Python :: 3.12",
27+
"Topic :: Scientific/Engineering :: GIS",
28+
"Topic :: Scientific/Engineering :: Image Recognition",
29+
]
30+
dependencies = [
31+
# Core
32+
"pyyaml>=5.1",
33+
"numpy>=1.20",
34+
"pandas>=1.3",
35+
"tqdm>=4.60",
36+
"opencv-python>=4.5",
37+
# Geospatial — shapely 2.x required by evaluation module (make_valid)
38+
"shapely>=2.0",
39+
"geopandas>=0.13",
40+
"rasterio>=1.2",
41+
"fiona>=1.8",
42+
"rtree>=0.9",
43+
# Evaluation utils
44+
"pycocotools>=2.0.4",
45+
]
46+
47+
[project.optional-dependencies]
48+
dev = [
49+
"pre-commit>=3.0",
50+
"flake8>=6.0",
51+
"pep8-naming",
52+
"pydocstyle",
53+
"isort>=5.0",
54+
"yapf",
55+
"mypy>=1.0",
56+
]
57+
test = [
58+
"pytest>=7.0",
59+
"pytest-cov>=4.0",
60+
"pytest-order",
61+
]
62+
docs = [
63+
"sphinx>=7.0",
64+
"sphinx-rtd-theme>=2.0",
65+
"nbsphinx>=0.9",
66+
]
67+
68+
[project.urls]
69+
Homepage = "https://github.com/PatBall1/detectree2"
70+
Documentation = "https://patball1.github.io/detectree2/"
71+
Repository = "https://github.com/PatBall1/detectree2"
72+
Issues = "https://github.com/PatBall1/detectree2/issues"
73+
Demo = "https://huggingface.co/spaces/forestmap-ai/Detectree2"
74+
Sponsor = "https://forestmap.ai"
75+
76+
[tool.setuptools.packages.find]
77+
include = ["detectree2*"]
78+
79+
[tool.setuptools.package-data]
80+
"detectree2" = ["tests/input/**/*.geojson"]
81+
82+
# ---------- Tool configuration (migrated from setup.cfg) ----------
83+
84+
[tool.flake8]
85+
max-line-length = 120
86+
docstring-convention = "google"
87+
ignore = ["D100", "D101", "D102", "D103", "D104", "D202", "D212", "W503", "N803", "N806"]
88+
exclude = ["detectree2/data_loading", "detectree2/models/train_tune.py"]
89+
max-complexity = 10
90+
91+
[tool.isort]
92+
profile = "black"
93+
multi_line_output = 3
94+
include_trailing_comma = true
95+
96+
[tool.mypy]
97+
disallow_untyped_defs = false
98+
disallow_any_unimported = false
99+
no_implicit_optional = false
100+
check_untyped_defs = false
101+
warn_unused_ignores = false
102+
show_error_codes = true
103+
ignore_missing_imports = true
104+
mypy_path = ".stubs"
105+
warn_return_any = true
106+
warn_unused_configs = true
107+
108+
[[tool.mypy.overrides]]
109+
module = "detectree2.data_loading.*"
110+
ignore_errors = true
111+
112+
[tool.pytest.ini_options]
113+
testpaths = ["detectree2/tests"]

setup.py

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

0 commit comments

Comments
 (0)