def mergeSpecifications(self, mergeSpecs, withSpecs): ''' Merges the provided specifications. @param mergeSpecs: dictionary{string: Specification} The specifications to be merged. @param withSpecs: dictionary{string: Specification} The specifications to merge with. @return: dictionary{string: Specification} The merged specifications. ''' assert isinstance(mergeSpecs, dict), 'Invalid specifications %s' % mergeSpecs assert isinstance(withSpecs, dict), 'Invalid specifications %s' % withSpecs specifications = dict(mergeSpecs) for name, spec in withSpecs.items(): ownSpec = specifications.get(name) if ownSpec is None: specifications[name] = spec else: assert isinstance(spec, Specification), 'Invalid specification %s' % spec try: specifications[name] = self.mergeSpecification(ownSpec, spec, definedIn=spec.definedIn) except AttrError: raise AttrError('Cannot merge attribute \'%s\', from:%s\n, with:%s' % (name, ''.join(locationStack(clazz) for clazz in ownSpec.usedIn), ''.join(locationStack(clazz) for clazz in spec.usedIn))) return specifications
def register(self, sources, resolvers, extensions, calls, report): ''' @see: IProcessor.register ''' assert isinstance(calls, list), 'Invalid calls %s' % calls assert isinstance(report, IReport), 'Invalid report %s' % report try: merge(resolvers, self.contexts) except: raise AssemblyError('Cannot merge contexts at:%s' % locationStack(self.function)) report = report.open('Branching processor at:%s' % locationStack(self.function)) processings = [] for branch in self.branches: assert isinstance(branch, IBranch), 'Invalid branch %s' % branch try: processing = branch.process(sources, resolvers, extensions, report) except: raise AssemblyError('Cannot create processing at:%s' % locationStack(self.function)) assert processing is None or isinstance( processing, Processing), 'Invalid processing %s' % processing processings.append(processing) def wrapper(*args, **keyargs): self.call(*itertools.chain(args, processings), **keyargs) updateWrapper(wrapper, self.call) calls.append(wrapper)
def __str__(self): ctxs = '\n'.join(('%s=%s' % item for item in self.contexts.items())) if ismethod(self.function): return '%s with:\n%s\n, defined at:%s\n, in instance %s' % \ (self.__class__.__name__, ctxs, locationStack(self.function), self.function.__self__) return '%s with:\n%s\n, defined at:%s' % ( self.__class__.__name__, ctxs, locationStack(self.function))
def assemble(self, assembly): ''' @see: Setup.assemble ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly for target in self._targets: if target not in assembly.calls: raise SetupError( 'There is no setup call for target \'%s\' to add the event on:%s' % (target, locationStack(self._function))) call = assembly.calls[target] if not isinstance(call, WithListeners): raise SetupError( 'Cannot find any listener support for target \'%s\' to add the event on:%s' % (target, locationStack(self._function))) assert isinstance(call, WithListeners) try: if self._event == self.BEFORE: call.addBefore(partial(assembly.processForName, self.name), self._auto) elif self._event == self.AFTER: call.addAfter(partial(assembly.processForName, self.name), self._auto) except SetupError: raise SetupError('Cannot add listener for \'%s\' from:%s' % (self._event, locationStack(self._function)))
def assemble(self, assembly): ''' @see: Setup.assemble ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name not in assembly.calls: raise SetupError( 'There is no setup call for name \'%s\' to be replaced by:%s' % (self.name, locationStack(self._function))) call = assembly.calls[self.name] if not isinstance(call, WithCall) and not isinstance(call, WithType): raise SetupError('Cannot replace call for name \'%s\' from:%s' % (self.name, locationStack(self._function))) assert isinstance(call, WithCall) if self._withOriginal: call.call = self.createCallWithOriginal(self._function, call.call) else: call.call = self._function if self._types: assert isinstance(call, WithType) if call.types: found = False for clazz in self._types: for clazzCall in call.types: if clazz == clazzCall or issubclass(clazz, clazzCall): found = True break if found: break if not found: raise SetupError( 'There is no common class for replaced classes %s and replace classes %s' % ([str(clazz) for clazz in self._types ], [str(clazz) for clazz in call.types])) call.types = self._types
def __init__(self, function, proceed=False): ''' Constructs a processor based on a function. @see: Processor.__init__ @param function: function|method The function of the processor with the arguments annotated. @param proceed: boolean Flag indicating that the processor should auto proceed for the executed chain. Attention if this flag is provided then the function should not have a 'chain' argument. ''' assert isinstance(proceed, bool), 'Invalid proceed flag %s' % proceed assert isfunction(function) or ismethod(function), 'Invalid function %s' % function self.proceed = proceed self.function = function fnArgs = getfullargspec(function) arguments, annotations = self.processArguments(fnArgs.args, fnArgs.annotations) assert isinstance(arguments, Iterable), 'Invalid arguments %s' % arguments assert isinstance(annotations, dict), 'Invalid annotations %s' % annotations contexts = {} for name in arguments: assert isinstance(name, str), 'Invalid argument name %s' % name clazz = annotations.get(name) if clazz is None: continue if not isinstance(clazz, ContextMetaClass): raise ProcessorError('Not a context class %s for argument %s, at:%s' % (clazz, name, locationStack(self.function))) contexts[name] = clazz if not contexts: raise ProcessorError('Cannot have a function with no context, at:%s' % locationStack(self.function)) super().__init__(contexts, self.processCall(function))
def process(self, chain, register: Register, Invoker: InvokerCall, **keyargs): ''' @see: HandlerProcessor.process Provides the invokers to be registered based on services. ''' assert isinstance(register, Register), 'Invalid register %s' % register assert issubclass(Invoker, InvokerCall), 'Invalid invoker %s' % Invoker assert isinstance(register.services, Iterable), 'Invalid services %s' % register.services if register.invokers is None: register.invokers = [] for implementation in register.services: service = typeFor(implementation) assert isinstance( service, TypeService ), 'Invalid service implementation %s' % implementation for call in service.calls.values(): assert isinstance(call, TypeCall), 'Invalid call %s' % call invokerId = '%s.%s.%s' % (service.clazz.__module__, service.clazz.__name__, call.name) if Register.exclude in register and register.exclude and invokerId in register.exclude: continue invoker = Invoker() assert isinstance(invoker, InvokerCall), 'Invalid invoker %s' % invoker invoker.id = invokerId invoker.service = service invoker.call = call invoker.method = call.method invoker.inputs = tuple(iterateInputs(call)) invoker.output = call.output invoker.location = locationStack( getattr(service.clazz, call.name)) if call.definer.__module__ != service.clazz.__module__ or call.definer.__name__ != service.clazz.__name__: invoker.location = '%s\n,inherited from %s' % ( locationStack(service.clazz), invoker.location) invoker.doInvoke = getattr(implementation, call.name) register.invokers.append(invoker) if Register.validations in register: validations = validationsFor(proxiedClass( type(implementation))) if validations: if register.validations is None: register.validations = {} svalidations = register.validations.get(service) if svalidations is None: register.validations[service] = validations else: svalidations.extend(validations) if register.invokers: register.doCopyInvoker = self.doCopyInvoker
def decorator(clazz): assert isclass(clazz), 'Invalid class %s' % clazz prototype = None service = clazz._ally_type = TypeService(clazz) for name, function in clazz.__dict__.items(): if not isfunction(function): continue try: service.calls[name] = TypeCall(service, clazz, *function._ally_call) except AttributeError: raise Exception('No call for method at:%s' % locationStack(function)) del function._ally_call classes = list(clazz.__bases__) while classes: base = classes.pop() inherited = typeFor(base) if inherited is None: if base == object: continue for name, function in base.__dict__.items(): if not isfunction(function) or name in service.calls: continue try: callPrototype = function._ally_call_prototype except AttributeError: pass else: if prototype is None: prototype = Prototype(replaces, clazz) service.calls[name] = TypeCall( service, base, *callPrototype(prototype)) continue try: service.calls[name] = TypeCall(service, base, *function._ally_call) except AttributeError: raise Exception('No call for inherited method at:%s' % locationStack(function)) classes.extend(base.__bases__) elif not isinstance(inherited, TypeService): raise Exception('Unexpected inherited type %s' % inherited) else: assert isinstance(inherited, TypeService) for name, cal in inherited.calls.items(): assert isinstance(cal, TypeCall) if name not in service.calls: service.calls[name] = TypeCall( service, cal.definer, *processGenericCall(cal, generics)) return processAsService(clazz, service)
def assemble(self, assembly): ''' @see: Setup.assemble ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name not in assembly.calls: raise SetupError( 'There is no setup call for name \'%s\' to be replaced by:%s' % (self.name, locationStack(self._function))) call = assembly.calls[self.name] if not isinstance(call, WithCall) and not isinstance(call, WithType): raise SetupError('Cannot replace call for name \'%s\' from:%s' % (self.name, locationStack(self._function))) assert isinstance(call, WithCall) call.call = self._function
def handleExploitError(exploit): ''' Handles the error for the provided exploit. ''' if isfunction(exploit) or ismethod(exploit): raise ResolveError('Problems with exploit at:%s' % locationStack(exploit)) else: raise ResolveError('Problems with exploit call %s' % exploit)
def do(self): ''' Called in order to do the next chain element. A *process* method needs to be executed first. @return: boolean True if the chain has performed the execution of the next element, False if there is no more to be executed. ''' while self._calls and isinstance(self._calls[0], Execution): if self._calls[0].do(): return True self._calls.popleft() if self._calls and self._status is None: call = self._calls.popleft() assert log.debug('Processing %s', call) or True try: call(self, **self.arg.__dict__) except Exception as e: if isinstance(e, TypeError) and 'arguments' in str(e): raise TypeError('A problem occurred while invoking with arguments %s, at:%s' % (', '.join(self.arg.__dict__), locationStack(call))) self._status = EXCEPTION if self._handleError(e): return True raise assert log.debug('Processing finalized \'%s\'', call) or True if self._status is None: if self._calls: return True self._status = CONSUMED if self._handleFinalization(): return True return False
def extractCriterias(clazz): ''' Extract the criteria's that are found in the provided class, including the inherited definitions. It will automatically remove the used definitions from the class. @param clazz: class The class to extract the criterias from. @return: dictionary{string, TypeCriteria} A dictionary containing as the key the criteria name and as a value the criteria type. ''' assert isclass(clazz), 'Invalid class %s' % clazz definitions = extractPropertiesInhertied(clazz, TypeQuery) for name, value in list(clazz.__dict__.items()): if name.startswith('_') or isfunction(value): continue criteria = typeFor(value) if isinstance(criteria, TypeCriteria): assert isinstance(criteria, TypeCriteria) definitions[name] = criteria.clazz delattr(clazz, name) else: log.warn('Invalid criteria \'%s\' definition \'%s\' at:%s', name, value, locationStack(clazz)) for name, typ in extractPropertiesInhertied(clazz, TypeQuery).items(): if not isinstance(typ, TypeCriteria): continue assert isinstance(typ, TypeCriteria) if name not in definitions: definitions[name] = typ.clazz return definitions
def decorator(function): assert isfunction(function), 'Invalid function %s' % function nonlocal method name = function.__name__ if method is None: for regex, m in NAME_TO_METHOD.items(): if match(regex, name): method = m break else: raise Exception( 'Cannot deduce method for function name \'%s\'' % name) inputs, output = extractInputOuput(function, types, modelToId=method in (GET, DELETE)) for inp in inputs: assert isinstance(inp, Input), 'Invalid input %s' % inp if not match(RULE_CALL_ARGUMENTS[0], inp.name): raise Exception(RULE_CALL_ARGUMENTS[1] % (inp.name, locationStack(function))) function.__isabstractmethod__ = True # Flag that notifies the ABCMeta that is is an actual abstract method. function._ally_call = name, method, inputs, output, hints return function
def place(self, clazz, name): ''' @see: IAttribute.place ''' if not self.isPlaced: assert isinstance(clazz, ContextMetaClass), 'Invalid class %s' % clazz assert isinstance(name, str), 'Invalid name %s' % name if __debug__: assert hasattr( clazz, name), 'Invalid class %s has no descriptor for %s' % ( clazz, name) self.descriptor = getattr(clazz, name) assert isinstance( self.descriptor, IGet), 'Invalid descriptor %s' % self.descriptor assert isinstance( self.descriptor, ISet), 'Invalid descriptor %s' % self.descriptor setattr(clazz, name, self) self.isPlaced, self.__objclass__, self.__name__ = True, clazz, name elif not issubclass(clazz, self.__objclass__) or self.__name__ != name: raise AttrError( '%s\n, is already placed in:%s as attribute %s' % (self, locationStack(self.__objclass__), self.__name__))
def extractProperties(clazz, forType=TypeContainer): ''' Extracts the properties definitions from the class, including the inherited definitions. It will automatically remove the used definitions from the class. @param clazz: class The class to extract the properties from. @param forType: class The inherited type to be extracted, the type needs to be a subclass of TypeContainer. @return: dictionary{string, Type} A properties definitions dictionary containing as a key the property name and as a value the property type. ''' assert isclass(clazz), 'Invalid class %s' % clazz definitions = extractPropertiesInhertied(clazz, forType) for name, value in list(clazz.__dict__.items()): if name.startswith('_') or isfunction(value): continue typ = typeFor(value) if typ is None: log.warn('Invalid property \'%s\' definition \'%s\' at:%s', name, value, locationStack(clazz)) else: definitions[name] = typ delattr(clazz, name) return definitions
def followWiring(): from ally.container.support import entityFor wiring = Wiring.wiringOf(value.__class__) if wiring: assert isinstance(wiring, Wiring), 'Invalid wiring %s' % wiring for wentity in wiring.entities: assert isinstance(wentity, WireEntity) if wentity.name not in value.__dict__: try: setattr(value, wentity.name, entityFor(wentity.type, wentity.name)) except: raise SetupError( 'Cannot solve wiring \'%s\' at: %s' % (wentity.name, locationStack(value.__class__))) mapping = wirings.get(wiring) if mapping: assert isinstance(mapping, dict), 'Invalid mapping %s' % mapping for wconfig in wiring.configurations: assert isinstance(wconfig, WireConfig) if wconfig.name not in value.__dict__: name = mapping.get(wconfig.name) if name is not None: setattr(value, wconfig.name, assembly.processForName(name)) if followUp: followUp()
def assemble(self, assembly): ''' @see: Setup.assemble ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name not in assembly.calls: raise SetupError('There is no setup call for name \'%s\' to be replaced by:%s' % (self.name, locationStack(self._function))) call = assembly.calls[self.name] if not isinstance(call, WithCall) and not isinstance(call, WithType): raise SetupError('Cannot replace call for name \'%s\' from:%s' % (self.name, locationStack(self._function))) assert isinstance(call, WithCall) call.call = self._function if self._types: assert isinstance(call, WithType) if call.types: found = False for clazz in self._types: for clazzCall in call.types: if clazz == clazzCall or issubclass(clazz, clazzCall): found = True break if found: break if not found: raise SetupError('There is no common class for replaced classes %s and replace classes %s' % ([str(clazz) for clazz in self._types], [str(clazz) for clazz in call.types])) call.types = self._types
def do(self): ''' Called in order to do the next chain element. A *process* method needs to be executed first. @return: boolean True if the chain has performed the execution of the next element, False if there is no more to be executed. ''' while self._calls and isinstance(self._calls[0], Execution): if self._calls[0].do(): return True self._calls.popleft() if self._calls and self._status is None: call = self._calls.popleft() assert log.debug('Processing %s', call) or True try: call(self, **self.arg.__dict__) except Exception as e: if isinstance(e, TypeError) and 'arguments' in str(e): raise TypeError( 'A problem occurred while invoking with arguments %s, at:%s' % (', '.join(self.arg.__dict__), locationStack(call))) self._status = EXCEPTION if self._handleError(e): return True raise assert log.debug('Processing finalized \'%s\'', call) or True if self._status is None: if self._calls: return True self._status = CONSUMED if self._handleFinalization(): return True return False
def process(self, chain, node:Node, invoker:Invoker, create:Create, **keyargs): ''' @see: HandlerProcessor.process Create the accesible path encoder. ''' assert isinstance(node, Node), 'Invalid node %s' % node assert isinstance(invoker, Invoker), 'Invalid invoker %s' % invoker assert isinstance(create, Create), 'Invalid create %s' % create if not node.invokersAccessible: return # No accessible paths if not invoker.target: return # No target available if create.encoder is not None: return # There is already an encoder, nothing to do. assert isinstance(invoker.target, TypeModel), 'Invalid target %s' % invoker.target accessible = [] for name, ainvoker in node.invokersAccessible: assert isinstance(ainvoker, Invoker), 'Invalid invoker %s' % ainvoker corrupted = False for pname in ainvoker.target.properties: if pname.startswith(ainvoker.target.name): log.error('Illegal property name \'%s\', is not allowed to start with the model name, at:%s', pname, locationStack(ainvoker.target.clazz)) corrupted = True break if corrupted: continue accessible.append(('%s%s' % (invoker.target.name, name), ainvoker)) accessible.sort(key=firstOf) create.encoder = EncoderAccessiblePath(self.nameRef, OrderedDict(accessible))
def createDescriptors(self, specifications): ''' Create the descriptors attribute. @param specifications: dictionary{string: Specification} The specifications to create the descriptors for. @return: dictionary{string: IAttribute} The created attributes. ''' assert isinstance(specifications, dict), 'Invalid specifications %s' % specifications attributes = {} for name, spec in specifications.items(): assert isinstance(name, str), 'Invalid name %s' % name assert isinstance(spec, Specification), 'Invalid specification %s' % spec if spec.status == REQUIRED: raise AttrError('Cannot generate attribute %s=%s, used in:%s' % (name, spec, ''.join( locationStack(clazz) for clazz in spec.usedIn))) if spec.status & OPTIONAL: continue # If is optional then no need to create it attributes[name] = AttributeObject(spec) return attributes
def __init__(self, function): ''' Constructs a processor based on a function. @see: Processor.__init__ @param function: function|method The function of the processor with the arguments annotated. ''' assert isfunction(function) or ismethod( function), 'Invalid function %s' % function self.function = function fnArgs = getfullargspec(function) arguments, annotations = self.processArguments(fnArgs.args, fnArgs.annotations) assert isinstance(arguments, Iterable), 'Invalid arguments %s' % arguments assert isinstance(annotations, dict), 'Invalid annotations %s' % annotations contexts = {} for name in arguments: assert isinstance(name, str), 'Invalid argument name %s' % name annot = annotations.get(name) if annot is None: raise ProcessorError( 'Context class required for argument %s, at:%s' % (name, locationStack(self.function))) if not isinstance(annot, tuple): annot = (annot, ) if not annot: raise ProcessorError( 'At least one context class is required for argument %s, at:%s' % (name, locationStack(self.function))) context = None for clazz in annot: if clazz is Context: continue if not isinstance(clazz, ContextMetaClass): raise ProcessorError( 'Not a context class %s for argument %s, at:%s' % (clazz, name, locationStack(self.function))) if context is None: context = resolverFor(clazz) else: context = context.solve(resolverFor(clazz)) if context is not None: contexts[name] = context super().__init__(contexts, function)
def process(self, chain, register:Register, **keyargs): ''' @see: HandlerProcessor.process Process the hints. ''' assert isinstance(register, Register), 'Invalid register %s' % register assert isinstance(register.doSuggest, IDo), 'Invalid do suggest %s' % register.doSuggest reported = set() if register.invokers: if register.hintsCall is None: hintsCall = {} else: hintsCall = register.hintsCall present = False for invoker in register.invokers: assert isinstance(invoker, Invoker), 'Invalid invoker %s' % invoker if not invoker.call: continue assert isinstance(invoker.call, TypeCall), 'Invalid call %s' % invoker.call unknown = [] for hname in invoker.call.hints: if hname not in hintsCall: unknown.append('\'%s\'' % hname) if unknown: if invoker.location not in reported: register.doSuggest('Unknown hints %s, at:%s', ', '.join(unknown), invoker.location) reported.add(invoker.location) present = True if present: available = [] for hname in sorted(hintsCall): available.append('\t%s: %s' % (hname, hintsCall[hname])) register.doSuggest('The available call hints are:\n%s', '\n'.join(available)) if register.relations: if register.hintsModel is None: hintsModel = {} else: hintsModel = register.hintsModel present = False for model in register.relations: assert isinstance(model, TypeModel), 'Invalid model %s' % model unknown = [] for hname in model.hints: if hname not in hintsModel: unknown.append('\'%s\'' % hname) if unknown: location = locationStack(model.clazz) if location not in reported: register.doSuggest('Unknown hints %s, at:%s', ', '.join(unknown), location) reported.add(location) present = True if present: available = [] for hname in sorted(hintsModel): available.append('\t%s: %s' % (hname, hintsModel[hname])) register.doSuggest('The available model hints are:\n%s', '\n'.join(available))
def index(self, assembly): ''' @see: Setup.index ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name in assembly.calls: raise SetupError('There is already a setup call for name \'%s\', overlaps with:%s' % (self.name, locationStack(self._function))) assembly.calls[self.name] = CallEvent(assembly, self.name, self._function)
def register(self, sources, resolvers, extensions, calls, report): ''' @see: IProcessor.register ''' assert isinstance(calls, list), 'Invalid calls %s' % calls try: merge(resolvers, self.contexts) except: raise AssemblyError('Cannot merge contexts at:%s' % locationStack(self.function)) calls.append(self.call)
def add(self, attribute): ''' Combines this attribute assembly with the provided attribute. @param attr: Attribute The attributes to be combined with. ''' assert isinstance(attribute, Attribute), 'Invalid attribute %s' % attribute if attribute.status & DEFINED: self.defined.update(attribute.types) if attribute.status & (REQUIRED | OPTIONAL): if not self.required: self.required.update(attribute.types) else: if self.required.isdisjoint(attribute.types): args = [] args.append(', '.join('\'%s\'' % typ.__name__ for typ in self.required)) args.append(', '.join('\'%s\'' % typ.__name__ for typ in attribute.types)) args.append(attribute) args.append(locationStack(attribute.clazz)) argss = ('%s\n, of attribute %s' % (locationStack(attr.clazz), attr) for attr in self.attributes) args.append(''.join(argss)) raise AssemblyError('The required assembly types %s are not compatible with the required types %s of ' 'attribute %s, from:%s\nCurrent assembly is based on attributes:%s' % tuple(args)) self.required.intersection_update(attribute.types) if self.required and self.defined and self.required != self.defined and self.defined.issuperset(self.required): args = [] args.append(', '.join('\'%s\'' % typ.__name__ for typ in self.defined)) args.append(', '.join('\'%s\'' % typ.__name__ for typ in self.required)) argss = ['%s\n, of attribute %s' % (locationStack(attr.clazz), attr) for attr in self.attributes] argss.append('%s\n, of attribute %s' % (locationStack(attribute.clazz), attribute)) args.append(''.join(argss)) raise AssemblyError('The defined attributes types %s are not compatible with the required types %s' '\nCurrent assembly is based on attributes:%s' % tuple(args)) self.status |= attribute.status self.attributes.append(attribute) docs = [] if self.doc is not None: docs.append(self.doc) if attribute.doc is not None: docs.append(attribute.doc) if docs: self.doc = '\n'.join(docs)
def process(self, chain, register:Register, Invoker:InvokerCall, **keyargs): ''' @see: HandlerProcessor.process Provides the invokers to be registered based on services. ''' assert isinstance(register, Register), 'Invalid register %s' % register assert issubclass(Invoker, InvokerCall), 'Invalid invoker %s' % Invoker assert isinstance(register.services, Iterable), 'Invalid services %s' % register.services if register.invokers is None: register.invokers = [] for implementation in register.services: service = typeFor(implementation) assert isinstance(service, TypeService), 'Invalid service implementation %s' % implementation for call in service.calls.values(): assert isinstance(call, TypeCall), 'Invalid call %s' % call invokerId = '%s.%s.%s' % (service.clazz.__module__, service.clazz.__name__, call.name) if Register.exclude in register and register.exclude and invokerId in register.exclude: continue invoker = Invoker() assert isinstance(invoker, InvokerCall), 'Invalid invoker %s' % invoker invoker.id = invokerId invoker.service = service invoker.call = call invoker.method = call.method invoker.inputs = tuple(iterateInputs(call)) invoker.output = call.output invoker.location = locationStack(getattr(service.clazz, call.name)) if call.definer.__module__ != service.clazz.__module__ or call.definer.__name__ != service.clazz.__name__: invoker.location = '%s\n,inherited from %s' % (locationStack(service.clazz), invoker.location) invoker.doInvoke = getattr(implementation, call.name) register.invokers.append(invoker) if Register.validations in register: validations = validationsFor(proxiedClass(type(implementation))) if validations: if register.validations is None: register.validations = {} svalidations = register.validations.get(service) if svalidations is None: register.validations[service] = validations else: svalidations.extend(validations) if register.invokers: register.doCopyInvoker = self.doCopyInvoker
def register(self, sources, resolvers, extensions, calls, report): ''' @see: IProcessor.register ''' assert isinstance(resolvers, Resolvers), 'Invalid resolvers %s' % resolvers assert isinstance(calls, list), 'Invalid calls %s' % calls try: resolvers.merge(self.contexts) except ResolverError: raise AssemblyError('Cannot merge contexts at:%s' % locationStack(self.function)) calls.append(self.call)
def assemble(self, assembly): ''' @see: Setup.assemble ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly for target in self._targets: if target not in assembly.calls: raise SetupError('There is no setup call for target \'%s\' to add the event on:%s' % (target, locationStack(self._function))) call = assembly.calls[target] if not isinstance(call, WithListeners): raise SetupError('Cannot find any listener support for target \'%s\' to add the event on:%s' % (target, locationStack(self._function))) assert isinstance(call, WithListeners) try: if self._event == self.BEFORE: call.addBefore(partial(assembly.processForName, self.name), self._auto) elif self._event == self.AFTER: call.addAfter(partial(assembly.processForName, self.name), self._auto) except SetupError: raise SetupError('Cannot add listener for \'%s\' from:%s' % (self._event, locationStack(self._function)))
def processArguments(self, arguments, annotations): ''' @see: Contextual.processArguments ''' arguments, annotations = super().processArguments(arguments, annotations) n = len(self.branches) if len(arguments) > n: return arguments[n:], annotations raise ProcessorError('Required function of form \'def processor(self, [chain], ' 'processing, ..., contex:Context ...)\' for:%s' % locationStack(self.function))
def index(self, assembly): ''' @see: Setup.index ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name in assembly.calls: raise SetupError( 'There is already a setup call for name \'%s\', overlaps with:%s' % (self.name, locationStack(self._function))) assembly.calls[self.name] = CallStart(assembly, self.name, self._function, self._priority)
def __str__(self): status = [] if self.status & DEFINED: status.append('DEFINES') if self.status & REQUIRED: status.append('REQUIRED') if self.status & OPTIONAL: status.append('OPTIONAL') st = ''.join(('|'.join(status), '[', ','.join(t.__name__ for t in self.types), ']')) st = ''.join((self.__class__.__name__, ' having ', st)) if self._clazz: return ''.join((st, ' in:', locationStack(self._clazz), ' as attribute ', self._name)) return ''.join((st, ' unplaced'))
def index(self, assembly): ''' @see: Setup.index ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name in assembly.calls: raise SetupError('There is already a setup call for name \'%s\', overlaps with:%s' % (self.name, locationStack(self._function))) if self._event == self.BEFORE or len(self._targets) == 1: assembly.calls[self.name] = CallEvent(assembly, self.name, self._function) else: assembly.calls[self.name] = CallEventOnCount(assembly, self.name, self._function, len(self._targets))
def __str__(self): status = [] if self.status & DEFINED: status.append('DEFINES') if self.status & REQUIRED: status.append('REQUIRED') if self.status & OPTIONAL: status.append('OPTIONAL') st = ''.join(('|'.join(status), '[', ','.join(t.__name__ for t in self.types), ']')) st = ''.join((self.__class__.__name__, ' having ', st)) if self.usedIn: used = (clazzName for clazzName, status in self.usedIn.items() if status == self.status) used = ['%s as attribute \'%s\'' % (locationStack(clazz), name) for clazz, name in used] return ''.join((st, ' used in:', ''.join(used), '\n')) return ''.join((st, ' unused'))
def assemble(self, assembly): ''' @see: Setup.assemble ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name not in assembly.calls: raise SetupError('There is no setup call for name \'%s\' to be replaced by:%s' % (self.name, locationStack(self._function))) call = assembly.calls[self.name] if not isinstance(call, WithCall) and not isinstance(call, WithType): raise SetupError('Cannot replace call for name \'%s\' from:%s' % (self.name, locationStack(self._function))) assert isinstance(call, WithCall) call.call = self._function
def processArguments(self, arguments, annotations): ''' Process the context arguments as seen fit. @param arguments: list[string]|tuple(string) The arguments to process. @param annotations: dictionary{string, object} The annotations to process. @return: tuple(list[string], dictionary{string, object}) A tuple containing the list of processed arguments names and second value the dictionary containing the annotation for arguments. ''' assert isinstance(arguments, (list, tuple)), 'Invalid arguments %s' % arguments assert isinstance(annotations, dict), 'Invalid annotations %s' % annotations if self.proceed: if len(arguments) > 1 and 'self' == arguments[0]: return arguments[1:], annotations raise ProcessorError('Required function of form \'def processor(self, contex:Context ...)\' for:%s' % locationStack(self.function)) if len(arguments) > 2 and 'self' == arguments[0]: return arguments[2:], annotations raise ProcessorError('Required function of form \'def processor(self, chain, contex:Context ...)\' for:%s' % locationStack(self.function))
def __init__(self, function): ''' Constructs a processor based on a function. @see: Processor.__init__ @param function: function|method The function of the processor with the arguments annotated. ''' assert isfunction(function) or ismethod(function), 'Invalid function %s' % function self.function = function fnArgs = getfullargspec(function) arguments, annotations = self.processArguments(fnArgs.args, fnArgs.annotations) assert isinstance(arguments, Iterable), 'Invalid arguments %s' % arguments assert isinstance(annotations, dict), 'Invalid annotations %s' % annotations contexts = {} for name in arguments: assert isinstance(name, str), 'Invalid argument name %s' % name annot = annotations.get(name) if annot is None: raise ProcessorError('Context class required for argument %s, at:%s' % (name, locationStack(self.function))) if not isinstance(annot, tuple): annot = (annot,) if not annot: raise ProcessorError('At least one context class is required for argument %s, at:%s' % (name, locationStack(self.function))) context = None for clazz in annot: if clazz is Context: continue if not isinstance(clazz, ContextMetaClass): raise ProcessorError('Not a context class %s for argument %s, at:%s' % (clazz, name, locationStack(self.function))) if context is None: context = resolverFor(clazz) else: context = context.solve(resolverFor(clazz)) if context is not None: contexts[name] = context super().__init__(contexts, function)
def prototype(prototype): assert isinstance(prototype, Prototype), 'Invalid replaces %s' % prototype inputs, output = extractInputOuput(function, types, modelToId=method in (GET, DELETE), prototype=prototype) for inp in inputs: assert isinstance(inp, Input), 'Invalid input %s' % inp if not match(RULE_CALL_ARGUMENTS[0], inp.name): raise Exception(RULE_CALL_ARGUMENTS[1] % (inp.name, locationStack(function))) return name, method, inputs, output, hints
def __str__(self): status = [] if self.status & DEFINED: status.append('DEFINES') if self.status & REQUIRED: status.append('REQUIRED') if self.status & OPTIONAL: status.append('OPTIONAL') st = ''.join( ('|'.join(status), '[', ','.join(t.__name__ for t in self.types), ']')) st = ''.join((self.__class__.__name__, ' having ', st)) if self._clazz: return ''.join((st, ' in:', locationStack(self._clazz), ' as attribute ', self._name)) return ''.join((st, ' unplaced'))
def index(self, assembly): ''' @see: Setup.index ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name in assembly.calls: raise SetupError('There is already a setup call for name \'%s\', overlaps with:%s' % (self.name, locationStack(self._function))) if self._event == DEPLOYER: assembly.calls[self.name] = CallEvent(assembly, self.name, self._function) else: assembly.calls[self.name] = CallEventAcknowledged(assembly, self.name, self._function, self._event) _distribution(assembly).events[self._event].append(self.name)
def assemble(self, assembly): ''' @see: Setup.assemble ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name not in assembly.calls: raise SetupError('There is no setup configuration call for name \'%s\' to be replaced by:%s' % (self.name, locationStack(self._function))) config = assembly.calls[self.name] assert isinstance(config, CallConfig), 'Invalid call configuration %s' % config try: config.value = self._function() except ConfigError as e: config.value = e assembly.configurations[self.name] = Config(self.name, config.value, self.group, self.target.documentation)
def register(self, sources, resolvers, extensions, calls, report): ''' @see: IProcessor.register ''' assert isinstance(calls, list), 'Invalid calls %s' % calls assert isinstance(report, IReport), 'Invalid report %s' % report try: merge(resolvers, self.contexts) except: raise AssemblyError('Cannot merge contexts at:%s' % locationStack(self.function)) report = report.open('Branching processor at:%s' % locationStack(self.function)) processings = [] for branch in self.branches: assert isinstance(branch, IBranch), 'Invalid branch %s' % branch try: processing = branch.process(sources, resolvers, extensions, report) except: raise AssemblyError('Cannot create processing at:%s' % locationStack(self.function)) assert processing is None or isinstance(processing, Processing), 'Invalid processing %s' % processing processings.append(processing) def wrapper(*args, **keyargs): self.call(*itertools.chain(args, processings), **keyargs) updateWrapper(wrapper, self.call) calls.append(wrapper)
def place(self, clazz, name): ''' @see: IAttribute.place ''' if not self.isPlaced: assert isinstance(clazz, ContextMetaClass), 'Invalid class %s' % clazz assert isinstance(name, str), 'Invalid name %s' % name self.isPlaced, self.__objclass__, self.__name__ = True, clazz, name self.specification.usedIn[clazz] = self.specification.status if self.specification.definedIn is None and self.specification.status == DEFINED: self.specification.definedIn = clazz elif not issubclass(clazz, self.__objclass__) or self.__name__ != name: raise AttrError('%s\n, is already placed in:%s as attribute %s' % (self, locationStack(self.__objclass__), self.__name__))
def mergeSpecifications(self, mergeSpecs, withSpecs): ''' Merges the provided specifications. @param mergeSpecs: dictionary{string: Specification} The specifications to be merged. @param withSpecs: dictionary{string: Specification} The specifications to merge with. @return: dictionary{string: Specification} The merged specifications. ''' assert isinstance(mergeSpecs, dict), 'Invalid specifications %s' % mergeSpecs assert isinstance(withSpecs, dict), 'Invalid specifications %s' % withSpecs specifications = dict(mergeSpecs) for name, spec in withSpecs.items(): ownSpec = specifications.get(name) if ownSpec is None: specifications[name] = spec else: assert isinstance( spec, Specification), 'Invalid specification %s' % spec try: specifications[name] = self.mergeSpecification( ownSpec, spec, definedIn=spec.definedIn) except AttrError: raise AttrError( 'Cannot merge attribute \'%s\', from:%s\n, with:%s' % (name, ''.join( locationStack(clazz) for clazz in ownSpec.usedIn), ''.join( locationStack(clazz) for clazz in spec.usedIn))) return specifications
def followWiring(): from ally.container.support import entityFor assert isinstance(wiring, Wiring) for wentity in wiring.entities: assert isinstance(wentity, WireEntity) if wentity.name not in value.__dict__: try: setattr(value, wentity.name, entityFor(wentity.type, wentity.name)) except: raise SetupError('Cannot solve wiring \'%s\' at: %s' % (wentity.name, locationStack(value.__class__))) for wconfig in wiring.configurations: assert isinstance(wconfig, WireConfig) if wconfig.name not in value.__dict__: name = self.nameFor(self.group, clazz, wconfig) setattr(value, wconfig.name, assembly.processForName(name)) if followUp: followUp()
def index(self, assembly): ''' @see: Setup.index ''' assert isinstance(assembly, Assembly), 'Invalid assembly %s' % assembly if self.name in assembly.calls: raise SetupError( 'There is already a setup call for name \'%s\', overlaps with:%s' % (self.name, locationStack(self._function))) if self._event == self.BEFORE or len(self._targets) == 1: assembly.calls[self.name] = CallEvent(assembly, self.name, self._function) else: assembly.calls[self.name] = CallEventOnCount( assembly, self.name, self._function, len(self._targets))
def place(self, clazz, name): ''' @see: IAttribute.place ''' if not self.isPlaced: assert isinstance(clazz, ContextMetaClass), 'Invalid class %s' % clazz assert isinstance(name, str), 'Invalid name %s' % name self.isPlaced, self.__objclass__, self.__name__ = True, clazz, name self.specification.usedIn[clazz] = self.specification.status if self.specification.definedIn is None and self.specification.status == DEFINED: self.specification.definedIn = clazz elif not issubclass(clazz, self.__objclass__) or self.__name__ != name: raise AttrError( '%s\n, is already placed in:%s as attribute %s' % (self, locationStack(self.__objclass__), self.__name__))
def __init__(self, name, after=None, before=None, **keywords): ''' Create a new priority. @param name: string The name for priority. @param after: Priority|None The created priority will be after the provided priority. @param before: Priority|None The created priority will be before the provided priority. ''' assert isinstance(name, str), 'Invalid name %s' % name self.name = name location = keywords.get('location') if location is None: self.location = locationStack(callerFrame()).strip() else: assert isinstance(location, str), 'Invalid location %s' % location self.location = location.strip() if before: assert isinstance(before, Priority), 'Invalid priority %s' % before assert after is None, 'Can only have before or after priority' if __debug__: try: assert before != PRIORITY_FIRST, 'Cannot add a priority above PRIORITY_FIRST' except NameError: pass self._group = before._group self._group.insert(self._group.index(before), self) elif after: assert isinstance(after, Priority), 'Invalid priority %s' % after if __debug__: try: assert before != PRIORITY_LAST, 'Cannot add a priority after PRIORITY_LAST' except NameError: pass self._group = after._group self._group.insert(self._group.index(after) + 1, self) else: self._group = [self] for k, priority in enumerate(self._group): priority._index = k
def wrapperWiredConfiguration(clazz, wconfig): ''' Wraps the wired configuration and behaves like a configuration function so it can be used for setup. @param clazz: class The class containing the wired configuration. @param wconfig: WireConfig The wired configuration to wrap. ''' assert isclass(clazz), 'Invalid class %s' % clazz assert isinstance(wconfig, WireConfig), 'Invalid wire configuration %s' % wconfig value = clazz.__dict__.get(wconfig.name, None) if value and not isclass(value): return deepcopy(value) if wconfig.hasValue: return deepcopy(wconfig.value) raise ConfigError('A configuration value is required for \'%s\' in:%s' % (wconfig.name, locationStack(clazz)))
def place(self, clazz, name): ''' @see: IAttribute.place ''' if not self.isPlaced: assert isinstance(clazz, ContextMetaClass), 'Invalid class %s' % clazz assert isinstance(name, str), 'Invalid name %s' % name if __debug__: assert hasattr(clazz, name), 'Invalid class %s has no descriptor for %s' % (clazz, name) self.descriptor = getattr(clazz, name) assert isinstance(self.descriptor, IGet), 'Invalid descriptor %s' % self.descriptor assert isinstance(self.descriptor, ISet), 'Invalid descriptor %s' % self.descriptor setattr(clazz, name, self) self.isPlaced, self.__objclass__, self.__name__ = True, clazz, name elif not issubclass(clazz, self.__objclass__) or self.__name__ != name: raise AttrError('%s\n, is already placed in:%s as attribute %s' % (self, locationStack(self.__objclass__), self.__name__))
def __str__(self): status = [] if self.status & DEFINED: status.append('DEFINES') if self.status & REQUIRED: status.append('REQUIRED') if self.status & OPTIONAL: status.append('OPTIONAL') st = ''.join( ('|'.join(status), '[', ','.join(t.__name__ for t in self.types), ']')) st = ''.join((self.__class__.__name__, ' having ', st)) if self.usedIn: used = (clazzName for clazzName, status in self.usedIn.items() if status == self.status) used = [ '%s as attribute \'%s\'' % (locationStack(clazz), name) for clazz, name in used ] return ''.join((st, ' used in:', ''.join(used), '\n')) return ''.join((st, ' unused'))
def process(self, chain, register:Register, Invoker:InvokerResources, **keyargs): ''' @see: HandlerProcessor.process Create the collection encoder. ''' assert isinstance(register, Register), 'Invalid register %s' % register assert issubclass(Invoker, InvokerResources), 'Invalid invoker class %s' % Invoker if self.nameResources in register.exclude: return if register.invokers is None: register.invokers = [] invoker = Invoker() register.invokers.append(invoker) assert isinstance(invoker, InvokerResources), 'Invalid invoker %s' % invoker invoker.id = self.nameResources invoker.location = locationStack(self.__class__) invoker.methodHTTP = HTTP_GET invoker.path = [] invoker.encoder = EncoderResources(self.nameResources, self.nameRef, invoker)
def __init__(self, name, after=None, before=None, **keywords): ''' Create a new priority. @param name: string The name for priority. @param after: Priority|None The created priority will be after the provided priority. @param before: Priority|None The created priority will be before the provided priority. ''' assert isinstance(name, str), 'Invalid name %s' % name self.name = name location = keywords.get('location') if location is None: self.location = locationStack(callerFrame()).strip() else: assert isinstance(location, str), 'Invalid location %s' % location self.location = location.strip() if before: assert isinstance(before, Priority), 'Invalid priority %s' % before assert after is None, 'Can only have before or after priority' if __debug__: try: assert before != PRIORITY_FIRST, 'Cannot add a priority above PRIORITY_FIRST' except NameError: pass self._group = before._group self._group.insert(self._group.index(before), self) elif after: assert isinstance(after, Priority), 'Invalid priority %s' % after if __debug__: try:assert before != PRIORITY_LAST, 'Cannot add a priority after PRIORITY_LAST' except NameError: pass self._group = after._group self._group.insert(self._group.index(after) + 1, self) else: self._group = [self] for k, priority in enumerate(self._group): priority._index = k
def createDescriptors(self, specifications): ''' Create the descriptors attribute. @param specifications: dictionary{string: Specification} The specifications to create the descriptors for. @return: dictionary{string: IAttribute} The created attributes. ''' assert isinstance(specifications, dict), 'Invalid specifications %s' % specifications attributes = {} for name, spec in specifications.items(): assert isinstance(name, str), 'Invalid name %s' % name assert isinstance(spec, Specification), 'Invalid specification %s' % spec if spec.status == REQUIRED: raise AttrError('Cannot generate attribute %s=%s, used in:%s' % (name, spec, ''.join(locationStack(clazz) for clazz in spec.usedIn))) if spec.status & OPTIONAL: continue # If is optional then no need to create it attributes[name] = AttributeObject(spec) return attributes