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.