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)
Example #3
0
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')
Example #6
0
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)