From 83d148b25c358302ed20f1373097576fd12b339a Mon Sep 17 00:00:00 2001 From: everoddandeven Date: Fri, 30 Oct 2026 00:34:37 +0100 Subject: [PATCH 1/5] build: read the version from pyproject.toml CMakeLists.txt reads the version declared in pyproject.toml instead of repeating it, and passes it to py_monero_utils.cpp, which reports it from get_version(). The function moves out of the header, so a new version only rebuilds that file instead of every one that includes the header. test_get_version now checks that the compiled module reports the version of pyproject.toml. Co-Authored-By: Claude Sonnet 5.5 --- CMakeLists.txt | 17 ++++++++++++++++- pyproject.toml | 2 ++ src/cpp/utils/py_monero_utils.cpp | 7 +++++++ src/cpp/utils/py_monero_utils.h | 2 +- tests/test_monero_utils.py | 8 +++++++- 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c691496..c59ceca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,17 @@ cmake_minimum_required(VERSION 3.15) -project(monero VERSION 0.9.10 LANGUAGES CXX) +# The version is declared only in pyproject.toml, which also gives it to the wheel +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/pyproject.toml" MONERO_PYTHON_PYPROJECT) +string(REGEX MATCH "(^|\n)version = \"([0-9]+\\.[0-9]+\\.[0-9]+)\"" MONERO_PYTHON_VERSION_MATCH "${MONERO_PYTHON_PYPROJECT}") +if(NOT MONERO_PYTHON_VERSION_MATCH) + message(FATAL_ERROR "Could not read the version from pyproject.toml") +endif() +set(MONERO_PYTHON_VERSION "${CMAKE_MATCH_2}") +# configure again when the version changes +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/pyproject.toml") + +project(monero VERSION ${MONERO_PYTHON_VERSION} LANGUAGES CXX) +message(STATUS "monero-python version ${PROJECT_VERSION}") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -274,6 +285,10 @@ set(LIBRARY_SRC_FILES src/cpp/py_monero.cpp ) +# only this file reports the version, so a new version does not rebuild the others +set_source_files_properties(src/cpp/utils/py_monero_utils.cpp PROPERTIES + COMPILE_DEFINITIONS "MONERO_PYTHON_VERSION=\"${PROJECT_VERSION}\"") + pybind11_add_module(monero ${LIBRARY_SRC_FILES}) if (WIN32) diff --git a/pyproject.toml b/pyproject.toml index 00e6bf9..2342dff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,7 @@ [project] name = "monero" +# the only place where the version is declared: CMakeLists.txt, docker/build.sh and +# the release workflow read it from here version = "0.9.10" description = "A Python library for using Monero" authors = [ diff --git a/src/cpp/utils/py_monero_utils.cpp b/src/cpp/utils/py_monero_utils.cpp index b7b92a3..0835616 100644 --- a/src/cpp/utils/py_monero_utils.cpp +++ b/src/cpp/utils/py_monero_utils.cpp @@ -55,6 +55,13 @@ #include "cryptonote_basic/cryptonote_format_utils.h" #include "py_monero_utils.h" +#ifndef MONERO_PYTHON_VERSION +#error "MONERO_PYTHON_VERSION is defined by CMakeLists.txt from the version in pyproject.toml" +#endif + +std::string PyMoneroUtils::get_version() { + return std::string(MONERO_PYTHON_VERSION); +} void PyMoneroUtils::validate_payment_id_long(const std::string& payment_id_str) { crypto::hash payment_id; diff --git a/src/cpp/utils/py_monero_utils.h b/src/cpp/utils/py_monero_utils.h index 5b76a0f..d6267ab 100644 --- a/src/cpp/utils/py_monero_utils.h +++ b/src/cpp/utils/py_monero_utils.h @@ -63,7 +63,7 @@ class PyMoneroUtils { public: PyMoneroUtils() {}; - static std::string get_version() { return std::string("0.9.10"); }; + static std::string get_version(); static std::string json_to_binary(const std::string &json); static std::string dict_to_binary(const py::dict &dictionary); static py::dict binary_to_dict(const std::string& bin); diff --git a/tests/test_monero_utils.py b/tests/test_monero_utils.py index 56bf741..bea7a0d 100644 --- a/tests/test_monero_utils.py +++ b/tests/test_monero_utils.py @@ -5,11 +5,13 @@ import subprocess import sys import gc +import re if sys.platform != "win32": import resource from typing import Any +from pathlib import Path from configparser import ConfigParser from monero import ( MoneroNetworkType, MoneroIntegratedAddress, MoneroUtils, MoneroTxConfig, @@ -604,11 +606,15 @@ def test_parse_payment_uri_unknown_parameter(self, config: TestMoneroUtils.Confi parsed: MoneroTxConfig = MoneroUtils.parse_payment_uri(f"monero:{address}?foo=bar") assert parsed.destinations[0].address == address - # Can get version + # Can get version, which is the one declared in pyproject.toml def test_get_version(self) -> None: version: str = MoneroUtils.get_version() logger.debug(f"Testing monero-python version: {version}") assert version != "", "Version is empty" + pyproject: str = (Path(__file__).resolve().parent.parent / "pyproject.toml").read_text(encoding="utf-8") + declared = re.search(r'^version = "(\d+\.\d+\.\d+)"$', pyproject, re.MULTILINE) + assert declared is not None, "Version not found in pyproject.toml" + assert version == declared.group(1) # Can get ring size def test_get_ring_size(self) -> None: From 8973e3d6347f41293b38b0bee4c7e8000a5dc153 Mon Sep 17 00:00:00 2001 From: everoddandeven Date: Fri, 30 Oct 2026 00:34:54 +0100 Subject: [PATCH 2/5] debian: keep a single control directory for all the distros The four debian/ directories had the same files: only a blank line of the changelog differed. The distro is already taken from /etc/os-release for the name of the package, and the dependencies are computed by dpkg-shlibdeps at build time, so debian/DEBIAN is copied as it is. Co-Authored-By: Claude Sonnet 5.5 --- debian/{noble => DEBIAN}/changelog | 0 debian/{bookworm => DEBIAN}/compat | 0 debian/{bookworm => DEBIAN}/control | 0 debian/{bookworm => DEBIAN}/copyright | 0 debian/{bookworm => DEBIAN}/format | 0 debian/{bookworm => DEBIAN}/rules | 0 debian/bookworm/changelog | 3 --- debian/jammy/changelog | 3 --- debian/jammy/compat | 1 - debian/jammy/control | 14 -------------- debian/jammy/copyright | 6 ------ debian/jammy/format | 1 - debian/jammy/rules | 4 ---- debian/noble/compat | 1 - debian/noble/control | 14 -------------- debian/noble/copyright | 6 ------ debian/noble/format | 1 - debian/noble/rules | 4 ---- debian/trixie/changelog | 4 ---- debian/trixie/compat | 1 - debian/trixie/control | 14 -------------- debian/trixie/copyright | 6 ------ debian/trixie/format | 1 - debian/trixie/rules | 4 ---- docker/build.sh | 2 +- 25 files changed, 1 insertion(+), 89 deletions(-) rename debian/{noble => DEBIAN}/changelog (100%) rename debian/{bookworm => DEBIAN}/compat (100%) rename debian/{bookworm => DEBIAN}/control (100%) rename debian/{bookworm => DEBIAN}/copyright (100%) rename debian/{bookworm => DEBIAN}/format (100%) rename debian/{bookworm => DEBIAN}/rules (100%) delete mode 100644 debian/bookworm/changelog delete mode 100644 debian/jammy/changelog delete mode 100644 debian/jammy/compat delete mode 100644 debian/jammy/control delete mode 100644 debian/jammy/copyright delete mode 100644 debian/jammy/format delete mode 100755 debian/jammy/rules delete mode 100644 debian/noble/compat delete mode 100644 debian/noble/control delete mode 100644 debian/noble/copyright delete mode 100644 debian/noble/format delete mode 100755 debian/noble/rules delete mode 100644 debian/trixie/changelog delete mode 100644 debian/trixie/compat delete mode 100644 debian/trixie/control delete mode 100644 debian/trixie/copyright delete mode 100644 debian/trixie/format delete mode 100755 debian/trixie/rules diff --git a/debian/noble/changelog b/debian/DEBIAN/changelog similarity index 100% rename from debian/noble/changelog rename to debian/DEBIAN/changelog diff --git a/debian/bookworm/compat b/debian/DEBIAN/compat similarity index 100% rename from debian/bookworm/compat rename to debian/DEBIAN/compat diff --git a/debian/bookworm/control b/debian/DEBIAN/control similarity index 100% rename from debian/bookworm/control rename to debian/DEBIAN/control diff --git a/debian/bookworm/copyright b/debian/DEBIAN/copyright similarity index 100% rename from debian/bookworm/copyright rename to debian/DEBIAN/copyright diff --git a/debian/bookworm/format b/debian/DEBIAN/format similarity index 100% rename from debian/bookworm/format rename to debian/DEBIAN/format diff --git a/debian/bookworm/rules b/debian/DEBIAN/rules similarity index 100% rename from debian/bookworm/rules rename to debian/DEBIAN/rules diff --git a/debian/bookworm/changelog b/debian/bookworm/changelog deleted file mode 100644 index d7b08ca..0000000 --- a/debian/bookworm/changelog +++ /dev/null @@ -1,3 +0,0 @@ -python3-monero (0.0.1-1) main; urgency=medium - - -- everoddandeven diff --git a/debian/jammy/changelog b/debian/jammy/changelog deleted file mode 100644 index d7b08ca..0000000 --- a/debian/jammy/changelog +++ /dev/null @@ -1,3 +0,0 @@ -python3-monero (0.0.1-1) main; urgency=medium - - -- everoddandeven diff --git a/debian/jammy/compat b/debian/jammy/compat deleted file mode 100644 index b4de394..0000000 --- a/debian/jammy/compat +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/debian/jammy/control b/debian/jammy/control deleted file mode 100644 index 53f7588..0000000 --- a/debian/jammy/control +++ /dev/null @@ -1,14 +0,0 @@ -Source: python3-monero -Section: python -Priority: optional -Maintainer: everoddandeven -Build-Depends: build-essential, cmake, pkg-config, debhelper, python3-all, libssl-dev, libzmq3-dev, libunbound-dev, libsodium-dev, libunwind8-dev, liblzma-dev, libreadline6-dev, libexpat1-dev, libpgm-dev, qttools5-dev-tools, libhidapi-dev, libusb-1.0-0-dev, libprotobuf-dev, protobuf-compiler, libudev-dev, libboost-chrono-dev, libboost-date-time-dev, libboost-filesystem-dev, libboost-locale-dev, libboost-program-options-dev, libboost-regex-dev libboost-serialization-dev, libboost-system-dev, libboost-thread-dev, python3, ccache, doxygen, graphviz, nettle-dev, libevent-dev, python3-pip, python3-pybind11, python3-pytest, pybind11-dev -Depends: ${shlibs:Depends} -Standards-Version: 4.5.0 -Homepage: https://github.com/everoddandeven/monero-python -Rules-Requires-Root: no -Package: python3-monero -Architecture: all -Description: Python bindings for monero-cpp - This package provides Python 3 bindings for the monero-cpp library using pybind11. -Version: 0.9.10 diff --git a/debian/jammy/copyright b/debian/jammy/copyright deleted file mode 100644 index 1398915..0000000 --- a/debian/jammy/copyright +++ /dev/null @@ -1,6 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: monero-python -Source: https://github.com/everoddandeven/monero-python -Files: * -Copyright: 2025 everoddandeven -License: MIT diff --git a/debian/jammy/format b/debian/jammy/format deleted file mode 100644 index 163aaf8..0000000 --- a/debian/jammy/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debian/jammy/rules b/debian/jammy/rules deleted file mode 100755 index 050e29a..0000000 --- a/debian/jammy/rules +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/make -f - -%: - dh $@ --buildsystem=cmake diff --git a/debian/noble/compat b/debian/noble/compat deleted file mode 100644 index b4de394..0000000 --- a/debian/noble/compat +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/debian/noble/control b/debian/noble/control deleted file mode 100644 index 53f7588..0000000 --- a/debian/noble/control +++ /dev/null @@ -1,14 +0,0 @@ -Source: python3-monero -Section: python -Priority: optional -Maintainer: everoddandeven -Build-Depends: build-essential, cmake, pkg-config, debhelper, python3-all, libssl-dev, libzmq3-dev, libunbound-dev, libsodium-dev, libunwind8-dev, liblzma-dev, libreadline6-dev, libexpat1-dev, libpgm-dev, qttools5-dev-tools, libhidapi-dev, libusb-1.0-0-dev, libprotobuf-dev, protobuf-compiler, libudev-dev, libboost-chrono-dev, libboost-date-time-dev, libboost-filesystem-dev, libboost-locale-dev, libboost-program-options-dev, libboost-regex-dev libboost-serialization-dev, libboost-system-dev, libboost-thread-dev, python3, ccache, doxygen, graphviz, nettle-dev, libevent-dev, python3-pip, python3-pybind11, python3-pytest, pybind11-dev -Depends: ${shlibs:Depends} -Standards-Version: 4.5.0 -Homepage: https://github.com/everoddandeven/monero-python -Rules-Requires-Root: no -Package: python3-monero -Architecture: all -Description: Python bindings for monero-cpp - This package provides Python 3 bindings for the monero-cpp library using pybind11. -Version: 0.9.10 diff --git a/debian/noble/copyright b/debian/noble/copyright deleted file mode 100644 index 1398915..0000000 --- a/debian/noble/copyright +++ /dev/null @@ -1,6 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: monero-python -Source: https://github.com/everoddandeven/monero-python -Files: * -Copyright: 2025 everoddandeven -License: MIT diff --git a/debian/noble/format b/debian/noble/format deleted file mode 100644 index 163aaf8..0000000 --- a/debian/noble/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debian/noble/rules b/debian/noble/rules deleted file mode 100755 index 050e29a..0000000 --- a/debian/noble/rules +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/make -f - -%: - dh $@ --buildsystem=cmake diff --git a/debian/trixie/changelog b/debian/trixie/changelog deleted file mode 100644 index dca30e8..0000000 --- a/debian/trixie/changelog +++ /dev/null @@ -1,4 +0,0 @@ -python3-monero (0.0.1-1) main; urgency=medium - - -- everoddandeven - diff --git a/debian/trixie/compat b/debian/trixie/compat deleted file mode 100644 index b4de394..0000000 --- a/debian/trixie/compat +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/debian/trixie/control b/debian/trixie/control deleted file mode 100644 index 53f7588..0000000 --- a/debian/trixie/control +++ /dev/null @@ -1,14 +0,0 @@ -Source: python3-monero -Section: python -Priority: optional -Maintainer: everoddandeven -Build-Depends: build-essential, cmake, pkg-config, debhelper, python3-all, libssl-dev, libzmq3-dev, libunbound-dev, libsodium-dev, libunwind8-dev, liblzma-dev, libreadline6-dev, libexpat1-dev, libpgm-dev, qttools5-dev-tools, libhidapi-dev, libusb-1.0-0-dev, libprotobuf-dev, protobuf-compiler, libudev-dev, libboost-chrono-dev, libboost-date-time-dev, libboost-filesystem-dev, libboost-locale-dev, libboost-program-options-dev, libboost-regex-dev libboost-serialization-dev, libboost-system-dev, libboost-thread-dev, python3, ccache, doxygen, graphviz, nettle-dev, libevent-dev, python3-pip, python3-pybind11, python3-pytest, pybind11-dev -Depends: ${shlibs:Depends} -Standards-Version: 4.5.0 -Homepage: https://github.com/everoddandeven/monero-python -Rules-Requires-Root: no -Package: python3-monero -Architecture: all -Description: Python bindings for monero-cpp - This package provides Python 3 bindings for the monero-cpp library using pybind11. -Version: 0.9.10 diff --git a/debian/trixie/copyright b/debian/trixie/copyright deleted file mode 100644 index 1398915..0000000 --- a/debian/trixie/copyright +++ /dev/null @@ -1,6 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: monero-python -Source: https://github.com/everoddandeven/monero-python -Files: * -Copyright: 2025 everoddandeven -License: MIT diff --git a/debian/trixie/format b/debian/trixie/format deleted file mode 100644 index 163aaf8..0000000 --- a/debian/trixie/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debian/trixie/rules b/debian/trixie/rules deleted file mode 100755 index 050e29a..0000000 --- a/debian/trixie/rules +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/make -f - -%: - dh $@ --buildsystem=cmake diff --git a/docker/build.sh b/docker/build.sh index 8fde234..12af76b 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -77,7 +77,7 @@ fi cp -R src/python build/${PACKAGE_NAME}/usr/lib/python3/dist-packages/monero rm -rf build/${PACKAGE_NAME}/usr/lib/python3/dist-packages/pybind11* rm -rf build/${PACKAGE_NAME}/usr/lib/python3/dist-packages/bin -cp -R "debian/${DISTRO_CODENAME}" "build/${PACKAGE_NAME}/DEBIAN" +cp -R debian/DEBIAN "build/${PACKAGE_NAME}/DEBIAN" CONTROL_FILE="build/${PACKAGE_NAME}/DEBIAN/control" if [ -f "$CONTROL_FILE" ]; then From c3611a9de6a64a9f7f11c154a36073c1e6a253f8 Mon Sep 17 00:00:00 2001 From: everoddandeven Date: Fri, 30 Oct 2026 00:35:42 +0100 Subject: [PATCH 3/5] docker: take the package version from pyproject.toml build.sh reads the version for the name of the package from pyproject.toml, and patches it in the control file as it already does for the architecture and the dependencies, so the template keeps a placeholder. Co-Authored-By: Claude Sonnet 5.5 --- debian/DEBIAN/control | 2 +- docker/build.sh | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/debian/DEBIAN/control b/debian/DEBIAN/control index 53f7588..156e921 100644 --- a/debian/DEBIAN/control +++ b/debian/DEBIAN/control @@ -11,4 +11,4 @@ Package: python3-monero Architecture: all Description: Python bindings for monero-cpp This package provides Python 3 bindings for the monero-cpp library using pybind11. -Version: 0.9.10 +Version: @VERSION@ diff --git a/docker/build.sh b/docker/build.sh index 12af76b..a23f4af 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -2,7 +2,13 @@ set -e DISTRO_CODENAME=$(grep VERSION_CODENAME /etc/os-release | cut -d'=' -f2) -DEFAULT_VERSION="0.9.10" + +# the version is declared only in pyproject.toml +VERSION=$(sed -n 's/^version = "\(.*\)"$/\1/p' pyproject.toml | head -n 1) +if [ -z "$VERSION" ]; then + echo "ERROR: could not read the version from pyproject.toml" >&2 + exit 1 +fi if [ -z "$DISTRO_CODENAME" ]; then DISTRO_CODENAME=$(lsb_release -c -s 2>/dev/null || echo "unknown") @@ -17,7 +23,7 @@ elif [[ "$ARCH" == armv7* || "$ARCH" == "armhf" ]]; then ARCH="armhf" fi -PACKAGE_NAME=${PACKAGE_NAME:-python3-monero_${DEFAULT_VERSION}-1${DISTRO_CODENAME}1_${ARCH}} +PACKAGE_NAME=${PACKAGE_NAME:-python3-monero_${VERSION}-1${DISTRO_CODENAME}1_${ARCH}} echo "Building package: ${PACKAGE_NAME}" echo "Distro codename: ${DISTRO_CODENAME}" @@ -84,6 +90,9 @@ if [ -f "$CONTROL_FILE" ]; then echo "Patching control file architecture to: ${ARCH}" sed -i "s/^Architecture: .*/Architecture: ${ARCH}/" "$CONTROL_FILE" + echo "Patching control file version to: ${VERSION}" + sed -i "s/^Version: .*/Version: ${VERSION}/" "$CONTROL_FILE" + echo "Computing runtime library dependencies with dpkg-shlibdeps" SO_FILES=$(find "build/${PACKAGE_NAME}/usr/lib/python3/dist-packages" -maxdepth 1 -name "*.so") if [ -z "$SO_FILES" ]; then From e2122f2518c25798ab795a8abdc1ae8549defee9 Mon Sep 17 00:00:00 2001 From: everoddandeven Date: Fri, 30 Oct 2026 00:35:42 +0100 Subject: [PATCH 4/5] remove setup.py The build backend is scikit-build-core, declared in pyproject.toml, so pip never runs setup.py. It imports skbuild from scikit-build, which no build requires or installs, and it only repeated the version. Co-Authored-By: Claude Sonnet 5.5 --- setup.py | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 setup.py diff --git a/setup.py b/setup.py deleted file mode 100644 index e6d54eb..0000000 --- a/setup.py +++ /dev/null @@ -1,18 +0,0 @@ -# setup.py -from skbuild import setup - -setup( - name='monero', - version='0.9.10', - author='everoddandeven', - author_email="everoddandeven@protonmail.com", - maintainer='everoddandeven', - maintainer_email='everoddandeven@protonmail.com', - license="MIT", - packages=["monero"], - url='https://github.com/everoddandeven/monero-python', - download_url="https://github.com/everoddandeven/monero-python/releases", - description='A Python library for using Monero.', - long_description='Python bindings for monero-cpp.', - keywords=["monero", "monero-python", "python", "bindings", "pybind11"], -) From be4199a8cc45c631e13d51d1a37b03847e289e5d Mon Sep 17 00:00:00 2001 From: everoddandeven Date: Fri, 30 Oct 2026 00:36:25 +0100 Subject: [PATCH 5/5] release: check the tag against the version in pyproject.toml The release fails before it looks for the build runs when the tag is not the version of the tagged commit, instead of publishing a draft with packages named after another version. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/release.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d91e58f..d1f5fa9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,6 +18,23 @@ jobs: actions: read steps: + - name: Check the tag against the version in pyproject.toml + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + run: | + version=$(gh api -H "Accept: application/vnd.github.raw+json" \ + "repos/${GITHUB_REPOSITORY}/contents/pyproject.toml?ref=${GITHUB_SHA}" \ + | sed -n 's/^version = "\(.*\)"$/\1/p' | head -n1) + if [ -z "$version" ]; then + echo "::error::Could not read the version from pyproject.toml at ${GITHUB_SHA}." + exit 1 + fi + if [ "v$version" != "$TAG" ]; then + echo "::error::The tag $TAG does not match the version $version in pyproject.toml. Bump the version before tagging." + exit 1 + fi + - name: Find main-branch build runs for this commit id: find_runs env: