Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e4431cd
[cppinterop] Add Cling-specific RAII, lookup and dispatch patches [u…
aaronj0 Apr 23, 2026
19793d0
[cppinterop] Fix GetEnumConstantValue when value can't be within int6…
aaronj0 May 11, 2026
a7f2614
[cppinterop] Fix JitCall codegen for deleted copy ctor in args [upstr…
aaronj0 May 11, 2026
52d1baf
[cppinterop] Use canonical return type in wrapper codegen [upstream]
aaronj0 May 21, 2026
83921a7
[cppyy-backend] Replace clingwrapper with compres forks [fork-baseline]
aaronj0 Apr 23, 2026
7f955af
[cppyy-backend] fix GetActualClass for null [upstream]
aaronj0 May 11, 2026
fea3742
[cppyy-backend] Add function-type comparison APIs [upstream]
aaronj0 May 21, 2026
e7bdfd6
[cppyy-backend] Pass CPPINTEROP_DIR directly to AddIncludePath [ROOT-…
aaronj0 May 19, 2026
c256ae2
[cppyy-backend] Apply ROOT patches on compres fork baseline [ROOT-pa…
aaronj0 Apr 23, 2026
3f1b4ae
[cppyy-backend] Stage CppInterOp headers via etc/cppinterop [ROOT-patch]
aaronj0 May 19, 2026
01fdbbf
[cppyy] Replace frontend with compres forks [fork-baseline]
aaronj0 Apr 24, 2026
5ae40df
[cppyy] Use qualified complete name for basic_string<char> NPOS check…
aaronj0 Apr 30, 2026
3cbdfb9
[cppyy] Apply ROOT-specific patches [ROOT-patch]
aaronj0 Apr 24, 2026
90de054
[CPyCppyy] Replace with compres forks [fork-baseline]
aaronj0 Apr 23, 2026
0b702fe
[CPyCppyy] Refactor CallContext policy system, add Py 3.13 guard [up…
aaronj0 Apr 24, 2026
f96dbf3
[CPyCppyy] Add converters/low-level views for fixed width integers […
aaronj0 Apr 24, 2026
8f6e6cb
[CPyCppyy] Fix typos, call GetActualClass in instance cast_actual [u…
aaronj0 Apr 23, 2026
1d761fe
[CPyCppyy] Use TCppType_t for fCppType and fUnderlyingType [upstream]
aaronj0 Apr 23, 2026
4ed5dee
[CPyCppyy] Apply memory policy refactor to CPPOverload.cxx [upstream]
aaronj0 Apr 23, 2026
542dd17
[CPyCppyy] Add CStringArrayConverter::ToMemory and buffer helper [up…
aaronj0 Apr 24, 2026
2ad2f28
[CPyCppyy] Add missing override on HasState in CPPYY_DECLARE_ARRAY_CO…
aaronj0 Apr 23, 2026
8ca272b
[CPyCppyy] Collapse CPyCppyyModule policy setters into a macro [upst…
aaronj0 Apr 24, 2026
6108147
[CPyCppyy] Use CallContext flag for implicit conversion check [upstr…
aaronj0 Apr 23, 2026
02d3a69
[CPyCppyy] Pythonize: fix __iadd__ return and disable buggy __array__…
aaronj0 Apr 24, 2026
19ba256
[CPyCppyy] add std::span branch in TCppType_t CreateConverter overloa…
aaronj0 Apr 30, 2026
4b43493
[CPyCppyy] Use complete basic_string<char> name with default template…
aaronj0 Apr 30, 2026
0ab1073
[CPyCppyy] Fall through to generic Python callable if overload signat…
aaronj0 May 4, 2026
8e6af49
[CPyCppyy] Match function-pointer overloads via TCppType_t [upstream]
aaronj0 May 21, 2026
3ba8a4c
[CPyCppyy] declare gException, drop CPYCPPYY_IMPORT from CPPInstance …
aaronj0 Apr 24, 2026
c293529
[CPyCppyy] Add more converter/executor name aliases [ROOT-patch]
aaronj0 Apr 24, 2026
13c7156
[CPyCppyy] Rename PyInit_libcppyy to Init for ROOT module split [ROO…
aaronj0 Apr 24, 2026
fef7186
[CPyCppyy] Pythonize: add std::span support and no-std wstring aliase…
aaronj0 Apr 24, 2026
eabb6f0
[CPyCppyy] Add __template_args__ and signature-plus-template overload…
aaronj0 Apr 23, 2026
b6c658a
[CPyCppyy] Always convert returned to Python string [ROOT-patch]
aaronj0 May 1, 2026
c724775
[CPyCppyy] Fix false addition of STLSequenceIter for pointer return-t…
aaronj0 May 3, 2026
d8dcef4
[cppyy] Update test std.string type checks to Python str [ROOT-patch]
aaronj0 May 2, 2026
070f3df
[cppyy] Newly enabled tests in ROOT by CppInterOp [ROOT-patch]
aaronj0 Apr 26, 2026
feeb239
[pyroot] Exclude canonical std::string from generic pretty-printer [R…
aaronj0 May 1, 2026
edf9112
[Python] Pythonize templated classes cached in namespace [ROOT-patch]
aaronj0 May 21, 2026
6923f10
[pyroot] Refactor RDF Filter/Define callable dispatch [ROOT-patch]
aaronj0 May 21, 2026
08d18b3
[Python] Inject `gPad` and `gVirtualX` into facade without ROOT meta
guitargeek May 4, 2026
f3b7dfb
[ROOT] Workaround diagnostics when slow type lookup of literal in TCo…
aaronj0 May 4, 2026
fa9056b
[ROOT] Use value_type instead of string manipulation to pythonize stl…
aaronj0 May 11, 2026
4a3cf9c
[ROOT][test] Canonical name includes UL suffix for literal
aaronj0 May 11, 2026
78f3fd4
[cppyy-backend] Fast-path identifier lookups in Cppyy::GetType / Appe…
aaronj0 May 26, 2026
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
11 changes: 7 additions & 4 deletions bindings/pyroot/cppyy/CPyCppyy/include/CPyCppyy/API.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
#endif
#include "Python.h"

#define CPYCPPYY_VERSION_HEX 0x010c10
#define CPYCPPYY_VERSION_HEX 0x011200

// Cppyy types
namespace Cppyy {
typedef size_t TCppScope_t;
typedef void* TCppScope_t;
typedef TCppScope_t TCppType_t;
typedef void* TCppEnum_t;
typedef void* TCppObject_t;
typedef intptr_t TCppMethod_t;
typedef void* TCppMethod_t;

typedef size_t TCppIndex_t;
typedef void* TCppFuncAddr_t;
Expand Down Expand Up @@ -123,6 +123,7 @@ class CPYCPPYY_CLASS_EXTERN Converter {

// create a converter based on its full type name and dimensions
CPYCPPYY_EXTERN Converter* CreateConverter(const std::string& name, cdims_t = 0);
CPYCPPYY_EXTERN Converter* CreateConverter(Cppyy::TCppType_t type, cdims_t = 0);

// delete a previously created converter
CPYCPPYY_EXTERN void DestroyConverter(Converter* p);
Expand Down Expand Up @@ -153,6 +154,7 @@ class CPYCPPYY_CLASS_EXTERN Executor {

// create an executor based on its full type name
CPYCPPYY_EXTERN Executor* CreateExecutor(const std::string& name, cdims_t = 0);
CPYCPPYY_EXTERN Executor* CreateExecutor(Cppyy::TCppType_t type, cdims_t = 0);

// delete a previously created executor
CPYCPPYY_EXTERN void DestroyConverter(Converter* p);
Expand Down Expand Up @@ -183,7 +185,8 @@ CPYCPPYY_EXTERN void* Instance_AsVoidPtr(PyObject* pyobject);
// void* to C++ Instance (python object proxy) conversion, returns a new reference
CPYCPPYY_EXTERN PyObject* Instance_FromVoidPtr(
void* addr, const std::string& classname, bool python_owns = false);

CPYCPPYY_EXTERN PyObject* Instance_FromVoidPtr(
void* addr, Cppyy::TCppScope_t klass_scope, bool python_owns = false);
// type verifiers for C++ Scope
CPYCPPYY_EXTERN bool Scope_Check(PyObject* pyobject);
CPYCPPYY_EXTERN bool Scope_CheckExact(PyObject* pyobject);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,29 @@
#ifdef _MSC_VER
// Windows requires symbols to be explicitly exported
#define CPYCPPYY_EXPORT extern __declspec(dllexport)
#define CPYCPPYY_IMPORT extern __declspec(dllimport)
#define CPYCPPYY_CLASS_EXPORT __declspec(dllexport)

// CPYCPPYY_EXTERN is dual use in the public API
#ifndef CPYCPPYY_INTERNAL
#define CPYCPPYY_EXTERN extern __declspec(dllexport)
#define CPYCPPYY_CLASS_EXTERN __declspec(dllexport)
#else
#define CPYCPPYY_EXTERN extern
#define CPYCPPYY_CLASS_EXTERN
#define CPYCPPYY_EXTERN extern __declspec(dllimport)
#define CPYCPPYY_CLASS_EXTERN __declspec(dllimport)
#endif

#define CPYCPPYY_STATIC

#else
// Linux, Mac, etc.
#define CPYCPPYY_EXPORT extern
#define CPYCPPYY_IMPORT extern
#define CPYCPPYY_CLASS_EXPORT
#define CPYCPPYY_EXTERN extern
#define CPYCPPYY_CLASS_EXTERN
#define CPYCPPYY_STATIC static

#endif

#define CPYCPPYY_IMPORT extern

#endif // !CPYCPPYY_COMMONDEFS_H
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,16 @@

// Bindings
#include "CPyCppyy/CommonDefs.h"

#include <Python.h>

namespace CPyCppyy {
class PythonGILRAII {
PyGILState_STATE state;

public:
PythonGILRAII() : state(PyGILState_Ensure()) {}
~PythonGILRAII() { PyGILState_Release(state); }
};

class CPYCPPYY_CLASS_EXTERN DispatchPtr {
public:
Expand Down
40 changes: 39 additions & 1 deletion bindings/pyroot/cppyy/CPyCppyy/src/API.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "CPPInstance.h"
#include "CPPOverload.h"
#include "CPPScope.h"
#include "CPyCppyy/DispatchPtr.h"
#include "ProxyWrappers.h"
#include "PyStrings.h"

Expand Down Expand Up @@ -85,6 +86,7 @@ static bool Initialize()
}

if (!gMainDict) {
CPyCppyy::PythonGILRAII python_gil_raii;
// retrieve the main dictionary
gMainDict = PyModule_GetDict(
PyImport_AddModule(const_cast<char*>("__main__")));
Expand Down Expand Up @@ -121,6 +123,8 @@ void* CPyCppyy::Instance_AsVoidPtr(PyObject* pyobject)
if (!Initialize())
return nullptr;

PythonGILRAII python_gil_raii;

// check validity of cast
if (!CPPInstance_Check(pyobject))
return nullptr;
Expand All @@ -137,6 +141,8 @@ PyObject* CPyCppyy::Instance_FromVoidPtr(
if (!Initialize())
return nullptr;

PythonGILRAII python_gil_raii;

// perform cast (the call will check TClass and addr, and set python errors)
PyObject* pyobject = BindCppObjectNoCast(addr, Cppyy::GetScope(classname), false);

Expand All @@ -147,6 +153,25 @@ PyObject* CPyCppyy::Instance_FromVoidPtr(
return pyobject;
}

//-----------------------------------------------------------------------------
PyObject* CPyCppyy::Instance_FromVoidPtr(
void* addr, Cppyy::TCppScope_t klass_scope, bool python_owns)
{
// Bind the addr to a python object of class defined by classname.
if (!Initialize())
return nullptr;

PythonGILRAII python_gil_raii;

// perform cast (the call will check TClass and addr, and set python errors)
PyObject* pyobject = BindCppObjectNoCast(addr, klass_scope, false);

// give ownership, for ref-counting, to the python side, if so requested
if (python_owns && CPPInstance_Check(pyobject))
((CPPInstance*)pyobject)->PythonOwns();

return pyobject;
}
namespace CPyCppyy {
// version with C type arguments only for use with Numba
PyObject* Instance_FromVoidPtr(void* addr, const char* classname, int python_owns) {
Expand All @@ -161,6 +186,7 @@ bool CPyCppyy::Scope_Check(PyObject* pyobject)
if (!Initialize())
return false;

PythonGILRAII python_gil_raii;
return CPPScope_Check(pyobject);
}

Expand All @@ -171,6 +197,7 @@ bool CPyCppyy::Scope_CheckExact(PyObject* pyobject)
if (!Initialize())
return false;

PythonGILRAII python_gil_raii;
return CPPScope_CheckExact(pyobject);
}

Expand All @@ -181,6 +208,7 @@ bool CPyCppyy::Instance_Check(PyObject* pyobject)
if (!Initialize())
return false;

PythonGILRAII python_gil_raii;
// detailed walk through inheritance hierarchy
return CPPInstance_Check(pyobject);
}
Expand All @@ -192,6 +220,7 @@ bool CPyCppyy::Instance_CheckExact(PyObject* pyobject)
if (!Initialize())
return false;

PythonGILRAII python_gil_raii;
// direct pointer comparison of type member
return CPPInstance_CheckExact(pyobject);
}
Expand Down Expand Up @@ -225,6 +254,7 @@ void CPyCppyy::Instance_SetCppOwns(PyObject* pyobject)
//-----------------------------------------------------------------------------
bool CPyCppyy::Sequence_Check(PyObject* pyobject)
{
PythonGILRAII python_gil_raii;
// Extends on PySequence_Check() to determine whether an object can be iterated
// over (technically, all objects can b/c of C++ pointer arithmetic, hence this
// check isn't 100% accurate, but neither is PySequence_Check()).
Expand Down Expand Up @@ -258,6 +288,7 @@ bool CPyCppyy::Sequence_Check(PyObject* pyobject)
//-----------------------------------------------------------------------------
bool CPyCppyy::Instance_IsLively(PyObject* pyobject)
{
PythonGILRAII python_gil_raii;
// Test whether the given instance can safely return to C++
if (!CPPInstance_Check(pyobject))
return true; // simply don't know
Expand All @@ -277,6 +308,7 @@ bool CPyCppyy::Overload_Check(PyObject* pyobject)
if (!Initialize())
return false;

PythonGILRAII python_gil_raii;
// detailed walk through inheritance hierarchy
return CPPOverload_Check(pyobject);
}
Expand All @@ -288,6 +320,7 @@ bool CPyCppyy::Overload_CheckExact(PyObject* pyobject)
if (!Initialize())
return false;

PythonGILRAII python_gil_raii;
// direct pointer comparison of type member
return CPPOverload_CheckExact(pyobject);
}
Expand All @@ -305,6 +338,8 @@ bool CPyCppyy::Import(const std::string& mod_name)
if (!Initialize())
return false;

PythonGILRAII python_gil_raii;

PyObject* mod = PyImport_ImportModule(mod_name.c_str());
if (!mod) {
PyErr_Print();
Expand Down Expand Up @@ -364,6 +399,8 @@ void CPyCppyy::ExecScript(const std::string& name, const std::vector<std::string
if (!Initialize())
return;

PythonGILRAII python_gil_raii;

// verify arguments
if (name.empty()) {
std::cerr << "Error: no file name specified." << std::endl;
Expand All @@ -388,7 +425,6 @@ void CPyCppyy::ExecScript(const std::string& name, const std::vector<std::string
// build new argv
const int argc = (int)args.size() + 1;
std::vector<wchar_t*> wargv(argc);

wargv[0] = Py_DecodeLocale(name.c_str(), nullptr);

for (int i = 1; i < argc; ++i) {
Expand Down Expand Up @@ -438,6 +474,7 @@ bool CPyCppyy::Exec(const std::string& cmd)
if (!Initialize())
return false;

PythonGILRAII python_gil_raii;
// execute the command
PyObject* result =
PyRun_String(const_cast<char*>(cmd.c_str()), Py_file_input, gMainDict, gMainDict);
Expand All @@ -459,6 +496,7 @@ void CPyCppyy::Prompt() {
if (!Initialize())
return;

PythonGILRAII python_gil_raii;
// enter i/o interactive mode
PyRun_InteractiveLoop(stdin, const_cast<char*>("\0"));
}
2 changes: 1 addition & 1 deletion bindings/pyroot/cppyy/CPyCppyy/src/CPPClassMethod.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ PyObject* CPyCppyy::CPPClassMethod::Call(CPPInstance*&
if ((!self || (PyObject*)self == Py_None) && nargs) {
PyObject* arg0 = CPyCppyy_PyArgs_GET_ITEM(args, 0);
if (CPPInstance_Check(arg0) && fArgsRequired <= nargs - 1 &&
Cppyy::IsSubtype(reinterpret_cast<CPPInstance *>(arg0)->ObjectIsA(), GetScope())) {
Cppyy::IsSubclass(reinterpret_cast<CPPInstance *>(arg0)->ObjectIsA(), GetScope())) {
args += 1; // drops first argument
nargsf -= 1;
}
Expand Down
19 changes: 11 additions & 8 deletions bindings/pyroot/cppyy/CPyCppyy/src/CPPConstructor.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
//- data _____________________________________________________________________
namespace CPyCppyy {
extern PyObject* gNullPtrObject;
void* Instance_AsVoidPtr(PyObject* pyobject);
PyObject* Instance_FromVoidPtr(void* addr, Cppyy::TCppScope_t klass_scope, bool python_owns);
}


Expand Down Expand Up @@ -44,7 +46,7 @@ PyObject* CPyCppyy::CPPConstructor::Reflex(
if (request == Cppyy::Reflex::RETURN_TYPE) {
std::string fn = Cppyy::GetScopedFinalName(this->GetScope());
if (format == Cppyy::Reflex::OPTIMAL || format == Cppyy::Reflex::AS_TYPE)
return CreateScopeProxy(fn);
return CreateScopeProxy(this->GetScope());
else if (format == Cppyy::Reflex::AS_STRING)
return CPyCppyy_PyText_FromString(fn.c_str());
}
Expand All @@ -56,7 +58,6 @@ PyObject* CPyCppyy::CPPConstructor::Reflex(
PyObject* CPyCppyy::CPPConstructor::Call(CPPInstance*& self,
CPyCppyy_PyArgs_t args, size_t nargsf, PyObject* kwds, CallContext* ctxt)
{

// setup as necessary
if (fArgsRequired == -1 && !this->Initialize(ctxt))
return nullptr; // important: 0, not Py_None
Expand All @@ -81,11 +82,12 @@ PyObject* CPyCppyy::CPPConstructor::Call(CPPInstance*& self,
const auto cppScopeFlags = ((CPPScope*)Py_TYPE(self))->fFlags;

// Do nothing if the constructor is explicit and we are in an implicit
// conversion context. We recognize this by checking the CPPScope::kNoImplicit
// flag, as further implicit conversions are disabled to prevent infinite
// recursion. See also the ConvertImplicit() helper in Converters.cxx.
if((cppScopeFlags & CPPScope::kNoImplicit) && Cppyy::IsExplicit(GetMethod()))
return nullptr;
// conversion context. See also the ConvertImplicit() helper in Converters.cxx.
if((cppScopeFlags & CPPScope::kActiveImplicitCall) && Cppyy::IsExplicit(GetMethod())) {
// FIXME: Cases with explicit marked std::complex constructors where we expect implicit conversionss
if (Cppyy::GetMethodSignature(GetMethod(), true).find("std::complex") == std::string::npos)
return nullptr;
}

// self provides the python context for lifelines
if (!ctxt->fPyContext)
Expand Down Expand Up @@ -135,7 +137,7 @@ PyObject* CPyCppyy::CPPConstructor::Call(CPPInstance*& self,

} else {
// translate the arguments
if (cppScopeFlags & CPPScope::kNoImplicit)
if (cppScopeFlags & CPPScope::kActiveImplicitCall)
ctxt->fFlags |= CallContext::kNoImplicit;
if (!this->ConvertAndSetArgs(cargs.fArgs, cargs.fNArgsf, ctxt))
return nullptr;
Expand Down Expand Up @@ -182,6 +184,7 @@ PyObject* CPyCppyy::CPPConstructor::Call(CPPInstance*& self,
return nullptr;
}


//----------------------------------------------------------------------------
CPyCppyy::CPPMultiConstructor::CPPMultiConstructor(Cppyy::TCppScope_t scope, Cppyy::TCppMethod_t method) :
CPPConstructor(scope, method)
Expand Down
Loading
Loading