This works. Thank you for the quick response and great libraries (I use
Mako as well).
Eric

On Fri, Aug 14, 2015 at 9:07 AM, Mike Bayer <mike...@zzzcomputing.com>
wrote:

> 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
> Python 2.7.10 (default, May 26 2015, 04:16:29)
> [GCC 5.1.0] on linux2
> Type "help", "copyright", "credits" or "license" for more information.
> >>> import psycopg2
> >>> import sqlalchemy
> >>>
> >>> 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'
> >>>
> >>> from collections import OrderedDict
> >>> from decimal import Decimal
> >>> from sqlalchemy import Column, Integer, Numeric
> >>> from sqlalchemy.ext.declarative import declarative_base
> >>>
> >>> def licensed(licenses):
> ...     def decorate(cls):
> ...         def ___init__(self, **kwargs):
> ...             for k, v in self.licenses.items():
> ...                 kwargs.setdefault('{}_license_rate'.format(k), v)
> ...             super(cls, self).__init__(**kwargs)
> ...         cls.__init__ = ___init__
> ...         for k, v in licenses.items():
> ...             licenses[k] = Decimal(v)
> ...         cls.licenses = licenses
> ...         for license in licenses:
> ...             setattr(cls, '{}_license_rate'.format(license), Column(
> Numeric, nullable=False))
> ...         return cls
> ...     return decorate
> ...
> >>>
> >>> Base = declarative_base()
> >>>
> >>> @licensed(OrderedDict((('foo', 100), ('bar', 150))))
> ... class Instance_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' object has no attribute '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.
> 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.
>
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "sqlalchemy" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/sqlalchemy/u_WdnuCSvCU/unsubscribe.
> To unsubscribe from this group and all its topics, 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.
>



-- 
CONFIDENTIALITY NOTICE:  This electronic message transmission contains
information from Eric G. Atkin, which may be confidential, may be protected
by
the attorney-client or other applicable privileges or otherwise constitutes
non-public information.  If you are not the intended recipient of this
message
please be aware that any disclosure, copying, distribution or other use of
this
information is unauthorized and may be unlawful.  If you have received this
transmission in error please immediately notify the sender by replying to
this
message and then permanently delete the communication from your computer
and/or
network systems.

-- 
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