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
41 changes: 41 additions & 0 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Build

on:
pull_request:
branches:
- main
push:
branches:
- main

jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]

steps:
- uses: actions/checkout@v6
with:
submodules: recursive
persist-credentials: false

# Used to host cibuildwheel
- uses: actions/setup-python@v6

- name: Install cibuildwheel
run: python -m pip install cibuildwheel==4.0.0rc1

- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
# to supply options, put them in 'env', like:
# env:
# CIBW_SOME_OPTION: value
# ...

- uses: actions/upload-artifact@v6
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "extern/rayx"]
path = extern/rayx
url = https://github.com/hz-b/rayx
[submodule "extern/nanobind"]
path = extern/nanobind
url = https://github.com/wjakob/nanobind
13 changes: 2 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
cmake_minimum_required(VERSION 3.25.2)

if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Install prefix" FORCE)
endif()

project(rayx-python)
add_subdirectory(extern)
add_subdirectory(src)
add_subdirectory(extern EXCLUDE_FROM_ALL)
add_subdirectory(rayx)

# Install Python package
install(DIRECTORY python/rayx DESTINATION .)

# Create and install rayxdata package (needed by C++ code)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/rayxdata/__init__.py" "")
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rayxdata" DESTINATION .)
57 changes: 3 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,60 +12,9 @@ pip install rayx

## Development

The project has two separate concerns that use different tools:

- **uv** manages the Python virtual environment and dependencies (numpy, pytest, etc.)
- **setup_dev.sh** builds the C++ extension and wires everything up for a fast dev loop
- **cibuildwheel** builds the final distributable wheel for release

### Setup

```bash
./setup_dev.sh
source .venv/bin/activate
```

`setup_dev.sh` will:
1. Create a virtual environment with uv if one doesn't exist
2. Build the C++ extension via CMake
3. Symlink the compiled `_core.so` into `python/rayx/` so it can be imported directly
4. Symlink `rayxdata` from the build directory
5. Generate `python/rayx/_core.pyi` type stubs so your LSP can resolve symbols from the C++ module


### Project structure

```
python/rayx/
├── __init__.py # Python wrapper and public API
├── _core.so # Symlink to compiled C++ extension (generated by setup_dev.sh)
├── _core.pyi # Type stubs for LSP (generated by setup_dev.sh, do not edit)
└── [...].py # Additional files/directories for organization (need to be added to __init__.py)
```

### LSP / editor support

Type stubs are generated automatically by `setup_dev.sh`. Point your LSP at the venv Python interpreter (`.venv/bin/python3`) and symbol resolution for `_core` will work out of the box.

If you need to regenerate stubs without a full rebuild:

```bash
source .venv/bin/activate
python3 -c "
import sys
sys.path.insert(0, 'python')
import rayx._core as m
with open('python/rayx/_core.pyi', 'w') as f:
f.write('# Auto-generated stub - do not edit, regenerated by setup_dev.sh\n')
for name in dir(m):
if name.startswith('_'): continue
obj = getattr(m, name)
if callable(obj):
f.write(f'def {name}(*args, **kwargs): ...\n')
else:
f.write(f'{name}: object\n')
"
```
To develop the package you need to:
1. build the core module with cmake
2.

### Running tests

Expand Down
70 changes: 36 additions & 34 deletions examples/metrix.ipynb

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions extern/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
set(RAYX_STATIC_LIB ON)
set(RAYX_BUILD_RAYX_CLI NO)
set(RAYX_BUILD_RAYX_UI NO)
set(RAYX_CUSTOM_DATA_DIR "rayxdata/share" CACHE STRING "Set this val")
# set(RAYX_CUSTOM_DATA_DIR "rayxdata/share" CACHE STRING "Set this val")

add_subdirectory(rayx)
add_subdirectory(pybind11)
add_subdirectory(nanobind)
1 change: 1 addition & 0 deletions extern/nanobind
Submodule nanobind added at 4bfeca
1 change: 0 additions & 1 deletion extern/pybind11
Submodule pybind11 deleted from 58c382
2 changes: 1 addition & 1 deletion extern/rayx
Submodule rayx updated 142 files
4 changes: 2 additions & 2 deletions publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

# publish to pypi if argument is RELEASE
if [ "$1" == "RELEASE" ]; then
./venv/bin/python3 -m twine upload --verbose --repository pypi wheelhouse/*
./.venv/bin/python3 -m twine upload --verbose --repository pypi wheelhouse/*
# publish to testpypi if argument is TEST
elif [ "$1" == "TEST" ]; then
./venv/bin/python3 -m twine upload --verbose --repository testpypi wheelhouse/*
./.venv/bin/python3 -m twine upload --verbose --repository testpypi wheelhouse/*
# error message if argument is not RELEASE or TEST
else
echo "Please provide either RELEASE or TEST as an argument"
Expand Down
19 changes: 8 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
[project]
name = "rayx"
version = "0.4.3"
version = "0.4.5"
description = "Python bindings for RAYX"
readme = "README.md"
license = { file = "LICENSE" }
dependencies = [
"matplotlib>=3.9.4",
"numpy >= 2.0.0",
"pandas>=2.3.3",
"pytest>=8.4.2",
Expand All @@ -16,18 +17,11 @@ maintainers = [
]

[project.optional-dependencies]
dev = [
"pytest>=7.0",
"matplotlib>=3.5",
"ipython",
]
test = [
"pytest>=7.0",
"pytest-cov",
]
dev = ["pytest>=7.0", "matplotlib>=3.5", "ipython"]
test = ["pytest>=7.0", "pytest-cov"]

[build-system]
requires = ["scikit-build-core", "pybind11"]
requires = ["scikit-build-core", "nanobind"]
build-backend = "scikit_build_core.build"

[tool.scikit-build]
Expand All @@ -44,3 +38,6 @@ pythonpath = ["python"]

[tool.uv]
package = false

[dependency-groups]
dev = ["twine>=6.2.0"]
37 changes: 0 additions & 37 deletions python/rayx/__init__.py

This file was deleted.

34 changes: 0 additions & 34 deletions python/rayx/data.py

This file was deleted.

50 changes: 50 additions & 0 deletions rayx/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
project(rayxpy LANGUAGES CXX CUDA)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_STANDARD 20)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF)

if (CMAKE_VERSION VERSION_LESS 3.18)
set(DEV_MODULE Development)
else()
set(DEV_MODULE Development.Module)
endif()

find_package(Python 3.9 COMPONENTS Interpreter ${DEV_MODULE} REQUIRED)

# Changed from 'rayx' to 'core' to make it a private module
nanobind_add_module(core main.cpp)
nanobind_add_stub(
core_stub
MODULE core
OUTPUT core.pyi
PYTHON_PATH $<TARGET_FILE_DIR:core>
DEPENDS core
)
target_link_libraries(core PRIVATE rayx-core)
target_include_directories(core PRIVATE
$<TARGET_PROPERTY:rayx-core,INTERFACE_INCLUDE_DIRECTORIES>
${CUDA_TOOLKIT_INCLUDE})

add_custom_command(
TARGET core
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${RAYX_SOURCE_DIR}/Data"
"${CMAKE_CURRENT_BINARY_DIR}/share/RAYX/Data"
)

file(GLOB_RECURSE PY_SRC *.py)

add_custom_command(
TARGET core
COMMAND ${CMAKE_COMMAND} -E copy
${PY_SRC}
"${CMAKE_CURRENT_BINARY_DIR}"
)

# Install the core library, *.py files and the share subdirectory to the "." install location for scikit_build_core
install(TARGETS core DESTINATION rayx)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/core.pyi" DESTINATION rayx)
install(FILES ${PY_SRC} DESTINATION rayx)
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/share/RAYX/Data" DESTINATION rayx/share/RAYX)
46 changes: 46 additions & 0 deletions rayx/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
RAY-X Python bindings
"""
import sys
from pathlib import Path

# Import the C++ extension module

# In development, we want to import from the local build directory

try:
from . import core
from .core import *
except ImportError:
# If the import fails, we might be in a development environment where the module is not built yet
# We can try to import from the build directory
build_dir = Path(__file__).parent.parent / "build" / "rayx"
if build_dir.exists():
sys.path.insert(0, str(build_dir))
try:
import core
from core import *
except ImportError:
raise ImportError("Could not import the RAYX C++ extension module. Make sure it is built and available.")
else:
raise ImportError("Could not import the RAYX C++ extension module. Make sure it is built and available.")




def get_info():
"""Get information about the RAYX installation"""
info = {
"version": __version__,
"python_wrapper": True,
"cpp_module": str(core.__file__),
"module_path": str(Path(__file__).parent),
}
return info

# From other files
from .data import rays_to_df

__name__ = "rayx"
__version__ = "0.4.3"
__all__ = ['get_info', 'rays_to_df']
Loading
Loading