From 460cf81169f9a9d022857923944c6a894a8971b1 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Mon, 11 Aug 2025 22:20:23 +0200 Subject: move to hittekaart-py instead of subprocess'ing --- fietsboek/hittekaart.py | 51 ++++++++++++++++++++++-------------------- fietsboek/scripts/fietscron.py | 4 +--- fietsboek/scripts/fietsctl.py | 3 +-- poetry.lock | 23 ++++++++++++++++++- pyproject.toml | 5 +++++ 5 files changed, 56 insertions(+), 30 deletions(-) diff --git a/fietsboek/hittekaart.py b/fietsboek/hittekaart.py index 15f2855..06319a4 100644 --- a/fietsboek/hittekaart.py +++ b/fietsboek/hittekaart.py @@ -6,11 +6,11 @@ import enum import logging import shutil -import subprocess import tempfile from pathlib import Path from typing import Optional +import hittekaart_py from sqlalchemy import select from sqlalchemy.orm import aliased from sqlalchemy.orm.session import Session @@ -21,6 +21,13 @@ from .models.track import TrackType LOGGER = logging.getLogger(__name__) +COMPRESSION_MAP = { + ".br": "brotli", + ".gz": "gzip", +} + +TILEHUNTER_ZOOM = 14 + class Mode(enum.Enum): """Heatmap generation mode. @@ -38,7 +45,6 @@ def generate( mode: Mode, input_files: list[Path], *, - exe_path: Optional[Path] = None, threads: int = 0, ): """Calls hittekaart with the given arguments. @@ -47,13 +53,23 @@ def generate( sqlite output mode. :param mode: What to generate. :param input_files: List of paths to the input files. - :param exe_path: Path to the hittekaart binary. If not given, - ``hittekaart`` is searched in the path. :param threads: Number of threads that ``hittekaart`` should use. Defaults to 0, which uses all available cores. """ if not input_files: return + + if mode == Mode.HEATMAP: + renderer = hittekaart_py.HeatmapRenderer() + elif mode == Mode.TILEHUNTER: + renderer = hittekaart_py.TilehuntRenderer(TILEHUNTER_ZOOM) + + LOGGER.debug("Loading tracks ...") + tracks = [ + hittekaart_py.Track.from_file(bytes(input_file), COMPRESSION_MAP.get(input_file.suffix)) + for input_file in input_files + ] + LOGGER.debug("Tracks loaded!") # There are two reasons why we do the tempfile dance: # 1. hittekaart refuses to overwrite existing files # 2. This way we can (hope for?) an atomic move (at least if temporary file @@ -61,23 +77,12 @@ def generate( # this, but for now, it's alright. with tempfile.TemporaryDirectory() as tempdir: tmpfile = Path(tempdir) / "hittekaart.sqlite" - binary = str(exe_path) if exe_path else "hittekaart" - cmdline = [ - binary, - "--sqlite", - "-o", - str(tmpfile), - "-m", - mode.value, - "-t", - str(threads), - "--", - ] - cmdline.extend(map(str, input_files)) - LOGGER.debug("Running %r", cmdline) - subprocess.run(cmdline, check=True, stdout=subprocess.DEVNULL) - - LOGGER.debug("Moving temporary file") + sink = hittekaart_py.Storage.Sqlite(bytes(tmpfile)) + settings = hittekaart_py.Settings(threads=threads) + LOGGER.debug("Running hittekaart (renderer %r) to %r", renderer, tmpfile) + hittekaart_py.generate(settings, tracks, renderer, sink) + + LOGGER.debug("Moving temporary file %r to %r", tmpfile, output) shutil.move(tmpfile, output) @@ -87,7 +92,6 @@ def generate_for( data_manager: DataManager, mode: Mode, *, - exe_path: Optional[Path] = None, threads: int = 0, ): """Uses :meth:`generate` to generate a heatmap for the given user. @@ -104,7 +108,6 @@ def generate_for( :param dbsession: The database session. :param data_manager: The data manager. :param mode: The mode of the heatmap. - :param exe_path: See :meth:`generate`. :param threads: See :meth:`generate`. """ # pylint: disable=too-many-arguments @@ -133,7 +136,7 @@ def generate_for( Mode.TILEHUNTER: user_dir.tilehunt_path(), } - generate(output_paths[mode], mode, input_paths, exe_path=exe_path, threads=threads) + generate(output_paths[mode], mode, input_paths, threads=threads) __all__ = ["Mode", "generate", "generate_for"] diff --git a/fietsboek/scripts/fietscron.py b/fietsboek/scripts/fietscron.py index a3f3f54..75575d8 100644 --- a/fietsboek/scripts/fietscron.py +++ b/fietsboek/scripts/fietscron.py @@ -142,7 +142,6 @@ def run_hittekaart(engine: Engine, data_manager: DataManager, redis: Redis, conf # re-generate all maps over time (e.g. if the hittekaart version changes or # we miss an update). modes = [hittekaart.Mode(mode) for mode in config.hittekaart_autogenerate] - exe_path = Path(config.hittekaart_bin) if config.hittekaart_bin else None session = Session(engine) had_hq_item = False @@ -164,7 +163,6 @@ def run_hittekaart(engine: Engine, data_manager: DataManager, redis: Redis, conf session, data_manager, mode, - exe_path=exe_path, threads=config.hittekaart_threads, ) @@ -188,7 +186,7 @@ def run_hittekaart(engine: Engine, data_manager: DataManager, redis: Redis, conf for mode in modes: LOGGER.info("Generating %s for user %d (low-priority)", mode.value, user.id) hittekaart.generate_for( - user, session, data_manager, mode, exe_path=exe_path, threads=config.hittekaart_threads + user, session, data_manager, mode, threads=config.hittekaart_threads ) diff --git a/fietsboek/scripts/fietsctl.py b/fietsboek/scripts/fietsctl.py index ad06e91..87d49e8 100644 --- a/fietsboek/scripts/fietsctl.py +++ b/fietsboek/scripts/fietsctl.py @@ -313,7 +313,6 @@ def cmd_user_hittekaart( else: query = models.User.query_by_email(email) - exe_path = env["request"].config.hittekaart_bin threads = env["request"].config.hittekaart_threads with env["request"].tm: dbsession = env["request"].dbsession @@ -338,7 +337,7 @@ def cmd_user_hittekaart( for mode in modes: hittekaart.generate_for( - user, dbsession, data_manager, mode, exe_path=exe_path, threads=threads + user, dbsession, data_manager, mode, threads=threads ) click.echo(f"Generated {mode.value}") diff --git a/poetry.lock b/poetry.lock index 440a4b2..c167492 100644 --- a/poetry.lock +++ b/poetry.lock @@ -787,6 +787,24 @@ markers = {main = "python_version < \"3.14\" and (platform_machine == \"aarch64\ docs = ["Sphinx", "furo"] test = ["objgraph", "psutil"] +[[package]] +name = "hittekaart-py" +version = "0.1.0" +description = "" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"hittekaart\"" +files = [] +develop = false + +[package.source] +type = "git" +url = "https://gitlab.com/dunj3/hittekaart" +reference = "6da6f0b5ce4cfb41aaf79699e289be678007e2ad" +resolved_reference = "6da6f0b5ce4cfb41aaf79699e289be678007e2ad" +subdirectory = "hittekaart-py" + [[package]] name = "hupper" version = "1.12.1" @@ -2562,7 +2580,10 @@ transaction = ">=1.6.0" [package.extras] test = ["zope.testing"] +[extras] +hittekaart = ["hittekaart-py"] + [metadata] lock-version = "2.1" python-versions = ">=3.11" -content-hash = "e35a5cd2b50b9643fbca57a4c55384041263bd8fffb5b53f118b5040c3fa2b83" +content-hash = "d455ec6a90988d2e6567d911e3b332162671e25b1335930413f926e6aa60d26a" diff --git a/pyproject.toml b/pyproject.toml index be56bfa..c47d037 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,11 @@ documentation = "https://docs.fietsboek.org/" homepage = "https://fietsboek.org/" repository = "https://gitlab.com/dunj3/fietsboek" +[project.optional-dependencies] +hittekaart = [ + "hittekaart-py @ git+https://gitlab.com/dunj3/hittekaart@6da6f0b5ce4cfb41aaf79699e289be678007e2ad#subdirectory=hittekaart-py", +] + [tool.poetry] classifiers = [ 'Development Status :: 3 - Alpha', -- cgit v1.2.3 From 818e75efb20127d29462370573f282a1c4549f53 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Mon, 11 Aug 2025 22:29:15 +0200 Subject: remove hittekaart.bin setting This is the first time we're removing a setting (I think)! --- fietsboek/config.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fietsboek/config.py b/fietsboek/config.py index beea820..2d25773 100644 --- a/fietsboek/config.py +++ b/fietsboek/config.py @@ -64,6 +64,10 @@ KNOWN_TILE_LAYERS = [ "hiking", ] +WARNINGS = { + "hittekaart.bin": "hittekaart is now used via a Python module. Enable extra `hittekaart` to install the dependency.", +} + class ValidationError(Exception): """Exception for malformed configurations. @@ -203,9 +207,6 @@ class Config(BaseModel): tile_layers: list[TileLayerConfig] = [] """Tile layers.""" - hittekaart_bin: str = Field("", alias="hittekaart.bin") - """Path to the hittekaart binary.""" - hittekaart_autogenerate: PyramidList = Field([], alias="hittekaart.autogenerate") """Overlay maps to automatically generate.""" @@ -350,6 +351,9 @@ def parse(config: dict) -> Config: for key in keys: LOGGER.warning("Unknown configuration key: %r", key) + if warning := WARNINGS.get(key): + LOGGER.warning(warning) + return parsed_config -- cgit v1.2.3 From 5ee7ae917c04cb43717b1be79146cb379cfa8715 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Mon, 11 Aug 2025 22:45:39 +0200 Subject: carefully import hittekaart_py --- fietsboek/hittekaart.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fietsboek/hittekaart.py b/fietsboek/hittekaart.py index 06319a4..25d4864 100644 --- a/fietsboek/hittekaart.py +++ b/fietsboek/hittekaart.py @@ -10,7 +10,10 @@ import tempfile from pathlib import Path from typing import Optional -import hittekaart_py +try: + import hittekaart_py +except ImportError: + hittekaart_py = None from sqlalchemy import select from sqlalchemy.orm import aliased from sqlalchemy.orm.session import Session @@ -56,6 +59,9 @@ def generate( :param threads: Number of threads that ``hittekaart`` should use. Defaults to 0, which uses all available cores. """ + if hittekaart_py is None: + raise RuntimeError("hittekaart not available") + if not input_files: return -- cgit v1.2.3 From f248091c780ff9bbe74c95bf8be4d2851c6d3b1e Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Tue, 12 Aug 2025 21:06:01 +0200 Subject: fix typing for hittekaart Now that it has type hints. --- fietsboek/hittekaart.py | 9 ++++++--- poetry.lock | 6 +++--- pyproject.toml | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/fietsboek/hittekaart.py b/fietsboek/hittekaart.py index 25d4864..220d8d9 100644 --- a/fietsboek/hittekaart.py +++ b/fietsboek/hittekaart.py @@ -13,7 +13,7 @@ from typing import Optional try: import hittekaart_py except ImportError: - hittekaart_py = None + pass from sqlalchemy import select from sqlalchemy.orm import aliased from sqlalchemy.orm.session import Session @@ -59,12 +59,15 @@ def generate( :param threads: Number of threads that ``hittekaart`` should use. Defaults to 0, which uses all available cores. """ - if hittekaart_py is None: - raise RuntimeError("hittekaart not available") + try: + hittekaart_py + except NameError: + raise RuntimeError("hittekaart not available") from None if not input_files: return + renderer: hittekaart_py.HeatmapRenderer | hittekaart_py.TilehuntRenderer if mode == Mode.HEATMAP: renderer = hittekaart_py.HeatmapRenderer() elif mode == Mode.TILEHUNTER: diff --git a/poetry.lock b/poetry.lock index c167492..6f0dce9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -801,8 +801,8 @@ develop = false [package.source] type = "git" url = "https://gitlab.com/dunj3/hittekaart" -reference = "6da6f0b5ce4cfb41aaf79699e289be678007e2ad" -resolved_reference = "6da6f0b5ce4cfb41aaf79699e289be678007e2ad" +reference = "e888344ba561bc6a52f96f7a7bc2ad24be287a82" +resolved_reference = "e888344ba561bc6a52f96f7a7bc2ad24be287a82" subdirectory = "hittekaart-py" [[package]] @@ -2586,4 +2586,4 @@ hittekaart = ["hittekaart-py"] [metadata] lock-version = "2.1" python-versions = ">=3.11" -content-hash = "d455ec6a90988d2e6567d911e3b332162671e25b1335930413f926e6aa60d26a" +content-hash = "e1192d038d1e88f26f51754cf5a4cd9357bbe2c996d1128de174887adfa76343" diff --git a/pyproject.toml b/pyproject.toml index c47d037..d02530b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ repository = "https://gitlab.com/dunj3/fietsboek" [project.optional-dependencies] hittekaart = [ - "hittekaart-py @ git+https://gitlab.com/dunj3/hittekaart@6da6f0b5ce4cfb41aaf79699e289be678007e2ad#subdirectory=hittekaart-py", + "hittekaart-py @ git+https://gitlab.com/dunj3/hittekaart@e888344ba561bc6a52f96f7a7bc2ad24be287a82#subdirectory=hittekaart-py", ] [tool.poetry] -- cgit v1.2.3 From 2ee924e42757b15fc3f06e5dd89bac022689825f Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Tue, 12 Aug 2025 21:06:43 +0200 Subject: fix lint --- fietsboek/scripts/fietsctl.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fietsboek/scripts/fietsctl.py b/fietsboek/scripts/fietsctl.py index 87d49e8..630660f 100644 --- a/fietsboek/scripts/fietsctl.py +++ b/fietsboek/scripts/fietsctl.py @@ -336,9 +336,7 @@ def cmd_user_hittekaart( click.echo(f"Generating overlay maps for {click.style(user.name, fg=FG_USER_NAME)}...") for mode in modes: - hittekaart.generate_for( - user, dbsession, data_manager, mode, threads=threads - ) + hittekaart.generate_for(user, dbsession, data_manager, mode, threads=threads) click.echo(f"Generated {mode.value}") -- cgit v1.2.3 From 5ac96fb4e903b12b3341516c14eb5e4c167741d5 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Tue, 12 Aug 2025 21:31:39 +0200 Subject: fix lint (again) --- fietsboek/config.py | 11 ++++++++--- fietsboek/hittekaart.py | 1 - fietsboek/scripts/fietscron.py | 1 - 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/fietsboek/config.py b/fietsboek/config.py index 2d25773..bd2347a 100644 --- a/fietsboek/config.py +++ b/fietsboek/config.py @@ -65,7 +65,8 @@ KNOWN_TILE_LAYERS = [ ] WARNINGS = { - "hittekaart.bin": "hittekaart is now used via a Python module. Enable extra `hittekaart` to install the dependency.", + "hittekaart.bin": "hittekaart is now used via a Python module. " + "Enable extra `hittekaart` to install the dependency.", } @@ -348,14 +349,18 @@ def parse(config: dict) -> Config: keys.discard(_field_name(field_name, field)) keys -= KNOWN_PYRAMID_SETTINGS + _warn_unknown(keys) + + return parsed_config + + +def _warn_unknown(keys): for key in keys: LOGGER.warning("Unknown configuration key: %r", key) if warning := WARNINGS.get(key): LOGGER.warning(warning) - return parsed_config - def _field_name(field_name, field): """Returns the field's alias, or the original name if the alias does not diff --git a/fietsboek/hittekaart.py b/fietsboek/hittekaart.py index 220d8d9..3b0c103 100644 --- a/fietsboek/hittekaart.py +++ b/fietsboek/hittekaart.py @@ -8,7 +8,6 @@ import logging import shutil import tempfile from pathlib import Path -from typing import Optional try: import hittekaart_py diff --git a/fietsboek/scripts/fietscron.py b/fietsboek/scripts/fietscron.py index 75575d8..1a8e855 100644 --- a/fietsboek/scripts/fietscron.py +++ b/fietsboek/scripts/fietscron.py @@ -3,7 +3,6 @@ import datetime import logging import logging.config -from pathlib import Path import click import gpxpy -- cgit v1.2.3 From 9d5d8e8dbb3cc4082ab0ba51bb167a5d15d791d0 Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Tue, 12 Aug 2025 21:38:48 +0200 Subject: install hittekaart extra for mypy --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 57ea65b..3757c78 100644 --- a/tox.ini +++ b/tox.ini @@ -60,7 +60,7 @@ commands = [testenv:mypy] commands_pre = - poetry install --with types + poetry install --with types --extras hittekaart commands = mypy fietsboek -- cgit v1.2.3 From 2bb2fd7bffda993ad06832301aedacb9512b8ccb Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Wed, 15 Oct 2025 21:56:52 +0200 Subject: update hittekaart-py version --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6f0dce9..2aec010 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -801,8 +801,8 @@ develop = false [package.source] type = "git" url = "https://gitlab.com/dunj3/hittekaart" -reference = "e888344ba561bc6a52f96f7a7bc2ad24be287a82" -resolved_reference = "e888344ba561bc6a52f96f7a7bc2ad24be287a82" +reference = "013dc01683c42177e132847475c8b57d1a67fc14" +resolved_reference = "013dc01683c42177e132847475c8b57d1a67fc14" subdirectory = "hittekaart-py" [[package]] @@ -2586,4 +2586,4 @@ hittekaart = ["hittekaart-py"] [metadata] lock-version = "2.1" python-versions = ">=3.11" -content-hash = "e1192d038d1e88f26f51754cf5a4cd9357bbe2c996d1128de174887adfa76343" +content-hash = "3f1bb6cb4a45dc69e8f7d5739bbbe451455ed2f03696c370c892e56102e4218d" diff --git a/pyproject.toml b/pyproject.toml index d02530b..d837345 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ repository = "https://gitlab.com/dunj3/fietsboek" [project.optional-dependencies] hittekaart = [ - "hittekaart-py @ git+https://gitlab.com/dunj3/hittekaart@e888344ba561bc6a52f96f7a7bc2ad24be287a82#subdirectory=hittekaart-py", + "hittekaart-py @ git+https://gitlab.com/dunj3/hittekaart@013dc01683c42177e132847475c8b57d1a67fc14#subdirectory=hittekaart-py", ] [tool.poetry] -- cgit v1.2.3