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

2015-08-14 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 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.


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

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 eat...@certusllc.us javascript: 
 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
@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 eat...@certusllc.us 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.