Ejemplo n.º 1
0
    def enterScope(self, name):
        """This is called when you enter a scope

        @param: string name

        @raise RuntimeException         When the parent scope is inactive
        @raise InvalidArgumentException When the scope does not exist

        @api

        """

        if name not in self._scopes:
            raise InvalidArgumentException(
                'The scope "{0}" does not exist.'.format(name))

        if self.SCOPE_CONTAINER != self._scopes[name] and self._scopes[
                name] not in self._scopedServices:
            raise RuntimeException(
                'The parent scope "{0}" must be active when entering this '
                'scope.'.format(self._scopes[name]))

        # check if a scope of this name is already active, if so we need to
        # remove all services of this scope, and those of any of its child
        # scopes from the global services map
        if name in self._scopedServices:
            services = OrderedDict()
            services[0] = self._services
            services[name] = self._scopedServices[name]
            self._scopedServices.pop(name, None)

            for child in self._scopeChildren[name]:
                if child in self._scopedServices:
                    services[child] = self._scopedServices[child]
                    self._scopedServices.pop(child, None)

            # update global map
            self._services = Array.diffKey(*services.values())
            services.pop(0)

            # add stack entry for this scope so we can restore the removed services later
            if name not in self._scopeStacks:
                self._scopeStacks[name] = list()

            self._scopeStacks[name].append(services)

        self._scopedServices[name] = dict()
Ejemplo n.º 2
0
class BaseNode(NodeInterface):
    """The base node class

    @author Johannes M. Schmitt <*****@*****.**>

    """
    def __init__(self, name, parent=None):
        """Constructor.

        @param name: string The name of the node
        @param parent: NodeInterface The parent of this node

        @raise InvalidArgumentException: if the name contains a period.
        """
        assert isinstance(name, String);
        if parent is not None:
            assert isinstance(parent, NodeInterface);

        self._attributes = OrderedDict();

        self._name = name;
        self._parent = parent;
        self._normalizationClosures = list();
        self._finalValidationClosures = list();
        self._allowOverwrite = True;
        self._required = False;
        self._equivalentValues = list();

        if '.' in name:
            raise InvalidArgumentException('The name must not contain ".".');

    def setAttribute(self, key, value):
        self._attributes[key] = value;

    def hasAttribute(self, key):
        return key in self._attributes;

    def getAttribute(self, key, default=None):
        if self.hasAttribute(key):
            return self._attributes[key];
        return default;

    def getAttributes(self, key):
        return self._attributes;

    def setAttributes(self, attributes):
        assert isinstance(attributes, dict);
        self._attributes = attributes;

    def removeAttribute(self, key):
        return self._attributes.pop(key);

    def setInfo(self, info):
        """Sets an info message.

        @param info: string
        """
        self.setAttribute('info', info);

    def getInfo(self):
        """Returns info message.

        @return: string The info message.
        """
        return self.getAttribute('info');

    def setExample(self, example):
        """Sets the example configuration for this node.

        @param example: string|array
        """
        self.setAttribute('example', example);

    def getExample(self):
        """Retrieves the example configuration for this node.

        @return: string|array
        """
        return self.getAttribute('example');

    def addEquivalentValue(self, originalValue, equivalentValue):
        """Adds an equivalent value.

        @param originalValue: mixed
        @param equivalentValue: mixed
        """
        self._equivalentValues.append([originalValue, equivalentValue]);

    def setRequired(self, boolean):
        """Set this node as required.

        @param boolean: Boolean Required node
        """
        self._required = bool(boolean);

    def setAllowOverwrite(self, allow):
        """Sets if this node can be overridden.

        @param allow: Boolean
        """
        self._allowOverwrite = bool(allow);

    def setNormalizationClosures(self, closures):
        """Sets the closures used for normalization.

        @param closures: callable[] An array of Closures used for normalization
        """
        assert isinstance(closures, list);
        self._normalizationClosures = closures;

    def setFinalValidationClosures(self, closures):
        """Sets the closures used for final validation.

        @param closures: callable[] An array of Closures used 
            for final validation
        """
        assert isinstance(closures, list);
        self._finalValidationClosures = closures;

    def isRequired(self):
        """Checks if this node is required.

        @return Boolean

        """
        return self._required;

    def getName(self):
        """Returns the name of this node

        @return string The Node's name.

        """
        return self._name;

    def getPath(self):
        """Retrieves the path of this node.

        @return string The Node's path

        """
        path = self._name;
        if not self._parent is None:
            path = ".".join([self._parent.getPath(), self._name]);
        return path;

    @final
    def merge(self, leftSide, rightSide):
        """Merges two values together.

        @param leftSide:  mixed
        @param rightSide: mixed

        @return mixed The merged value

        @raise ForbiddenOverwriteException:

        """
        if not self._allowOverwrite:
            raise ForbiddenOverwriteException(
                'Configuration path "{0}" cannot be overwritten. You have to '
                'define all options for this path, and any of its sub-paths '
                'in one configuration section.'.format(self.getPath())
            );

        self._validateType(leftSide);
        self._validateType(rightSide);

        return self._mergeValues(leftSide, rightSide);

    @final
    def normalize(self, value):
        """Normalizes a value, applying all normalization closures.

        @param value: mixed Value to normalize.

        @return: mixed The normalized value.

        """
        # pre-normalize value
        value  = self._preNormalize(value);

        # run custom normalization closures
        for closure in self._normalizationClosures:
            value = closure(value);

        # replace value with their equivalent
        for data in self._equivalentValues:
            if data[0] == value:
                value = data[1];

        # validate type
        self._validateType(value);

        # normalize value
        return self._normalizeValue(value);

    def _preNormalize(self, value):
        """Normalizes the value before any other normalization is applied.

        @param value:

        @return: mixed The normalized array value

        """
        return value;

    @final
    def finalize(self, value):
        """Finalizes a value, applying all finalization closures.

        @param mixed $value The value to finalize

        @return mixed The finalized value

        @raise InvalidConfigurationException:

        """
        self._validateType(value);
        value = self._finalizeValue(value);

        # Perform validation on the final value if a closure has been set.
        # The closure is also allowed to return another value.
        for closure in self._finalValidationClosures:
            try:
                value = closure(value);
            except DefinitionException as correctEx:
                raise correctEx;
            except Exception as invalid:
                raise InvalidConfigurationException(
                    'Invalid configuration for path "{0}": {1}'
                    ''.format(self.getPath(), str(invalid)),
                    previous=invalid
                );
        return value;

    @abstract
    def _validateType(self, value):
        """Validates the type of a Node.

        @param value: mixed The value to validate

        @raise InvalidTypeException: When the value is invalid
        """
        pass;

    @abstract
    def _normalizeValue(self, value):
        """Normalizes the value.

        @param value: mixed The value to normalize.

        @return: mixed The normalized value
        """
        pass;

    @abstract
    def _mergeValues(self, leftSide, rightSide):
        """Merges two values together.

        @param leftSide: mixed
        @param rightSide: mixed

        @return: mixed
        """
        pass;

    @abstract
    def _finalizeValue(self, value):
        """Finalizes a value.

        @param value: The value to finalize

        @return: mixed The finalized value
        """
        pass;
Ejemplo n.º 3
0
class BaseNode(NodeInterface):
    """The base node class

    @author Johannes M. Schmitt <*****@*****.**>

    """
    def __init__(self, name, parent=None):
        """Constructor.

        @param name: string The name of the node
        @param parent: NodeInterface The parent of this node

        @raise InvalidArgumentException: if the name contains a period.
        """
        assert isinstance(name, String)
        if parent is not None:
            assert isinstance(parent, NodeInterface)

        self._attributes = OrderedDict()

        self._name = name
        self._parent = parent
        self._normalizationClosures = list()
        self._finalValidationClosures = list()
        self._allowOverwrite = True
        self._required = False
        self._equivalentValues = list()

        if '.' in name:
            raise InvalidArgumentException('The name must not contain ".".')

    def setAttribute(self, key, value):
        self._attributes[key] = value

    def hasAttribute(self, key):
        return key in self._attributes

    def getAttribute(self, key, default=None):
        if self.hasAttribute(key):
            return self._attributes[key]
        return default

    def getAttributes(self, key):
        return self._attributes

    def setAttributes(self, attributes):
        assert isinstance(attributes, dict)
        self._attributes = attributes

    def removeAttribute(self, key):
        return self._attributes.pop(key)

    def setInfo(self, info):
        """Sets an info message.

        @param info: string
        """
        self.setAttribute('info', info)

    def getInfo(self):
        """Returns info message.

        @return: string The info message.
        """
        return self.getAttribute('info')

    def setExample(self, example):
        """Sets the example configuration for this node.

        @param example: string|array
        """
        self.setAttribute('example', example)

    def getExample(self):
        """Retrieves the example configuration for this node.

        @return: string|array
        """
        return self.getAttribute('example')

    def addEquivalentValue(self, originalValue, equivalentValue):
        """Adds an equivalent value.

        @param originalValue: mixed
        @param equivalentValue: mixed
        """
        self._equivalentValues.append([originalValue, equivalentValue])

    def setRequired(self, boolean):
        """Set this node as required.

        @param boolean: Boolean Required node
        """
        self._required = bool(boolean)

    def setAllowOverwrite(self, allow):
        """Sets if this node can be overridden.

        @param allow: Boolean
        """
        self._allowOverwrite = bool(allow)

    def setNormalizationClosures(self, closures):
        """Sets the closures used for normalization.

        @param closures: callable[] An array of Closures used for normalization
        """
        assert isinstance(closures, list)
        self._normalizationClosures = closures

    def setFinalValidationClosures(self, closures):
        """Sets the closures used for final validation.

        @param closures: callable[] An array of Closures used 
            for final validation
        """
        assert isinstance(closures, list)
        self._finalValidationClosures = closures

    def isRequired(self):
        """Checks if this node is required.

        @return Boolean

        """
        return self._required

    def getName(self):
        """Returns the name of this node

        @return string The Node's name.

        """
        return self._name

    def getPath(self):
        """Retrieves the path of this node.

        @return string The Node's path

        """
        path = self._name
        if not self._parent is None:
            path = ".".join([self._parent.getPath(), self._name])
        return path

    @final
    def merge(self, leftSide, rightSide):
        """Merges two values together.

        @param leftSide:  mixed
        @param rightSide: mixed

        @return mixed The merged value

        @raise ForbiddenOverwriteException:

        """
        if not self._allowOverwrite:
            raise ForbiddenOverwriteException(
                'Configuration path "{0}" cannot be overwritten. You have to '
                'define all options for this path, and any of its sub-paths '
                'in one configuration section.'.format(self.getPath()))

        self._validateType(leftSide)
        self._validateType(rightSide)

        return self._mergeValues(leftSide, rightSide)

    @final
    def normalize(self, value):
        """Normalizes a value, applying all normalization closures.

        @param value: mixed Value to normalize.

        @return: mixed The normalized value.

        """
        # pre-normalize value
        value = self._preNormalize(value)

        # run custom normalization closures
        for closure in self._normalizationClosures:
            value = closure(value)

        # replace value with their equivalent
        for data in self._equivalentValues:
            if data[0] == value:
                value = data[1]

        # validate type
        self._validateType(value)

        # normalize value
        return self._normalizeValue(value)

    def _preNormalize(self, value):
        """Normalizes the value before any other normalization is applied.

        @param value:

        @return: mixed The normalized array value

        """
        return value

    @final
    def finalize(self, value):
        """Finalizes a value, applying all finalization closures.

        @param mixed $value The value to finalize

        @return mixed The finalized value

        @raise InvalidConfigurationException:

        """
        self._validateType(value)
        value = self._finalizeValue(value)

        # Perform validation on the final value if a closure has been set.
        # The closure is also allowed to return another value.
        for closure in self._finalValidationClosures:
            try:
                value = closure(value)
            except DefinitionException as correctEx:
                raise correctEx
            except Exception as invalid:
                raise InvalidConfigurationException(
                    'Invalid configuration for path "{0}": {1}'
                    ''.format(self.getPath(), str(invalid)),
                    previous=invalid)
        return value

    @abstract
    def _validateType(self, value):
        """Validates the type of a Node.

        @param value: mixed The value to validate

        @raise InvalidTypeException: When the value is invalid
        """
        pass

    @abstract
    def _normalizeValue(self, value):
        """Normalizes the value.

        @param value: mixed The value to normalize.

        @return: mixed The normalized value
        """
        pass

    @abstract
    def _mergeValues(self, leftSide, rightSide):
        """Merges two values together.

        @param leftSide: mixed
        @param rightSide: mixed

        @return: mixed
        """
        pass

    @abstract
    def _finalizeValue(self, value):
        """Finalizes a value.

        @param value: The value to finalize

        @return: mixed The finalized value
        """
        pass