diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dc2627f..3d8e0bc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,27 +22,30 @@ jobs: matrix: variant: # https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json - - {runner: macos-13, qt-os: mac, arch: x64, py-arch: x64, qt-compiler: clang_64, config: Release, py-version: '3.9' } - - {runner: macos-13, qt-os: mac, arch: x64, py-arch: x64, qt-compiler: clang_64, config: Release, py-version: '3.10' } - - {runner: macos-13, qt-os: mac, arch: x64, py-arch: x64, qt-compiler: clang_64, config: Release, py-version: '3.11' } - - {runner: macos-13, qt-os: mac, arch: x64, py-arch: x64, qt-compiler: clang_64, config: Release, py-version: '3.12' } - - {runner: macos-13, qt-os: mac, arch: x64, py-arch: x64, qt-compiler: clang_64, config: Release, py-version: '3.13' } - - {runner: ubuntu-22.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.9' } - - {runner: ubuntu-22.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.10' } - - {runner: ubuntu-22.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.11' } - - {runner: ubuntu-22.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.12' } - - {runner: ubuntu-22.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.13' } - - {runner: ubuntu-24.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.9' } - - {runner: ubuntu-24.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.10' } - - {runner: ubuntu-24.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.11' } - - {runner: ubuntu-24.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.12' } - - {runner: ubuntu-24.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.13' } - - {runner: ubuntu-24.04-arm, qt-os: linux_arm64, arch: arm64, py-arch: arm64, qt-compiler: gcc_arm64, config: RelWithDebInfo, py-version: '3.13' } - - {runner: windows-2022, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.9' } - - {runner: windows-2022, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.10' } - - {runner: windows-2022, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.11' } - - {runner: windows-2022, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.12' } - - {runner: windows-2022, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.13' } + - {runner: macos-14-large, qt-os: mac, arch: x64, py-arch: x64, qt-compiler: clang_64, config: Release, py-version: '3.11' } + - {runner: macos-14-large, qt-os: mac, arch: x64, py-arch: x64, qt-compiler: clang_64, config: Release, py-version: '3.12' } + - {runner: macos-14-large, qt-os: mac, arch: x64, py-arch: x64, qt-compiler: clang_64, config: Release, py-version: '3.13' } + - {runner: macos-14-large, qt-os: mac, arch: x64, py-arch: x64, qt-compiler: clang_64, config: Release, py-version: '3.14' } + - {runner: ubuntu-22.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.11' } + - {runner: ubuntu-22.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.12' } + - {runner: ubuntu-22.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.13' } + - {runner: ubuntu-22.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.14' } + - {runner: ubuntu-24.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.11' } + - {runner: ubuntu-24.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.12' } + - {runner: ubuntu-24.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.13' } + - {runner: ubuntu-24.04, qt-os: linux, arch: x64, py-arch: x64, qt-compiler: gcc_64, config: RelWithDebInfo, py-version: '3.14' } + - {runner: ubuntu-24.04-arm, qt-os: linux_arm64, arch: arm64, py-arch: arm64, qt-compiler: gcc_arm64, config: RelWithDebInfo, py-version: '3.13' } + - {runner: ubuntu-24.04-arm, qt-os: linux_arm64, arch: arm64, py-arch: arm64, qt-compiler: gcc_arm64, config: RelWithDebInfo, py-version: '3.14' } + - {runner: windows-2022, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.11' } + - {runner: windows-2022, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.12' } + - {runner: windows-2022, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.13' } + - {runner: windows-2022, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.14' } + - {runner: windows-2025, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.11' } + - {runner: windows-2025, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.12' } + - {runner: windows-2025, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.13' } + - {runner: windows-2025, qt-os: windows, arch: x64, py-arch: x64, qt-compiler: msvc2019_64, config: RelWithDebInfo, py-version: '3.14' } + - {runner: windows-11-arm, qt-os: windows, arch: x64, py-arch: arm64, qt-compiler: msvc2019_arm64, config: RelWithDebInfo, py-version: '3.13' } + - {runner: windows-11-arm, qt-os: windows, arch: x64, py-arch: arm64, qt-compiler: msvc2019_arm64, config: RelWithDebInfo, py-version: '3.14' } runs-on: ${{ matrix.variant.runner }} name: python${{ matrix.variant.py-version }} / ${{ matrix.variant.runner }} / ${{ matrix.variant.config }} env: @@ -50,10 +53,10 @@ jobs: QT_VERSION: 6.7.3 # arm64 support in aqt appears from >= 6.7.0 - and almalinux ships an old libc incompat with >= 6.8.x steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.variant.py-version }} architecture: ${{ matrix.variant.py-arch }} @@ -80,7 +83,7 @@ jobs: - name: Cache Artifacts id: cache-artifacts - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: build/${{ env.QT_VERSION }} key: aqt-install-${{ matrix.variant.runner }}-${{ matrix.variant.arch }}-${{ env.QT_VERSION }}-${{ matrix.variant.qt-compiler }} @@ -91,6 +94,11 @@ jobs: python -m pip install aqtinstall --user --upgrade python -m aqt install-qt -O build/ ${{ matrix.variant.qt-os }} desktop ${{ env.QT_VERSION }} win64_${{ matrix.variant.qt-compiler }} + - name: Setup Qt (Windows/ARM64) + if: steps.cache-artifacts.outputs.cache-hit != 'true' && matrix.variant.qt-compiler == 'msvc2019_arm64' + run: | + python -m aqt install-qt -O build/ ${{ matrix.variant.qt-os }} desktop ${{ env.QT_VERSION }} win64_msvc2019_64 + - name: Setup Qt (macOS) if: steps.cache-artifacts.outputs.cache-hit != 'true' && startsWith(matrix.variant.runner, 'macos-') run: | @@ -113,7 +121,7 @@ jobs: python -m pytest -v python/tests - name: Build wheels (Linux arm64) - if: matrix.variant.runner == 'ubuntu-24.04-arm' && matrix.variant.py-version == '3.13' + if: matrix.variant.runner == 'ubuntu-24.04-arm' && matrix.variant.py-version == '3.14' run: | python -m pip uninstall --quiet --yes die-python rm -fr -- build/cp* @@ -121,7 +129,7 @@ jobs: python -m cibuildwheel --output-dir wheelhouse --archs aarch64 - name: Build wheels (Linux x64) - if: matrix.variant.runner == 'ubuntu-24.04' && matrix.variant.py-version == '3.13' + if: matrix.variant.runner == 'ubuntu-24.04' && matrix.variant.py-version == '3.14' run: | python -m pip uninstall --quiet --yes die-python rm -fr -- build/cp* @@ -150,19 +158,16 @@ jobs: matrix: variant: # https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json - - {runner: macos-13, config: Release, py-version: '3.9' } - - {runner: macos-13, config: Release, py-version: '3.10' } - - {runner: macos-13, config: Release, py-version: '3.11' } - - {runner: macos-13, config: Release, py-version: '3.12' } - - {runner: macos-13, config: Release, py-version: '3.13' } - # - {runner: ubuntu-24.04, config: RelWithDebInfo, py-version: '3.12' } - - {runner: ubuntu-24.04, config: RelWithDebInfo, py-version: '3.13' } - - {runner: ubuntu-24.04-arm, config: RelWithDebInfo, py-version: '3.13' } - - {runner: windows-2022, config: RelWithDebInfo, py-version: '3.9' } - - {runner: windows-2022, config: RelWithDebInfo, py-version: '3.10' } + - {runner: macos-15-large, config: Release, py-version: '3.11' } + - {runner: macos-15-large, config: Release, py-version: '3.12' } + - {runner: macos-15-large, config: Release, py-version: '3.13' } + - {runner: macos-15-large, config: Release, py-version: '3.14' } + - {runner: ubuntu-24.04, config: RelWithDebInfo, py-version: '3.14' } + - {runner: ubuntu-24.04-arm, config: RelWithDebInfo, py-version: '3.14' } - {runner: windows-2022, config: RelWithDebInfo, py-version: '3.11' } - {runner: windows-2022, config: RelWithDebInfo, py-version: '3.12' } - {runner: windows-2022, config: RelWithDebInfo, py-version: '3.13' } + - {runner: windows-2022, config: RelWithDebInfo, py-version: '3.14' } runs-on: ubuntu-latest if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') name: PyPI upload of ${{ matrix.variant.runner }}/${{ matrix.variant.config }}/py${{ matrix.variant.py-version }} diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..2c07333 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.11 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c1e294..6ddad68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.26) project( DIE - VERSION 0.5.1 + VERSION 0.5.0 LANGUAGES CXX DESCRIPTION "DIE Library implementation" ) diff --git a/README.md b/README.md index fe35a81..ef50cfb 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # DetectItEasy-Python -[![Python 3.8+](https://img.shields.io/pypi/v/die-python.svg)](https://pypi.org/project/die-python/) +[![Python 3.11+](https://img.shields.io/pypi/v/die-python.svg)](https://pypi.org/project/die-python/) [![Downloads](https://static.pepy.tech/badge/die-python)](https://pepy.tech/project/die-python) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Licence Apache2](https://img.shields.io/badge/License-Apache_2-blue)](https://github.com/elastic/die-python/blob/main/LICENSE) [![Build](https://github.com/elastic/die-python/actions/workflows/build.yml/badge.svg)](https://github.com/elastic/die-python/actions/workflows/build.yml) -Native Python 3.8+ bindings for [@horsicq](https://github.com/horsicq/)'s [Detect-It-Easy](https://github.com/horsicq/Detect-It-Easy) +Native Python 3.11+ bindings for [@horsicq](https://github.com/horsicq/)'s [Detect-It-Easy](https://github.com/horsicq/Detect-It-Easy) ## Install @@ -33,6 +33,7 @@ python -m pip install aqtinstall --user -U python -m aqt install-qt -O ./build linux desktop 6.7.3 linux_gcc_64 # linux x64 only python -m aqt install-qt -O ./build linux_arm64 desktop 6.7.3 linux_gcc_arm64 # linux arm64 only python -m aqt install-qt -O ./build windows desktop 6.7.3 win64_msvc2019_64 # windows x64 only +python -m aqt install-qt -O ./build windows desktop 6.7.3 win64_msvc2019_arm64 # windows arm64 only (will requires `win64_msvc2019_64`) python -m aqt install-qt -O ./build mac desktop 6.7.3 clang_64 # mac only ``` diff --git a/cmake/FindDieLibrary.cmake b/cmake/FindDieLibrary.cmake index 6b3ddc5..b4783e5 100644 --- a/cmake/FindDieLibrary.cmake +++ b/cmake/FindDieLibrary.cmake @@ -9,8 +9,16 @@ set(QT_BUILD_VERSION "6.7.3") # TODO (calladoum) : here we oversimplify by assuming that compilation HOST and TARGET have same architecture if(WIN32) - # python -m aqt install-qt -O build windows desktop ${QT_BUILD_VERSION} win64_msvc2019_64 - set(QT_BUILD_COMPILER "msvc2019_64") + if (${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "AMD64") + # python -m aqt install-qt -O build windows desktop ${QT_BUILD_VERSION} win64_msvc2019_64 + set(QT_BUILD_COMPILER "msvc2019_64") + elseif(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "ARM64") + # python -m aqt install-qt -O build windows desktop ${QT_BUILD_VERSION} win64_msvc2019_64 + # python -m aqt install-qt -O build windows desktop ${QT_BUILD_VERSION} win64_msvc2019_arm64 + set(QT_BUILD_COMPILER "msvc2019_arm64") + else() + message(FATAL_ERROR, "Unsupported processor ${CMAKE_HOST_SYSTEM_PROCESSOR}") + endif() elseif(LINUX) if (${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64") @@ -26,6 +34,8 @@ elseif(LINUX) elseif(APPLE) # python -m aqt install-qt -O build mac desktop ${QT_BUILD_VERSION} clang_64 set(QT_BUILD_COMPILER "macos") +else() + message(FATAL_ERROR, "Unsupported OS") endif() if(NOT QT_BUILD_COMPILER) @@ -40,6 +50,11 @@ set(Qt6_CMAKE_ROOT "${ROOT_DIR}/build/${QT_BUILD_VERSION}/${QT_BUILD_COMPILER}/l set(Qt6_DIR ${Qt6_CMAKE_ROOT}/Qt6) set(QT_DIR ${Qt6_DIR}) +if(WIN32 AND ${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "ARM64") + # WoA only - set cross-compile path + set(QT_HOST_PATH "${ROOT_DIR}/build/${QT_BUILD_VERSION}/msvc2019_64") +endif() + message(STATUS "Qt6_CMAKE_ROOT: ${Qt6_CMAKE_ROOT}") message(STATUS "Qt6_DIR: ${Qt6_DIR}") diff --git a/pyproject.toml b/pyproject.toml index 66a59a8..8b4b162 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,20 +4,19 @@ build-backend = "scikit_build_core.build" [project] name = "die_python" -version = "0.5.1" +version = "0.5.0" description = "Python bindings for Detect It Easy (DIE)." readme = "./README.md" license.file = "./LICENSE" -requires-python = ">=3.9" +requires-python = ">=3.11" authors = [{ name = "@calladoum-elastic" }] classifiers = [ "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Natural Language :: English", ] dependencies = ["setuptools", "wheel", "nanobind"] @@ -25,6 +24,16 @@ dependencies = ["setuptools", "wheel", "nanobind"] [project.optional-dependencies] tests = ["pytest", "black", "beautifulsoup4", "lxml"] +[dependency-groups] +tests = ["pytest"] +dev = [ + { include-group = "tests" }, + "black", + "beautifulsoup4", + "lxml", + "aqtinstall", +] + [project.urls] Homepage = "https://github.com/elastic/die-python" @@ -37,6 +46,9 @@ minimum-version = "0.4" build-dir = "build/{wheel_tag}" cmake.minimum-version = "3.20" +[tool.uv] +default-groups = ["dev"] + # Note: VS2022 throws a compiler crash when building nanobind, forcing VS2019 for now # cmake.args = ["-G", "Visual Studio 16 2019"] @@ -48,7 +60,7 @@ cmake.minimum-version = "3.20" [tool.cibuildwheel] before-build = "dnf install libstdc++ glibc -y && ldconfig" build = "" -skip = "cp27-* cp35-* cp36-* cp37-* cp38-* pp* *musllinux*" +skip = "cp27-* cp35-* cp36-* cp37-* cp38-* cp39-* cp310-* pp* *musllinux*" test-skip = "" free-threaded-support = false # use images from https://github.com/pypa/manylinux diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index ae26041..f5f4eb6 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,7 +1,7 @@ project( die-python LANGUAGES CXX - VERSION 0.5.1 + VERSION 0.5.0 ) find_package(Python 3 diff --git a/python/die/__init__.py b/python/die/__init__.py index 7c39b40..73ab8b2 100644 --- a/python/die/__init__.py +++ b/python/die/__init__.py @@ -4,24 +4,26 @@ from typing import Generator, Optional, Union -from ._die import __version__ # type: ignore -from ._die import DieFlags as _DieFlags # type: ignore -from ._die import ( - ScanFileA as _ScanFileA, # type: ignore - ScanFileExA as _ScanFileExA, # type: ignore - ScanMemoryA as _ScanMemoryA, # type: ignore - ScanMemoryExA as _ScanMemoryExA, # type: ignore - LoadDatabaseA as _LoadDatabaseA, # type: ignore +from ._die import __version__ # ty:ignore[unresolved-import] +from ._die import DieFlags as _DieFlags # ty:ignore[unresolved-import] +from ._die import ( # ty:ignore[unresolved-import] + ScanFileA as _ScanFileA, + ScanFileExA as _ScanFileExA, + ScanMemoryA as _ScanMemoryA, + ScanMemoryExA as _ScanMemoryExA, + LoadDatabaseA as _LoadDatabaseA, ) -from ._die import die_version, dielib_version # type: ignore +from ._die import die_version, dielib_version # ty:ignore[unresolved-import] +__all__ = ["die_version", "dielib_version"] version_major, version_minor, version_patch = map(int, __version__.split(".")) # Use concrete Path type to maintain isinstance() compatibility _BasePath = type(pathlib.Path()) -class _DatabasePath(_BasePath): + +class _DatabasePath(_BasePath): # ty:ignore[unsupported-base] """ Smart database path that maintains backward compatibility. @@ -44,7 +46,7 @@ def _get_resolved_str(self): # Use getattr with default to handle Python 3.9's pathlib behavior # where __new__ may not be called in path operations # See: https://github.com/python/cpython/issues/100479 - resolved = getattr(self, '_resolved_path_str', None) + resolved = getattr(self, "_resolved_path_str", None) if resolved is None: # Use parent class's __str__ to get path without triggering our override @@ -52,10 +54,10 @@ def _get_resolved_str(self): path_str = super().__str__() concrete_path = pathlib.Path(path_str) - if (concrete_path / 'PE').exists(): + if (concrete_path / "PE").exists(): resolved = path_str - elif (concrete_path / 'db' / 'PE').exists(): - resolved = str(concrete_path / 'db') + elif (concrete_path / "db/PE").exists(): + resolved = str(concrete_path / "db") else: resolved = path_str @@ -65,21 +67,21 @@ def _get_resolved_str(self): def __truediv__(self, other): """Handle path concatenation with backward compatibility.""" - if other == 'db': + if other == "db": # User is using the old workaround: database_path / 'db' # Check if the base path (before resolution) already contains PE/ # If yes, this is the new version and /'db' is redundant base_path_str = super().__str__() base_path = pathlib.Path(base_path_str) - if (base_path / 'PE').exists(): + if (base_path / "PE").exists(): # New fixed version: database is at die/db/PE/ warnings.warn( "Using 'database_path / \"db\"' is deprecated and no longer needed. " "The database is now directly at 'database_path'. " "Simply use 'database_path' instead.", DeprecationWarning, - stacklevel=2 + stacklevel=2, ) return self # else: Old version, database is at die/db/db/PE/ diff --git a/python/src/die.cpp b/python/src/die.cpp index 3cdc015..312590b 100644 --- a/python/src/die.cpp +++ b/python/src/die.cpp @@ -123,7 +123,7 @@ NB_MODULE(_die, m) .export_values(); m.doc() = "The native `die` module"; - m.attr("__version__") = "0.5.1"; + m.attr("__version__") = "0.5.0"; m.attr("die_version") = DIE_VERSION; m.attr("dielib_version") = DIELIB_VERSION;