On Wed, Jul 3, 2019, at 4:47 AM, Simon King wrote:
> On Wed, Jul 3, 2019 at 3:46 AM gamcil <clmgilchr...@gmail.com> wrote:
> >
> >
> > Awesome thanks for the extensive reply.
> >
> > This is the first time I've played with descriptor classes, so I'm sorry if 
> > this is really basic stuff.
> >
> > I set up my view class:
> >
> > class View:
> > def __init__(self, gene, attrs):
> > self.gene = gene
> > self.attrs = attrs
> >
> > def keys(self):
> > return iter(self.attrs)
> >
> > def items(self):
> > return ((attr, getattr(self.gene, attr)) for attr in self.attrs)
> >
> > def __getitem__(self, key):
> > return getattr(self.gene, key)
> >
> > def __setitem__(self, key, value):
> > setattr(self.gene, key, value)
> >
> > and a descriptor class:
> > class Descriptor:
> > def __init__(self, *attrs):
> > self.attrs = attrs
> >
> > def __get__(self, instance, owner):
> > return View(instance, self.attrs)
> >
> > def __set__(self, instance, value):
> > self.attrs = value
> >
> > then the Gene class using __declare_first__ becomes:
> > class Gene(Base):
> > __tablename__ = 'Gene'
> > id = Column(Integer, primary_key=True)
> > identifiers = Descriptor('locus', 'protein')
> > features = Descriptor('gene', 'mRNA', 'CDS')
> >
> > def __init__(self, **kwargs):
> > for dic in kwargs.values():
> > for key, value in dic.items():
> > setattr(self, key, value)
> >
> > @classmethod
> > def __declare_first__(cls):
> > for value in list(cls.__dict__.values()).copy():
> > if isinstance(value, Descriptor):
> > for attr in value.attrs:
> > setattr(cls, key, Column(attr, String))
> >
> > This seems to give me close to the interface I would like. A couple of 
> > questions:
> > 1) So I guess this is still just directly mapping columns to Class 
> > attributes, accessable by directly getting an attribute, i.e. 
> > gene.features['mRNA'] is equivalent to gene.mRNA. Would you then mask the 
> > class attributes by e.g. prepending with underscore?
> 
> That's entirely up to you. It's not *necessary* (no harm will be done
> if you access the data through both mechanisms, since the value is
> only stored in a single place), so it's just an aesthetic choice.
> 
> >
> > 2) Currently, every time a method is called on the descriptor, a new 
> > instance of the View class is returned. Is that by design, or is there a 
> > way of persisting the one View per attribute (identifiers, features, ...) 
> > for each Gene instance? Is that even an overhead I should be worried about? 
> > It seems like the equivalent of creating a new dictionary every time I want 
> > to access attributes on the Gene object.
> 
> This is probably a case of "don't bother optimising until you know
> it's a problem", but in this case the optimisation is simple. You
> could change your Descriptor.__get__ method to store the View instance
> on the object itself, perhaps under a name derived from the list of
> attributes. For example:
> 
> def __get__(self, instance, owner):
>  cachename = '_descriptor_' + '_'.join(self.attrs)
>  result = getattr(instance, cachename, None)
>  if result is None:
>  result = View(instance, self.attrs)
>  setattr(instance, cachename, result)
>  return result
> 
> >
> > 3) When I call Base.metadata.create_all(bind=engine) without first creating 
> > a Gene instance, the generated SQL is:
> > CREATE TABLE "gene" (
> > id INTEGER NOT NULL,
> > PRIMARY KEY (id)
> > )
> >
> > missing all of the other mappings. After calling e.g. gene = Gene(), it's 
> > as expected:
> > CREATE TABLE "gene" (
> > id INTEGER NOT NULL,
> > locus VARCHAR,
> > protein VARCHAR,
> > gene VARCHAR,
> > "mRNA" VARCHAR,
> > "CDS" VARCHAR,
> > PRIMARY KEY (id)
> > )
> >
> 
> This seems like a bug; I would have expected the __declare_first__
> method to be called automatically when you call create_all.
> 
> As a workaround, does it make any difference if you add a call to
> sqlalchemy.orm.configure_mappers() before your call to create_all?

oh, whoops sorry it does not :) just call configure_mappers() :)


> 
> Simon
> 
> -- 
> SQLAlchemy - 
> The Python SQL Toolkit and Object Relational Mapper
> 
> http://www.sqlalchemy.org/
> 
> To post example code, please provide an MCVE: Minimal, Complete, and 
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> description.
> --- 
> 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 https://groups.google.com/group/sqlalchemy.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sqlalchemy/CAFHwexdP95%2BWy5-8OjqhoQcYcs8jRT9RFp-G-SCY9fwwO5UoHg%40mail.gmail.com.
> For more options, visit https://groups.google.com/d/optout.
> 

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
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 https://groups.google.com/group/sqlalchemy.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/c2e6d8b4-e508-464c-af2f-f58e983a01f7%40www.fastmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to