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?
1 Answers
Answers 1
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.
0 comments:
Post a Comment