On Sat, Feb 24, 2018 at 5:33 AM, Sven <sven.du...@gmail.com> 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 sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> 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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to