add python bindings

This commit is contained in:
Bechir
2024-03-07 03:09:43 +01:00
parent 22fb8763be
commit 5690a61284
10 changed files with 147 additions and 46 deletions

1
python/CMakeLists.txt Normal file
View File

@ -0,0 +1 @@
pybind11_add_module(_aare src/bindings.cpp)

57
python/aare/File.py Normal file
View File

@ -0,0 +1,57 @@
import json
from typing import Any
import _aare
import os
class File:
"""
File class. uses proxy pattern to wrap around the pybinding class
abstracts the python binding class that is requires type and detector information
(e.g. _FileHandler_Jungfrau_16)
"""
def __init__(self, path):
"""
opens the master file and checks the dynamic range and detector
"""
self.path = path
# check if file exists
if not os.path.exists(path):
raise FileNotFoundError(f"File not found: {path}")
ext = os.path.splitext(path)[1]
if ext not in (".raw", ".json"):
raise ValueError(f"Invalid file extension: {ext}")
if ext == ".json":
# read the master file and get the detector and bitdepth
master_data = json.load(open(path))
detector = master_data["Detector Type"]
bitdepth = None
if 'Dynamic Range' not in master_data and detector == "Jungfrau":
bitdepth = 16
else:
bitdepth = master_data["Dynamic Range"]
else:
NotImplementedError("Raw file not implemented yet")
# class_name is of the form _FileHandler_Jungfrau_16...
class_name = f"_FileHandler_{detector}_{bitdepth}"
# this line is the equivalent of:
# self._file = _FileHandler_Jungfrau_16(path)
self._file = getattr(_aare, class_name)(path)
def __getattribute__(self, __name: str) -> Any:
"""
Proxy pattern to call the methods of the _file
"""
return getattr(object.__getattribute__(self, "_file"), __name)

16
python/aare/Frame.py Normal file
View File

@ -0,0 +1,16 @@
from typing import Any
class Frame:
"""
Frame class. uses proxy pattern to wrap around the pybinding class
the intention behind it is to only use one class for frames in python (not Frame_8, Frame_16, etc)
"""
def __init__(self, frameImpl):
self._frameImpl = frameImpl
def __getattribute__(self, __name: str) -> Any:
"""
Proxy pattern to call the methods of the frameImpl
"""
return getattr(object.__getattribute__(self, "_frameImpl"), __name)

3
python/aare/__init__.py Normal file
View File

@ -0,0 +1,3 @@
from _aare import *
from .Frame import Frame
from .File import File

View File

View File

@ -0,0 +1,7 @@
from aare import File, Frame
if __name__ == "__main__":
file = File("/home/bb/github/aare/data/jungfrau_single_master_0.json")
frame = file.get_frame(0)
print(frame.rows, frame.cols)
print(frame.get(0,0))

41
python/src/bindings.cpp Normal file
View File

@ -0,0 +1,41 @@
#include <cstdint>
#include <filesystem>
#include <pybind11/pybind11.h>
#include <string>
#include "common/defs.hpp"
#include "core/Frame.hpp"
#include "file_io/FileHandler.hpp"
namespace py = pybind11;
PYBIND11_MODULE(_aare, m) {
// helps to convert from std::string to std::filesystem::path
py::class_<std::filesystem::path>(m, "Path")
.def(py::init<std::string>());
py::implicitly_convertible<std::string, std::filesystem::path>();
//TODO: find a solution to avoid code duplication and include other detectors
py::class_<FileHandler<DetectorType::Jungfrau, uint16_t>>(m, "_FileHandler_Jungfrau_16")
.def(py::init<std::filesystem::path>())
.def("get_frame", &FileHandler<DetectorType::Jungfrau, uint16_t>::get_frame);
py::enum_<DetectorType>(m, "DetectorType");
py::class_<Frame<uint16_t>>(m, "_Frame16")
.def(py::init<std::byte*, ssize_t, ssize_t>())
.def("get", &Frame<uint16_t>::get)
.def_readonly("rows", &Frame<uint16_t>::rows)
.def_readonly("cols", &Frame<uint16_t>::cols)
.def_readonly("bitdepth", &Frame<uint16_t>::bitdepth);
}