On Sat, Feb 24, 2018 at 5:33 AM, Sven <[email protected]> wrote:
> Hello,
>
> I have now a small example which illustrates the problem.
>
> Program logic : each NPC inherites from Character and each NPC is based on a
> prototype. It means, for example, that you can define the prototype
> "red_guard" and then create 100 red guards all based on this prototype. Most
> part of the NPC attributes are stored in the class Prototype. For example, I
> can define in the prototype that a red guard has 1000 health point and it
> will be reflected automatically in every NPC based on the prototype. This is
> why, the __getattr_ function of NPC is looking in the prototype attributes.
your NPC class is making it impossible to test if the class has an
attribute present or not and additionally `__getattr__()` assumes that
the "self.prototype" attribute is present, when it's not, causing an
endless loop:
class Character(object):
def __init__(self):
if hasattr(self, '_foo'):
print("yup")
class Prototype(object):
pass
class NPC(Character):
def __init__(self):
Character.__init__(self)
self.prototype = Prototype()
def __getattr__(self, nom_attr):
return getattr(self.prototype, nom_attr)
NPC()
using pdb inside of __getattr__ would reveal that the attributes
being asked for here start with underscores, so one way to work around
this is:
def __getattr__(self, nom_attr):
if nom_attr.startswith("_"):
return object.__getattribute__(self, nom_attr)
else:
return getattr(self.prototype, nom_attr)
>
> Code:
>
> from sqlalchemy import create_engine
> from sqlalchemy.orm import sessionmaker
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy import Column, Integer, String, ForeignKey
> from sqlalchemy import orm
> from sqlalchemy.orm import relationship
>
> BaseBDD = declarative_base()
> engine = create_engine('sqlite:///getattr_loop.db', echo=True)
> Session = sessionmaker(bind=engine)
> session = Session()
>
> class Prototype(BaseBDD):
> __tablename__ = "prototypes"
> id = Column(Integer, primary_key=True)
>
> npc = relationship("NPC", back_populates="prototype")
>
> class Character(BaseBDD):
> __tablename__ = "personnages"
> id = Column(Integer, primary_key=True)
>
> type = Column(String)
>
> __mapper_args__ = {
> 'polymorphic_on':type,
> 'polymorphic_identity':'personnage'
> }
>
> class NPC(Character):
>
> prototype_id = Column(ForeignKey('prototypes.id'))
> prototype = relationship("Prototype", back_populates="npc")
>
> __mapper_args__ = {
> 'polymorphic_identity':'npc'
> }
>
> def __init__(self, prototype):
> Character.__init__(self)
> self.prototype = prototype
> prototype.npc.append(self)
>
> def __getattr__(self, nom_attr):
> return getattr(self.prototype, nom_attr)
>
> BaseBDD.metadata.create_all(engine)
>
> proto_jean = Prototype()
> jean = NPC(proto_jean)
>
> Trace:
>
> Traceback (most recent call last):
> File "C:\Users\Sven\Downloads\loop_test_trace.py", line 52, in <module>
> jean = NPC(proto_jean)
> File "<string>", line 2, in __init__
> File "C:\Python34\lib\site-packages\sqlalchemy\orm\instrumentation.py",
> line 379, in _new_state_if_none
> if hasattr(instance, self.STATE_ATTR):
> File "C:\Users\Sven\Downloads\loop_test_trace.py", line 47, in __getattr__
> return getattr(self.prototype, nom_attr)
> File "C:\Python34\lib\site-packages\sqlalchemy\orm\attributes.py", line
> 242, in __get__
> return self.impl.get(instance_state(instance), dict_)
> File "C:\Users\Sven\Downloads\loop_test_trace.py", line 47, in __getattr__
> return getattr(self.prototype, nom_attr)
> File "C:\Python34\lib\site-packages\sqlalchemy\orm\attributes.py", line
> 242, in __get__
> return self.impl.get(instance_state(instance), dict_)
> File "C:\Users\Sven\Downloads\loop_test_trace.py", line 47, in __getattr__
> return getattr(self.prototype, nom_attr)
> File "C:\Python34\lib\site-packages\sqlalchemy\orm\attributes.py", line
> 242, in __get__
> return self.impl.get(instance_state(instance), dict_)
> File "C:\Users\Sven\Downloads\loop_test_trace.py", line 47, in __getattr__
> return getattr(self.prototype, nom_attr)
>
> Unfortunately, the line "return getattr(self.prototype, nom_attr)" is
> causing an endless loop.
>
> Has someone a solution ? How can I avoid this loop ?
>
> Thank you !
>
> Sven
>
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at https://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
http://www.sqlalchemy.org/
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable
Example. See http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.