From 555f54b52f1afaba986108fca306a318bb9776f3 Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Sat, 3 Jan 2026 10:51:27 +0100 Subject: [PATCH 1/3] replace boost iterator with C++ iterator and remove dependency --- CMakeLists.txt | 3 --- README.md | 7 ++----- README.rst | 5 ++--- docs/index.md | 3 +-- lib/merge_input_reader.cc | 19 +++++++++---------- 5 files changed, 14 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f492c3..4ea29db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,9 +60,6 @@ endif() message(STATUS "Building in C++${CMAKE_CXX_STANDARD} mode") -find_package(Boost 1.66 REQUIRED COMPONENTS) -include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) - # Modules without any Python code and just one source file. foreach(PYMOD geom index io area) pybind11_add_module(${PYMOD} lib/${PYMOD}.cc) diff --git a/README.md b/README.md index f6c1e10..a9c444e 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,7 @@ For other versions, a source wheel is provided. Make sure to install all external dependencies first. On Debian/Ubuntu-like systems, the following command installs all required packages: - sudo apt-get install build-essential cmake libboost-dev \ - libexpat1-dev zlib1g-dev libbz2-dev + sudo apt-get install build-essential cmake libexpat1-dev zlib1g-dev libbz2-dev ### Installing from source @@ -45,7 +44,6 @@ pyosmium has the following dependencies: * [expat](https://libexpat.github.io/) * [libz](https://www.zlib.net/) * [libbz2](https://www.sourceware.org/bzip2/) - * [Boost](https://www.boost.org/) variant and iterator >= 1.70 * [Python Requests](https://docs.python-requests.org/) * [scikit-build-core](https://scikit-build-core.readthedocs.io) * a C++17-compatible compiler (Clang 13+, GCC 10+ are supported) @@ -53,8 +51,7 @@ pyosmium has the following dependencies: ### Compiling from Source -Make sure to install the development packages for expat, libz, libbz2 -and boost. +Make sure to install the development packages for expat, libz and libbz2. The appropriate versions for Libosmium and Protozero will be downloaded into the `contrib` directory when building the source package: diff --git a/README.rst b/README.rst index ce2cab5..f17f939 100644 --- a/README.rst +++ b/README.rst @@ -17,11 +17,10 @@ pyosmium can be installed with pip: The Pypi source package already comes bundled with a matching version of libosmium, protozero and pybind11. Pyosmium additionally depends on -expat, libz, libbz2 and Boost variant and iterator. You need to install +expat, libz and libbz2. You need to install development packages for these libraries. On Debian/Ubuntu do:: - sudo apt-get install build-essential cmake libboost-dev \ - libexpat1-dev zlib1g-dev libbz2-dev + sudo apt-get install build-essential cmake libexpat1-dev zlib1g-dev libbz2-dev Python >= 3.8 is supported. Pypy is known not to work. diff --git a/docs/index.md b/docs/index.md index 68e7d77..f50e180 100644 --- a/docs/index.md +++ b/docs/index.md @@ -28,7 +28,6 @@ the following additional dependencies need to be available: * [expat](https://libexpat.github.io/) * [libz](https://www.zlib.net/) * [libbz2](https://www.sourceware.org/bzip2/) - * [Boost](https://www.boost.org/) variant and iterator >= 1.41 * [Python Requests](https://docs.python-requests.org/en/master/) * a recent C++ compiler (Clang 3.4+, GCC 4.8+) @@ -41,7 +40,7 @@ of the build process: On Debian/Ubuntu-like systems, the following command installs all required packages: - sudo apt-get install python3-dev build-essential cmake libboost-dev \ + sudo apt-get install python3-dev build-essential cmake \ libexpat1-dev zlib1g-dev libbz2-dev Compatible versions of libosmium and protozero are shipped with the source diff --git a/lib/merge_input_reader.cc b/lib/merge_input_reader.cc index 3691a95..62a91f8 100644 --- a/lib/merge_input_reader.cc +++ b/lib/merge_input_reader.cc @@ -2,14 +2,13 @@ * * This file is part of pyosmium. (https://osmcode.org/pyosmium/) * - * Copyright (C) 2025 Sarah Hoffmann and others. + * Copyright (C) 2026 Sarah Hoffmann and others. * For a full list of authors see the git log. */ #include #include - -#include +#include #include #include @@ -30,20 +29,21 @@ namespace { /** * Copy the first OSM object with a given Id to the output. Keep * track of the Id of each object to do this. - * - * We are using this functor class instead of a simple lambda, because the - * lambda doesn't build on MSVC. */ class copy_first_with_id { osmium::io::Writer* writer; osmium::object_id_type id = 0; public: + using iterator_category = std::output_iterator_tag; + using value_type = const osmium::OSMObject; + using reference = const osmium::OSMObject&; + explicit copy_first_with_id(osmium::io::Writer& w) : writer(&w) { } - void operator()(const osmium::OSMObject& obj) { + void push_back(const osmium::OSMObject& obj) { if (obj.id() != id) { if (obj.visible()) { (*writer)(obj); @@ -112,9 +112,8 @@ class MergeInputReader std::reverse(objects.ptr_begin(), objects.ptr_end()); objects.sort(osmium::object_order_type_id_reverse_version()); - auto output_it = boost::make_function_output_iterator( - copy_first_with_id(*writer.get()) - ); + copy_first_with_id copy_first{*writer.get()}; + auto output_it = std::back_inserter(copy_first); std::set_union(objects.begin(), objects.end(), From 46d656ba1b30efa5a5473232590587ffc6386d16 Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Sat, 3 Jan 2026 10:53:50 +0100 Subject: [PATCH 2/3] CI: remove boost installation --- .github/workflows/build_wheels.yml | 6 +++--- .github/workflows/ci.yml | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml index 9597757..d597618 100644 --- a/.github/workflows/build_wheels.yml +++ b/.github/workflows/build_wheels.yml @@ -44,10 +44,10 @@ jobs: CIBW_TEST_REQUIRES: pytest pytest-httpserver CIBW_TEST_COMMAND: pytest {project}/test CIBW_BUILD_FRONTEND: build - CIBW_BEFORE_BUILD_LINUX: yum install -y expat-devel boost-devel zlib-devel bzip2-devel lz4-devel - CIBW_BEFORE_BUILD_MACOS: brew install boost + CIBW_BEFORE_BUILD_LINUX: yum install -y expat-devel zlib-devel bzip2-devel lz4-devel + CIBW_BEFORE_BUILD_MACOS: brew install CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=11.0 SKBUILD_CMAKE_ARGS=-DWITH_LZ4=OFF - CIBW_BEFORE_BUILD_WINDOWS: vcpkg install bzip2 expat zlib boost-variant boost-iterator lz4 + CIBW_BEFORE_BUILD_WINDOWS: vcpkg install bzip2 expat zlib lz4 CIBW_ENVIRONMENT_WINDOWS: 'CMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake"' CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: 'pipx run delvewheel repair --add-path ${{ matrix.vcpkg }}/bin/ --add-path ${{ matrix.vcpkg }}/debug/bin -w {dest_dir} {wheel}' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb18044..f1dcd62 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: - name: Install packages run: | sudo apt-get update -y -qq - sudo apt-get install -y -qq libboost-dev libexpat1-dev zlib1g-dev libbz2-dev libproj-dev libgeos-dev liblz4-dev pipx + sudo apt-get install -y -qq libexpat1-dev zlib1g-dev libbz2-dev libproj-dev libgeos-dev liblz4-dev pipx pipx install mypy pipx inject mypy types-requests pipx install flake8 @@ -116,7 +116,7 @@ jobs: - name: Install packages run: | sudo apt-get update -y -qq - sudo apt-get install -y -qq libboost-dev libexpat1-dev zlib1g-dev libbz2-dev libproj-dev libgeos-dev liblz4-dev pipx + sudo apt-get install -y -qq libexpat1-dev zlib1g-dev libbz2-dev libproj-dev libgeos-dev liblz4-dev pipx pipx install mypy pipx inject mypy types-requests pipx install flake8 @@ -329,11 +329,11 @@ jobs: - name: Install packages run: | sudo apt-get update -y -qq - sudo apt-get install -y -qq libboost-dev libexpat1-dev zlib1g-dev libbz2-dev libproj-dev libgeos-dev liblz4-dev virtualenv + sudo apt-get install -y -qq libexpat1-dev zlib1g-dev libbz2-dev libproj-dev libgeos-dev liblz4-dev virtualenv if: ${{ matrix.flavour == 'linux' }} - name: Install packages - run: brew install boost geos virtualenv + run: brew install geos virtualenv shell: bash if: ${{ matrix.flavour == 'macos' }} @@ -404,7 +404,7 @@ jobs: shell: bash - name: Install packages - run: vcpkg install bzip2:x64-windows expat:x64-windows zlib:x64-windows boost-variant:x64-windows boost-iterator:x64-windows lz4:x86-windows + run: vcpkg install bzip2:x64-windows expat:x64-windows zlib:x64-windows lz4:x86-windows shell: bash - name: Set up Python 3.8 @@ -531,7 +531,7 @@ jobs: - name: Install packages run: | - vcpkg install bzip2:x64-windows expat:x64-windows zlib:x64-windows boost-variant:x64-windows boost-iterator:x64-windows lz4:x86-windows + vcpkg install bzip2:x64-windows expat:x64-windows zlib:x64-windows lz4:x86-windows shell: bash - name: Set up Python 3.13t From 8cc9d7bde5513b4e4cff8c74fa4837d9c8b25660 Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Sat, 3 Jan 2026 11:39:27 +0100 Subject: [PATCH 3/3] add simple test for merging in MergeInputReader --- test/test_merge_input_reader.py | 101 ++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 test/test_merge_input_reader.py diff --git a/test/test_merge_input_reader.py b/test/test_merge_input_reader.py new file mode 100644 index 0000000..94dd5b1 --- /dev/null +++ b/test/test_merge_input_reader.py @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: BSD-2-Clause +# +# This file is part of pyosmium. (https://osmcode.org/pyosmium/) +# +# Copyright (C) 2026 Sarah Hoffmann and others. +# For a full list of authors see the git log. +from textwrap import dedent +import uuid + +import pytest + +import osmium + + +class ListHandler: + def __init__(self): + self.data = [] + + def node(self, o): + self.data.append(f"N{o.id}/{o.version}") + + def way(self, o): + self.data.append(f"W{o.id}/{o.version}") + + def relation(self, o): + self.data.append(f"R{o.id}/{o.version}") + + def area(self, _): + assert not "Area handler should not be called" + + +def add_as_buffer(mir, opl, tmp_path): + mir.add_buffer(dedent(opl).encode('utf-8'), format='opl') + + +def add_as_file(mir, opl, tmp_path): + fn = tmp_path / (str(uuid.uuid4()) + '.opl') + fn.write_text(dedent(opl)) + + mir.add_file(str(fn)) + + +@pytest.mark.parametrize('adder', [add_as_buffer, add_as_file]) +def test_simple_input(adder, tmp_path): + mir = osmium.MergeInputReader() + + opl = """\ + n1 v1 x1 y1 + w3 v34 Nn1 + """ + + adder(mir, opl, tmp_path) + + h = ListHandler() + mir.apply(h) + + assert h.data == ['N1/1', 'W3/34'] + + +@pytest.mark.parametrize('adder', [add_as_buffer, add_as_file]) +def test_multibuffer_no_simplify(adder, tmp_path): + mir = osmium.MergeInputReader() + + opls = ["""\ + n1 v1 x1 y1 + w3 v2 Nn1 + """, + """\ + n2 v1 x1 y1 + w3 v1 Nn2 + """] + + for opl in opls: + adder(mir, opl, tmp_path) + + h = ListHandler() + mir.apply(h, simplify=False) + + assert h.data == ['N1/1', 'N2/1', 'W3/1', 'W3/2'] + + +@pytest.mark.parametrize('adder', [add_as_buffer, add_as_file]) +def test_multibuffer_simplify(adder, tmp_path): + mir = osmium.MergeInputReader() + + opls = ["""\ + n1 v1 x1 y1 + w3 v2 Nn1 + """, + """\ + n2 v1 x1 y1 + w3 v1 Nn2 + """] + + for opl in opls: + adder(mir, opl, tmp_path) + + h = ListHandler() + mir.apply(h, simplify=True) + + assert h.data == ['N1/1', 'N2/1', 'W3/2']