Skip to content

Commit d3ef696

Browse files
OLILHRKonstantin
andauthored
refactor: use src instead of flat layout (#13)
* Use src layout and fix imports * Add setup descriptions and contribution notes to readme * Add license * Create main entry point for script * Fix `pyproject.toml` formatting * fix: "pyproject.toml: [mypy]: Unrecognized option: truthy-bool = True" * minor modifications to tox.ini just to be compliant with template repo * improve type ignore * make black formatting compatible with python 3.11 (as long as we officially support 3.11) * format * test packaging in CI * Add publishing workflow --------- Co-authored-by: Konstantin <[email protected]>
1 parent a9483d9 commit d3ef696

File tree

13 files changed

+152
-41
lines changed

13 files changed

+152
-41
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# This GitHub workflow is only needed for python package releases which are supposed to be published on pypi.
2+
# It requires the Github "environments" feature (see instructions below) it might not be available for private free accounts (but works for public or organization repos).
3+
# After creating the "release" environment in the Github repo settings, you need to enter your Github organization/user name + repo name + "python-publish.yml" workflow file name in the PyPI UI to make this work.
4+
5+
# This workflow uploads a Python Package using Twine when a release is created.
6+
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
7+
8+
name: Upload Python Package
9+
10+
on:
11+
release:
12+
types: [created, edited]
13+
14+
jobs:
15+
tests:
16+
if: startsWith(github.ref, 'refs/tags/v')
17+
runs-on: ${{ matrix.os }}
18+
strategy:
19+
matrix:
20+
python-version: ["3.12"]
21+
os: [ubuntu-latest]
22+
steps:
23+
- uses: actions/checkout@v4
24+
- name: Set up Python ${{ matrix.python-version }}
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: ${{ matrix.python-version }}
28+
- name: Install tox
29+
run: |
30+
python -m pip install --upgrade pip
31+
pip install tox
32+
- name: Run tox
33+
run: |
34+
tox
35+
36+
build-n-publish:
37+
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
38+
runs-on: ${{ matrix.os }}
39+
strategy:
40+
matrix:
41+
python-version: ["3.12"]
42+
os: [ubuntu-latest]
43+
# Specifying a GitHub environment, # Specifying a GitHub environment, which is strongly recommended by PyPI: https://docs.pypi.org/trusted-publishers/adding-a-publisher/
44+
# you have to create an environment in your repository settings and add the environment name here
45+
environment: release
46+
permissions:
47+
# IMPORTANT: this permission is mandatory for trusted publishing
48+
id-token: write
49+
needs: tests
50+
steps:
51+
- uses: actions/checkout@v4
52+
- name: Set up Python ${{ matrix.python-version }}
53+
uses: actions/setup-python@v5
54+
with:
55+
python-version: ${{ matrix.python-version }}
56+
- name: Install dependencies
57+
run: |
58+
python -m pip install --upgrade pip
59+
pip install .[packaging]
60+
- name: Build wheel and source distributions
61+
run: |
62+
python -m build
63+
- name: Publish distribution 📦 to PyPI
64+
if: startsWith(github.ref, 'refs/tags/v')
65+
uses: pypa/gh-action-pypi-publish@release/v1

.github/workflows/pythonlint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
matrix:
1313
python-version: ["3.13"]
1414
os: [ubuntu-latest]
15-
linter-env: ["linting", "type_check", "spell_check"]
15+
linter-env: ["linting", "type_check", "spell_check", "test_packaging"]
1616
steps:
1717
- uses: actions/checkout@v4
1818
- name: Set up Python ${{ matrix.python-version }}

README.md

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,37 @@
1-
# ahb-diff
1+
<img src="https://raw.githubusercontent.com/Hochfrequenz/ahlbatross/main/ahlbatross.png" alt="ahlbatross.png">
22

3-
![Unittests status badge](https://github.com/Hochfrequenz/ahb-diff/workflows/Unittests/badge.svg)
4-
![Coverage status badge](https://github.com/Hochfrequenz/ahb-diff/workflows/Coverage/badge.svg)
5-
![Pylint status badge](https://github.com/Hochfrequenz/ahb-diff/workflows/Linting/badge.svg)
6-
![Formatting status badge](https://github.com/Hochfrequenz/ahb-diff/workflows/Formatting/badge.svg)
3+
# AHlBatross
4+
5+
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?labelColor=30363D&color=fccccc)](LICENSE)
6+
![Unittests status badge](https://github.com/Hochfrequenz/ahlbatross/workflows/Unittests/badge.svg)
7+
![Coverage status badge](https://github.com/Hochfrequenz/ahlbatross/workflows/Coverage/badge.svg)
8+
![Pylint status badge](https://github.com/Hochfrequenz/ahlbatross/workflows/Linting/badge.svg)
9+
![Formatting status badge](https://github.com/Hochfrequenz/ahlbatross/workflows/Formatting/badge.svg)
710

811
Tool for **automatic AHB comparison** of consecutive `Formatversionen` provided by
9-
[machine-readable-anwendungshandbücher](https://github.com/Hochfrequenz/machine-readable_anwendungshandbuecher/).
12+
[machine-readable-anwendungshandbücher](https://github.com/Hochfrequenz/machine-readable_anwendungshandbuecher/).<br>
13+
Highlighted changes between `PruefIDs` of various `Nachrichtenformate` are stored in the `.xlsx` files located inside
14+
the `./data/output/` [directory](https://github.com/Hochfrequenz/ahlbatross/tree/main/data/output).
15+
16+
<img width="75%" src="https://raw.githubusercontent.com/Hochfrequenz/ahlbatross/main/output.png" alt="output.png">
17+
18+
## Development setup
19+
20+
To set up the python development environment, install the required dependencies via
21+
22+
```shell
23+
$ tox -e dev
24+
```
25+
26+
For local testing and code quality maintenance, run
27+
28+
```shell
29+
tox
30+
```
1031

11-
Merged `.csv` and `.xlsx` files are located inside the `./data/output/`
12-
[directory](https://github.com/Hochfrequenz/ahb-diff/tree/main/data/output).
32+
Check out our [Python Template Repository](https://github.com/Hochfrequenz/python_template_repository#how-to-use-this-repository-on-your-machine)
33+
for detailed descriptions and step-by-step instructions.
1334

14-
<img width="90%" src="https://raw.githubusercontent.com/Hochfrequenz/ahb-diff/main/output.png" alt="output.png">
35+
## Contribute
1536

37+
Feel free to contribute to this project by opening a pull request against the main branch.

ahlbatross.png

175 KB
Loading

pyproject.toml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[project]
2-
name = "ahb-diff"
2+
name = "ahlbatross"
33
description = ""
44
version = "0.1.0"
55
license = { text = "MIT" }
@@ -25,6 +25,13 @@ dependencies = [
2525
"xlsxwriter>=3.2.0"
2626
]
2727

28+
[project.scripts]
29+
ahlbatross = "ahlbatross.main:main"
30+
31+
[project.urls]
32+
Changelog = "https://github.com/Hochfrequenz/ahlbatross/releases"
33+
Homepage = "https://github.com/Hochfrequenz/ahlbatross"
34+
2835
[project.optional-dependencies]
2936
tests = [
3037
"pytest==8.3.3"
@@ -53,13 +60,9 @@ dev = [
5360
"pip-tools"
5461
]
5562

56-
[project.urls]
57-
Changelog = "https://github.com/Hochfrequenz/ahb-diff/releases"
58-
Homepage = "https://github.com/Hochfrequenz/ahb-diff"
59-
6063
[tool.black]
6164
line-length = 120
62-
target_version = ["py312", "py313"]
65+
target_version = ["py311", "py312", "py313"]
6366

6467
[tool.isort]
6568
line_length = 120
@@ -70,7 +73,6 @@ max-line-length = 120
7073

7174
[mypy]
7275
truethy-bool = true
73-
7476
[tool.mypy]
7577
disable_error_code = []
7678

requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ numpy==2.1.3
99
# pandas
1010
# pandas-stubs
1111
pandas==2.2.3
12-
# via ahb-diff (pyproject.toml)
12+
# via ahlbatross (pyproject.toml)
1313
pandas-stubs==2.2.3.241009
14-
# via ahb-diff (pyproject.toml)
14+
# via ahlbatross (pyproject.toml)
1515
python-dateutil==2.9.0.post0
1616
# via pandas
1717
pytz==2024.2
@@ -23,4 +23,4 @@ types-pytz==2024.2.0.20241003
2323
tzdata==2024.2
2424
# via pandas
2525
xlsxwriter==3.2.0
26-
# via ahb-diff (pyproject.toml)
26+
# via ahlbatross (pyproject.toml)
File renamed without changes.

ahb_diff/main.py renamed to src/ahlbatross/main.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
import logging
66
import sys
77
from pathlib import Path
8-
from typing import Any, Tuple, TypeAlias
8+
from typing import Any, Optional, Tuple, TypeAlias
99

1010
import pandas as pd
1111
from pandas.core.frame import DataFrame
12-
from xlsxwriter.format import Format # type: ignore
12+
from xlsxwriter.format import Format # type:ignore[import-untyped]
1313

1414
logging.basicConfig(level=logging.INFO, format="%(message)s", stream=sys.stdout)
1515
logger = logging.getLogger(__name__)
1616

1717
SUBMODULE = Path("data/machine-readable_anwendungshandbuecher")
18-
OUTPUT_DIR = Path("data/output")
18+
DEFAULT_OUTPUT_DIR = Path("data/output")
1919

2020
XlsxFormat: TypeAlias = Format
2121

@@ -596,7 +596,9 @@ def export_to_excel(df: DataFrame, output_path_xlsx: str) -> None:
596596
logger.info("✅successfully exported XLSX file to: %s", {output_path_xlsx})
597597

598598

599-
def _process_files(previous_formatversion: str, subsequent_formatversion: str) -> None:
599+
def _process_files(
600+
previous_formatversion: str, subsequent_formatversion: str, output_dir: Path = DEFAULT_OUTPUT_DIR
601+
) -> None:
600602
"""
601603
process all matching ahb/<pruefid>.csv files between two <formatversion> directories.
602604
"""
@@ -606,7 +608,7 @@ def _process_files(previous_formatversion: str, subsequent_formatversion: str) -
606608
logger.warning("No matching files found to compare")
607609
return
608610

609-
output_base = OUTPUT_DIR / f"{subsequent_formatversion}_{previous_formatversion}"
611+
output_base = output_dir / f"{subsequent_formatversion}_{previous_formatversion}"
610612

611613
for previous_pruefid, subsequent_pruefid, nachrichtentyp, pruefid in matching_files:
612614
logger.info("Processing %s - %s", nachrichtentyp, pruefid)
@@ -641,7 +643,7 @@ def _process_files(previous_formatversion: str, subsequent_formatversion: str) -
641643
logger.error("❌data processing error for %s/%s: %s", nachrichtentyp, pruefid, str(e))
642644

643645

644-
def _process_submodule() -> None:
646+
def _process_submodule(output_dir: Path = DEFAULT_OUTPUT_DIR) -> None:
645647
"""
646648
processes all valid consecutive <formatversion> subdirectories.
647649
"""
@@ -656,7 +658,7 @@ def _process_submodule() -> None:
656658
"⌛processing consecutive formatversions: %s -> %s", subsequent_formatversion, previous_formatversion
657659
)
658660
try:
659-
_process_files(previous_formatversion, subsequent_formatversion)
661+
_process_files(previous_formatversion, subsequent_formatversion, output_dir)
660662
except (OSError, pd.errors.EmptyDataError, ValueError) as e:
661663
logger.error(
662664
"❌error processing formatversions %s -> %s: %s",
@@ -667,5 +669,17 @@ def _process_submodule() -> None:
667669
continue
668670

669671

672+
def main(output_dir: Optional[Path] = None) -> None:
673+
"""
674+
main entrypoint for AHlBatross.
675+
"""
676+
try:
677+
_process_submodule(output_dir or DEFAULT_OUTPUT_DIR)
678+
except (OSError, pd.errors.EmptyDataError, ValueError) as e:
679+
logger.error("❌error processing AHB files: %s", str(e))
680+
sys.exit(1)
681+
682+
683+
# run locally using $ PYTHONPATH=src python -m ahlbatross.main
670684
if __name__ == "__main__":
671-
_process_submodule()
685+
main()
File renamed without changes.

tox.ini

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ commands = python -m pip install --upgrade pip
1616
deps =
1717
-r requirements.txt
1818
.[tests]
19-
setenv = PYTHONPATH = {toxinidir}/ahb_diff
19+
setenv = PYTHONPATH = {toxinidir}/src
2020
commands = python -m pytest --basetemp={envtmpdir} {posargs}
2121

2222
[testenv:linting]
@@ -25,31 +25,31 @@ deps =
2525
{[testenv:tests]deps}
2626
.[linting]
2727
# add your fixtures like e.g. pytest_datafiles here
28-
setenv = PYTHONPATH = {toxinidir}/ahb_diff
28+
setenv = PYTHONPATH = {toxinidir}/src
2929
commands =
30-
pylint ahb_diff
30+
pylint ahlbatross
3131
pylint unittests --rcfile=unittests/.pylintrc
3232
# add single files (ending with .py) or packages here
3333

3434
[testenv:type_check]
3535
# the type_check environment checks the type hints using mypy
36-
setenv = PYTHONPATH = {toxinidir}/ahb_diff
36+
setenv = PYTHONPATH = {toxinidir}/src
3737
deps =
3838
{[testenv:tests]deps}
3939
.[type_check]
4040
commands =
41-
mypy --show-error-codes ahb_diff --strict
41+
mypy --show-error-codes src/ahlbatross --strict
4242
mypy --show-error-codes unittests --strict
4343
# add single files (ending with .py) or packages here
4444

4545
[testenv:spell_check]
4646
# the spellcheck environment checks the code for typos
47-
setenv = PYTHONPATH = {toxinidir}/ahb_diff
47+
setenv = PYTHONPATH = {toxinidir}/src
4848
deps =
4949
-r requirements.txt
5050
.[spell_check]
5151
commands =
52-
codespell ahb_diff
52+
codespell src
5353
codespell README.md
5454
# add single files (ending with .py) or packages here
5555

@@ -59,7 +59,7 @@ changedir = unittests
5959
deps =
6060
{[testenv:tests]deps}
6161
.[coverage]
62-
setenv = PYTHONPATH = {toxinidir}/ahb_diff
62+
setenv = PYTHONPATH = {toxinidir}/src
6363
commands =
6464
coverage run -m pytest --basetemp={envtmpdir} {posargs}
6565
coverage html --omit .tox/*,unittests/*
@@ -71,6 +71,14 @@ deps =
7171
commands =
7272
pip-compile-multi -d dev_requirements --autoresolve
7373

74+
[testenv:test_packaging]
75+
skip_install = true
76+
deps =
77+
.[packaging]
78+
commands =
79+
python -m build
80+
twine check dist/*
81+
7482
[testenv:dev]
7583
# the dev environment contains everything you need to start developing on your local machine.
7684
deps =

0 commit comments

Comments
 (0)