Package: algen
# AlgenAlgen generates opionated ORM classes for sqlalchemy given a simple schemaeither as a commandline string or as a yaml file. It is designed to haveminimal dependencies and is trivially extensible. A command line toolis bundled along to help generate the models. For DB specific types,only postgres is currently supported. The tool currently assumes thatsqlalchemy's declarative base object is to be imported like```from .alchemy_base import Base```The library prefers making the code verbose rather than concise for thesake of having better auto-completion and help from your editor/IDEe.g. first style is preferred to the second one:```pythondef update(self, a=None, b=None):if a is not None:self.a = aif b is not None:self.b = b``````pythondef update(self, **kwargs):for k,v in kwargs.items():if hasattr(self, k) and v is not None:setattr(self, k, v)```### CLI```bash$ algen --helpUsage: algen [OPTIONS]Options:-n, --name TEXT         Name of model-c, --columns TEXT      Column definition. e.g. col_name:col_type Can beused multiple times hence named columns. e.g. -cfoo:Int -c bar:Unicode(20)-d, --destination PATH  Destination directory. Default will assume 'models'directory inside the current working directory-y, --yaml PATH         Yaml file describing the Model. This supersedes thecolumn definition provided through --columns option.--help                  Show this message and exit.```Given a file as follows:```yamlPerson:columns:- name: idtype: BigIntegerprimary_key: Trueauto_increment: True- name: nametype: Unicode(255)- name: is_viptype: Boolean- name: created_attype: DateTime(timezone=True)server_default: now() at time zone 'utc'- name: updated_attype: DateTime(timezone=True)server_default: now() at time zone 'utc'relationships:- name: addressesclass: Addressback_populates: 'person'Address:columns:- name: idtype: BigIntegerprimary_key: Trueauto_increment: True- name: line1type: Unicode()- name: line2type: Unicode()- name: line3type: Unicode()- name: postcodetype: Unicode(10)index: True- name: created_attype: DateTime(timezone=True)server_default: now() at time zone 'utc'- name: updated_attype: DateTime(timezone=True)server_default: now() at time zone 'utc'foreign_keys:- name: person_idtype: BigIntegerreference:table: personscolumn: idnullable: Falserelationships:- name: personclass: Personback_populates: 'addresses'```The cli tool will create two the following two files ```person.py```  and  ```address.py```.```pythonfrom __future__ import unicode_literals, absolute_import, print_functionfrom collections import namedtuplefrom sqlalchemy import Column, Unicode, BigInteger, DateTime, ForeignKeyfrom sqlalchemy.orm import relationshipfrom .alchemy_base import Base__author__ = 'danishabdullah'class Address(Base):__tablename__ = 'addresses'id = Column(BigInteger, auto_increment=True, primary_key=True)line1 = Column(Unicode(), )line2 = Column(Unicode(), )line3 = Column(Unicode(), )postcode = Column(Unicode(10), index=True)created_at = Column(DateTime(timezone=True), server_default="now() at time zone 'utc'")updated_at = Column(DateTime(timezone=True), server_default="now() at time zone 'utc'")# --- Foreign Keys ---person_id = Column(BigInteger, ForeignKey('persons.id'), nullable=False)# --- Relationships ---person = relationship('Person', back_populates='addresses')def __init__(self, id=None, line1=None, line2=None, line3=None, postcode=None, created_at=None, updated_at=None, person_id=None):self.id = idself.line1 = line1self.line2 = line2self.line3 = line3self.postcode = postcodeself.created_at = created_atself.updated_at = updated_atself.person_id = person_iddef add(self, session):session.add(self)def update(self, line1=None, line2=None, line3=None, postcode=None, created_at=None, updated_at=None, person_id=None):# This function only updates a value if it is not None.# Falsy values go through in the normal way.# To set things to None use the usual syntax:#    Address.column_name = Noneif line1 is not None:self.line1 = line1if line2 is not None:self.line2 = line2if line3 is not None:self.line3 = line3if postcode is not None:self.postcode = postcodeif created_at is not None:self.created_at = created_atif updated_at is not None:self.updated_at = updated_atif person_id is not None:self.person_id = person_iddef delete(self, session):session.delete(self)def to_dict(self):return {x: y for x, y in self.__dict__.items() if not x.startswith("_sa")}def get_proxy_cls(self):# AddressProxy is useful when you want to persist data# independent of the sqlalchemy session. It's just a namedtuple# that has very low memory/cpu footprint compared the regular# orm class instances.keys = self.to_dict().keys()name = "AddressProxy"return namedtuple(name, keys)def to_proxy(self):# Proxy-ing is useful when you want to persist data# independent of the sqlalchemy session. It's just a namedtuple# that has very low memory/cpu footprint compared the regular# orm class instances.cls = self._get_proxy_cls()return cls(**self.to_dict())@classmethoddef from_proxy(cls, proxy):return cls(**proxy._asdict())def __hash__(self):return hash(str(self.id))def __eq__(self, other):return (self.id == other.id)def __neq__(self, other):return not (self.id == other.id)def __str__(self):return "<Address: {id}>".format(id=self.id)def __unicode__(self):return "<Address: {id}>".format(id=self.id)def __repr__(self):return "<Address: {id}>".format(id=self.id)``````pythonfrom __future__ import unicode_literals, absolute_import, print_functionfrom collections import namedtuplefrom sqlalchemy import Column, Unicode, BigInteger, Boolean, DateTimefrom sqlalchemy.orm import relationshipfrom .alchemy_base import Base__author__ = 'danishabdullah'class Person(Base):__tablename__ = 'persons'id = Column(BigInteger, auto_increment=True, primary_key=True)name = Column(Unicode(255), )is_vip = Column(Boolean, )created_at = Column(DateTime(timezone=True), server_default="now() at time zone 'utc'")updated_at = Column(DateTime(timezone=True), server_default="now() at time zone 'utc'")# --- Foreign Keys ---# --- Relationships ---addresses = relationship('Address', back_populates='person')def __init__(self, id=None, name=None, is_vip=None, created_at=None, updated_at=None):self.id = idself.name = nameself.is_vip = is_vipself.created_at = created_atself.updated_at = updated_atdef add(self, session):session.add(self)def update(self, name=None, is_vip=None, created_at=None, updated_at=None):# This function only updates a value if it is not None.# Falsy values go through in the normal way.# To set things to None use the usual syntax:#    Person.column_name = Noneif name is not None:self.name = nameif is_vip is not None:self.is_vip = is_vipif created_at is not None:self.created_at = created_atif updated_at is not None:self.updated_at = updated_atdef delete(self, session):session.delete(self)def to_dict(self):return {x: y for x, y in self.__dict__.items() if not x.startswith("_sa")}def get_proxy_cls(self):# PersonProxy is useful when you want to persist data# independent of the sqlalchemy session. It's just a namedtuple# that has very low memory/cpu footprint compared the regular# orm class instances.keys = self.to_dict().keys()name = "PersonProxy"return namedtuple(name, keys)def to_proxy(self):# Proxy-ing is useful when you want to persist data# independent of the sqlalchemy session. It's just a namedtuple# that has very low memory/cpu footprint compared the regular# orm class instances.cls = self._get_proxy_cls()return cls(**self.to_dict())@classmethoddef from_proxy(cls, proxy):return cls(**proxy._asdict())def __hash__(self):return hash(str(self.id))def __eq__(self, other):return (self.id == other.id)def __neq__(self, other):return not (self.id == other.id)def __str__(self):return "<Person: {id}>".format(id=self.id)def __unicode__(self):return "<Person: {id}>".format(id=self.id)def __repr__(self):return "<Person: {id}>".format(id=self.id)```