Abstract:
I have one cython class which represents a business unit. This class is declared in pure cython style.
In one project, I need to map the business unit to a database. For doing this I would like to import the .pxd file and "map" it with SQLAlchemy.
Cython definition
Let's suppose the class Equipment. The class is defined the .pyx and the class interface in a .pxd (because I need to cimport it in other module).
equipment.pxd
cdef class Equipment:
cdef readonly int x
cdef readonly str y
equipment.pyx
cdef class Equipment:
def __init__(self, int x, str y):
self.x = x
self.y = y
I compile everything and get a equipment.pyd file. So far, it's ok. This file contains the business logic model and must not be altered.
Mapping
Then in one application, I import the equipment.pyd and map it with SQLAlchemy.
from sqlalchemy import Table, Column, Integer, String
from sqlalchemy.orm import mapper
from equipment import Equipment
metadata = MetaData()
# Table definition
equipment = Table(
'equipment', metadata,
Column('id', Integer, primary_key=True),
Column('x', Integer),
Column('y', String),
)
# Mapping the table definition with the class definition
mapper(Equipment, equipment)
TypeError: can't set attributes of built-in/extension type 'equipment.Equipment'
Indeed, SQLAlchemy is trying to create the Equipment.c.x, Equipment.c.y, ... Which is not possible in Cython because it is not defined in the .pxd...
So how can I map Cython class to SQLAlchemy?
Not satisfying solution
If I define the equipment class in python mode in .pyx file, it's working because at the end, it's only 'python' object in cython class definition.
equipment.pyx
class Equipment:
def __init__(self, x, y):
self.x = x
self.y = y
But I'm losing at lot of functionnalities which is why I need pure Cython.
Thank you! :-)
-- EDIT PART --
Semi satisfying solution
Keep the .pyx and .pxd files. Inherit from the .pyd. Try to Map.
mapping.py
from sqlalchemy import Table, Column, Integer, String
from sqlalchemy.orm import mapper
from equipment import Equipment
metadata = MetaData()
# Table definition
equipment = Table(
'equipment', metadata,
Column('id', Integer, primary_key=True),
Column('x', Integer),
Column('y', String),
)
# Inherit Equipment to a mapped class
class EquipmentMapped(Equipment):
def __init__(self, x, y):
super(EquipmentMapped, self).__init__(x, y)
# Mapping the table definition with the class definition
mapper(EquipmentMapped, equipment)
from mapping import EquipmentMapped
e = EquipmentMapped(2, 3)
print e.x
## This is empty!
In order to make it work, I must define each attributes as a property!
equipment.pxd
cdef class Equipment:
cdef readonly int _x
cdef readonly str _y
equipment.pyx
cdef class Equipment:
def __init__(self, int x, str y):
self.x = x
self.y = y
property x:
def __get__(self):
return self._x
def __set__(self, x):
self._x = x
property y:
def __get__(self):
return self._y
def __set__(self, y):
self._y = y
This is not satisfying because :lazy_programmer_mode on: I have a lot of changes to do in the business logic... :lazy_programmer_mode off: