Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ coverage.xml
.hypothesis/
.pytest_cache/
cover/
testdata/*

# Translations
*.mo
Expand Down Expand Up @@ -139,3 +140,6 @@ cython_debug/

# Extraction plugin test runner
.runner

#Intellij
.idea
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.14
25 changes: 15 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
# Multi-stage Dockerfile, to build and package an extraction plugin
# Recommended way to build the plugin is by calling tox:
# tox -e package
# Recommended way to build the plugin is by calling poe:
# poe package
# if you need to pass a proxy:
# tox -e package -- --build-arg https_proxy=https://your-proxy
# poe package -- --build-arg https_proxy=https://your-proxy
# if you want to pass a private Python package index:
# tox -e package -- --build-arg PIP_INDEX_URL=https://your-pypi-mirror
# poe package -- --build-arg PIP_INDEX_URL=https://your-pypi-mirror

###############################################################################
# Stage 1: build the plugin
# use a 'fat' image to setup the dependencies we'll need

FROM python:3.13 AS builder
FROM python:3.14 AS builder
ARG PIP_INDEX_URL=https://pypi.org/simple/
ENV UV_INDEX_URL=${PIP_INDEX_URL}
RUN python -m venv /venv
ENV VIRTUAL_ENV="/venv"
ENV UV_PROJECT_ENVIRONMENT="/venv"
ENV PATH="/venv/bin:$PATH"
COPY requirements.txt /requirements.txt
RUN pip install -Ur /requirements.txt
RUN pip install uv
WORKDIR /app

# Change package name to match your plugin.
COPY dist/hansken_extraction_plugin_template_python-*-py3-none-any.whl /app/
RUN uv pip install /app/hansken_extraction_plugin_template_python-*.whl

###############################################################################
# Stage 2: create the distributable plugin image
# use a 'slim' image for running the actual plugin

FROM python:3.13-slim
FROM python:3.14-slim
COPY --from=builder /venv /venv
ENV PATH="/venv/bin:$PATH"

COPY plugin.py /app/
EXPOSE 8999
ENTRYPOINT ["serve_plugin", "-v"]
CMD ["/app/plugin.py", "8999"]
CMD ["hansken_extraction_plugin_template_python.plugin", "8999"]
33 changes: 17 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,36 @@ The [Hansken Extraction Plugins for plugin developers documentation](https://net

To transform this skeleton in your plugin your may want to:

* Update the plugin info in [`plugin.py`](plugin.py)
* Update the plugin info in [`plugin.py`](hansken_extraction_plugin_template_python/plugin.py)
* Create test input data in the folder [`testdata/input`](testdata/input)
(refer to the [SDK manual for more details on how to define test data](https://netherlandsforensicinstitute.github.io/hansken-extraction-plugin-sdk-documentation/latest/dev/concepts/test_framework.html))
* Implement your plugin `process()` logic in [`plugin.py`](plugin.py)
* (Optional) Implement your own transformers(https://netherlandsforensicinstitute.github.io/hansken-extraction-plugin-sdk-documentation/latest/dev/python/transformers.html) in the example_transformer() [`plugin.py`](plugin.py),
* Implement your plugin `process()` logic in [`plugin.py`](hansken_extraction_plugin_template_python/plugin.py)
* (Optional) Implement your own transformers(https://netherlandsforensicinstitute.github.io/hansken-extraction-plugin-sdk-documentation/latest/dev/python/transformers.html) in the example_transformer() [`plugin.py`](hansken_extraction_plugin_template_python/plugin.py),
or remove the transformer method from the plugin.
* Add your plugin dependencies to [`requirements.in`](requirements.in)
and regenerate `requirements.txt` by calling `tox -e upgrade`
* Add your dependencies by using `uv add <dependency>`. Once all dependencies are added, run `poe upgrade` to update the `uv.lock` file.
* Add any system dependencies to the [`Dockerfile`](Dockerfile)
* (Re)generate your expected test result data with `tox -e regenerate`
* (Re)generate your expected test result data with `poe regenerate`
* Verify your expected test result data in [`testdata/result`](testdata/result)
* Update this `README.md`
* Publish your plugin to the Hansken community!

Tox commands that may be useful:
* `tox`: runs your tests
* `tox -e integration-test`: runs your tests against the packaged version of your plugin (requires Docker)
* `tox -e regenerate`: regenerates the expected test results (use after you update your plugin)
* `tox -e package`: creates a extraction plugin OCI/Docker image that can be published to Hansken (requires Docker)
* `tox -e upgrade`: regenerates `requirements.txt` from [`requirements.in`](requirements.in)
* `poe build`: builds the python package to `./dist`.
* `poe lint`: runs the ruff check command. Configure the ruff linting in the `pyproject.toml` file.
* `poe tests`: runs your tests
* `poe integration-test`: runs your tests against the packaged version of your plugin (requires Docker)
* `poe regenerate`: regenerates the expected test results (use after you update your plugin)
* `poe package`: creates a extraction plugin OCI/Docker image that can be published to Hansken (requires Docker)
* `poe upgrade`: regenerates the [uv.lock](uv.lock) file

Note: see the readme text in the [`Dockerfile`](Dockerfile) if you need to set proxies or private Python package registries for building a plugin.

> [TIP] If you want to pass in additional arguments to the poe tasks separate poe args with `--`. For example:
> `poe package -- --build-arg=MY_ARG=my_value`


> [!TIP]
> If you want to update your plugin to a newer Hansken Plugin SDK version, update the `hansken-extraction-plugin` version in [`requirements.in`](requirements.in), and then run:
>
> ```shell
> tox -e upgrade
> ```
> If you want to update your plugin to a newer Hansken Plugin SDK version, run `uv add hansken-extraction-plugin==<new_version>`.

> [!IMPORTANT]
> Plugins based on this template require Hansken version `47.22.0` or higher.
Expand Down
Empty file.
File renamed without changes.
117 changes: 117 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
[project]
name = "hansken-extraction-plugin-template-python"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.14"
dependencies = [
"certifi==2026.5.20",
"charset-normalizer==3.4.7",
"decorator==5.3.1",
"docker==7.1.0",
"grpcio==1.81.0",
"hansken==2026.5.27",
"hansken-extraction-plugin==0.10.0",
"idna==3.18",
"ijson==3.5.0",
"iso8601==2.1.0",
"logbook==1.9.2",
"more-itertools==11.1.0",
"poethepoet>=0.46.0",
"protobuf==7.35.1",
"python-dateutil==2.9.0.post0",
"pytz==2026.2",
"requests==2.34.2",
"requests-toolbelt==1.0.0",
"six==1.17.0",
"tabulate==0.10.0",
"typing-extensions==4.15.0",
"urllib3==2.7.0",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["hansken_extraction_plugin_template_python"]

[dependency-groups]
dev = [
"poethepoet>=0.46.0",
"ruff>=0.15.17",
]

[tool.poe.tasks]
lint = "uv run ruff check"
build = "uv build"
test = "uv run test_plugin --standalone plugin.py"
regenerate = "uv run test_plugin --standalone plugin.py --regenerate"

[tool.poe.tasks.package]
sequence = [
{ cmd = "uv build" },
{ cmd = "uv run build_plugin ." }
]

[tool.poe.tasks.integration-test]
sequence = [
{ cmd = "uv run build_plugin . plugin-to-test" },
{ cmd = "uv run test_plugin --docker plugin-to-test" },
]

[tool.poe.tasks.upgrade]
sequence = [
{ cmd = "uv lock" },
{ cmd = "uv sync" },
]

[tool.ruff]
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".ipynb_checkpoints",
".mypy_cache",
".nox",
".pants.d",
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"site-packages",
"venv",
]

line-length = 140
indent-width = 4

[tool.ruff.lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
select = [
"E4",
"E5",
"E7",
"E9",
"F",
"PLC"
]
ignore = []


1 change: 0 additions & 1 deletion requirements.in

This file was deleted.

52 changes: 0 additions & 52 deletions requirements.txt

This file was deleted.

26 changes: 0 additions & 26 deletions tox.ini

This file was deleted.

Loading