Skip to content
Open
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
17 changes: 8 additions & 9 deletions cpp/csp/python/Conversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,22 +446,21 @@ inline PyObject * toPython( const CspEnum & e, const CspType & type )
auto & enumType = static_cast<const CspEnumType&>( type );
const auto * emeta = static_cast<const DialectCspEnumMeta*>( enumType.meta().get() );

PyObject * obj = emeta -> pyMeta() -> toPyEnum( e );
if( !obj ) [[unlikely]]
CSP_THROW( ValueError, e.value() << " is not a valid value on csp.enum type " << emeta -> name() );
return obj;
return emeta -> toPyEnum( e.value() );
}

template<>
inline CspEnum fromPython( PyObject * o, const CspType & type )
{
assert( type.type() == CspType::Type::ENUM );

if( !PyType_IsSubtype( Py_TYPE( o ), &PyCspEnum::PyType ) ||
static_cast<PyCspEnum *>( o ) -> meta() != static_cast<const CspEnumType &>( type ).meta().get() )
CSP_THROW( TypeError, "Invalid enum type, expected enum type " << static_cast<const CspEnumType &>( type ).meta() -> name() << " got " << Py_TYPE( o ) -> tp_name );

return static_cast<PyCspEnum *>( o ) -> enum_;
auto & enumType = static_cast<const CspEnumType&>( type );
const auto * emeta = static_cast<const DialectCspEnumMeta*>( enumType.meta().get() );

if( !PyObject_IsInstance( o, ( PyObject * ) emeta -> pyType().get() ) )
CSP_THROW( TypeError, "Invalid enum type, expected enum type " << emeta -> pyType() -> tp_name << " got " << Py_TYPE( o ) -> tp_name );

return static_cast<const CspEnumType &>( type ).meta() -> create( PyLong_AsLong( o ) );
}

//TimeDelta
Expand Down
47 changes: 43 additions & 4 deletions cpp/csp/python/CspTypeFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,23 @@
namespace csp::python
{

CspTypeFactory::CspTypeFactory()
{
PyObject *enum_mod = PyImport_ImportModule( "enum" );
m_intEnumPyType = ( PyTypeObject * ) PyObject_GetAttrString( enum_mod, "IntEnum" );
}

CspTypeFactory & CspTypeFactory::instance()
{
static CspTypeFactory s_instance;
return s_instance;
//We let this leak since some csp types ( ie CspEnum ) can hold a ref to DialectCspEnumMeta which holds Ptrs
//to python objects, which cant be destroyed statically after python interpreter is shutdown
static CspTypeFactory * s_instance = new CspTypeFactory();
return *s_instance;
}

bool CspTypeFactory::isCspEnumPyType( PyTypeObject * pyType )
{
return PyType_IsSubtype( pyType, m_intEnumPyType );
}

CspTypePtr & CspTypeFactory::typeFromPyType( PyObject * pyTypeObj )
Expand Down Expand Up @@ -59,9 +72,9 @@ CspTypePtr & CspTypeFactory::typeFromPyType( PyObject * pyTypeObj )
auto meta = ( ( PyStructMeta * ) pyType ) -> structMeta;
rv.first -> second = std::make_shared<csp::CspStructType>( meta );
}
else if( PyType_IsSubtype( pyType, &PyCspEnum::PyType ) )
else if( isCspEnumPyType( pyType ) )
{
auto meta = ( ( PyCspEnumMeta * ) pyType ) -> enumMeta;
auto meta = createCspEnumMetaFromIntEnum( PyTypeObjectPtr::incref( pyType ) );
rv.first -> second = std::make_shared<csp::CspEnumType>( meta );
}
else if( pyType == PyDateTimeAPI -> DateTimeType )
Expand All @@ -88,4 +101,30 @@ void CspTypeFactory::removeCachedType( PyTypeObject * pyType )
m_cache.erase( pyType );
}

std::shared_ptr<CspEnumMeta> CspTypeFactory::createCspEnumMetaFromIntEnum( PyTypeObjectPtr pyIntEnumType )
{
CspEnumMeta::ValueDef metadef;

PyObjectPtr iter = PyObjectPtr::check( PyObject_GetIter( ( PyObject * ) pyIntEnumType.get() ) );
PyObject * member;
while( ( member = PyIter_Next( iter.get() ) ) != NULL )
{
PyObjectPtr name = PyObjectPtr::check( PyObject_GetAttrString( member, "name" ) );

const char * namestr = PyUnicode_AsUTF8( name.get() );
if( !namestr )
CSP_THROW( PythonPassthrough, "" );

if( !PyLong_Check( member ) )
CSP_THROW( TypeError, "enum key " << namestr << " expected an integer got " << PyObjectPtr::incref( member ) );

int64_t value = fromPython<int64_t>( member );
metadef[ namestr ] = value;

Py_DECREF( member );
}

return std::make_shared<DialectCspEnumMeta>( pyIntEnumType, pyIntEnumType -> tp_name, metadef );
}

}
9 changes: 9 additions & 0 deletions cpp/csp/python/CspTypeFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <csp/core/Platform.h>
#include <csp/engine/CspType.h>
#include <csp/python/PyObjectPtr.h>
#include <unordered_map>
#include <Python.h>

Expand All @@ -17,9 +18,17 @@ class CSPTYPESIMPL_EXPORT CspTypeFactory
CspTypePtr & typeFromPyType( PyObject * );
void removeCachedType( PyTypeObject * );

bool isCspEnumPyType( PyTypeObject * pyType );

private:
using Cache = std::unordered_map<PyTypeObject *, CspTypePtr>;

std::shared_ptr<CspEnumMeta> createCspEnumMetaFromIntEnum( PyTypeObjectPtr pyIntEnumType );

CspTypeFactory();
Cache m_cache;

PyTypeObject * m_intEnumPyType;
};

}
Expand Down
Loading
Loading