this code is incorrect from a Python perspective. You're removing the original `__init__` method entirely and it is never called; the attempt to call it using super() just calls object.__init__. SQLAlchemy is already decorating the __init__ method of the mapped class so you can't just throw it away, you can decorate it but you need to make sure its still called.

Here is a plain demonstration without any SQLAlchemy:

def licensed():
    def decorate(cls):
        def ___init__(self, **kwargs):
            print "magic new init!"
            super(cls, self).__init__(**kwargs)
        cls.__init__ = ___init__
        return cls
    return decorate


@licensed()
class SomeClass(object):
    def __init__(self):
        print "normal init!"


SomeClass()

Only "magic new init!" is printed.   SomeClass.__init__ is never called.


Here's the correct way to decorate a function in this context:

def licensed(licenses):
    def decorate(cls):
        orig_init = cls.__init__

        def ___init__(self, **kwargs):
            for k, v in self.licenses.items():
                kwargs.setdefault('{}_license_rate'.format(k), v)
            orig_init(self, **kwargs)
        cls.__init__ = ___init__





On 8/14/15 2:41 AM, Eric Atkin wrote:
Hi,

I've written a class decorator to define a boilerplate __init__ on some of my models that inherit from a declarative_base superclass. The problem is that sqlalchemy.orm.instrumentation._generate_init() has already installed an __init__ and when I overwrite that, things break with "object has no attribute '_sa_instance_state'" exceptions. I've provided a sample below. It actually throws a different exception than my code but I think the root issue is the same, that is, my __init__ replaced the generated one and so the ClassManager events are not being emitted.

Is there some blessed way to add an __init__ method after a class is already defined or is that just impossible with sqlalchemy's metaprogramming environment?

Love the library. Very powerful and excellent documentation. Thanks.
Eric

|
$ python
Python2.7.10(default,May262015,04:16:29)
[GCC 5.1.0]on linux2
Type"help","copyright","credits"or"license"formore information.
>>>importpsycopg2
>>>importsqlalchemy
>>>
>>>psycopg2.__version__
'2.6 (dt dec pq3 ext lo64)'
>>>conn =psycopg2.connect("dbname=dispatch_dev")
>>>cur =conn.cursor()
>>>cur.execute("SELECT version();")
>>>cur.fetchone()
('PostgreSQL 9.4.4 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 5.1.0, 64-bit',)
>>>
>>>sqlalchemy.__version__
'0.9.7'
>>>
>>>fromcollections importOrderedDict
>>>fromdecimalimportDecimal
>>>fromsqlalchemy importColumn,Integer,Numeric
>>>fromsqlalchemy.ext.declarative importdeclarative_base
>>>
>>>deflicensed(licenses):
...defdecorate(cls):
...def___init__(self,**kwargs):
...fork,v inself.licenses.items():
...kwargs.setdefault('{}_license_rate'.format(k),v)
...super(cls,self).__init__(**kwargs)
...        cls.__init__ =___init__
...fork,v inlicenses.items():
...            licenses[k]=Decimal(v)
...        cls.licenses =licenses
...forlicense inlicenses:
... setattr(cls,'{}_license_rate'.format(license),Column(Numeric,nullable=False))
...returncls
...returndecorate
...
>>>
>>>Base=declarative_base()
>>>
>>>@licensed(OrderedDict((('foo',100),('bar',150))))
...classInstance_Link(Base):
...    __tablename__ ='instance_link'
...    id =Column(Integer,primary_key=True)
...
>>>Instance_Link(foo_license_rate=50)
Traceback(most recent call last):
File"<stdin>",line 1,in<module>
File"<stdin>",line 6,in___init__
File"(...)/env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py",line 526,in_declarative_constructor
    setattr(self,k,kwargs[k])
File"(...)/env/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py",line 225,in__set__
self.impl.set(instance_state(instance),
AttributeError:'NoneType'objecthas noattribute 'set'
>>>
|

--
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 <mailto:sqlalchemy+unsubscr...@googlegroups.com>. To post to this group, send email to sqlalchemy@googlegroups.com <mailto:sqlalchemy@googlegroups.com>.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

--
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 http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to