Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pytest GitHub workflow & convert to src/ layout #19

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This instructs pre-commit to use the local versions of hooks. It guarantees that the version of black thats run on git commit matches whats in Poetry's lock file.

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$
Comment on lines +20 to +25
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hook keeps the poetry.lock file in sync with the dependencies specified in 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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added ShadowFinder to shadowfinder/__init__.py, which allows us to import from the shadowfinder/ module like it was a file. This makes it easier for users to import classes/functions/etc. without having to know which file those entities belongs to.

Copy link
Collaborator

@GalenReich GalenReich Jul 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I assume this will require updating the import in the notebook too - is that right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eye. Updated the import in ShadowFinderColab.ipynb in ad92a31


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>
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" }]
GalenReich marked this conversation as resolved.
Show resolved Hide resolved
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"
GalenReich marked this conversation as resolved.
Show resolved Hide resolved

[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"
GalenReich marked this conversation as resolved.
Show resolved Hide resolved
pre-commit = "^3.7.1"

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

[build-system]
requires = ["poetry-core"]
requires = ["poetry-core>=1.0.0"]
GalenReich marked this conversation as resolved.
Show resolved Hide resolved
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"]
GalenReich marked this conversation as resolved.
Show resolved Hide resolved
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
GalenReich marked this conversation as resolved.
Show resolved Hide resolved
Loading