def registerValidation(mapped, exclude=None): ''' Register to mapped class all the validations that can be performed based on the SQL alchemy mapping. @param mapped: class The mapped model class. @param exclude: list[string]|tuple(string) A list of column names to be excluded from automatic validation. @return: Property The property id of the model. ''' assert isclass(mapped), 'Invalid class %s' % mapped mapper, typeModel = mappingFor(mapped), typeFor(mapped) assert isinstance(mapper, Mapper), 'Invalid mapped class %s' % mapped assert isinstance(typeModel, TypeModel), 'Invalid model class %s' % mapped assert not exclude or isinstance(exclude, (list, tuple)), 'Invalid exclude %s' % exclude model = typeModel.container assert isinstance(model, Model) properties = set(model.properties) for cp in mapper.iterate_properties: if not isinstance(cp, ColumnProperty): continue assert isinstance(cp, ColumnProperty) if cp.key: prop = cp.key try: properties.remove(prop) except KeyError: continue if not (exclude and prop in exclude): propRef = getattr(mapped, prop) column = getattr(mapper.c, cp.key, None) assert isinstance(column, Column), 'Invalid column %s' % column if __debug__: propType = typeFor(propRef) assert isinstance(propType, TypeModelProperty), 'Invalid property %s with type %s' % (prop, propType) if column.primary_key and column.autoincrement: if prop != model.propertyId: raise MappingError('The primary key is expected to be %s, but got SQL primary key for %s' % (model.propertyId, prop)) validateAutoId(propRef) elif not column.nullable: validateRequired(propRef) if isinstance(column.type, String) and column.type.length: validateMaxLength(propRef, column.type.length) if column.unique: validateProperty(propRef, partial(onPropertyUnique, mapped)) if column.foreign_keys: for fk in column.foreign_keys: assert isinstance(fk, ForeignKey) try: fkcol = fk.column except AttributeError: raise MappingError('Invalid foreign column for %s, maybe you are not using the meta class' % prop) validateProperty(propRef, partial(onPropertyForeignKey, mapped, fkcol), index=INDEX_PROP_FK) for prop in properties: if not (exclude and prop in exclude): validateManaged(getattr(mapped, prop))
def isCompatible(theProperty, withProperty): ''' Checks if the provided property type is compatible with the provided type. @param theProperty: TypeProperty container The property type to check if compatible with the type. @param withProperty: TypeProperty container The type to check. @return: boolean True if the property type is compatible with the provided type. ''' typ, wtyp = typeFor(theProperty), typeFor(withProperty) if not isinstance(typ, TypeProperty): return False assert isinstance(typ, TypeProperty) if not isinstance(typ.parent, TypeContainer): return False assert isinstance(typ.parent, TypeContainer) if not isinstance(wtyp, TypeProperty): return False assert isinstance(wtyp, TypeProperty) if not isinstance(wtyp.parent, TypeContainer): return False assert isinstance(wtyp.parent, TypeContainer) if typ.name != wtyp.name: return False if typ.type != wtyp.type: return False if not issubclass(wtyp.parent.clazz, typ.parent.clazz): return False return True
def add(self, forRef, theRef): ''' Adds 'theRef' reference as an alternate 'forRef' reference. @param forRef: tuple(class, string) The call reference for which the alternate is specified. @param theRef: tuple(class, string) The call reference which is an alternative the for reference. @return: self This instance for chaining purposes. ''' assert isinstance(forRef, tuple), 'Invalid for reference %s' % forRef assert isinstance(theRef, tuple), 'Invalid the reference %s' % theRef clazz, forName = forRef forService = typeFor(clazz) assert isinstance(forService, TypeService), 'Invalid service class %s' % clazz assert isinstance(forService.service, Service) assert forName in forService.service.calls, 'Invalid service call name %s' % forName clazz, theName = theRef theService = typeFor(clazz) assert isinstance(theService, TypeService), 'Invalid service class %s' % clazz assert isinstance(theService.service, Service) assert theName in theService.service.calls, 'Invalid service call name %s' % theName key = (forService, forService.service.calls[forName]) alternates = self._alternates.get(key) if alternates is None: alternates = self._alternates[key] = set() alternates.add((theService, theService.service.calls[theName])) return self
def processWithRepository(self, alternatesRepository, invoker, invokerAlt): ''' Process the invoker and alternate invoker against the alternates repository. @return: boolean True if the invoker and alternate invoker are configured in the repository. ''' assert isinstance( alternatesRepository, dict), 'Invalid alternates repository %s' % alternatesRepository if invoker == invokerAlt: return True # If the invoker is the same with the alternate it is valid by default invokerCall, invokerCallAlt = invokerCallOf(invoker), invokerCallOf( invokerAlt) if not invoker or not invokerCallAlt: return False # If there are no invoker call then we cannot add them assert isinstance(invokerCall, InvokerCall) assert isinstance(invokerCallAlt, InvokerCall) alternates = alternatesRepository.get( (typeFor(invokerCallAlt.implementation), invokerCallAlt.call)) if alternates is None: return False # There is no alternate repository configuration for the invoker try: alternates.remove( (typeFor(invokerCall.implementation), invokerCall.call)) except KeyError: return False # Not found in the repository alternate return True
def __init__(self, Entity, QEntity=None): ''' Construct the entity support for the provided model class and query class. @param Entity: class The mapped entity model class. @param QEntity: class|None The query mapped class if there is one. ''' assert isclass(Entity), 'Invalid class %s' % Entity assert issubclass(Entity, api.Entity), 'Invalid entity class %s' % Entity assert isinstance(Entity, MappedSupport), 'Invalid mapped class %s' % Entity self.modelType = typeFor(Entity) assert isinstance(self.modelType, TypeModel), 'Invalid model class %s' % Entity self.model = self.modelType.container self.Entity = Entity if QEntity is not None: assert isclass(QEntity), 'Invalid class %s' % QEntity assert issubclass(QEntity, api.QEntity), 'Invalid query entity class %s' % QEntity self.queryType = typeFor(QEntity) assert isinstance(self.queryType, TypeQuery), 'Invalid query class %s' % QEntity self.query = self.queryType.query else: self.query = self.queryType = None self.QEntity = QEntity
def testSuccesModel(self): a = APIModel() modelType = typeFor(APIModel) self.assertTrue(isinstance(modelType, TypeModel)) self.assertTrue(len(modelType.properties) == 5) self.assertTrue(APIModel.X not in a) self.assertTrue(a.X == None) a.X = None self.assertTrue(APIModel.X in a) self.assertTrue(a.X == None) self.assertTrue(isinstance(APIModel.X, Reference)) a.X = 100 self.assertTrue(a.X == 100) a.X = 101.2 self.assertTrue(a.X == 101.2) self.assertTrue(APIModel.Y not in a) a.Y = 'heloo' self.assertTrue(APIModel.Y in a) self.assertTrue(a.Y == 'heloo') self.assertTrue(typeFor(APIModel.Y).type.isOf(str)) del a.Y self.assertTrue(a.Y == None) self.assertTrue(typeFor(APIModel.Entity.Id).type.isOf(str)) a.Entity = '121' self.assertTrue(APIModel.Entity in a) self.assertTrue(isinstance(a.Entity, str)) self.assertTrue(a.Entity == '121') del a.Entity self.assertTrue(a.Entity == None)
def equalContainer(ainstance, oinstance, exclude=()): ''' Checks if the values for the provided instances are equal, this means that all properties except the ones in exclude need to be equal. @param ainstance: container object A container instance to check. @param oinstance: container object The other instance to check. @param exclude: list[string]|tuple(string)|set(string) A list of properties names to exclude from equal check. @return: boolean True if the instances are equal, False otherwise. ''' assert ainstance is not None and oinstance is not None, 'Invalid instances %s, %s' % (ainstance, oinstance) atype, otype = typeFor(ainstance), typeFor(oinstance) assert isinstance(atype, TypeContainer), 'Invalid container %s' % ainstance assert isinstance(otype, TypeContainer), 'Invalid container %s' % oinstance if atype != otype: properties = set(atype.properties) properties.symmetric_difference_update(otype.properties) properties.difference_update(exclude) if properties: return False # It means that they are properties that are not accounted for in one of the containers. for name in atype.properties: if name in exclude: continue if getattr(ainstance, name) != getattr(oinstance, name): return False return True
def processHintReplace(self, invoker, prevInvoker): """ Processes the replace for hint for the invokers. @param invoker: Invoker The invoker to be processed. @param prevInvoker: Invoker|None The previous invoker found on the node if is the case. @return: Invoker The invoker to be used. """ assert isinstance(invoker, Invoker), "Invalid invoker %s" % invoker if prevInvoker: replace = invoker.hints.get(self.hintCallReplaceFor) if replace is None: if isinstance(prevInvoker, Invoker): assert isinstance(prevInvoker, Invoker) replace = prevInvoker.hints.get(self.hintCallReplaceFor) if replace is None: raise AssembleError( "Invoker %s conflicts with invoker %s and none of them has a replace specified" % (invoker, prevInvoker) ) prevInvoker, invoker = invoker, prevInvoker typ = typeFor(replace) assert isinstance(typ, TypeService), ( "Invalid replace for reference %s, cannot extract a service from it, provide a service API" % replace ) if typeFor(prevInvoker.implementation) != typ: raise AssembleError( "The current invoker %s does not belong to the targeted replaced service %s" % (prevInvoker, typ) ) return invoker
def testSuccesSimpleMapping(self): self.assertTrue(typeFor(UserMapped.Id).isOf(int)) self.assertTrue(typeFor(UserMapped.Name).isOf(str)) session = self.sessionCreate() user = UserMapped() self.assertTrue(UserMapped.Id not in user) self.assertTrue(UserMapped.Name not in user) user.Name = 'Hello world' self.assertTrue(UserMapped.Name in user) self.assertTrue(UserMapped.Id not in user) session.add(user) session.flush((user,)) self.assertTrue(UserMapped.Id in user) session.commit() session.close() session = self.sessionCreate() users = session.query(UserMapped).filter(UserMapped.Name == 'Hello world').all() self.assertEqual(len(users), 1) self.assertTrue(UserMapped.Id in users[0]) self.assertTrue(UserMapped.Name in users[0]) self.assertEqual(users[0].Name, 'Hello world') self.assertEqual(users[0].Id, 1) session.close()
def __init__(self, Mapped, QEntity=None, **mapping): ''' Construct the entity support for the provided model class and query class. @param Mapped: class The mapped entity model class. @param QEntity: class|None The query mapped class if there is one. @param mapping: key arguments of columns The column mappings provided for criteria name in case they are needed, this is only used if a QEntity is provided. ''' assert isclass(Mapped), 'Invalid class %s' % Mapped assert isinstance(Mapped, MappedSupport), 'Invalid mapped class %s' % Mapped model = typeFor(Mapped) assert isinstance(model, TypeModel), 'Invalid model class %s' % Mapped assert isinstance(model.propertyId, TypeProperty), 'Invalid model property id %s' % model.propertyId self.Entity = model.clazz self.Mapped = Mapped self.MappedId = modelId(Mapped) if QEntity is not None: assert isclass(QEntity), 'Invalid class %s' % QEntity assert isinstance(typeFor(QEntity), TypeQuery), 'Invalid query entity class %s' % QEntity if __debug__: for name in mapping: assert name in typeFor(QEntity).properties, 'Invalid criteria name \'%s\' for %s' % (name, QEntity) self._mapping = mapping else: assert not mapping, 'Illegal mappings %s with no QEntity provided' % mapping self.QEntity = QEntity
def equalContainer(ainstance, oinstance, exclude=()): ''' Checks if the values for the provided instances are equal, this means that all properties except the ones in exclude need to be equal. @param ainstance: container object A container instance to check. @param oinstance: container object The other instance to check. @param exclude: list[string]|tuple(string)|set(string) A list of properties names to exclude from equal check. @return: boolean True if the instances are equal, False otherwise. ''' assert ainstance is not None and oinstance is not None, 'Invalid instances %s, %s' % ( ainstance, oinstance) atype, otype = typeFor(ainstance), typeFor(oinstance) assert isinstance(atype, TypeContainer), 'Invalid container %s' % ainstance assert isinstance(otype, TypeContainer), 'Invalid container %s' % oinstance if atype != otype: properties = set(atype.properties) properties.symmetric_difference_update(otype.properties) properties.difference_update(exclude) if properties: return False # It means that they are properties that are not accounted for in one of the containers. for name in atype.properties: if name in exclude: continue if getattr(ainstance, name) != getattr(oinstance, name): return False return True
def __init__(self, Entity, QEntity=None): ''' Construct the entity support for the provided model class and query class. @param Entity: class The mapped entity model class. @param QEntity: class|None The query mapped class if there is one. ''' assert isclass(Entity), 'Invalid class %s' % Entity assert issubclass(Entity, api.Entity), 'Invalid entity class %s' % Entity assert isinstance(Entity, MappedSupport), 'Invalid mapped class %s' % Entity self.modelType = typeFor(Entity) assert isinstance(self.modelType, TypeModel), 'Invalid model class %s' % Entity self.model = self.modelType.container self.Entity = Entity if QEntity is not None: assert isclass(QEntity), 'Invalid class %s' % QEntity assert issubclass( QEntity, api.QEntity), 'Invalid query entity class %s' % QEntity self.queryType = typeFor(QEntity) assert isinstance(self.queryType, TypeQuery), 'Invalid query class %s' % QEntity self.query = self.queryType.query else: self.query = self.queryType = None self.QEntity = QEntity
def processHintReplace(self, invoker, prevInvoker): ''' Processes the replace for hint for the invokers. @param invoker: Invoker The invoker to be processed. @param prevInvoker: Invoker|None The previous invoker found on the node if is the case. @return: Invoker The invoker to be used. ''' assert isinstance(invoker, Invoker), 'Invalid invoker %s' % invoker if prevInvoker: replace = invoker.hints.get(self.hintCallReplaceFor) if replace is None: if isinstance(prevInvoker, Invoker): assert isinstance(prevInvoker, Invoker) replace = prevInvoker.hints.get(self.hintCallReplaceFor) if replace is None: raise AssembleError( 'Invoker %s conflicts with invoker %s and none of them has a replace specified' % (invoker, prevInvoker)) prevInvoker, invoker = invoker, prevInvoker typ = typeFor(replace) assert isinstance(typ, TypeService), \ 'Invalid replace for reference %s, cannot extract a service from it, provide a service API' % replace if typeFor(prevInvoker.implementation) != typ: raise AssembleError( 'The current invoker %s does not belong to the targeted replaced service %s' % (prevInvoker, typ)) return invoker
def __init__(self): assert isinstance(self.resourcesRoot, Node), 'Invalid root node %s' % self.resourcesRoot node = NodePath(self.resourcesRoot, True, 'MemoryStatus') node.get = InvokerFunction(GET, self.present, typeFor(Non), [ Input('limit', typeFor(Integer), True, None), Input('include', typeFor(String), True, None), Input('exclude', typeFor(String), True, None), ], {})
def __init__(self): ''' Construct the item service. ''' self.Entity = ItemMapped self.QEntity = QItem self.modelType = typeFor(self.Entity) self.model = self.modelType.container self.queryType = typeFor(QItem)
def signature(obj): ''' Provides the signature for the provided type. @param obj: Type or container for type container The type to provide the signature for. @return: string The signature. ''' ftype = typeFor(obj) assert isinstance(ftype, Type), 'Invalid type %s' % ftype if ftype in _signature_cache: return _signature_cache[ftype] names, ctype, bname = [], ftype, '%s' if isinstance(ctype, Iter): assert isinstance(ctype, Iter) bname = '%s[%%s]' % ctype.__class__.__name__ ctype = ctype.itemType if isinstance(ctype, (TypeProperty, TypeContainer)): isProperty, types = isinstance(ctype, TypeProperty), [ctype] while types: ctype = types.pop() if isProperty: assert isinstance(ctype, TypeProperty), 'Invalid property type %s' % ctype mtype = ctype.parent assert isinstance(mtype, TypeContainer), 'Invalid parent %s' % mtype names.append(bname % ('%s.%s.%s' % (mtype.clazz.__module__, mtype.clazz.__name__, ctype.name))) bases = ctype.parent.clazz.__bases__ else: assert isinstance(ctype, TypeContainer), 'Invalid container type %s' % ctype names.append(bname % ('%s.%s' % (ctype.clazz.__module__, ctype.clazz.__name__))) bases = ctype.clazz.__bases__ inherited = [] for base in bases: mtype = typeFor(base) if not isinstance(mtype, TypeContainer): continue if isProperty: assert isinstance(mtype, TypeContainer) ptype = mtype.properties.get(ctype.name) if not ptype: continue assert isinstance(ptype, TypeProperty), 'Invalid property type %s' % ptype if ctype.type == ptype.type: inherited.append(ptype) else: inherited.append(mtype) if inherited: inherited.reverse() types.extend(inherited) else: names.append(bname % ctype) signature = _signature_cache[ftype] = ''.join(('{0:0>8x}'.format(crc32(name.encode()))).upper() for name in names) return signature
def testSuccesBoolean(self): bt = typeFor(Boolean) self.assertTrue(isinstance(bt, Type)) self.assertTrue(bt.isOf(bool)) self.assertTrue(bt.isValid(True)) bt = typeFor(bool) self.assertTrue(bt.isValid(False)) self.assertTrue(bt.isValid(True))
def __init__(self, name, bases, namespace): assert isinstance(namespace, dict), 'Invalid namespace %s' % namespace mapped, models = [], [] for cls in bases: typ = typeFor(cls) if isinstance(typ, TypeModelMapped): mapped.append(cls) elif isinstance(typ, TypeModel): models.append(cls) if not mapped and not models: assert log.debug( 'Cannot find any API model class for \'%s\', no merging required', name) or True DeclarativeMeta.__init__(self, name, bases, namespace) return if len(mapped) > 1: raise MappingError( 'Cannot inherit more then one mapped class, got %s' % models) if len(models) > 1: raise MappingError( 'Cannot merge with more then one API model class, got %s' % models) if models: typeModel = typeFor(models[0]) else: typeModel = None if mapped: if typeModel is None: typeModel = typeFor(mapped[0]).base assert isinstance(typeModel, TypeModel) typeModel = TypeModelMapped(self, typeModel) self._ally_reference = { prop: Reference(TypeModelProperty(typeModel, prop, propType)) for prop, propType in typeModel.container.properties.items() } self._ally_listeners = {} # Provides the BindableSupport self._ally_type = typeModel # Provides the TypeSupport DeclarativeMeta.__init__(self, name, bases, namespace) # TODO: see if required: self.__clause_element__ = lambda: self.__table__ for prop in typeModel.container.properties: if typeFor(getattr(self, prop)) != typeFor( self._ally_reference[prop]): value, _class = getAttrAndClass(self, prop) setattr(self, prop, value) try: mappings = self.metadata._ally_mappers except AttributeError: mappings = self.metadata._ally_mappers = deque() mappings.append(self)
def testSuccesInt(self): it = typeFor(Integer) self.assertTrue(isinstance(it, Type)) self.assertTrue(it.isOf(int)) self.assertTrue(it.isValid(100)) it = typeFor(int) self.assertTrue(it.isValid(-12)) self.assertTrue(it.isValid(0))
def testSuccesStr(self): st = typeFor(String) self.assertTrue(isinstance(st, Type)) self.assertTrue(st.isOf(str)) self.assertTrue(st.isValid('ugu')) st = typeFor(str) self.assertTrue(st.isValid("heloo world")) self.assertTrue(st.isValid('Moi'))
def __init__(self, name, bases, namespace): assert isinstance(namespace, dict), "Invalid namespace %s" % namespace mapped, models = [], [] for cls in bases: typ = typeFor(cls) if isinstance(typ, TypeModelMapped): mapped.append(cls) elif isinstance(typ, TypeModel): models.append(cls) if not mapped and not models: assert log.debug("Cannot find any API model class for '%s', no merging required", name) or True DeclarativeMeta.__init__(self, name, bases, namespace) return if len(mapped) > 1: raise MappingError("Cannot inherit more then one mapped class, got %s" % models) if len(models) > 1: raise MappingError("Cannot merge with more then one API model class, got %s" % models) if models: typeModel = typeFor(models[0]) else: typeModel = None if mapped: if typeModel is None: typeModel = typeFor(mapped[0]).base assert isinstance(typeModel, TypeModel) typeModel = TypeModelMapped(self, typeModel) self._ally_reference = { prop: Reference(TypeModelProperty(typeModel, prop, propType)) for prop, propType in typeModel.container.properties.items() } self._ally_listeners = {} # Provides the BindableSupport self._ally_type = typeModel # Provides the TypeSupport DeclarativeMeta.__init__(self, name, bases, namespace) # TODO: see if required: self.__clause_element__ = lambda: self.__table__ for prop in typeModel.container.properties: if typeFor(getattr(self, prop)) != typeFor(self._ally_reference[prop]): value, _class = getAttrAndClass(self, prop) setattr(self, prop, value) try: mappings = self.metadata._ally_mappers except AttributeError: mappings = self.metadata._ally_mappers = deque() mappings.append(self)
def __init__(self): ''' Construct the handler. ''' assert self.maximumLimit is None or isinstance(self.maximumLimit, int), 'Invalid maximum limit %s' % self.maximumLimit assert self.defaultLimit is None or isinstance(self.defaultLimit, int), 'Invalid default limit %s' % self.defaultLimit assert self.defaultWithTotal is None or isinstance(self.defaultWithTotal, bool), \ 'Invalid default with total %s' % self.defaultWithTotal super().__init__(Decoding=Decoding) self.typeLimit = typeFor(Slice.limit) self.typeTotal = typeFor(SliceAndTotal.withTotal)
def handle(e, entity): ''' Handles the SQL alchemy exception while inserting or updating. ''' if isinstance(e, IntegrityError): raise InputError( Ref(_('Cannot persist, failed unique constraints on entity'), model=typeFor(entity).container)) if isinstance(e, OperationalError): raise InputError( Ref(_('A foreign key is not valid'), model=typeFor(entity).container)) raise e
def testSuccesNumber(self): nt = typeFor(Number) self.assertTrue(isinstance(nt, Type)) self.assertTrue(nt.isOf(numbers.Number)) self.assertTrue(nt.isValid(100)) nt = typeFor(float) self.assertTrue(nt.isValid(100.12)) nt = typeFor(numbers.Number) self.assertTrue(nt.isValid(-1.12))
def testSuccessInheritAndForeignKey(self): self.assertTrue(typeFor(UserWithParent.Id).isOf(int)) self.assertTrue(typeFor(UserWithParent.Name).isOf(str)) self.assertTrue(typeFor(UserWithParent.Parent).isOf(Parent)) session = self.sessionCreate() user = UserWithParent() self.assertTrue(UserWithParent.Id not in user) self.assertTrue(UserWithParent.Name not in user) self.assertTrue(UserWithParent.Parent not in user) user.Name = 'Hello world' self.assertTrue(UserWithParent.Name in user) user.Parent = 1 self.assertTrue(UserWithParent.Parent in user) self.assertTrue(UserWithParent.Id not in user) session.add(user) session.flush((user,)) self.assertTrue(UserWithParent.Id in user) session.commit() session.close() session = self.sessionCreate() users = session.query(UserWithParent).filter(UserWithParent.Name == 'Hello world').all() self.assertEqual(len(users), 1) user = users[0] self.assertTrue(UserWithParent.Id in user) self.assertTrue(UserWithParent.Name in user) self.assertTrue(UserWithParent.Parent in user) self.assertEqual(user.Name, 'Hello world') self.assertEqual(user.Id, 1) self.assertEqual(user.Parent, 1) session.close() session = self.sessionCreate() users = session.query(UserWithParent).filter(UserWithParent.Parent == 1).all() self.assertEqual(len(users), 1) user = users[0] self.assertTrue(UserWithParent.Id in user) self.assertTrue(UserWithParent.Name in user) self.assertTrue(UserWithParent.Parent in user) self.assertEqual(user.Name, 'Hello world') self.assertEqual(user.Id, 1) self.assertEqual(user.Parent, 1) session.close()
def updateModel(Mapped, model, **data): ''' Updates the provided model entity using the current session. @param Mapped: class The mapped class to update the model for, the model type is required to have a property id. @param model: object The model to be updated. @param data: key arguments Additional data to place on the updated model. @return: object The database model that has been updated. ''' assert isclass(Mapped), 'Invalid class %s' % Mapped assert isinstance(Mapped, MappedSupport), 'Invalid mapped class %s' % Mapped if isinstance(model, Mapped): dbModel = model openSession().merge(dbModel) else: typ = typeFor(Mapped) assert isinstance(typ, TypeModel), 'Invalid model class %s' % Mapped assert typ.isValid(model), 'Invalid model %s for %s' % (model, typ) assert isinstance(typ.propertyId, TypeProperty), 'Invalid property id of %s' % typ dbModel = openSession().query(Mapped).get(getattr(model, typ.propertyId.name)) if not dbModel: raise IdError(typ.propertyId) for name, prop in typ.properties.items(): if name in data or not isinstance(getattr(Mapped, name), InstrumentedAttribute): continue if prop in model: setattr(dbModel, name, getattr(model, name)) for name, value in data.items(): setattr(dbModel, name, value) openSession().flush((dbModel,)) return dbModel
def __call__(self, value, normalizer, converter, render, resolve, name=None, **data): assert isinstance(normalizer, Normalizer), 'Invalid normalizer %s' % normalizer assert isinstance(converter, Converter), 'Invalid converter %s' % converter assert isinstance(render, IRender), 'Invalid render %s' % render assert isinstance(resolve, IResolve), 'Invalid resolve %s' % resolve if self.getter: value = self.getter(value) if value is None: return assert isinstance(value, Iterable), 'Invalid value %s' % value typeValue = typeFor(value) if typeValue and isinstance(typeValue, TypeExtension): assert isinstance(typeValue, TypeExtension) assert isinstance(typeValue.container, Container) attrs = {} for prop, propType in typeValue.container.properties.items(): propValue = getattr(value, prop) if propValue is not None: attrs[normalizer.normalize(prop)] = converter.asString(propValue, propType) else: attrs = None data.update(normalizer=normalizer, converter=converter, render=render, resolve=resolve) render.collectionStart(normalizer.normalize(name or self.name), attrs) resolve.queueBatch(self.exploitItem, (dict(data, value=item) for item in value)) resolve.queue(self.finalize, render=render)
def allFor(self, method, *services, filter=None): ''' Used for adding to the right the service calls that have the specified method. @param method: integer The method or methods composed by using the | operator to be associated with the right. @param service: arguments[service type] The services types to be used. @param filter: Filter|None The filter to be used with the added services, for more details about filter policy. @return: self The self object for chaining purposes. ''' assert isinstance(method, int), 'Invalid method %s' % method assert services, 'At least one service is required' for service in services: typ = typeFor(service) assert isinstance(typ, TypeService), 'Invalid service %s' % service assert isinstance(typ.service, Service) for call in typ.service.calls.values(): assert isinstance(call, Call) if call.method & method: structCall = self.structure.obtainCall(typ, call) if filter: structCall.pushFilter(filter) return self
def add(self, *references, filter=None): ''' Used for adding to the right the service calls. @param references: arguments[tuple(class, string)] The references of the service call to associate with the right. @param filter: Filter|None The filter to be used with the added calls, for more details about filter policy. @return: self The self object for chaining purposes. ''' indexed = iterRef(references) assert indexed, 'At least one reference is required' for service, names in indexed.items(): typ = typeFor(service) assert isinstance(typ, TypeService), 'Invalid service %s' % service assert isinstance(typ.service, Service) for name in names: if isfunction(name): name = name.__name__ assert name in typ.service.calls, 'Invalid call name \'%s\' for service %s' % (name, typ) call = typ.service.calls[name] assert isinstance(call, Call) structCall = self.structure.obtainCall(typ, call) if filter: structCall.pushFilter(filter) return self
def callsOf(stack): ''' Provides the call types for the provided stack object. @param stack: Exception|traceback The exception or trace back object to extract the calls from. @return: list[TypeCall] The calls from the stack. ''' if isinstance(stack, Exception): assert isinstance(stack, Exception) tb = stack.__traceback__ else: tb = stack assert isinstance(tb, TracebackType), 'Invalid trace back %s' % tb calls = [] while tb: instance = tb.tb_frame.f_locals.get('self') if instance is not None: service = typeFor(instance) if isinstance(service, TypeService): assert isinstance(service, TypeService) call = service.calls.get(tb.tb_frame.f_code.co_name) if call: calls.append(call) tb = tb.tb_next return calls
def isOf(self, type): ''' @see: TypeClass.isOf ''' if isclass(type) and (issubclass(type, self.clazz) or issubclass(self.clazz, type)): return True if self == typeFor(type): return True return False
def populate(self, obj, specifications, support): ''' @see: ISpecifier.populate ''' ext = typeFor(obj) if not ext or not isinstance(ext, TypeExtension): return # Is not an extension object, nothing to do assert isinstance(ext, TypeExtension) if ext not in self.propertiesByType: properties = self.propertiesByType[ext] = [] for name, prop in ext.properties.items(): assert isinstance(prop, TypeProperty), 'Invalid property %s' % prop encoder = createEncoderNamed(self.processing, name, prop) if encoder is None: log.error('Cannot encode %s of %s', prop, ext) else: properties.append((name, encoder)) else: properties = self.propertiesByType[ext] attributes = specifications.get('attributes') if attributes is None: attributes = specifications['attributes'] = {} render = RenderAttributes(attributes) for name, encoder in properties: assert isinstance(encoder, ITransfrom), 'Invalid property encoder %s' % encoder objValue = getattr(obj, name) if objValue is None: continue encoder.transform(objValue, render, support)
def process(self, request: Request, **keyargs): ''' @see: HandlerProcessorProceed.process Transpose the additional arguments into the main arguments. ''' assert isinstance(request, Request), 'Invalid request %s' % request if request.invoker is None: return # If there is no invoker it means that no arguments need to be processed assert isinstance(request.path, Path), 'Invalid request path %s' % request.path assert isinstance( request.invoker, Invoker), 'Invalid request invoker %s' % request.invoker if request.argumentsOfType: for inp in request.invoker.inputs: assert isinstance(inp, Input), 'Invalid input %s' % inp if inp.name in request.arguments: continue for argType, value in request.argumentsOfType.items(): if typeFor(argType) == inp.type: if inp.name not in request.arguments: request.arguments[inp.name] = value break request.arguments.update(request.path.toArguments(request.invoker))
def insertModel(Mapped, model, **data): ''' Inserts the provided model entity using the current session. @param Mapped: class The mapped class to insert the model for. @param model: object The model to insert. @param data: key arguments Additional data to place on the inserted model. @return: object The database model that has been inserted. ''' assert isclass(Mapped), 'Invalid class %s' % Mapped assert isinstance(Mapped, MappedSupport), 'Invalid mapped class %s' % Mapped if isinstance(model, Mapped): dbModel = model else: typ, mapper = typeFor(Mapped), mappingFor(Mapped) assert isinstance(typ, TypeModel), 'Invalid model class %s' % Mapped assert isinstance(mapper, Mapper), 'Invalid mapper %s' % mapper dbModel = Mapped() for name, prop in typ.properties.items(): if name in data or not isinstance(getattr(Mapped, name), InstrumentedAttribute): continue if prop in model: setattr(dbModel, name, getattr(model, name)) for name, value in data.items(): setattr(dbModel, name, value) openSession().add(dbModel) openSession().flush((dbModel, )) return dbModel
def processHintWebName(self, types, hints, isGroup=False): """ Processes the web name hint found on the call and alters the provided types list according to it. @param types: list[Input|TypeModel|Model|tuple(string,boolean)] The list of types to be altered based on the web name hint. @param hints: dictionary{string, object} The hints to be processed for the types. @param isGroup: boolean Flag indicating that the web name hint should be considered a group node (True) or an object node (False). """ assert isinstance(types, list), "Invalid types %s" % types assert isinstance(hints, dict), "Invalid hints %s" % hints assert isinstance(isGroup, bool), "Invalid is group flag %s" % isGroup webName = hints.get(self.hintCallWebName) if isclass(webName): typ = typeFor(webName) assert isinstance(typ, TypeModel), "Invalid web name hint class %s" % webName types.append(typ.container) elif webName: assert isinstance(webName, str), "Invalid web name hint %s" % webName webName = webName.split("/") for k, name in enumerate(webName): assert re.match("^[\w]+$", name), 'Invalid name "%s" in web name "%s"' % (name, "/".join(webName)) types.append((name, False if k <= len(webName) - 1 else isGroup)) return types
def deleteModel(Mapped, identifier): ''' Delete the provided model based on the provided identifier using the current session. @param Mapped: class The mapped class to update the model for, the model type is required to have a property id. @param identifier: object The identifier to delete for. @return: boolean True if any entry was deleted, False otherwise. ''' assert isclass(Mapped), 'Invalid class %s' % Mapped assert isinstance(Mapped, MappedSupport), 'Invalid mapped class %s' % Mapped typ = typeFor(Mapped) assert isinstance(typ, TypeModel), 'Invalid model class %s' % Mapped assert isinstance(typ.propertyId, TypeProperty), 'Invalid property id of %s' % typ assert typ.propertyId.isValid( identifier), 'Invalid identifier %s for %s' % (identifier, typ.propertyId) try: model = openSession().query(Mapped).filter( getattr(Mapped, typ.propertyId.name) == identifier).one() except NoResultFound: return False openSession().delete(model) return True
def authenticate(self, identifier, attributes, arguments): ''' @see: IAuthenticationSupport.authenticate ''' assert isinstance(identifier, str), 'Invalid identifier %s' % identifier assert isinstance(attributes, dict), 'Invalid attributes %s' % attributes assert isinstance(arguments, dict), 'Invalid arguments %s' % arguments olderThan = self.session().query(current_timestamp()).scalar() olderThan -= self.sessionTimeOut sql = self.session().query(LoginMapped) sql = sql.filter(LoginMapped.Session == identifier) sql = sql.filter(LoginMapped.AccessedOn > olderThan) try: login = sql.one() except NoResultFound: return False assert isinstance(login, LoginMapped), 'Invalid login %s' % login login.AccessedOn = current_timestamp() self.session().flush((login,)) self.session().expunge(login) commitNow() # We need to fore the commit because if there is an exception while processing the request we need to make # sure that the last access has been updated. for authType in arguments: assert isinstance(authType, Type), 'Invalid type %s' % authType if authType == typeFor(User.Id): arguments[authType] = login.User else: raise DevelError('Invalid authenticated type %s' % authType) return True
def __init__(self): ''' Construct the handler. ''' assert self.maximumLimit is None or isinstance( self.maximumLimit, int), 'Invalid maximum limit %s' % self.maximumLimit assert self.defaultLimit is None or isinstance( self.defaultLimit, int), 'Invalid default limit %s' % self.defaultLimit assert self.defaultWithTotal is None or isinstance(self.defaultWithTotal, bool), \ 'Invalid default with total %s' % self.defaultWithTotal super().__init__(Decoding=Decoding) self.typeLimit = typeFor(Slice.limit) self.typeTotal = typeFor(SliceAndTotal.withTotal)
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 processHintWebName(self, types, hints, isGroup=False): ''' Processes the web name hint found on the call and alters the provided types list according to it. @param types: list[Input|TypeModel|Model|tuple(string,boolean)] The list of types to be altered based on the web name hint. @param hints: dictionary{string, object} The hints to be processed for the types. @param isGroup: boolean Flag indicating that the web name hint should be considered a group node (True) or an object node (False). ''' assert isinstance(types, list), 'Invalid types %s' % types assert isinstance(hints, dict), 'Invalid hints %s' % hints assert isinstance(isGroup, bool), 'Invalid is group flag %s' % isGroup webName = hints.get(self.hintCallWebName) if isclass(webName): typ = typeFor(webName) assert isinstance( typ, TypeModel), 'Invalid web name hint class %s' % webName types.append(typ.container) elif webName: assert isinstance(webName, str), 'Invalid web name hint %s' % webName webName = webName.split('/') for k, name in enumerate(webName): assert re.match('^[\w]+$', name), 'Invalid name "%s" in web name "%s"' % ( name, '/'.join(webName)) types.append( (name, False if k <= len(webName) - 1 else isGroup)) return types
def process(self, chain, register:Register, **keyargs): ''' @see: HandlerProcessor.process Populate the content flag if required. ''' assert isinstance(register, Register), 'Invalid register %s' % register if not register.invokers: return # No invokers to process. aborted = [] for invoker in register.invokers: assert isinstance(invoker, InvokerAssembler), 'Invalid invoker %s' % invoker if not invoker.inputs: continue inpContent, toMany = None, False for inp in invoker.inputs: assert isinstance(inp, Input), 'Invalid input %s' % inp if inp.type == self.contentType: if inpContent is not None: toMany = True inpContent = inp if toMany: log.error('Cannot use because there are to many \'%s\' inputs, only a maximum of one is allowed, at:%s', typeFor(Content), invoker.location) aborted.append(invoker) elif inpContent: if invoker.solved is None: invoker.solved = set() invoker.solved.add(inpContent) invoker.inputContent = inpContent if aborted: raise Abort(*aborted)
def process(self, chain, register:Register, **keyargs): ''' @see: HandlerProcessor.process Provides the conflict resolving. ''' assert isinstance(register, Register), 'Invalid register %s' % register if Register.hintsCall in register: if register.hintsCall is None: register.hintsCall = {} register.hintsCall[self.hintName] = self.hintDescription if not register.nodes: return reported, aborted = set(), [] for node in register.nodes: assert isinstance(node, Node), 'Invalid node %s' % node if not node.conflicts: continue assert isinstance(node.conflicts, dict), 'Invalid conflicts %s' % node.conflicts for invokers in node.conflicts.values(): assert isinstance(invokers, list), 'Invalid invokers %s' % invokers byService, solving = {}, [] for invoker in invokers: assert isinstance(invoker, Invoker), 'Invalid invoker %s' % invoker if not invoker.service or not invoker.call: continue if invoker.service in byService: continue replaces = invoker.call.hints.get(self.hintName) if not replaces: continue if not isinstance(replaces, tuple): replaces = (replaces,) byService[invoker.service] = invoker solving.append((invoker, replaces)) if byService: locations = [] for invoker, replaces in solving: locations.append(invoker.location) for clazz in replaces: service = typeFor(clazz) if not isinstance(service, TypeService): log.error('Cannot use invoker because the replace hints are invalid, at:%s, ' 'it should be:\n%s', invoker.location, self.hintDescription) aborted.append(invoker) break assert isinstance(service, TypeService), 'Invalid service class %s' % clazz byService.pop(service, None) if not byService: if reported.isdisjoint(locations): log.error('Cannot use invokers because the replace hints are circular among them, at:%s', ''.join(locations)) reported.update(locations) aborted.extend(invokers) else: solved = set(byService) for invoker, replaces in solving: if invoker not in solved: aborted.append(invoker) if aborted: raise Abort(*aborted)
def populate(self, obj, specifications, support): ''' @see: ISpecifier.populate ''' ext = typeFor(obj) if not ext or not isinstance(ext, TypeExtension): return # Is not an extension object, nothing to do assert isinstance(ext, TypeExtension) if ext not in self.propertiesByType: properties = self.propertiesByType[ext] = [] for name, prop in ext.properties.items(): assert isinstance(prop, TypeProperty), 'Invalid property %s' % prop encoder = createEncoderNamed(self.processing, name, prop) if encoder is None: log.error('Cannot encode %s of %s', prop, ext) else: properties.append((name, encoder)) else: properties = self.propertiesByType[ext] attributes = specifications.get('attributes') if attributes is None: attributes = specifications['attributes'] = {} render = RenderAttributes(attributes) for name, encoder in properties: assert isinstance( encoder, ITransfrom), 'Invalid property encoder %s' % encoder objValue = getattr(obj, name) if objValue is None: continue encoder.transform(objValue, render, support)
def process(self, chain, decoding: Decoding, definition: Context = None, **keyargs): ''' @see: HandlerProcessor.process Wrap with explode decoders. ''' assert isinstance(decoding, Decoding), 'Invalid decoding %s' % decoding if not decoding.doDecode: return if not isinstance(decoding.type, List): return # The type is not a list, just move along. assert isinstance(decoding.type, List) decoding.doDecode = self.createExplode(decoding.doDecode) assert isinstance(definition, Definition), 'Invalid definition %s' % definition assert isinstance(definition.types, list), 'Invalid definition %s' % definition.types definition.types.append(typeFor(str))
def process(self, chain, register: Register, **keyargs): ''' @see: HandlerProcessor.process Populate the content flag if required. ''' assert isinstance(register, Register), 'Invalid register %s' % register if not register.invokers: return # No invokers to process. aborted = [] for invoker in register.invokers: assert isinstance(invoker, InvokerAssembler), 'Invalid invoker %s' % invoker if not invoker.inputs: continue inpContent, toMany = None, False for inp in invoker.inputs: assert isinstance(inp, Input), 'Invalid input %s' % inp if inp.type == self.contentType: if inpContent is not None: toMany = True inpContent = inp if toMany: log.error( 'Cannot use because there are to many \'%s\' inputs, only a maximum of one is allowed, at:%s', typeFor(Content), invoker.location) aborted.append(invoker) elif inpContent: if invoker.solved is None: invoker.solved = set() invoker.solved.add(inpContent) invoker.inputContent = inpContent if aborted: raise Abort(*aborted)
def findNodesFor(node, typeService, name): ''' Finds all the nodes in the root node for the provided service type and call name. @param node: Node The root node to start the find in. @param typeService: TypeService The service type to find the paths for. @param name: string The call name to find the paths for. @return: list[Node] The nodes of the service type and call name. ''' assert isinstance(node, Node), 'Invalid node %s' % node assert isinstance(typeService, TypeService), 'Invalid type service %s' % typeService assert isinstance(name, str), 'Invalid call name %s' % name assert isinstance(typeService.service, Service) call = typeService.service.calls.get(name) assert isinstance( call, Call), 'Invalid call name \'%s\' for service %s' % (name, typeService) nodes, attr = [], METHOD_NODE_ATTRIBUTE[call.method] for node in iterateNodes(node): invoker = getattr(node, attr) if not invoker: continue invoker = invokerCallOf(invoker) if not invoker: continue assert isinstance(invoker, InvokerCall) assert isinstance(invoker.call, Call) if typeService == typeFor( invoker.implementation) and invoker.call.name == name: nodes.append(node) return nodes
def onPropertyUnique(mapped, prop, obj, errors): ''' Validation of a sql alchemy unique property. @param mapped: class The mapped model class. @param prop: string The property name to be checked if unique. @param obj: object The entity to check for the property value. @param errors: list[Ref] The list of errors. ''' assert isclass(mapped), 'Invalid class %s' % mapped assert isinstance(prop, str), 'Invalid property name %s' % prop assert obj is not None, 'None is not a valid object' assert isinstance(errors, list), 'Invalid errors list %s' % errors propRef = getattr(mapped, prop) if propRef in obj: try: db = openSession().query(mapped).filter(propRef == getattr(obj, prop)).one() except NoResultFound: return propId = typeFor(mapped).container.propertyId if getattr(obj, propId) != getattr(db, propId): errors.append(Ref(_('Already an entry with this value'), ref=propRef)) return False