def get_colid(col): coltgv = TaggedValues(col) colid = coltgv.direct('id','sql:column',None) or \ coltgv.direct('id','sql:primary',None) if not colid: colid = col.name return colid
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 generate_static_view(self, source, target): directory = read_target_node(source, target.target) tok = token('pyramid_configuration', True, static_views=[]) tgv = TaggedValues(source) path = source.name url = tgv.direct('url', 'pyramid:static_view', source.name) tok.static_views.append([url, path, '']) # if from_template is given, copy the files from the given # resource template into the target from_template = tgv.direct('from_template', 'pyramid:static_view', None) if from_template: basepath = os.path.dirname(agx.generator.pyramid.__file__) srcpath = os.path.join(basepath, 'resources', 'static_templates', from_template) tgtpath = os.path.join(*directory.fs_path) if not os.path.exists(tgtpath): os.makedirs(tgtpath) # copy over the files flist = os.listdir(srcpath) for f in flist: srcfile = os.path.join(srcpath, f) tgtfile = os.path.join(tgtpath, f) if not os.path.exists(tgtfile): if os.path.isdir(srcfile): shutil.copytree(srcfile, tgtfile) else: shutil.copy(srcfile, tgtfile)
def sql_config(self, source, target): """writes the sql config. """ nsmap = { None: 'http://namespaces.zope.org/zope', 'saconfig':'http://namespaces.zope.org/db', } tg = read_target_node(source, target.target) conf = zcautils.get_zcml(tg, 'configure.zcml', nsmap=nsmap) tgv = TaggedValues(source) engine_name = tgv.direct('engine_name', 'sql:z3c_saconfig', 'default') engine_url = tgv.direct( 'engine_url', 'sql:z3c_saconfig', 'sqlite:///test.db') session_name = tgv.direct('session_name', 'sql:z3c_saconfig', 'default') zcautils.set_zcml_directive( tg, 'configure.zcml', 'include', 'package', 'z3c.saconfig', file='meta.zcml') zcautils.set_zcml_directive( tg, 'configure.zcml', 'saconfig:engine', 'name', engine_name, url=engine_url) zcautils.set_zcml_directive( tg, 'configure.zcml', 'saconfig:session', 'name', session_name, engine=engine_name)
def interfacegeneralization(self, source, target): """Create generalization between interfaces . """ inheritance = Inheritance(source) targetclass = read_target_node(source, target.target) if targetclass: tok = token(str(targetclass.uuid), True, depends_on=set()) for obj in inheritance.values(): tok.depends_on.add(read_target_node(obj.context, target.target)) if not obj.context.name in targetclass.bases: targetclass.bases.append(obj.context.name) tgv = TaggedValues(obj.context) import_from = tgv.direct('import', 'pyegg:stub') if import_from is not UNSET: imp = Imports(targetclass.__parent__) imp.set(import_from, [[obj.context.name, None]]) derive_from = read_target_node(obj.context, target.target) if not derive_from: continue if targetclass.__parent__ is not derive_from.__parent__: imp = Imports(targetclass.__parent__) imp.set(class_base_name(derive_from), [[derive_from.classname, None]]) if targetclass and not targetclass.bases: targetclass.bases.append('Interface')
def sqlcontentclass_engine_created_handler(self, source, target): """create and register the handler for the IEngineCreatedEvent. """ if source.stereotype('pyegg:stub'): return targetpack=read_target_node(source,target.target) targetpack['saconfig.py']=Module() module = targetpack['saconfig.py'] imps = Imports(module) # check if one of the parent packages has the z3c_saconfig stereotype z3c_saconfig=get_z3c_saconfig(source) # add engine-created handler if z3c_saconfig: eggtgv=TaggedValues(z3c_saconfig) engine_name = eggtgv.direct( 'engine_name', 'sql:z3c_saconfig', 'default') globalfuncs = [f for f in module.filtereditems(IFunction)] globalfuncnames = [f.functionname for f in globalfuncs] if 'engineCreatedHandler' not in globalfuncnames: imps.set('z3c.saconfig.interfaces', [['IEngineCreatedEvent', None]]) imps.set('zope', [['component', None]]) imps.set('z3c.saconfig.interfaces',[['IEngineFactory',None]]) imps.set('sqlalchemy.ext.declarative','declarative_base') #att = [att for att in module.filtereditems(IAttribute) \ # if att.targets == ['Base']][0] bases=module.attributes('Base') if not bases: base=Attribute('Base','declarative_base()') module.insertafterimports(base) else: base=bases[0] ff = Function('engineCreatedHandler') # 'engineCreatedHandler' ff.__name__ = ff.uuid ff.args = ('event',) dec = Decorator('component.adapter') dec.__name__ = dec.uuid dec.args = ('IEngineCreatedEvent',) ff.insertfirst(dec) block_lines = [ "fact = component.queryUtility(IEngineFactory, '%s')" \ % engine_name, "if fact and fact._args == event.engine_args:", " Base.metadata.create_all(event.engine)", ] block = Block('\n'.join(block_lines)) block.__name__ = block.uuid ff.insertlast(block) module.insertafter(ff, base) prov = Block('component.provideHandler(engineCreatedHandler)') prov.__name__ = prov.uuid module.insertafter(prov, ff)
def make_generators(self, source, target): if source.stereotype('pyegg:stub'): return egg = egg_source(source) eggtarget = read_target_node(egg, target.target) zcml = get_zcml(eggtarget, 'configure.zcml', nsmap={None: 'http://namespaces.zope.org/zope', 'agx': 'http://namespaces.zope.org/agx'}) tgv = TaggedValues(source) # if transform isnt specified as tgv, get it from dependency relations to # other generators transform = tgv.direct('transform', 'generator:generator', None) if not transform: transforms = token(str(source.uuid), True, transforms=[]).transforms if len(transforms) > 1: msg = 'Currently only one transform per generator allowed (%s)' msg = msg % source.name raise ValueError(msg) elif len(transforms) == 1: transform = transforms[0].name if not transform: transform = 'uml2fs' # if depends isnt specified as tgv, get it from dependency relations to # transforms depend = tgv.direct('depends', 'generator:generator', None) if not depend: depends = token(str(source.uuid), True, depends_on=[]).depends_on if len(depends) > 1: msg = 'Currently only one depends per generator allowed (%s)' msg = msg % source.name raise ValueError(msg) elif len(depends) == 1: depend = depends[0].name if not depend: depend = 'NO' directives = zcml.filter(tag='agx:generator', attr='name') directive = None for d in directives: if d.attrs['name'] == source.name: directive = d break if not directive: directive = SimpleDirective(name='agx:generator', parent=zcml) directive.attrs['name'] = source.name directive.attrs['transform'] = transform directive.attrs['depends'] = depend set_zcml_directive(eggtarget, 'configure.zcml', 'agx:generator', 'name', source.name, overwrite=True)
def inheritancetokenizer(self, source, target): """Write inheritanceorder to token. """ tgv = TaggedValues(source) order = tgv.direct('order', 'pyegg:derive', -1) if order == -1: return tok = token(source.specific.path, True, order=dict()) tok.order[source.general.name] = order
def zcaadapts(self, source, target): adapter = source if adapter.stereotype('pyegg:function'): # XXX: <<function>> <<adapter>> on class return targetadapter = read_target_node(adapter, target.target) tok = token(str(adapter.uuid), True) pack = source.parent target = read_target_node(pack, target.target) targetclass = read_target_node(adapter, target) if isinstance(target, python.Module): targetdir = target.parent else: targetdir = target path = targetdir.path path.append('adapters.zcml') fullpath = os.path.join(*path) if 'adapters.zcml' not in targetdir.keys(): zcml = ZCMLFile(fullpath) targetdir['adapters.zcml'] = zcml else: zcml = targetdir['adapters.zcml'] addZcmlRef(targetdir, zcml) targettok = token(str(targetclass.uuid), True, realizes=[], provides=None) if not hasattr(tok, 'adapts'): msg = 'adapter class %s has no <<adapts>> dependency' \ % dotted_path(adapter) raise ValueError(msg) _for = [token(str(adaptee.uuid), False).fullpath for adaptee in tok.adapts] factory = class_full_name(targetadapter) tgv = TaggedValues(adapter) name = tgv.direct('name', 'zca:adapter') found_adapts = zcml.filter(tag='adapter', attr='factory', value=factory) if found_adapts: adapts = found_adapts[0] else: adapts = SimpleDirective(name='adapter', parent=zcml) adapts.attrs['for'] = _for if not name is UNSET: adapts.attrs['name'] = name adapts.attrs['factory'] = factory # write the provides which is collected in the zcarealize handler if len(targettok.realizes) == 1: provides = targettok.realizes[0] else: provides = targettok.provides if not provides: msg = 'adapter class %s has no interface realization' \ % dotted_path(adapter) raise ValueError(msg) adapts.attrs['provides'] = provides['path'] if hasattr(tok, 'permission'): adapts.attrs['permission'] = tok.permission
def set_args_kwargs_code(source, function): tgv = TaggedValues(source) _args = tgv.direct('args', 'pyegg:function') _kwargs = tgv.direct('kwargs', 'pyegg:function') _code = tgv.direct('code', 'pyegg:function') if _args is not UNSET: function.s_args = _args if _kwargs is not UNSET: function.s_kwargs = _kwargs if _code is not UNSET: if not function.blocks(): function.insertlast(Block(_code))
def finalize_handler(self, source, target): func = read_target_node(source, target.target) tok = token(str(source.uuid), True, scopes=[], generators=[]) tgv = TaggedValues(source) order = tgv.direct('order', 'generator:handler', None) func.args = ['self', 'source', 'target'] # ...or by dependency on a generator if tok.generators: generatornames = [g.name for g in tok.generators] else: # the generator can be defined by tgv generatornames = [tgv.direct('generator', 'generator:handler', None)] for scope in tok.scopes: stgv = TaggedValues(scope) scopename = stgv.direct('scopename', 'generator:class_scope', None) or \ stgv.direct('scopename', 'generator:simple_scope', None) or \ scope.name.lower() transform = stgv.direct('transform', 'generator:class_scope', None) or \ stgv.direct('transform', 'generator:class_scope', None) or \ 'uml2fs' transformarg = "'%s'" % transform scopenamearg = "'%s'" % scopename decfound = None for generatorname in generatornames: generatornamearg = "'%s'" % generatorname # find the dec for dec in func.decorators(): if dec.args[1] == transformarg \ and dec.args[2] == generatornamearg \ and dec.args[3] == scopenamearg: decfound = dec if decfound: dec = decfound # if not found make it else: dec = Decorator() dec.decoratorname = 'handler' dec.__name__ = dec.uuid func.insertfirst(dec) # define the args for the generator dec.args = [ "'%s'" % source.name, transformarg, generatornamearg, scopenamearg ] if not order is None: dec.kwargs['order'] = order
def console_scripts_collect(self, source, target): # collect information to define console_script entry points tok = token('console_scripts', True, defs={}) tgv = TaggedValues(source) name = tgv.direct('script_name', 'pyegg:console_script', source.name) tgt = read_target_node(source, target.target) if source.stereotype('pyegg:function') and not source.parent.stereotype('pyegg:pymodule'): path = class_base_name(tgt.parent) else: path = class_base_name(tgt) tok.defs[name] = '%s:%s' % (path, source.name)
def pyfunctionfromclass(self, source, target): """Convert Class to function if class has stereotype function set. """ if not is_class_a_function(source): return class_ = read_target_node(source, target.target) dec_keys = [dec.name for dec in class_.decorators()] decorators = [class_.detach(key) for key in dec_keys] module = class_.parent container = module if not source.parent.stereotype('pyegg:pymodule'): container = module.parent['__init__.py'] functions = container.functions(class_.classname) if functions: if len(functions) > 1: raise "expected exactly one function by name '%s'" \ % class_.classname function = functions[0] else: function = python.Function(class_.classname) function.__name__ = function.uuid container.insertlast(function) del module[str(class_.uuid)] # resync target to function, class was deleted writesourcepath(source, function) write_source_to_target_mapping(source, function) tgv = TaggedValues(source) _args = tgv.direct('args', 'pyegg:function') _kwargs = tgv.direct('kwargs', 'pyegg:function') _code = tgv.direct('code', 'pyegg:function') if _args is not UNSET: function.s_args = _args if _kwargs is not UNSET: function.s_kwargs = _kwargs if _code is not UNSET: if not function.blocks(): function.insertlast(Block(_code)) other_decorators = function.decorators() for dec in decorators: exists = 0 for other in other_decorators: if dec.equals(other): exists = 1 if exists: continue function[str(dec.uuid)] = dec
def generatescopeclass(self, source, target): """Generates scope classes. """ if source.stereotype('pyegg:stub'): return targetclass = read_target_node(source, target.target) module = targetclass.parent methods = [m for m in targetclass.functions()] methnames = [m.functionname for m in methods] methname = '__call__' tgv = TaggedValues(source) stereotypes = tgv.direct('stereotypes', 'generator:class_scope', None) or \ tgv.direct('stereotypes', 'generator:simple_scope', None) or [] transform = tgv.direct('transform', 'generator:class_scope', None) or \ tgv.direct('transform', 'generator:simple_scope', None) or \ 'uml2fs' if stereotypes: for st in stereotypes: if ':' not in st: msg = 'you have to specify the stereotype in the form ' + \ '"namespace:stereotype", but forgot the namespace ' + \ '(scope %s, stereotype %s)' % (source.name, st) raise ValueError(msg) #if not stereotypes: # msg = 'scope %s must have a stereotype attribute!!' % source.name # raise ValueError(msg) if 'Scope' not in targetclass.bases: targetclass.bases.append('Scope') if methname not in methnames: f = Function() f.functionname = methname f.args = ['self', 'node'] f.__name__ = str(f.uuid) targetclass.insertfirst(f) bl = Block() bl.__name__ = str(bl.uuid) conds = ["node.stereotype('%s') is not None" % st for st in stereotypes] cond = ' or '.join(conds) bl.lines.append("return %s" % cond) f.insertfirst(bl)
def zcarealize(self, source, target): klass = source.implementingClassifier # if klass.stereotype('pyegg:function'): # # XXX: <<function>> <<adapter>> on class # return ifacename = source.contract.name targetclass = read_target_node(klass, target.target) targetinterface = read_target_node(source.contract, target.target) tok = token(str(targetclass.uuid), True, realizes=[], provides=None) ifdef = {'name':source.contract.name} if targetinterface: ifdef['path'] = dotted_path(source.contract) # then its a stub else: tgv = TaggedValues(source.contract) impf = tgv.direct('import', 'pyegg:stub') if not impf: msg = 'Stub class %s needs a TaggedValue for "import"' \ % dotted_path(klass) raise ValueError(msg) ifdef['path'] = '.'.join([impf, ifdef['name']]) tok.realizes.append(ifdef) if source.stereotype('zca:provides'): tok.provides = ifdef # import the interface tgv = TaggedValues(source.contract) import_from = tgv.direct('import', 'pyegg:stub') imp = Imports(targetclass.__parent__) if targetinterface: tok = token(str(targetclass.uuid), True, depends_on=set()) tok.depends_on.add(targetinterface) # if (targetinterface is None -> Stub) or targetinterface is in another # module -> import if not targetinterface \ or targetclass.__parent__ is not targetinterface.__parent__: # we have a stub interface if import_from is not UNSET: basepath = import_from imp.set(basepath, [[source.contract.name, None]]) else: basepath = class_base_name(targetinterface) imp.set(basepath, [[targetinterface.classname, None]])
def gsdynamicview(self, source, target): """Add view method to FTI's of all dependent content types. """ if not source.supplier.stereotype('plone:content_type') \ or not source.client.stereotype('plone:dynamic_view'): return view = source.client content_type = source.supplier package = read_target_node(egg_source(content_type), target.target) default = package['profiles']['default'] full_name = type_id(content_type, target.target) name = '%s.xml' % full_name type_xml = default['types'][name] tgv = TaggedValues(view) viewname = tgv.direct('name', 'plone:dynamic_view', view.name) type_xml.params['ctype']['view_methods'].append(viewname)
def generate_vanilla_profile(self, source, target): egg = egg_source(source) if not is_generator_egg(egg): return tgv = TaggedValues(source) profilename = tgv.direct('name', 'generator:profile', source.name) basepath = os.path.dirname(agx.generator.generator.__file__) profilepath = os.path.join(basepath, 'resources', 'vanilla_profile') # read the model files model_di = open(os.path.join(profilepath, 'model.profile.di')).read() model_uml = open(os.path.join(profilepath, 'model.profile.uml')).read() model_notation = open(os.path.join(profilepath, 'model.profile.notation')).read() eggdir = read_target_node(egg_source(source), target.target) # create profiles dir if 'profiles' not in eggdir.keys(): profiles = Directory() profiles.__name__ = 'profiles' eggdir['profiles'] = profiles profiles = eggdir['profiles'] # add the model files with correct name and change the references if profilename + '.profile.di' not in profiles.keys(): ff = File() ff._data = model_di.replace('model.profile.notation', profilename + '.profile.notation') profiles[profilename + '.profile.di'] = ff if profilename + '.profile.uml' not in profiles.keys(): ff = File() ff._data = model_uml.replace('profilename_changeme', profilename) profiles[profilename + '.profile.uml'] = ff if profilename + '.profile.notation' not in profiles.keys(): ff = File() ff._data = model_notation.replace('model.profile.uml', profilename + '.profile.uml') profiles[profilename + '.profile.notation'] = ff
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 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 generate_vanilla_profile(self, source, target): egg = egg_source(source) if not is_generator_egg(egg): return tgv = TaggedValues(source) profilename = tgv.direct('name', 'generator:profile', source.name) basepath = os.path.dirname(agx.generator.generator.__file__) profilepath = os.path.join(basepath, 'resources', 'vanilla_profile') # read the model files model_di = open(os.path.join(profilepath, 'model.profile.di')).read() model_uml = open(os.path.join(profilepath, 'model.profile.uml')).read() model_notation = open( os.path.join(profilepath, 'model.profile.notation')).read() eggdir = read_target_node(egg_source(source), target.target) # create profiles dir if 'profiles' not in eggdir.keys(): profiles = Directory() profiles.__name__ = 'profiles' eggdir['profiles'] = profiles profiles = eggdir['profiles'] # add the model files with correct name and change the references if profilename + '.profile.di' not in profiles.keys(): ff = File() ff._data = model_di.replace( 'model.profile.notation', profilename + '.profile.notation') profiles[profilename + '.profile.di'] = ff if profilename + '.profile.uml' not in profiles.keys(): ff = File() ff._data = model_uml.replace('profilename_changeme', profilename) profiles[profilename + '.profile.uml'] = ff if profilename + '.profile.notation' not in profiles.keys(): ff = File() ff._data = model_notation.replace( 'model.profile.uml', profilename + '.profile.uml') profiles[profilename + '.profile.notation'] = ff
def pydecorator(self, source, target): """Create Decorator. """ tgv = TaggedValues(source) name = tgv.direct('name', 'pyegg:decorator', None) if not name: raise ValueError, 'decorator for %s must have a TaggedValue "name"' % \ dotted_path(source) args = tgv.direct('args', 'pyegg:decorator', None) kwargs = tgv.direct('kwargs', 'pyegg:decorator', None) container = read_target_node(source, target.target) if container.decorators(name): decorator = container.decorators(name)[0] else: decorator = python.Decorator(name) container[str(decorator.uuid)] = decorator if args is not None: decorator.s_args = args if kwargs is not None: decorator.s_kwargs = kwargs
def pyattribute(self, source, target): """Create Attribute. """ if source.parent.stereotype('pyegg:stub'): return expression = None tgv = TaggedValues(source) expression = tgv.direct('expression', 'pyegg:expression', None) name = source.name container = target.anchor if container.attributes(name): attribute = container.attributes(name)[0] if expression is not None: attribute.value = expression target.finalize(source, attribute) return value = expression is not None and expression or 'None' attribute = python.Attribute([name], value=value) container[str(attribute.uuid)] = attribute target.finalize(source, attribute)
def transform_attribute(source, target, group, fetch_tgv): field_def = lookup_field_def(source, group) attribute = read_target_node(source, target.target) if not attribute: # attribute has been removed return attribute.value = field_def['factory'] tgv = TaggedValues(source) fetch_tgv(tgv, attribute, field_def['stereotype']) imp = Imports(attribute.parent.parent) imp.set(field_def['import_from'], [[field_def['import'], None]]) if field_def['depends']: pass # XXX write to setup.py setup_dependencies
def finalize_handler(self, source, target): func = read_target_node(source, target.target) tok = token(str(source.uuid), True, scopes=[], generators=[]) tgv = TaggedValues(source) order = tgv.direct('order', 'generator:handler', None) func.args = ['self', 'source', 'target'] # ...or by dependency on a generator if tok.generators: generatornames = [g.name for g in tok.generators] else: # the generator can be defined by tgv generatornames = [tgv.direct('generator', 'generator:handler', None)] for scope in tok.scopes: stgv = TaggedValues(scope) scopename = stgv.direct('scopename', 'generator:class_scope', None) or \ stgv.direct('scopename', 'generator:simple_scope', None) or \ scope.name.lower() transform = stgv.direct('transform', 'generator:class_scope', None) or \ stgv.direct('transform', 'generator:class_scope', None) or \ 'uml2fs' transformarg = "'%s'" % transform scopenamearg = "'%s'" % scopename decfound = None for generatorname in generatornames: generatornamearg = "'%s'" % generatorname # find the dec for dec in func.decorators(): if dec.args[1] == transformarg \ and dec.args[2] == generatornamearg \ and dec.args[3] == scopenamearg: decfound = dec if decfound: dec = decfound # if not found make it else: dec = Decorator() dec.decoratorname = 'handler' dec.__name__ = dec.uuid func.insertfirst(dec) # define the args for the generator dec.args = ["'%s'" % source.name, transformarg, generatornamearg, scopenamearg] if not order is None: dec.kwargs['order'] = order
def sql_sample(self, source, target): if not source.stereotype('sql:z3c_saconfig'): return root=target.anchor tgv = TaggedValues(source) engine_name = tgv.direct('engine_name', 'sql:z3c_saconfig', 'default') engine_url = tgv.direct( 'engine_url', 'sql:z3c_saconfig', 'sqlite:///test.db') session_name = tgv.direct('session_name', 'sql:z3c_saconfig', 'default') # write the readme fname = 'sample-sqlalchemy.py' if fname not in root.keys(): readme = JinjaTemplate() readme.template = templatepath(fname + '.jinja') readme.params = { 'engine_name': engine_name, 'engine_url': engine_url, 'session_name': session_name, 'packagename': dotted_path(source), } root[fname] = readme
def generatescopeclass(self, source, target): """Generates scope classes. """ if source.stereotype('pyegg:stub'): return targetclass = read_target_node(source, target.target) module = targetclass.parent methods = [m for m in targetclass.functions()] methnames = [m.functionname for m in methods] methname = '__call__' tgv = TaggedValues(source) stereotypes = tgv.direct('stereotypes', 'generator:class_scope', None) or \ tgv.direct('stereotypes', 'generator:simple_scope', None) or [] transform = tgv.direct('transform', 'generator:class_scope', None) or \ tgv.direct('transform', 'generator:simple_scope', None) or \ 'uml2fs' if stereotypes: for st in stereotypes: if ':' not in st: msg = 'you have to specify the stereotype in the form ' + \ '"namespace:stereotype", but forgot the namespace ' + \ '(scope %s, stereotype %s)' % (source.name, st) raise ValueError(msg) #if not stereotypes: # msg = 'scope %s must have a stereotype attribute!!' % source.name # raise ValueError(msg) if 'Scope' not in targetclass.bases: targetclass.bases.append('Scope') if methname not in methnames: f = Function() f.functionname = methname f.args = ['self', 'node'] f.__name__ = str(f.uuid) targetclass.insertfirst(f) bl = Block() bl.__name__ = str(bl.uuid) conds = [ "node.stereotype('%s') is not None" % st for st in stereotypes ] cond = ' or '.join(conds) bl.lines.append("return %s" % cond) f.insertfirst(bl)
def generate_profile_location_zcml(self, source, target): if source.stereotype('pyegg:stub'): return targetclass = read_target_node(source, target.target) module = targetclass.parent blocks = module.blocks() egg = egg_source(source) eggtarget = read_target_node(egg, target.target) tgv = TaggedValues(source) #name = tgv.direct('name', 'generator:profile', None) set_zcml_directive(eggtarget, 'configure.zcml', 'utility', 'name', implicit_dotted_path(source), provides="agx.core.interfaces.IProfileLocation", component=implicit_dotted_path(source))
def createschemaclass(self, source, target): """create the schema interface class on the fly. """ klass = read_target_node(source, target.target) module = klass.parent schemaclassname = 'I' + klass.classname found = module.classes(schemaclassname) if found: schemaclass = found[0] else: schemaclass = python.Class(classname=schemaclassname) schemaclass.__name__ = schemaclass.uuid module.insertbefore(schemaclass, klass) # expose it in __init__ imp = Imports(module.parent['__init__.py']) imp.set(class_base_name(schemaclass), [[schemaclassname, None]]) # mark the content class for deletion if not needed createit = TaggedValues(source).direct('create_contentclass', 'plone:content_type', False) if not (createit or klass.functions()): token(str(klass.uuid), True, dont_generate=True)
def zcviewdepcollect(self, source, target): """Collect all view dependencies """ scope = getUtility(IScope, 'uml2fs.viewclass') pack = source.parent dep = source context = source.supplier view = source.client if not scope(view): #we are only interested in views! return target = read_target_node(pack, target.target) targetcontext = read_target_node(context, target) targetview = read_target_node(view, target) tok = token(str(view.uuid), True, browserpages=[]) contexttok = token(str(context.uuid), True, fullpath=None) if targetcontext: try: dont_generate = token(str(targetcontext.uuid), False, dont_generate=False).dont_generate if dont_generate: iface = targetcontext.parent.classes( 'I' + targetcontext.classname)[0] contexttok.fullpath = class_full_name(iface) else: contexttok.fullpath = class_full_name(targetcontext) # dont_generate doesnt seem to be defined here except ComponentLookupError: pass # its a stub else: contexttok.fullpath = '.'.join([ TaggedValues(context).direct('import', 'pyegg:stub'), context.name ]) if isinstance(target, python.Module): targetdir = target.parent else: targetdir = target tok.browserpages.append(dep)
def getservicepath(source): tgv = TaggedValues(source) name = tgv.direct('name', 'cornice:service', source.name.lower()) path = tgv.direct('path', 'cornice:service', '/' + name) return path
def make_generators(self, source, target): if source.stereotype('pyegg:stub'): return egg = egg_source(source) eggtarget = read_target_node(egg, target.target) zcml = get_zcml(eggtarget, 'configure.zcml', nsmap={ None: 'http://namespaces.zope.org/zope', 'agx': 'http://namespaces.zope.org/agx' }) tgv = TaggedValues(source) # if transform isnt specified as tgv, get it from dependency relations to # other generators transform = tgv.direct('transform', 'generator:generator', None) if not transform: transforms = token(str(source.uuid), True, transforms=[]).transforms if len(transforms) > 1: msg = 'Currently only one transform per generator allowed (%s)' msg = msg % source.name raise ValueError(msg) elif len(transforms) == 1: transform = transforms[0].name if not transform: transform = 'uml2fs' # if depends isnt specified as tgv, get it from dependency relations to # transforms depend = tgv.direct('depends', 'generator:generator', None) if not depend: depends = token(str(source.uuid), True, depends_on=[]).depends_on if len(depends) > 1: msg = 'Currently only one depends per generator allowed (%s)' msg = msg % source.name raise ValueError(msg) elif len(depends) == 1: depend = depends[0].name if not depend: depend = 'NO' directives = zcml.filter(tag='agx:generator', attr='name') directive = None for d in directives: if d.attrs['name'] == source.name: directive = d break if not directive: directive = SimpleDirective(name='agx:generator', parent=zcml) directive.attrs['name'] = source.name directive.attrs['transform'] = transform directive.attrs['depends'] = depend set_zcml_directive(eggtarget, 'configure.zcml', 'agx:generator', 'name', source.name, overwrite=True)
def generate_view_function(self, source, target): tgv = TaggedValues(source) func = read_target_node(source, target.target) if IPythonClass.providedBy(func.parent): # We have a method module = func.parent.parent klass = source.parent token(str(klass.uuid), True, has_view_methods=True) is_method = True else: module = func.parent is_method = False imps = Imports(module) funccode = "return Response('this is the stub for view %s')" % source.name # name of view route_name = tgv.direct('route_name', 'pyramid:view', source.name) if route_name == '/': route_name = '' if not func.decorators('view_config'): func.insertfirst(Decorator('view_config')) dec = func.decorators('view_config')[0] dec.kwargs['name'] = "'%s'" % route_name # necessary imports imps.set('pyramid.view', 'view_config') # the request argument if not is_method and not 'request' in func.args: func.args.append('request') # create the page template template = tgv.direct('template', 'pyramid:view', None) # template from which the template file will be generated from_template = tgv.direct('from_template', 'pyramid:view', None) if from_template and from_template != 'none' and not template: template = source.name + '.pt' print 'template name:', template, from_template if template: tdir = module.parent # set the renderer parameter based on the template name dec.kwargs['renderer'] = "'%s'" % template # create the template in target dir template_code = tgv.direct('template_code', 'pyramid:view', None) create_template_file(tdir, template, from_template, template_code=template_code and template_code.strip()) # generate default function body funccode = '''return {"page_title": "%s"}''' % source.name # if given set the renderer parameter renderer = tgv.direct('renderer', 'pyramid:view', None) if renderer and not dec.kwargs.get('renderer'): dec.kwargs['renderer'] = "'%s'" % renderer # if view function is empty, make a default code displaying info if not func.blocks(): func.insertfirst(Block(funccode)) imps.set('pyramid.response', 'Response')
def generatescopereg(self, source, target): if source.stereotype('pyegg:stub'): return targetclass = read_target_node(source, target.target) module = targetclass.parent blocks = module.blocks() tgv = TaggedValues(source) transform = tgv.direct('transform', 'generator:class_scope', None) or \ tgv.direct('transform', 'generator:simple_scope', None) or \ 'uml2fs' interfaces = tgv.direct('interfaces', 'generator:class_scope', None) or \ tgv.direct('interfaces', 'generator:simple_scope', None) scopename = tgv.direct('scopename', 'generator:class_scope', None) or \ tgv.direct('scopename', 'generator:simple_scope', None) or \ source.name.lower() #do some common imports imps = Imports(module) imps.set('node.ext.uml.interfaces', [ ['IOperation', None], ['IClass', None], ['IPackage', None], ['IInterface', None], ['IInterfaceRealization', None], ['IDependency', None], ['IProperty', None], ['IAssociation', None], ]) imps.set('agx.core', [ ['handler', None], ['Scope', None], ['registerScope', None], ['token', None], ]) # make the register statement if interfaces: ifstring = "[%s]" % ','.join(interfaces) else: ifstring = None if source.stereotype('generator:class_scope'): classname = source.name else: classname = 'Scope' reg = "registerScope('%s', '%s', %s, %s)" % \ (scopename, transform, ifstring, classname) # look if the reg stmt already exists regsearch = "registerScope('%s'" % scopename blockfound = None for b in blocks: for i in range(len(b.lines)): lcode = b.lines[i].strip().replace(' ', '') if lcode.startswith(regsearch): # replace the line b.lines[i] = reg return # else make a new block after the class declaration bl = Block() bl.__name__ = str(bl.uuid) bl.lines.append(reg) classes = [c for c in module.classes() if c.classname == source.name] if classes: klass = classes[0] module.insertafter(bl, klass) else: module.insertlast(bl)
def get_tablename(klass): tgv = TaggedValues(klass) return tgv.direct('tablename', 'sql:sql_content', klass.name.lower())
def pyattribute(self, source, target): """Create Attribute. """ klass = source.parent if klass.stereotype('pyegg:stub'): return if not klass.stereotype('sql:sql_content'): return targetclass = read_target_node(klass, target.target) module = targetclass.parent read_target_node(source, target.target) typename = source.type.name options = {} if source.stereotype('sql:primary'): options['primary_key'] = 'True' colid = None # retrieve options if the primitive type has <<sql_type>> if source.type.stereotype('sql:sql_type'): tgv = TaggedValues(source.type) typename = tgv.direct('classname', 'sql:sql_type', typename) default = tgv.direct('default', 'sql:sql_type', None) if default: options['default'] = default import_from = tgv.direct('import_from', 'sql:sql_type', None) if import_from: imps = Imports(module) imps.set(import_from, [[typename, None]]) positionals = [typename] # collect params from column stereotype if source.stereotype('sql:column') or source.stereotype('sql:primary'): coltgv = TaggedValues(source) # id colid = coltgv.direct('id', 'sql:column', None) or \ coltgv.direct('id', 'sql:primary', None) if colid: positionals.insert(0, "'%s'" % colid) # index index = coltgv.direct('index', 'sql:column', None) or \ source.stereotype('sql:primary') if index: options['index'] = 'True' # default default = coltgv.direct('default', 'sql:column', None) or \ coltgv.direct('dafault', 'sql:primary', None) or \ options.get('default') if default: options['default'] = default # nullable not_null = None if coltgv.direct('not_null', 'sql:column', None) is not None: not_null = coltgv.direct('not_null', 'sql:column') if not_null is not None: options['nullable'] = { 'true': False, 'false': True, }[not_null] # server_default server_default = coltgv.direct( 'server_default', 'sql:column', None) or coltgv.direct( 'server_default', 'sql:primary', None) if server_default: options['server_default'] = server_default # sequence sequence = coltgv.direct('sequence', 'sql:column', None) or \ coltgv.direct('sequence', 'sql:primary', None) if sequence: positionals.append("Sequence('%s')" % sequence) targetatt = read_target_node(source, target.target) if options: oparray = [] for k in options: oparray.append('%s = %s' % (k, options[k])) targetatt.value = 'Column(%s,%s)' % ( ','.join(positionals), ', '.join(oparray)) else: targetatt.value = 'Column(%s)' % (','.join(positionals))
def plonebrowserview(self, source, target): view = source if view.stereotype('pyegg:function'): # XXX: <<function>> <<adapter>> on class return tok = token(str(view.uuid), True, browserpages=[]) pack = source.parent target = read_target_node(pack, target.target) targetclass = read_target_node(view, target) if isinstance(target, python.Module): targetdir = target.parent else: targetdir = target path = targetdir.path path.append('browser.zcml') fullpath = os.path.join(*path) if 'browser.zcml' not in targetdir: zcml = ZCMLFile(fullpath) zcml.nsmap['browser'] = 'http://namespaces.zope.org/browser' targetdir['browser.zcml'] = zcml else: zcml = targetdir['browser.zcml'] addZcmlRef(targetdir, zcml) targettok = token(str(targetclass.uuid), True, browserpages=[], provides=None) _for = [token(str(context.supplier.uuid), False).fullpath \ for context in tok.browserpages] or ['*'] classpath = class_full_name(targetclass) tgv = TaggedValues(view) # create the templates dir if 'templates' not in targetdir.keys(): targetdir['templates'] = Directory('templates') templates = targetdir['templates'] templates.factories['.pt'] = XMLTemplate #create the browser:page entries for bp in tok.browserpages or [None]: #name of view: if it should have a constant name, change the last param viewname = tgv.direct('name', 'plone:view', None) or \ tgv.direct('name', 'plone:dynamic_view', view.xminame.lower()) name_raw = tgv.direct('name', 'plone:view', None) or \ tgv.direct('name', 'plone:vdynamic_view', None) name = name_raw or view.xminame.lower() template_name_raw = tgv.direct('template_name', 'plone:view', None) or \ tgv.direct('template_name', 'plone:dynamic_view', None) template_name = template_name_raw or name + '.pt' permission = tgv.direct('permission', 'plone:view', None) or \ tgv.direct('permission', 'plone:dynamic_view', None) layer = tgv.direct('layer', 'plone:view', None) or \ tgv.direct('layer', 'plone:dynamic_view', None) if bp: bptgv = TaggedValues(bp) bptok = token(str(bp.supplier.uuid), False) _for = bptok.fullpath print 'xminame:', bp, bp.xminame # consider uuid as an unset name if bp.xminame is None or re.match( '[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}', bp.xminame): bpname = None else: bpname = bp.xminame.lower() if bp.xminame: viewname = bp.xminame viewname = bptgv.direct('name', 'plone:view', None) or \ bptgv.direct('name', 'plone:dynamic_view', viewname) name = bptgv.direct('name', 'plone:view', None) or \ bptgv.direct('name', 'plone:dynamic_view', bpname or name) # override template name template_name = bptgv.direct( 'template_name', 'plone:view', None) or \ bptgv.direct( 'template_name', 'plone:dynamic_view', None) or \ template_name_raw or name + '.pt' permission = bptgv.direct('permission', 'plone:view', None) or \ bptgv.direct('permission', 'plone:dynamic_view', permission) layer = bptgv.direct('layer', 'plone:view', None) or \ bptgv.direct('layer', 'plone:dynamic_view', layer) else: _for = '*' found_browserpages = zcml.filter(tag='browser:page', attr='name', value=viewname) browser = None templatepath = 'templates/' + template_name if found_browserpages: for br in found_browserpages: #check if it really matches if br.attrs.get('class') == classpath and \ _for == br.attrs['for']: browser = br break if not browser: browser = SimpleDirective(name='browser:page', parent=zcml) browser.attrs['for'] = _for if viewname and not viewname is UNSET: browser.attrs['name'] = viewname browser.attrs['class'] = classpath browser.attrs['template'] = templatepath browser.attrs['permission'] = permission or 'zope2.View' if layer: browser.attrs['layer'] = layer # spit out the page vanilla template if template_name not in templates.keys(): pt = XMLTemplate() templates[template_name] = pt # set template for viewtemplate pt.template = 'agx.generator.plone:templates/viewtemplate.pt'
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 zcaeventfor(self, source, target): adapter = source tok = token(str(adapter.uuid), True) if not hasattr(tok, 'fors'): msg = 'subscriber class %s has no <<for>> dependency' \ % dotted_path(adapter) raise ValueError(msg) pack = source.parent target = read_target_node(pack, target.target) if isinstance(target, python.Module): targetdir = target.parent else: targetdir = target path = targetdir.path path.append('subscribers.zcml') fullpath = os.path.join(*path) if 'subscribers.zcml' not in targetdir.keys(): zcml = ZCMLFile(fullpath) targetdir['subscribers.zcml'] = zcml else: zcml = targetdir['subscribers.zcml'] addZcmlRef(targetdir, zcml) targetclass = read_target_node(adapter, target) targettok = token(str(targetclass.uuid), True, realizes=[], provides=None) # make sure that the event is the second entry in the for list if tok.fors[0].stereotype('zca:event'): tok.fors.reverse() _for = [token(str(adaptee.uuid), False).fullpath for adaptee in tok.fors] factory = dotted_path(adapter) tgv = TaggedValues(adapter) name = tgv.direct('name', 'zca:for') isfunc = adapter.stereotype('pyegg:function') # functions are declared handler, classes factories if isfunc: attrname = 'handler' else: attrname = 'factory' found_adapts = zcml.filter(tag='subscriber', attr=attrname, value=factory) if found_adapts: adapts = found_adapts[0] else: adapts = SimpleDirective(name='subscriber', parent=zcml) adapts.attrs['for'] = _for if not name is UNSET: adapts.attrs['name'] = name adapts.attrs[attrname] = factory # write the provides which is collected in the zcarealize handler if len(targettok.realizes) == 1: provides = targettok.realizes[0] else: provides = targettok.provides if not isfunc: if provides: adapts.attrs['provides'] = provides['path'] if hasattr(tok, 'permission'): adapts.attrs['permission'] = tok.permission
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)
def eggdocuments(self, source, target): """Create egg ``setup.py`` and default documents. """ root = target.anchor # setup.py root.factories['setup.py'] = JinjaTemplate tgv = TaggedValues(source) version = tgv.direct('version', 'pyegg:pyegg', '1.0') project = source.name cp = tgv.direct('copyright', 'pyegg:pyegg', '') cp = cp.split(',') cp = [line.strip() for line in cp] description = tgv.direct('description', 'pyegg:pyegg', '') classifiers = tgv.direct('classifiers', 'pyegg:pyegg', '') classifiers = classifiers.split(',') classifiers = [cla.strip() for cla in classifiers] keywords = tgv.direct('keywords', 'pyegg:pyegg', '') author = tgv.direct('author', 'pyegg:pyegg', '') author_email = tgv.direct('email', 'pyegg:pyegg', '') url = tgv.direct('url', 'pyegg:pyegg', '') license_name = tgv.direct('license', 'pyegg:pyegg', '') namespace = project.split('.') namespace_packages = list() if len(namespace) > 1: for i in range(len(namespace) - 1): namespace_packages.append('"%s"' % '.'.join(namespace[:i + 1])) namespace_packages = ', '.join(namespace_packages) zip_safe = tgv.direct('zipsafe', 'pyegg:pyegg', 'False') if 'setup.py' in root: setup = root['setup.py'] else: setup = JinjaTemplate() root['setup.py'] = setup # read entry_points from token, so that other generators have the chance # to define entry_points entry_points_tok = token('entry_points', True, defs=[]) setup_dependencies = token('setup_dependencies', True, deps=[]) setup.template = templatepath('setup.py.jinja') setup.params = { 'cp': cp, 'version': version, 'project': project, 'description': description, 'classifiers': classifiers, 'keywords': keywords, 'author': author, 'author_email': author_email, 'url': url, 'license_name': license_name, 'namespace_packages': namespace_packages, 'zip_safe': zip_safe, 'setup_dependencies': setup_dependencies.deps, 'entry_points':'\n'.join(entry_points_tok.defs), } # README.rst if 'README.rst' not in root: readme = JinjaTemplate() root['README.rst'] = readme readme.template = templatepath('README.rst.jinja') readme.params = setup.params # MANIFEST.rst if 'MANIFEST.in' not in root: manifest = JinjaTemplate() root['MANIFEST.rst'] = manifest manifest.template = templatepath('MANIFEST.in.jinja') manifest.params = {} # LICENSE.rst if 'LICENSE.rst' not in root: license = JinjaTemplate() root['LICENSE.rst'] = license license.template = templatepath('LICENSE.rst.jinja') license.params = {}