Re: [sqlalchemy] Overwriting __init__() after class definition breaks sqlalchemy with declarative

2015-08-14 Thread Eric Atkin
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 
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 "", line 1, in 
>   File "", line 6, in ___init__
>   File
> "(...)/env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py"
> , lin

[sqlalchemy] Overwriting __init__() after class definition breaks sqlalchemy with declarative

2015-08-13 Thread Eric Atkin
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 "", line 1, in 
  File "", 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.


Re: [sqlalchemy] override relationship in subclass

2014-02-12 Thread Eric Atkin
@gdelta.expression is a typo. Should be @delta.expression.

On Wednesday, February 12, 2014 11:53:05 AM UTC-7, Eric Atkin wrote:
>
> Yeah sorry I missed that. conversion is an attribute on Measured_Source.
> So the intent is that a Production_Load is a Load with its own additional 
> attributes over Load as well as a constraint that its source is a 
> Measured_Source which has its own attribute extensions over Source. One of 
> the goals here is to add that constraint enforcement. I was able to make it 
> work with the following hybrid_method and hybrid_method.expression, but the 
> isinstance(Production_Load.source, Measured_Source) enforcement is missing.
> Eric
>
> {{{
> class Production_Load(Load):
> __tablename__ = 'production_load'
> __mapper_args__ = { 'polymorphic_identity':'production_load' }
>
> id = Column(Integer, ForeignKey('load.id'), primary_key=True)
> top = Column(Numeric, nullable=False)
> bottom = Column(Numeric, nullable=False)
>
> @hybrid_method
> def delta(self):
> return (self.top-self.bottom)*self.source.conversion if 
> self.source else None
>
> @gdelta.expression
> def delta(self):
> # not sure about the performance here
> return 
> (self.top-self.bottom)*select([Measured_Source.conversion]).where(Measured_Source.id==self.source_id).label('delta')
> }}}
>
> On Wednesday, February 12, 2014 7:17:08 AM UTC-7, Michael Bayer wrote:
>>
>>
>> On Feb 11, 2014, at 9:38 PM, Eric Atkin  wrote: 
>>
>> > Hi, 
>> > I want to override a relationship in a subclass to relate to a subclass 
>> of the base attributes' related class. Perhaps an example of how I thought 
>> it should work: 
>> > 
>> > {{{ 
>> > class Load(Base): 
>> > __tablename__ = 'load' 
>> > __mapper_args__ = { 
>> > 'polymorphic_identity':'load', 
>> > 'polymorphic_on':'polymorphic_type', 
>> > } 
>> > id = Column(Integer, primary_key=True) 
>> > polymorphic_type = Column(Text, nullable=False) 
>> > source_id = Column(Integer, ForeignKey('source.id')) 
>> > source = relationship('Source') 
>> > 
>> > class Production_Load(Load): 
>> > __tablename__ = 'production_load' 
>> > __mapper_args__ = { 'polymorphic_identity':'production_load' } 
>> > id = Column(Integer, ForeignKey('load.id'), primary_key=True) 
>> > source_id = Column(Integer, ForeignKey('measured_source.id')) 
>> > source = relationship('Measured_Source') 
>> > 
>> > class Source(Base): 
>> > __tablename__ = 'source' 
>> > __mapper_args__ = { 
>> > 'polymorphic_identity':'source', 
>> > 'polymorphic_on':'polymorphic_type', 
>> > } 
>> > id = Column(Integer, primary_key=True) 
>> > polymorphic_type = Column(Text, nullable=False) 
>> > 
>> > class Measured_Source(Source): 
>> > __tablename__ = 'measured_source' 
>> > __mapper_args__ = { 'polymorphic_identity':'measured_source' } 
>> > 
>> > id = Column(Integer, ForeignKey('source.id'), primary_key=True) 
>> > }}} 
>> > 
>> > As you can see, we have Load.source -> Source and I want 
>> Production_Load.source -> Measured_Source, but when I import the models, I 
>> get the following warning: 
>> > 
>> > 
>> {...}/env/lib/python2.7/site-packages/sqlalchemy/orm/properties.py:1028: 
>> SAWarning: Warning: relationship 'source' on mapper 
>> 'Mapper|Production_Load|production_load' supersedes the same relationship 
>> on inherited mapper 'Mapper|Load|load'; this can cause dependency issues 
>> during flush 
>> > 
>> > and when I try to use Production_Load.source (class level attr) in a 
>> query, I get the following error: 
>> > 
>> > AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' 
>> object associated with Production_Load.source has an attribute 'conversion' 
>> > 
>> > Is such a thing possible, even with a re-factor of the models? 
>>
>> “conversion” sounds like an attribute name on your end, but generally 
>> being able to supersede a relationship like that when the inheritance is 
>> not “concrete” is not supported.  you’d need to name it to something else. 
>>
>>

-- 
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/groups/opt_out.


Re: [sqlalchemy] override relationship in subclass

2014-02-12 Thread Eric Atkin
Yeah sorry I missed that. conversion is an attribute on Measured_Source.
So the intent is that a Production_Load is a Load with its own additional 
attributes over Load as well as a constraint that its source is a 
Measured_Source which has its own attribute extensions over Source. One of 
the goals here is to add that constraint enforcement. I was able to make it 
work with the following hybrid_method and hybrid_method.expression, but the 
isinstance(Production_Load.source, Measured_Source) enforcement is missing.
Eric

{{{
class Production_Load(Load):
__tablename__ = 'production_load'
__mapper_args__ = { 'polymorphic_identity':'production_load' }

id = Column(Integer, ForeignKey('load.id'), primary_key=True)
top = Column(Numeric, nullable=False)
bottom = Column(Numeric, nullable=False)

@hybrid_method
def delta(self):
return (self.top-self.bottom)*self.source.conversion if self.source 
else None

@gdelta.expression
def delta(self):
# not sure about the performance here
return 
(self.top-self.bottom)*select([Measured_Source.conversion]).where(Measured_Source.id==self.source_id).label('delta')
}}}

On Wednesday, February 12, 2014 7:17:08 AM UTC-7, Michael Bayer wrote:
>
>
> On Feb 11, 2014, at 9:38 PM, Eric Atkin > 
> wrote: 
>
> > Hi, 
> > I want to override a relationship in a subclass to relate to a subclass 
> of the base attributes' related class. Perhaps an example of how I thought 
> it should work: 
> > 
> > {{{ 
> > class Load(Base): 
> > __tablename__ = 'load' 
> > __mapper_args__ = { 
> > 'polymorphic_identity':'load', 
> > 'polymorphic_on':'polymorphic_type', 
> > } 
> > id = Column(Integer, primary_key=True) 
> > polymorphic_type = Column(Text, nullable=False) 
> > source_id = Column(Integer, ForeignKey('source.id')) 
> > source = relationship('Source') 
> > 
> > class Production_Load(Load): 
> > __tablename__ = 'production_load' 
> > __mapper_args__ = { 'polymorphic_identity':'production_load' } 
> > id = Column(Integer, ForeignKey('load.id'), primary_key=True) 
> > source_id = Column(Integer, ForeignKey('measured_source.id')) 
> > source = relationship('Measured_Source') 
> > 
> > class Source(Base): 
> > __tablename__ = 'source' 
> > __mapper_args__ = { 
> > 'polymorphic_identity':'source', 
> > 'polymorphic_on':'polymorphic_type', 
> > } 
> > id = Column(Integer, primary_key=True) 
> > polymorphic_type = Column(Text, nullable=False) 
> > 
> > class Measured_Source(Source): 
> > __tablename__ = 'measured_source' 
> > __mapper_args__ = { 'polymorphic_identity':'measured_source' } 
> > 
> > id = Column(Integer, ForeignKey('source.id'), primary_key=True) 
> > }}} 
> > 
> > As you can see, we have Load.source -> Source and I want 
> Production_Load.source -> Measured_Source, but when I import the models, I 
> get the following warning: 
> > 
> > {...}/env/lib/python2.7/site-packages/sqlalchemy/orm/properties.py:1028: 
> SAWarning: Warning: relationship 'source' on mapper 
> 'Mapper|Production_Load|production_load' supersedes the same relationship 
> on inherited mapper 'Mapper|Load|load'; this can cause dependency issues 
> during flush 
> > 
> > and when I try to use Production_Load.source (class level attr) in a 
> query, I get the following error: 
> > 
> > AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' 
> object associated with Production_Load.source has an attribute 'conversion' 
> > 
> > Is such a thing possible, even with a re-factor of the models? 
>
> “conversion” sounds like an attribute name on your end, but generally 
> being able to supersede a relationship like that when the inheritance is 
> not “concrete” is not supported.  you’d need to name it to something else. 
>
>

-- 
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/groups/opt_out.


[sqlalchemy] override relationship in subclass

2014-02-11 Thread Eric Atkin
Hi,
I want to override a relationship in a subclass to relate to a subclass of 
the base attributes' related class. Perhaps an example of how I thought it 
should work:

{{{
class Load(Base):
__tablename__ = 'load'
__mapper_args__ = {
'polymorphic_identity':'load',
'polymorphic_on':'polymorphic_type',
}
id = Column(Integer, primary_key=True)
polymorphic_type = Column(Text, nullable=False)
source_id = Column(Integer, ForeignKey('source.id'))
source = relationship('Source')

class Production_Load(Load):
__tablename__ = 'production_load'
__mapper_args__ = { 'polymorphic_identity':'production_load' }
id = Column(Integer, ForeignKey('load.id'), primary_key=True)
source_id = Column(Integer, ForeignKey('measured_source.id'))
source = relationship('Measured_Source')

class Source(Base):
__tablename__ = 'source'
__mapper_args__ = {
'polymorphic_identity':'source',
'polymorphic_on':'polymorphic_type',
}
id = Column(Integer, primary_key=True)
polymorphic_type = Column(Text, nullable=False)

class Measured_Source(Source):
__tablename__ = 'measured_source'
__mapper_args__ = { 'polymorphic_identity':'measured_source' }

id = Column(Integer, ForeignKey('source.id'), primary_key=True)
}}}

As you can see, we have Load.source -> Source and I want 
Production_Load.source -> Measured_Source, but when I import the models, I 
get the following warning:

{...}/env/lib/python2.7/site-packages/sqlalchemy/orm/properties.py:1028: 
SAWarning: Warning: relationship 'source' on mapper 
'Mapper|Production_Load|production_load' supersedes the same relationship 
on inherited mapper 'Mapper|Load|load'; this can cause dependency issues 
during flush

and when I try to use Production_Load.source (class level attr) in a query, 
I get the following error:

AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' 
object associated with Production_Load.source has an attribute 'conversion'

Is such a thing possible, even with a re-factor of the models?

Thanks,
Eric

-- 
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/groups/opt_out.