def prepare(priority=PRIORITY_NORMAL): ''' Decorator for application prepare setup functions. The prepare function will be called mainly in order to prepare the application arguments. @param priority: one of priority markers The priority to associate with the event. ''' if isinstance(priority, Priority): return onDecorator((APP_PREPARE,), priority, callerLocals()) return onDecorator((APP_PREPARE,), PRIORITY_NORMAL, callerLocals())(priority)
def start(priority=PRIORITY_NORMAL): ''' Decorator for application start setup functions. The start function will be called after the application arguments have been parsed. @param priority: one of priority markers The priority to associate with the event. ''' if isinstance(priority, Priority): return onDecorator((APP_START,), priority, callerLocals()) return onDecorator((APP_START,), PRIORITY_NORMAL, callerLocals())(priority)
def deploy(*triggers, priority=PRIORITY_NORMAL): ''' Decorator for deploy setup functions. The deploy function will be called every time the application is started. This should manly be used to gather data. @param triggers: arguments[ITrigger] Triggers to be considered for the deploy call, this will actually condition the deploy call to the provided triggers. @param priority: one of priority markers The priority to associate with the event. ''' if not triggers: return onDecorator((DEPLOY,), priority, callerLocals()) if len(triggers) == 1 and not isinstance(triggers[0], ITrigger): return onDecorator((DEPLOY,), priority, callerLocals())(triggers[0]) return onDecorator(triggers, priority, callerLocals())
def dump(*triggers, priority=PRIORITY_NORMAL): ''' Decorator for deploy setup functions. The deploy function will be called every time the application is started. This should manly be used to gather data. @param triggers: arguments[ITrigger] Triggers to be considered for the deploy call, this will actually condition the deploy call to the provided triggers. @param priority: one of priority markers The priority to associate with the event. ''' if not triggers: return onDecorator((DUMP,), priority, callerLocals()) if len(triggers) == 1 and not isinstance(triggers[0], ITrigger): return onDecorator((DUMP,), priority, callerLocals())(triggers[0]) return onDecorator(triggers, priority, callerLocals())
def relationshipModel(mappedId, *spec): ''' Creates a relationship with the model, this should only be used in case the mapped model database id is different from the actual model id. @param mappedId: InstrumentedAttribute The mapped model id to create the relation with. @param spec: arguments containing column: string The column name containing the foreign key relation, attention if target is provided then also column needs to be provided, if None provided it will create one automatically. target: string The SQL alchemy relationship target name, if None provided it will create one automatically. ''' assert isinstance(mappedId, InstrumentedAttribute), 'Invalid mapped id %s' % mappedId register = callerLocals() assert '__module__' in register, 'This function should only be used inside meta class definitions' rtype = typeFor(mappedId.class_) assert isinstance(rtype, TypeModel), 'Invalid class %s' % mappedId.class_ assert isinstance(rtype.propertyId, TypeProperty), 'No property id for %s' % rtype assert rtype.propertyId.name != mappedId.property.key, 'Same database id with the model id \'%s\' for %s' % mappedId.class_ column = target = None if spec: column, *spec = spec assert isinstance(column, str), 'Invalid column %s' % column if spec: target, = spec assert isinstance(target, str) and target, 'Invalid target %s' % target if target is None: target = modifyFirst(rtype.name, False) if column is None: column = '%sId' % target register[column] = Column('fk_%s_id' % toUnderscore(target), ForeignKey(mappedId, ondelete='CASCADE'), nullable=False) register[target] = relationship(mappedId.class_, uselist=False, lazy='joined', viewonly=True) def fget(self): rel = getattr(self, target) if rel: return getattr(rel, rtype.propertyId.name) columnId = columnFor(getattr(mappedId.class_, rtype.propertyId.name)) def fset(self, value): setattr(self, column, select([mappedId], columnId == value)) validation = validate(Mandatory, Relation) return validation( hybrid_property(fget, fset, expr=joinedExpr(mappedId.class_, rtype.propertyId.name)))
def config(name, type=None, doc=None): ''' Used for defining a wired configuration attribute. If the type is not provided the configuration attribute needs to contain a class or type that will help the wiring to know exactly the expected type, if the attribute is None or not existing than the attribute is not validate by type. @param name: string The configurations attribute names to be added to the wiring context. @param type: class The type of the attribute @param doc: string The description of the attribute ''' assert isinstance(name, str), 'Invalid attribute name %s' % name assert not doc or isinstance(doc, str), 'Invalid description %s' % doc if not name.islower(): raise WireError('Invalid name %r for configuration, needs to be lower case only' % name) locals = callerLocals() hasValue, value = False, None if not type: if name in locals: v = locals[name] if isclass(v): type = v else: hasValue, value = True, v if v is not None: type = v.__class__ if type and not isclass(type): raise WireError('Invalid type %s for %r' % (type, name)) else: if not isclass(type): raise WireError('Invalid type %s for %r' % (type, name)) v = locals[name] if isinstance(v, type): hasValue, value = True, v type = normalizeConfigType(type) Wiring.wiringFor(locals).addConfiguration(name, type, hasValue, value, doc)
def populate(*triggers, priority=PRIORITY_NORMAL): ''' Decorator for populate setup functions. The populate function will be called until a True or None value is returned. This should manly be used in order to populate default data. If the function returns False it means it needs to be called again for the same event, if True or None is returned it means the function executed successfully. @param triggers: arguments[ITrigger] Additional triggers to be considered for the populate, this events will trigger the populate for other situations rather just the application first start. @param priority: one of priority markers The priority to associate with the event. ''' if not triggers: return onDecorator((POPULATE,), priority, callerLocals()) if len(triggers) == 1 and not isinstance(triggers[0], ITrigger): return onDecorator((POPULATE,), priority, callerLocals())(triggers[0]) return onDecorator(chain(triggers, (POPULATE,)), priority, callerLocals())
def publish(*args): ''' To be used as decorator whenever publishing GUI files ''' decorator = onDecorator((app.POPULATE, app.DEVEL), app.PRIORITY_NORMAL, callerLocals()) if not args: return decorator assert len(args) == 1, 'Expected only one argument that is the decorator function, got %s arguments' % len(args) return decorator(args[0])
def decorator(setup): from .support import nameEntity, nameInEntity registry = callerLocals() assert '__name__' in registry, 'The wire call needs to be made directly from the setup module' group = registry['__name__'] for clazz in classes: if not createWirings(clazz, setup, group, registry, nameEntity, nameInEntity): raise SetupError('Invalid class %s, has no wirings' % clazz) return setup
def _distribution(args, event): ''' FOR INTERNAL USE ONLY! Populates the distribution setup. ''' if not args: return deploy assert len(args) == 1, 'Expected only one argument that is the decorator function, got %s arguments' % len(args) function = args[0] hasType, type = _process(function) if hasType: raise SetupError('No return annotation expected for function %s' % function) return update_wrapper(register(SetupDistribution(function, event), callerLocals(2)), function)
def publish(*args): ''' To be used as decorator whenever publishing GUI files ''' decorator = onDecorator((app.POPULATE, app.DEVEL, app.CHANGED), app.PRIORITY_NORMAL, callerLocals()) if not args: return decorator assert len( args ) == 1, 'Expected only one argument that is the decorator function, got %s arguments' % len( args) return decorator(args[0])
def enableMultiProcessPool(): ''' Wraps all the engines in the current assembly with a pool that allows for working on multiple processes. ''' def present(engine): ''' Used for listening to all sql alchemy engines that are created in order to wrap the engine pool with a pool that can handle multiple processors. ''' if not isinstance(engine.pool, SingletonProcessWrapper): engine.pool = SingletonProcessWrapper(engine.pool) support.listenToEntities(Engine, listeners=present, module=callerLocals(), all=True)
def relationshipModel(mappedId, *spec): ''' Creates a relationship with the model, this should only be used in case the mapped model database id is different from the actual model id. @param mappedId: InstrumentedAttribute The mapped model id to create the relation with. @param spec: arguments containing column: string The column name containing the foreign key relation, attention if target is provided then also column needs to be provided, if None provided it will create one automatically. target: string The SQL alchemy relationship target name, if None provided it will create one automatically. ''' assert isinstance(mappedId, InstrumentedAttribute), 'Invalid mapped id %s' % mappedId register = callerLocals() assert '__module__' in register, 'This function should only be used inside meta class definitions' rtype = typeFor(mappedId.class_) assert isinstance(rtype, TypeModel), 'Invalid class %s' % mappedId.class_ assert isinstance(rtype.propertyId, TypeProperty), 'No property id for %s' % rtype assert rtype.propertyId.name != mappedId.property.key, 'Same database id with the model id \'%s\' for %s' % mappedId.class_ column = target = None if spec: column, *spec = spec assert isinstance(column, str), 'Invalid column %s' % column if spec: target, = spec assert isinstance(target, str) and target, 'Invalid target %s' % target if target is None: target = modifyFirst(rtype.name, False) if column is None: column = '%sId' % target register[column] = Column('fk_%s_id' % toUnderscore(target), ForeignKey(mappedId, ondelete='CASCADE'), nullable=False) register[target] = relationship(mappedId.class_, uselist=False, lazy='joined', viewonly=True) def fget(self): rel = getattr(self, target) if rel: return getattr(rel, rtype.propertyId.name) columnId = columnFor(getattr(mappedId.class_, rtype.propertyId.name)) def fset(self, value): setattr(self, column, select([mappedId], columnId == value)) validation = validate(Mandatory, Relation) return validation(hybrid_property(fget, fset, expr=joinedExpr(mappedId.class_, rtype.propertyId.name)))
def entity(name, type=None): ''' Used for defining a wired entity attribute. If the type is not provided the entity attribute needs to contain a class or type that will help the wiring to know exactly the expected type. @param attribute: string The entities attribute name to be added to the wiring context. @param type: class The class of the expected attribute value. ''' assert isinstance(name, str), 'Invalid attribute name %s' % name locals = callerLocals() if not type: if name not in locals: raise WireError('Invalid entity name %r, cannot find it in locals' % name) type = locals[name] if not isclass(type): raise WireError('Invalid type %s for %r' % (type, name)) Wiring.wiringFor(locals).addEntity(name, type)
def entity(name, type=None): ''' Used for defining a wired entity attribute. If the type is not provided the entity attribute needs to contain a class or type that will help the wiring to know exactly the expected type. @param attribute: string The entities attribute name to be added to the wiring context. @param type: class The class of the expected attribute value. ''' assert isinstance(name, str), 'Invalid attribute name %s' % name locals = callerLocals() if not type: if name not in locals: raise WireError( 'Invalid entity name %r, cannot find it in locals' % name) type = locals[name] if not isclass(type): raise WireError('Invalid type %s for %r' % (type, name)) Wiring.wiringFor(locals).addEntity(name, type)
def config(name, type=None, doc=None): ''' Used for defining a wired configuration attribute. If the type is not provided the configuration attribute needs to contain a class or type that will help the wiring to know exactly the expected type, if the attribute is None or not existing than the attribute is not validate by type. @param name: string The configurations attribute names to be added to the wiring context. @param type: class The type of the attribute @param doc: string The description of the attribute ''' assert isinstance(name, str), 'Invalid attribute name %s' % name assert not doc or isinstance(doc, str), 'Invalid description %s' % doc if not name.islower(): raise WireError( 'Invalid name %r for configuration, needs to be lower case only' % name) locals = callerLocals() hasValue, value = False, None if not type: if name in locals: v = locals[name] if isclass(v): type = v else: hasValue, value = True, v if v is not None: type = v.__class__ if type and not isclass(type): raise WireError('Invalid type %s for %r' % (type, name)) else: if not isclass(type): raise WireError('Invalid type %s for %r' % (type, name)) v = locals[name] if isinstance(v, type): hasValue, value = True, v type = normalizeConfigType(type) Wiring.wiringFor(locals).addConfiguration(name, type, hasValue, value, doc)
def registerSupport(): ''' Register the support setup in this module in order to process the support APIs. ''' register(SetupDistributionSupport(), callerLocals())