class Info(StructuredNode): # ---- attributi info_id = StringProperty(UniqueIndex=True, Required=True) END = IntegerProperty() ID = StringProperty() QUAL = FloatProperty() FILTER = StringProperty() FORMAT = StringProperty() HETEROZIGOSITY = FloatProperty() dbSNP = StringProperty() DP = FloatProperty() Gene_refGene = ArrayProperty() Func_refGene = ArrayProperty() QD = FloatProperty() SIFT_score = FloatProperty() otg_all = FloatProperty() NM = IntegerProperty() LM = ArrayProperty() FS = FloatProperty() MQ0 = FloatProperty() attributes = JSONProperty() # ---- relazioni contains = RelationshipFrom('File', 'Contains') supportedBy = RelationshipTo('Genotype', 'Supported_By', model=SupportedByRel) forVariant = RelationshipTo('Variant', 'For_Variant')
class Gene(StructuredNode): # ---- attributi gene_id = StringProperty(UniqueIndex=True, Required=True) # ---- relazioni inVariant = RelationshipTo('Variant', 'In_Variant') inChromosomome = RelationshipTo('Chromosome', 'In_Chromosome')
class Experiment(StructuredNode): # ---- attributi name = StringProperty(Required=True) # ---- relazioni created = RelationshipFrom('User', 'Created') forSpecies = RelationshipTo('Species', 'For_Species') composedBy = RelationshipTo('File', 'Composed_By')
class Fusion(StructuredNode): fusion_id = IntegerProperty() # with_fc_script = RelationshipTo('FusionCatcher', "WITH_FC_SCRIPT") with_eric_script = RelationshipTo('EricScript', "WITH_ERIC_SCRIPT") with_tophat_script = RelationshipTo('Tophat', "WITH_TOPHAT_SCRIPT") with_gene = RelationshipTo('Gene', "WITH") at_chromosome = RelationshipTo('Chromosome', "AT_CHROMOSOME") # fromCellLineToFusion = RelationshipFrom('CellLine', "HAPPEN") fromGeneToFusion = RelationshipFrom('Gene', "HAD")
class Couple(StructuredNode): couple = IntegerProperty() # with_other_transcript = RelationshipTo('Transcript', "WITH_OTHER_TRANSCRIPT", model=WITH_OTHER_TRANSCRIPT) with_protein = RelationshipTo('Protein', "WITH_PROTEIN") # fromTranscriptToCouple = RelationshipFrom('Transcript', "IN_COUPLE", model=IN_COUPLE) fromFusionToCouple = RelationshipFrom('FusionCatcher', "WITH_TRANS_COUPLE")
class User(StructuredNode): # ---- attributi username = StringProperty(UniqueIndex=True, Required=True) # ---- relazioni created = RelationshipTo('Experiment', 'Created')
class Chromosome(StructuredNode): chromosome = StringProperty() # of_gene = RelationshipTo('Gene', "OF_GENE") # fromFusiontoChromosome = RelationshipFrom('Fusion', "AT_CHROMOSOME", model=AT_CHROMOSOME)
class Transcript(StructuredNode): transcript = StringProperty() # in_couple = RelationshipTo('Couple', "IN_COUPLE", model=IN_COUPLE) # fromCoupleToTranscript = RelationshipFrom('Couple', "WITH_OTHER_TRANSCRIPT", model=WITH_OTHER_TRANSCRIPT)
class Chromosome(StructuredNode): # ---- attributi chromosome = StringProperty(UniqueIndex=True, Required=True) # ---- relazioni inChromosomome = RelationshipFrom('Gene', 'In_Chromosome') hasVariant = RelationshipTo('Variant', 'Has_Variant')
class PersonaNode(DjangoNode): uid = UniqueIdProperty() nombre = StringProperty() creada = DateTimeProperty(default=datetime.utcnow) beacons = RelationshipTo('BeaconNode', 'INTERACCION', model=InteraccionRel) class Meta: app_label = 'logs'
class Genotype(StructuredNode): # ---- attributi sample = StringProperty(UniqueIndex=True, Required=True) # ---- relazioni supportedBy = RelationshipFrom('Info', 'Supported_By', model=SupportedByRel) ofSpecies = RelationshipTo('Species', 'Of_Species')
class File(StructuredNode): # ---- attributi name = StringProperty(UniqueIndex=True, Required=True) extension = StringProperty() statistics = JSONProperty() # ---- relazioni composedBy = RelationshipFrom('Experiment', 'Composed_By') contains = RelationshipTo('Info', 'Contains')
class Gene(StructuredNode): ensid = StringProperty() symbol = StringProperty() description = StringProperty() # had = RelationshipTo('Fusion', "HAD") # #fromFusion = RelationshipFrom('Fusion',"WITH", model=WITH) fromExonToGene = RelationshipFrom('Exon', "IN_GENE") fromChromosomeToGene = RelationshipFrom('Chromosome', "OF_GENE") fromFusionToGene = RelationshipFrom('Fusion', 'WITH')
class FusionCatcher(StructuredNode): fusion_id = IntegerProperty() description = ArrayProperty() common_mapping_reads = IntegerProperty() spanning_pairs = IntegerProperty() spanning_unique_reads = IntegerProperty() longest_anchor_found = IntegerProperty() fusion_finding_method = StringProperty() fusion_sequence = StringProperty() fusion_point_1 = IntegerProperty() fusion_point_2 = IntegerProperty() strand_1 = StringProperty() strand_2 = StringProperty() predicted_effect_1 = StringProperty() predicted_effect_2 = StringProperty() # at_exon = RelationshipTo('Exon', "AT_EXON") with_trans_couple = RelationshipTo('Couple', "WITH_TRANS_COUPLE") with_gene = RelationshipTo('Gene', "WITH") # #fromCellLineToFusion = RelationshipFrom('CellLine',"HAPPEN") fromFusionToFusionCatcher = RelationshipFrom('Fusion', "WITH_FC_SCRIPT")
class Payment(BaseModel): """ Payment object represents a payment for a card contained in a wallet """ value = FloatProperty() date_time = DateTimeProperty(default_now=True) card = RelationshipTo('.card.Card', 'FOR', cardinality=One) wallet = RelationshipFrom('.wallet.Wallet', 'FOR', cardinality=One) def to_dict(self): return dict(value=self.value, cid=self.card.single().uid, date_time=self.date_time, wid=self.wallet.single().uid)
class Purchase(BaseModel): """ Purchase objects represents a purchase made with wallet, it is, with one or more cards """ total = FloatProperty(required=True) cards_ = RelationshipTo('.card.Card', 'WITH', model=BillingAction) wallet_ = RelationshipFrom('.wallet.Wallet', 'DONE_WITH', cardinality=One) @property def wallet(self): return self.wallet_ @wallet.setter def wallet(self, wallet): raise PurchaseUnchangeableProperty() @property def cards(self): return self.cards_ @cards.setter def cards(self, card): raise PurchaseUnchangeableProperty() def use_card(self, card, value): self.cards_.connect(card, {'value': value}) self.save() card.purchases.connect(self, {'value': value}) card.decrease_free_limit(value) card.save() return self def to_dict(self): card_relations = [] for card in self.cards: relation = dict() relation['cid'] = card.uid rel = self.cards.relationship(card) relation['value'] = rel.value relation['date_time'] = rel.date_time card_relations.append(relation) return dict(wid=self.wallet.single().uid, total=self.total, relations=relation) def set_wallet(self, wallet): self.save() self.wallet_.connect(wallet) wallet.purchases.connect(self) self.save() wallet.save() return self
class User(BaseModel): """ This class models an user in database """ # Basic field names name = StringProperty(required=True) username = StringProperty(required=True, unique_index=True) address = StringProperty(default=None) mail_address = EmailProperty(default=None) # Sensible data # TODO: Would be good hide password_ on collecting object password_ = StringProperty(db_property='password', required=True) # Relationships wallets = RelationshipTo('.wallet.Wallet', 'OWN') def wallet_uid(self): if self.wallets.single(): return self.wallets.single().uid return None def to_dict(self): return dict(name=self.name, username=self.username, uid=self.uid, mail_address=self.mail_address, active=self.active, wid=self.wallet_uid()) @property def password(self): """ Return hashed password :return: hashed password """ return self.password_ if self.password_ else None @password.setter def password(self, value): """ Once password need to be hashed, this method/property is used to hash entered password and save the hash instead of clean one """ self.password_ = mixture_pwd(self.uid, value) @property def active(self): return self.active_ @active.setter def active(self, state): self.active_ = state def save(self): """ validates if an username is in use before save it :return: * Saved user object if it's ok * 'username_in_use' if username already in use * 'no_password_given' if password is not set * 'no_username_given' if username is not set """ if not hasattr(self, 'username') or self.username is None: raise UsernameNotGiven() if not hasattr(self, 'password_') or self.password_ is None: raise UserPasswordNotGiven() # validate username if len(User.nodes.filter(username=self.username, uid__ne=self.uid)) == 0: return super(User, self).save() else: # Found user with same username and different uid, so, username is in use raise UsernameInUse() def create_wallet(self, label): """ Create Wallet associated with user :param label: name to identify this wallet :return: generated wallet """ wallet = Wallet(label=label) wallet.save() wallet.owner.connect(self) self.wallets.connect(wallet) self.save() wallet.save() return wallet @staticmethod def login(username, passwd): """ Try to login an user :param username: username to login :param passwd: user password before hash :return: * True if login is ok, * False if wrong password * 'inexistent' if username not found * 'inactive' if user.active is False """ # find user by username user = User.nodes.get_or_none(username=username) if user is None: raise UsernameNotFound() # Test if user is active if user.active: # If user is active, compare password hash_passwd = mixture_pwd(user.uid, passwd) if user.password_ == hash_passwd: return user else: # If password is wrong, raise an exception raise UserPasswordIncorrect() else: # If user is inactive, raise an exception raise UserInactive()
class CellLine(StructuredNode): cell_line = StringProperty() # happen = RelationshipTo('Fusion', "HAPPEN") with_viruses = RelationshipTo('Virus', "WITH_VIRUSES", model=WITH_VIRUSES)
class Exon(StructuredNode): exon = StringProperty() # in_gene = RelationshipTo('Gene', "IN_GENE") # fromFusionToExon = RelationshipFrom('FusionCatcher', "AT_EXON")
class Wallet(BaseModel): """ Model a wallet in database """ label = StringProperty(required=True) max_limit_ = FloatProperty(db_property='max_limit', default=0) real_limit_ = FloatProperty(db_property='real_limit', default=0) free_limit_ = FloatProperty(db_property='free_limit', default=0) owner = RelationshipFrom('.user.User', 'OWNED', cardinality=One) cards = RelationshipTo('.card.Card', 'CONTAINS') purchases = RelationshipTo('.billing.Purchase', 'DID') payments = RelationshipFrom('.billing.Payment', 'RECEIVED') # === real_limit === @property def real_limit(self): """ real_limit is set to max_limit by default """ return self.real_limit_ if self.real_limit_ else self.max_limit @real_limit.setter def real_limit(self, value): """ Wallet limit set by user. Should be less than max_limit and non-negative :param value: new real limit :return: """ if value > self.max_limit: raise WalletLimitExceed() elif value < 0: raise WalletLimitNotAllowed() else: self.real_limit_ = value self.save() # === max_limit === @property def max_limit(self): return self.max_limit_ @max_limit.setter def max_limit(self, value): raise UnchangeableWalletValue() # === free_limit === @property def free_limit(self): """ usable remaining limit related to max_limit """ return self.free_limit_ @free_limit.setter def free_limit(self, value): raise UnchangeableWalletValue() # === real_free_limit === @property def real_free_limit(self): """ Analogous to free limit, but related to real_limit instead of max_limit :return: """ return self.real_limit - self.total_used # === total_used === @property def total_used(self): return self.max_limit - self.free_limit # === Limits Manipulators === def increase_free_limit(self, value=1.0): """ Increase free_limit of wallet, usually in card bill payments. :param value: amount to be increased :return: new free limit """ self.free_limit_ += value self.save() return self.free_limit def decrease_free_limit(self, value=1.0): """ Decrease free_limit of wallet, usually in purchases Raises an exception if limit become negative :param value: amount to reduce :return: new limit """ if self.free_limit < value: raise WalletLimitNotAllowed() else: return self.increase_free_limit(-value) def increase_max_limit(self, amount=1.0): self.max_limit_ += amount self.save() return self.max_limit def decrease_max_limit(self, amount=1.0): # Raise exception if limit become negative if amount > self.max_limit: raise WalletLimitNotAllowed() self.max_limit_ -= amount self.save() if self.real_limit > self.max_limit: self.real_limit = self.max_limit return self.max_limit # === Card manipulators === def create_card(self, **kwargs): card = Card(**kwargs) card.save() card.wallet.connect(self) self.cards.connect(card) self.increase_max_limit(card.max_limit) self.increase_free_limit(card.free_limit) self.save() card.save() return card def sorted_cards(self, fake_today=None, date_format='%m/%d/%Y'): """ Sort cards by distance to due date, than to lower limit considering today as fake_today :param fake_today: a pseudo date (or None for today) :param date_format: (format of used date) :return: active cards sorted according to rules in (enuntiate)[https://slack-files.com/T06M9ENDT-F5XK4J0P2-532510c5c0] """ cards = [] for card in self.cards: if card.active: card.set_fake_today(fake_today, date_format) cards.append(card) cards.sort() return cards # === object dictionarization === def to_dict(self): return dict(real_limit=self.real_limit, max_limit=self.max_limit, free_limit=self.free_limit, real_free_limit=self.real_free_limit, total_used=self.total_used, total_cards=len(self.cards)) # === purchase === def purchase(self, value): """ Purchase following rules in (enuntiate)[https://slack-files.com/T06M9ENDT-F5XK4J0P2-532510c5c0] :param value: :return: Purchase object generated on purchase """ # Raise RealLimitExceeded if purchase exceeds real_free_limit if self.real_free_limit < value: raise RealLimitExceeded() purchase = Purchase() purchase.total = value purchase = purchase.set_wallet(self) # If possible, purchase with only one card for card in self.sorted_cards(): if card.free_limit >= value: purchase = purchase.use_card(card, value) return purchase # Else, purchase with multiple cards for card in self.sorted_cards(): value_in_card = value if card.free_limit > value else card.free_limit purchase = purchase.use_card(card, value_in_card) value -= value_in_card if value <= 0: break return purchase