def candidate(cls): return relationship( 'Candidate', backref=backref( camel_to_under(cls.__name__) + 's', cascade='all, delete-orphan', cascade_backrefs=False), cascade_backrefs=False)
def candidate(cls): return relationship( "Candidate", backref=backref( camel_to_under(cls.__name__) + "s", cascade="all, delete-orphan", cascade_backrefs=False, ), cascade_backrefs=False, )
def key(cls): return relationship( '%sKey' % cls.__name__, backref=backref( camel_to_under(cls.__name__) + 's', cascade='all, delete-orphan'))
def __tablename__(cls): return camel_to_under(cls.__name__)
def candidate_subclass(class_name, args, table_name=None, cardinality=None, values=None): """ Creates and returns a Candidate subclass with provided argument names, which are Context type. Creates the table in DB if does not exist yet. Import using: .. code-block:: python from fonduer.models import candidate_subclass :param class_name: The name of the class, should be "camel case" e.g. NewCandidate :param args: A list of names of consituent arguments, which refer to the Contexts--representing mentions--that comprise the candidate :param table_name: The name of the corresponding table in DB; if not provided, is converted from camel case by default, e.g. new_candidate :param cardinality: The cardinality of the variable corresponding to the Candidate. By default is 2 i.e. is a binary value, e.g. is or is not a true mention. """ if table_name is None: table_name = camel_to_under(class_name) # If cardinality and values are None, default to binary classification if cardinality is None and values is None: values = [True, False] cardinality = 2 # Else use values if present, and validate proper input elif values is not None: if cardinality is not None and len(values) != cardinality: raise ValueError("Number of values must match cardinality.") if None in values: raise ValueError("`None` is a protected value.") # Note that bools are instances of ints in Python... if any([isinstance(v, int) and not isinstance(v, bool) for v in values]): raise ValueError( ("Default usage of values is consecutive integers." "Leave values unset if trying to define values as integers.")) cardinality = len(values) # If cardinality is specified but not values, fill in with ints elif cardinality is not None: values = list(range(cardinality)) class_spec = (args, table_name, cardinality, values) if class_name in candidate_subclasses: if class_spec == candidate_subclasses[class_name][1]: return candidate_subclasses[class_name][0] else: raise ValueError( 'Candidate subclass ' + class_name + ' already exists in memory with incompatible ' + 'specification: ' + str(candidate_subclasses[class_name][1])) else: # Set the class attributes == the columns in the database class_attribs = { # Declares name for storage table '__tablename__': table_name, # Connects candidate_subclass records to generic Candidate records 'id': Column( Integer, ForeignKey('candidate.id', ondelete='CASCADE'), primary_key=True), # Store values & cardinality information in the class only 'values': values, 'cardinality': cardinality, # Polymorphism information for SQLAlchemy '__mapper_args__': { 'polymorphic_identity': table_name }, # Helper method to get argument names '__argnames__': args, } # Create named arguments, i.e. the entity mentions comprising the relation # mention # For each entity mention: id, cid ("canonical id"), and pointer to Context unique_args = [] for arg in args: # Primary arguments are constituent Contexts, and their ids class_attribs[arg + '_id'] = Column(Integer, ForeignKey( 'context.id', ondelete='CASCADE')) class_attribs[arg] = relationship( 'Context', backref=backref( table_name + '_' + arg + 's', cascade_backrefs=False, cascade='all, delete-orphan'), cascade_backrefs=False, foreign_keys=class_attribs[arg + '_id']) unique_args.append(class_attribs[arg + '_id']) # Canonical ids, to be set post-entity normalization stage class_attribs[arg + '_cid'] = Column(String) # Add unique constraints to the arguments class_attribs['__table_args__'] = (UniqueConstraint(*unique_args), ) # Create class C = type(class_name, (Candidate, ), class_attribs) # Create table in DB if not _meta.engine.dialect.has_table(_meta.engine, table_name): C.__table__.create(bind=_meta.engine) candidate_subclasses[class_name] = C, class_spec return C
def key(cls): return relationship( "%sKey" % cls.__name__, backref=backref(camel_to_under(cls.__name__) + "s", cascade="all, delete-orphan"), )