On Wed, Jul 3, 2019 at 3:46 AM gamcil <[email protected]> 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?
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 [email protected].
To post to this group, send email to [email protected].
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.