Skip to content

Commit

Permalink
Add pytest GitHub workflow & convert to src/ layout (#19)
Browse files Browse the repository at this point in the history
* Add pre-commit hooks and run hooks on all files

* Refactor project to use src/ layout

* Add basic tox.ini file to test across python versions

* Add pytest GitHub workflow to run tox

* Update README to include poetry run tox

* minor: Wrap python version in string

* Improve GitHub tox workflow to target specific python version

* Rename test workflow for improved readability

* test: Create test to run executable

* Run black on single file

* build: Update tox - resolve deps w/ pyproject.toml

* Update ShadowFinder import in Jupyter Notebook
  • Loading branch information
jordan-gillard authored Jul 9, 2024
1 parent 9d5bfcf commit e5f636b
Show file tree
Hide file tree
Showing 16 changed files with 448 additions and 182 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/tox.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: tox

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
pytest:
runs-on: ubuntu-latest

strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
fail-fast: false

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox
- name: Run Tests
run: tox run -m ${{ matrix.python-version }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
__pycache__/
*.py[cod]
*$py.class
dist/

# Environments
.env
Expand All @@ -11,6 +12,7 @@ venv/
ENV/
env.bak/
venv.bak/
.tox/

# Output files
*.png
Expand Down
15 changes: 13 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,18 @@ repos:
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/psf/black
rev: 24.2.0

- repo: local
hooks:
- id: black
name: black
entry: poetry run black
language: system
types: [ python ]

- id: poetry-lock
name: poetry lock
entry: poetry lock --no-update
language: system
types: [yaml]
files: ^pyproject\.toml$
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pip install shadowfinder
If you want to use ShadowFinder directly from Python, the usage is as follows.

```python
from shadowfinder.shadowfinder import ShadowFinder
from shadowfinder import ShadowFinder

finder = ShadowFinder()

Expand Down Expand Up @@ -111,7 +111,10 @@ poetry run pre-commit install
# Run the tool
poetry run shadowfinder --help

# After making changes, format your code with black:
poetry run black ./
# Run tests against your current Python interpreter
poetry run pytest

# Or, run pytest against all shadowfinder supported Python versions
poetry run tox p # p=run in parallel
```
</details>
2 changes: 1 addition & 1 deletion ShadowFinderColab.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"![ ! -f \"timezone_grid.json\" ] && wget https://raw.githubusercontent.com/bellingcat/ShadowFinder/main/timezone_grid.json >> {logfile} 2>&1\n",
"![ ! -f \"deps_loaded\" ] && pip install shadowfinder >> {logfile} 2>&1 && touch deps_loaded\n",
"\n",
"from shadowfinder.shadowfinder import ShadowFinder\n",
"from shadowfinder import ShadowFinder\n",
"import datetime\n",
"\n",
"datetime_date = datetime.datetime.strptime(date, \"%Y-%m-%d\").date()\n",
Expand Down
464 changes: 304 additions & 160 deletions poetry.lock

Large diffs are not rendered by default.

12 changes: 7 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
[tool.poetry]
name = "ShadowFinder"
version = "0.3.1"
version = "0.4.0"
description = "Find possible locations of shadows."
authors = ["Bellingcat"]
license = "MIT License"
readme = "README.md"
packages = [{ include = "shadowfinder", from = "src" }]
repository = "https://github.com/bellingcat/ShadowFinder"
classifiers = [
"Intended Audience :: Developers",
Expand All @@ -20,7 +21,7 @@ keywords=["shadow", "finder", "locator", "map"]
"Bug Tracker" = "https://github.com/bellingcat/ShadowFinder/issues"

[tool.poetry.scripts]
shadowfinder = "shadowfinder.main:main_entrypoint"
shadowfinder = "shadowfinder.__main__:main"

[tool.poetry.dependencies]
python = ">=3.9,<3.13"
Expand All @@ -34,10 +35,11 @@ numpy = "^1"
pytz = "^2024.1"

[tool.poetry.group.dev.dependencies]
black = "^24.2.0"
black = "24.2.0"
pre-commit = "^3.7.1"

tox = "^4.15.1"
pytest = "^8.2.2"

[build-system]
requires = ["poetry-core"]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Empty file removed shadowfinder/__init__.py
Empty file.
10 changes: 0 additions & 10 deletions shadowfinder/main.py

This file was deleted.

4 changes: 4 additions & 0 deletions src/shadowfinder/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .shadowfinder import ShadowFinder
from .cli import ShadowFinderCli

__all__ = ["ShadowFinder", "ShadowFinderCli"]
10 changes: 10 additions & 0 deletions src/shadowfinder/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from . import ShadowFinderCli
import fire


def main():
fire.Fire(ShadowFinderCli)


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion shadowfinder/cli.py → src/shadowfinder/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import datetime

from shadowfinder.shadowfinder import ShadowFinder
from shadowfinder import ShadowFinder


def _validate_args(
Expand Down
File renamed without changes.
34 changes: 34 additions & 0 deletions tests/test_executable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
The tests in this file test that running shadowfinder as an executable behaves
as expected.
"""

import subprocess


def test_executable_without_args():
"""Tests that running shadowfinder without any arguments returns the CLI's help string and 0 exit code."""
# GIVEN
expected = """
NAME
shadowfinder
SYNOPSIS
shadowfinder COMMAND
COMMANDS
COMMAND is one of the following:
find
Find the shadow length of an object given its height and the date and time.
find_sun
Locate a shadow based on the solar altitude angle and the date and time.
"""

# WHEN
result = subprocess.run(["shadowfinder"], capture_output=True, text=True)

# THEN
assert result.returncode == 0
assert result.stdout.strip() == expected.strip()
17 changes: 17 additions & 0 deletions tests/test_shadowfinder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from datetime import datetime

from shadowfinder import ShadowFinder


def test_creation_with_valid_arguments_should_pass():
"""Baseline test to assert that we can create an instance of ShadowFinder with only object height, shadow length,
and a datetime object."""
# GIVEN
object_height = 6
shadow_length = 3.2
date_time = datetime.now()

# WHEN / THEN
ShadowFinder(
object_height=object_height, shadow_length=shadow_length, date_time=date_time
)
14 changes: 14 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[tox]
envlist = py39, py310, py311, py312
labels =
; Used to map GitHub workflow python version to tox env
3.9 = py39
3.10 = py310
3.11 = py311
3.12 = py312

[testenv]
deps =
pytest>=8
commands =
pytest tests/ --import-mode=importlib

0 comments on commit e5f636b

Please sign in to comment.