A game engine provides me with a Player
class that has an uniqueid
read-only property to identify players. I would like to "convert" this into an SQLAlchemy's Column
so that I can query players with it like this:
query = session.query(Player).filter(Player.uniqueid=='STEAM_0:0:1234567')
player = query.one_or_none()
if player is None:
player = Player(uniqueid='STEAM_0:0:1234567')
Here's what my class currently looks like:
class Player(game.Player, db.Model):
_uniqueid = Column('uniqueid', String(21), unique=True, nullable=False)
def __init__(self, index, **kwargs):
game.Player.__init__(index) # initializes uniqueid
db.Model.__init__(_uniqueid=self.uniqueid, **kwargs)
Next I would like to create a read-only interface for the _uniqueid
, so the API users can no longer write to the variable (well, they can through _uniqueid
, but that's on their responsibility since accessing it should happen through the non-private uniqueid
).
I think of overriding the original uniqueid
with a new one:
@property
def uniqueid(self):
return self._uniqueid
This is read-only and "hides" the original _uniqueid
, preventing anyone from writing to it unless they intentionally access the private one (I won't even list it in documentation, I'll only expose the non-private one).
The only problem is that this completely overrides the old one, meaning that my __init__
's _uniqueid=self.uniqueid
won't work due to self.uniqueid
using the new getter, not the old one.
So summed up, what I want is to convert a read-only property into a read-only something that can be used to query with SQLAlchemy. Is this possible, and if, how?
You can use super
to access the property of game.Player
. We can test using a simple C extension type created with Cython:
# game.pyx
cdef class Player:
cdef int index;
def __init__(self, index):
self.index = index
@property
def uniqueid(self):
return "foo"
# test.py
class Player(game.Player, Base):
__tablename__ = "player"
id = Column(Integer, primary_key=True)
_uniqueid = Column('uniqueid', String(21), unique=True, nullable=False)
def __init__(self, index, **kwargs):
game.Player.__init__(self, index) # initializes uniqueid
Base.__init__(self, _uniqueid=super().uniqueid, **kwargs)
@property
def uniqueid(self):
return self._uniqueid
print(Player(1).uniqueid) # "foo"
Because of the precariousness of inheriting from C extension types, this may or may not work depending on exactly what C magic the game.Player
type uses.
Also, because the ORM bypasses __init__
when it loads instances from the database, you'll have to hook into the load
event in order to initialize the game.Player
type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With