def calculate_joins(source, targetclass, otherclass, otherendname, nullable=False, force_fullname=False): joins = [] pks = get_pks(otherclass) my_pks=get_pks(source) if not pks: raise ValueError,'class %s has no primary key defined' % dotted_path(otherclass) try: lastattr = targetclass.attributes()[-1] except IndexError: lastattr = None for pk in pks: pkname = get_colid(pk) #import pdb;pdb.set_trace() fkname = get_fkname(source, pkname, otherendname, force_fullname=force_fullname) # this stmt will be attached to otherend in order to be used # for the join in the relationship stmt joinstmt = '%s.%s == %s.%s' % ( source.name, fkname, otherclass.name, pkname) if not targetclass.attributes(fkname): attr = Attribute() attr.__name__ = str(attr.uuid) if lastattr: targetclass.insertafter(attr, lastattr) else: targetclass.insertfirst(attr) attr.targets = [fkname] fk = "ForeignKey('%s.%s')" % ( get_tablename(otherclass), pkname) options = {} typename = pk.type.name # handle custom types (PrimitveType) if pk.type.stereotype('sql:sql_type'): tgv = TaggedValues(pk.type) typename = tgv.direct( 'classname', 'sql:sql_type', typename) import_from = tgv.direct( 'import_from', 'sql:sql_type', None) if import_from: imps = Imports(module) imps.set(import_from, [[typename, None]]) if nullable: options['nullable'] = 'True' else: options['nullable'] = 'False' if not my_pks: options['primary_key'] = 'True' oparray = [] for k in options: oparray.append('%s = %s' % (k, options[k])) attr.value = 'Column(%s, %s, %s)' % ( typename, fk, ', '.join(oparray)) joins.append(joinstmt) return joins
def setup_i18n(self, source, target): tdir = read_target_node(source, target.target) init = tdir['__init__.py'] imps = Imports(init) imps.set('pyramid.i18n', 'TranslationStringFactory') if not init.attributes('_'): att = Attribute(['_'], "TranslationStringFactory('%s')" % source.name) att.__name__ = str(att.uuid) init.insertafterimports(att)
def generate_profile_location(self, source, target): targetclass = read_target_node(source, target.target) module = targetclass.parent ifspec = { 'path': 'agx.core.interfaces.IProfileLocation', 'name': 'IProfileLocation', } tok = token(str(targetclass.uuid), False, realizes=[]) if ifspec not in tok.realizes: tok.realizes.append(ifspec) tgv = TaggedValues(source) name = tgv.direct('profile_name', 'generator:profile', None) if not name: name = source.name #msg = 'profile_name tagged value not defined for %s!' % source.name #raise ValueError(msg) imps = Imports(module) frompath = '.'.join(ifspec['path'].split('.')[:-1]) imps.set(frompath, [[ifspec['name'], None]]) attributenames = [att.targets[0] for att in targetclass.attributes()] if 'name' not in attributenames: att = Attribute() att.__name__ = att.uuid targetclass[att.name] = att att.targets = ['name'] att.value = "'%s.profile.uml'" % name if 'package' not in attributenames: att = Attribute() att.__name__ = att.uuid targetclass[att.name] = att att.targets = ['package'] att.value = dotted_path(source.parent) imps.set('', [[att.value, None]]) # remove the import from this class init = targetclass.parent.parent['__init__.py'] fromimp = '.'.join(implicit_dotted_path(source).split('.')[:-1]) imps = [imp for imp in init.imports() if imp.fromimport == fromimp] for imp in imps: init.detach(str(imp.uuid))
def sqljoinedtablebaseclass(self, source, target): """preparation for joined table inheritance base class. """ if source.stereotype('pyegg:stub'): return targetclass = read_target_node(source, target.target) module = targetclass.parent classatts = [att for att in targetclass.filtereditems(IAttribute)] # if a class is a base class for joined_table_inheritance it must have # discriminator and __mapper_args__ if not [a for a in classatts if a.targets == ['__mapper_args__']]: abstract = Attribute(['__mapper_args__'], "{'polymorphic_on':discriminator}") abstract.__name__ = '__mapper_args__' targetclass.insertfirst(abstract) if not [a for a in classatts if a.targets == ['discriminator']]: abstract = Attribute(['discriminator'], "Column(String)") abstract.__name__ = 'discriminator' targetclass.insertfirst(abstract)
def create_service(self, source, target): """create a module 'services.py' to hold the cornice services create a docstring at the top of the module. create an import statement (from cornice import Service). create an attribute of the name of the UML::Class and set it to a Service(with parameters) parameters are name = name of the """ klass = read_target_node(source, target.target) module = klass.parent # create imports for cornice service imps = Imports(module) imps.set('cornice', 'Service') # from cornice import Service # add the dep deps = token('setup_dependencies', True, deps=[]) if not 'cornice' in deps.deps: deps.deps.append('cornice') # prepare for later: get name of the service servicename = getservicename(source) servicepath = getservicepath(source) # create an Attribute that will define a cornice service serviceattr = Attribute() serviceattr.targets = [source.name] serviceattr.value = 'Service(name="%s", path="%s")' % (servicename, servicepath) serviceattr.__name__ = serviceattr.uuid # lets insert it after the class definition if not module.attributes(source.name): module.insertafter(serviceattr, klass) # mark importme dependencies for pyramid tok = token('pyramid_importmes', True, packages=[]) if 'cornice' not in tok.packages: tok.packages.append('cornice')
def plone__init__(self, source, target): egg = egg_source(source) eggname = egg.name targetdir = read_target_node(source, target.target) module = targetdir['__init__.py'] imp = Imports(module) imp.set('zope.i18nmessageid', [['MessageFactory', None]]) value = 'MessageFactory("%s")' % eggname atts = [att for att in module.attributes() if '_' in att.targets] if atts: atts[0].value = value else: module['_'] = Attribute('_', value)
def generate_profile_location(self, source, target): targetclass = read_target_node(source, target.target) module = targetclass.parent ifspec = { 'path': 'agx.core.interfaces.IProfileLocation', 'name': 'IProfileLocation', } tok = token(str(targetclass.uuid), False, realizes=[]) if ifspec not in tok.realizes: tok.realizes.append(ifspec) tgv = TaggedValues(source) name = tgv.direct('profile_name', 'generator:profile', None) if not name: name=source.name #msg = 'profile_name tagged value not defined for %s!' % source.name #raise ValueError(msg) imps = Imports(module) frompath = '.'.join(ifspec['path'].split('.')[:-1]) imps.set(frompath, [[ifspec['name'], None]]) attributenames = [att.targets[0] for att in targetclass.attributes()] if 'name' not in attributenames: att = Attribute() att.__name__ = att.uuid targetclass[att.name] = att att.targets = ['name'] att.value = "'%s.profile.uml'" % name if 'package' not in attributenames: att = Attribute() att.__name__ = att.uuid targetclass[att.name] = att att.targets = ['package'] att.value = dotted_path(source.parent) imps.set('', [[att.value, None]]) # remove the import from this class init = targetclass.parent.parent['__init__.py'] fromimp = '.'.join(implicit_dotted_path(source).split('.')[:-1]) imps = [imp for imp in init.imports() if imp.fromimport == fromimp] for imp in imps: init.detach(str(imp.uuid))
def sqlrelations_relations(self, source, target): """generate relations. """ if source.stereotype('pyegg:stub'): return if not source.stereotype('sql:sql_content'): return targetclass = read_target_node(source, target.target) module = targetclass.parent directory = module.parent # get the last attribute and append there the relations attrs = targetclass.attributes() attrnames = [att.targets[0] for att in attrs] try: lastattr = targetclass.attributes()[-1] except IndexError: lastattr = None outgoing_relations = token(str(source.uuid), True, outgoing_relations=[]).outgoing_relations imps = Imports(module) if outgoing_relations: imps.set('sqlalchemy.orm', [['relationship', None]]) for relend in outgoing_relations: assoc = relend.association if relend==relend.association.memberEnds[0]: otherend = relend.association.memberEnds[1] else: otherend = relend.association.memberEnds[0] #Association classes are handled seperately #once we support association tables, we have to handle it here tgv = TaggedValues(assoc) if IAssociationClass.providedBy(assoc): # tgv = TaggedValues(otherend) We need to build support for tgvs on # member ends later klass = relend.type otherclass = relend.association relname = token(str(otherend.uuid), True, relname=otherend.name+'_associations').relname else: klass = relend.type otherclass = otherend.type relname = otherend.name if relname not in attrnames: attr = Attribute() attr.__name__ = str(attr.uuid) if lastattr: targetclass.insertafter(attr, lastattr) else: targetclass.insertfirst(attr) attr.targets = [relname] options = {} # collect options for relationship if otherend.aggregationkind == 'composite': options['cascade'] = "'all, delete-orphan'" if assoc.stereotype('sql:ordered'): order_by = tgv.direct('order_by', 'sql:ordered', None) if not order_by: msg = 'when setting a relation ordered you have to ' +\ 'specify order_by!' raise ValueError(msg) # if not prefixed, lets prefix it if not '.' in order_by: order_by = '%s.%s' % (otherclass.name, order_by) options['order_by'] = "'%s'" % order_by if assoc.stereotype('sql:attribute_mapped'): keyname = tgv.direct('key', 'sql:attribute_mapped', None) if not keyname: msg = 'when defining attribute_mapped you have to ' + \ 'specify a key' raise ValueError(msg) if assoc.stereotype('sql:ordered'): # support for ordered mapped collection # in this case we have to provide our own collection # see http://docs.sqlalchemy.org/en/rel_0_7/orm/collections.html, # secion 'Custom Dictionary-Based Collections' fname = 'orderedcollection.py' if fname not in directory: src = JinjaTemplate() src.template = templatepath(fname + '.jinja') src.params = {} directory[fname] = src # XXX: so that emptymoduleremoval doesnt kick the # template out better would be that jinjatemplates # dont get removed at all token('pymodules', True, modules=set()).modules.add(src) options['collection_class'] = \ "ordered_attribute_mapped_collection('%s')" % keyname imps.set('orderedcollection', [['ordered_attribute_mapped_collection', None]]) # unordered else: options['collection_class'] = \ "attribute_mapped_collection('%s')" % keyname imps.set('sqlalchemy.orm.collections', [['attribute_mapped_collection', None]]) # make the primaryjoin stmt if 1 or not IAssociationClass.providedBy(relend.association): tok = token(str(relend.uuid), True, joins=[]) if tok.joins: options['primaryjoin'] = "'%s'" % ','.join(tok.joins) # XXX: .navigable isn't yet correctly parsed from uml, thus the # hardcoding if True or relend.navigable: options['backref'] = "'%s'" % relend.name.lower() if assoc.stereotype('sql:lazy'): laziness = tgv.direct('laziness', 'sql:lazy', 'dynamic') options['lazy'] = "'%s'" % laziness #convert options into keyword params oparray = [] for k in options: oparray.append('%s = %s' % (k, options[k])) attr.value = "relationship('%s', %s)" % ( otherclass.name, ', '.join(oparray))
def sqlcontentclass(self, source, target): """sqlalchemy class. """ if source.stereotype('pyegg:stub'): return targetclass = read_target_node(source, target.target) module = targetclass.parent imps = Imports(module) imps.set('sqlalchemy', [['Column', None], ['Integer', None], ['String', None], ['ForeignKey', None], ['Sequence', None]]) # find last import and do some assignments afterwards lastimport = [imp for imp in module.filtereditems(IImport)][-1] globalatts = [att for att in module.filtereditems(IAttribute)] classatts = [att for att in targetclass.filtereditems(IAttribute)] # generate the Base=declarative_base() statement saconfig=get_z3c_saconfig(source) if saconfig: # if we have a z3c_saconfig setting we import the Base from # the corresponding package imps.set(dotted_path(saconfig)+'.saconfig','Base') else: # otherwise we create it by default imps.set('sqlalchemy.ext.declarative', 'declarative_base') att = Attribute(['Base'], 'declarative_base()') att.__name__ = 'Base' if not [a for a in globalatts if a.targets == ['Base']]: module.insertafter(att, lastimport) # generate the __tablename__ attribute if not [a for a in classatts if a.targets == ['__tablename__']]: tablename = Attribute(['__tablename__'], "'%s'" % (get_tablename(source))) tablename.__name__ = '__tablename__' targetclass.insertfirst(tablename) # if a class is a base class for concrete_table_inheritance it must be # abstract if source.stereotype('sql:concrete_table_inheritance'): if not [a for a in classatts if a.targets == ['__abstract__']]: abstract = Attribute(['__abstract__'], "True") abstract.__name__ = '__abstract__' targetclass.insertfirst(abstract) # lets inherit from Base unless we dont inherit from a sql_content class has_sql_parent = False joined_parents = [] table_per_class_parents = [] for inh in Inheritance(source).values(): if inh.context.stereotype('sql:sql_content'): has_sql_parent = True if inh.context.stereotype('sql:joined_table_inheritance'): joined_parents.append(inh.context) elif inh.context.stereotype('sql:concrete_table_inheritance'): table_per_class_parents.append(inh.context) else: msg = 'when inheriting from an sql_content class (%s) ' + \ 'the parent has to have either ' + \ '<<joined_table_inheritance>> or ' + \ '<<concrete_table_inheritance>> stereotype! ' + \ 'see "http://docs.sqlalchemy.org/en/rel_0_7/' + \ 'orm/inheritance.html" for further info' msg = msg % source.name raise ValueError(msg) if targetclass.bases == ['object']: targetclass.bases = ['Base'] else: if not has_sql_parent and 'Base' not in targetclass.bases: targetclass.bases.insert(0, 'Base') # if the class has parents that are joined base classes # we need __mapper_args__ and a foreign primary key for parent in joined_parents: pks = get_pks(parent) if not pks: msg = 'class %s must have a primary key defined!' % parent.name raise ValueError(msg) pk = pks[0] pkname = get_colid(pk) pfkname = pkname typename = pk.type.name if pk.type.stereotype('sql:sql_type'): tgv = TaggedValues(pk.type) typename = tgv.direct('classname', 'sql:sql_type', typename) fk = "ForeignKey('%s.%s')" % (get_tablename(parent), pkname) pfkstmt = "Column(%s, %s,primary_key = True)" % (typename, fk) if not [a for a in classatts if a.targets == [pfkname]]: pfk = Attribute([pfkname], pfkstmt) pfk.__name__ = pfkname targetclass.insertfirst(pfk) if not [a for a in classatts if a.targets == ['__mapper_args__']]: mapper_val = "{'polymorphic_identity':'%s'}" % source.name.lower() abstract = Attribute(['__mapper_args__'], mapper_val) abstract.__name__ = '__mapper_args__' targetclass.insertfirst(abstract)