Skip to content
Merged
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
18 changes: 10 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
Expand All @@ -39,7 +39,7 @@ jobs:
name: Format, static analysis, snapshot, and metadata
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: prefix-dev/setup-pixi@v0.10.0
Expand All @@ -66,9 +66,11 @@ jobs:
pixi run python - <<'PY'
from importlib.metadata import metadata, version

import pynetft

project = metadata("pynetft")
assert project["Name"] == "pynetft"
assert version("pynetft") == "2.0.1"
assert version("pynetft") == pynetft.__version__
assert project["Requires-Python"] == ">=3.10"
PY

Expand All @@ -80,7 +82,7 @@ jobs:
matrix:
build-type: [Debug, Release]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: prefix-dev/setup-pixi@v0.10.0
Expand Down Expand Up @@ -108,7 +110,7 @@ jobs:
arch: arm64
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: prefix-dev/setup-pixi@v0.10.0
Expand Down Expand Up @@ -140,7 +142,7 @@ jobs:
- library: static
build-shared: "OFF"
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: prefix-dev/setup-pixi@v0.10.0
Expand All @@ -164,7 +166,7 @@ jobs:
name: Native ASan and UBSan
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: prefix-dev/setup-pixi@v0.10.0
Expand Down Expand Up @@ -200,7 +202,7 @@ jobs:
name: ARM64 Release
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: prefix-dev/setup-pixi@v0.10.0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
build-mode: manual
suppression-pack: +codeql/cpp-queries:AlertSuppression.ql
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- name: Initialize Python CodeQL
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
coverage:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: prefix-dev/setup-pixi@v0.10.0
Expand Down
31 changes: 30 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,35 @@ jobs:
path: wheelhouse/*.whl
if-no-files-found: error

windows-wheels:
needs: validate
runs-on: windows-2025
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14"
cache: pip
- name: Install wheel build and validation tools
run: python -m pip install cibuildwheel==3.4.1 pefile twine
- name: Build and install-test every supported wheel
run: python -m cibuildwheel --platform windows --output-dir wheelhouse
env:
CIBW_ARCHS_WINDOWS: AMD64
- name: Validate every wheel
shell: pwsh
run: |
$wheels = Get-ChildItem wheelhouse/*.whl
python -m twine check $wheels
python tools/check_wheel.py --self-contained $wheels
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-wheels-windows-x86_64
path: wheelhouse/*.whl
if-no-files-found: error

sdist:
needs: validate
runs-on: ubuntu-24.04
Expand All @@ -173,7 +202,7 @@ jobs:
if-no-files-found: error

assemble:
needs: [wheels, macos-wheels, sdist]
needs: [wheels, macos-wheels, windows-wheels, sdist]
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
Expand Down
69 changes: 64 additions & 5 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
curl-build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
Expand All @@ -39,7 +39,7 @@ jobs:
needs: curl-build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
Expand Down Expand Up @@ -78,7 +78,7 @@ jobs:
runner: macos-15
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
Expand All @@ -104,6 +104,36 @@ jobs:
path: wheelhouse/*.whl
if-no-files-found: error

windows-smoke:
if: github.event_name == 'pull_request'
needs: curl-build
runs-on: windows-2025
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14"
cache: pip
- name: Install wheel build frontend
run: python -m pip install cibuildwheel==3.4.1 pefile
- name: Build CPython 3.10 Windows wheel
run: python -m cibuildwheel --platform windows --output-dir wheelhouse
env:
CIBW_BUILD: cp310-*
CIBW_ARCHS_WINDOWS: AMD64
- name: Validate wheel structure and dependencies
shell: pwsh
run: |
$wheels = Get-ChildItem wheelhouse/*.whl
python tools/check_wheel.py --self-contained $wheels
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: wheels-smoke-windows-x86_64
path: wheelhouse/*.whl
if-no-files-found: error

wheels:
if: github.event_name != 'pull_request'
needs: curl-build
Expand All @@ -117,7 +147,7 @@ jobs:
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
Expand Down Expand Up @@ -155,7 +185,7 @@ jobs:
runner: macos-15
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
Expand All @@ -179,3 +209,32 @@ jobs:
name: wheels-macos-${{ matrix.arch }}
path: wheelhouse/*.whl
if-no-files-found: error

windows-wheels:
if: github.event_name != 'pull_request'
needs: curl-build
runs-on: windows-2025
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14"
cache: pip
- name: Install wheel build frontend
run: python -m pip install cibuildwheel==3.4.1 pefile
- name: Build supported Windows wheels
run: python -m cibuildwheel --platform windows --output-dir wheelhouse
env:
CIBW_ARCHS_WINDOWS: AMD64
- name: Validate wheel structure and dependencies
shell: pwsh
run: |
$wheels = Get-ChildItem wheelhouse/*.whl
python tools/check_wheel.py --self-contained $wheels
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: wheels-windows-x86_64
path: wheelhouse/*.whl
if-no-files-found: error
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

All notable changes to this project are documented in this file.

## 2.1.0 - 2026-07-29

### Added

- Publish self-contained CPython 3.10–3.14 wheels for 64-bit Windows.

### Changed

- Update the pinned native core to netft-cpp 0.3.0, including its WinSock transport and cross-platform lifecycle coverage.
- Build a pinned static HTTP-only curl dependency for Windows wheels.

## 2.0.1 - 2026-07-25

### Added
Expand Down
14 changes: 13 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
cmake_minimum_required(VERSION 3.16)
project(pynetft VERSION 2.0.1 LANGUAGES CXX)
project(pynetft VERSION 2.1.0 LANGUAGES CXX)

option(PYNETFT_BUILD_TESTING "Build pyNetFT native tests" OFF)

set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
set(NETFT_BUILD_CLI OFF CACHE BOOL "" FORCE)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
find_package(pybind11 CONFIG REQUIRED)

add_subdirectory(core EXCLUDE_FROM_ALL)
if(WIN32)
target_compile_definitions(netft PRIVATE CURL_STATICLIB)
target_link_libraries(netft PRIVATE
advapi32
bcrypt
crypt32
iphlpapi
secur32
ws2_32
)
endif()

pybind11_add_module(_native MODULE
bindings/python/bind_types.cpp
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@

pyNetFT is a synchronous, typed Python client for ATI Industrial Automation Net F/T Ethernet force/torque sensors. It discovers the sensor calibration, streams RDT measurements through a native C++ core, and exposes raw counts, physical measurements, health, and recovery information without requiring NumPy.

- **Tested native core:** the protocol and recovery implementation is pinned to [netft-cpp 0.2.2](https://github.com/netft/netft-cpp/releases/tag/v0.2.2), includes its GCC 10/manylinux2014 compatibility fix and corrected libcurl minimum, and is exercised with offline fake sensors and native sanitizers.
- **Tested native core:** the protocol and recovery implementation is pinned to [netft-cpp 0.3.0](https://github.com/netft/netft-cpp/releases/tag/v0.3.0) and is exercised with offline fake sensors and native sanitizers.
- **Sensor-aware data:** calibration, force and torque units, configuration revisions, sequence progress, and faults remain visible to the application.
- **Self-contained typed wheels:** Linux and macOS wheels include the native core and a minimal static HTTP-only curl build, plus inline type information for Python 3.10–3.14.
- **Self-contained typed wheels:** Linux, macOS, and Windows wheels include the native core and a minimal static HTTP-only curl build, plus inline type information for Python 3.10–3.14.

## Supported platforms

| Install method | Platform | Support |
| --- | --- | --- |
| PyPI | Linux and macOS (x86_64 and ARM64), CPython 3.10–3.14 | Supported |
| Source | Linux, macOS, and other POSIX systems, CPython 3.10–3.14 | Best effort |
| PyPI | Linux and macOS (x86_64 and ARM64), Windows (x86_64), CPython 3.10–3.14 | Supported |
| Source | Linux, macOS, Windows, and other supported C++17 platforms, CPython 3.10–3.14 | Best effort |

Windows, PyPy, and asyncio are not supported by the 2.x package.
PyPy and asyncio are not supported by the 2.x package.

## Installation

Expand Down
36 changes: 23 additions & 13 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
cmake_minimum_required(VERSION 3.16)

project(netft VERSION 0.2.2 LANGUAGES CXX)
project(netft VERSION 0.3.0 LANGUAGES CXX)

include(CTest)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

option(NETFT_SANITIZERS "Enable address and undefined behavior sanitizers" OFF)
option(NETFT_BUILD_CLI "Build the netft command-line tool" ON)

add_library(netft_sanitizers INTERFACE)
if(NETFT_SANITIZERS)
Expand All @@ -31,11 +32,16 @@ add_library(netft
src/client.cpp
src/detail/client_impl.cpp
src/detail/fault_latch.cpp
src/detail/posix_transport.cpp
src/detail/protocol.cpp
src/detail/sequence.cpp
src/detail/xml_config.cpp
)
if(WIN32)
target_sources(netft PRIVATE src/detail/udp_transport_windows.cpp)
target_link_libraries(netft PRIVATE ws2_32)
else()
target_sources(netft PRIVATE src/detail/udp_transport_posix.cpp)
endif()
add_library(netft::netft ALIAS netft)

target_compile_definitions(netft PRIVATE NETFT_BUILDING_LIBRARY)
Expand All @@ -62,14 +68,16 @@ target_link_libraries(netft
$<BUILD_INTERFACE:netft_sanitizers>
)

add_library(netft_cli_lib STATIC app/cli.cpp)
target_compile_features(netft_cli_lib PUBLIC cxx_std_17)
target_include_directories(netft_cli_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/app)
target_link_libraries(netft_cli_lib PUBLIC netft::netft)
if(NETFT_BUILD_CLI)
add_library(netft_cli_lib STATIC app/cli.cpp)
target_compile_features(netft_cli_lib PUBLIC cxx_std_17)
target_include_directories(netft_cli_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/app)
target_link_libraries(netft_cli_lib PUBLIC netft::netft)

add_executable(netft_cli app/main.cpp)
set_target_properties(netft_cli PROPERTIES OUTPUT_NAME netft)
target_link_libraries(netft_cli PRIVATE netft_cli_lib)
add_executable(netft_cli app/main.cpp)
set_target_properties(netft_cli PROPERTIES OUTPUT_NAME netft)
target_link_libraries(netft_cli PRIVATE netft_cli_lib)
endif()

install(
DIRECTORY include/netft
Expand All @@ -82,10 +90,12 @@ install(
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(
TARGETS netft_cli
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if(NETFT_BUILD_CLI)
install(
TARGETS netft_cli
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
endif()

set(netft_cmake_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/netft")
configure_package_config_file(
Expand Down
Loading
Loading