Ejemplo n.º 1
0
    def __init__(self, transDict, machine,
                 fromStateName):  # pylint: disable-msg=R0912
        """ Builds a _TransitionConfig from a dictionary representation. 
            This transition is not added to the machine. """

        self.machineName = machine.name

        # check for bad attributes
        badAttributes = set()
        for attribute in transDict.iterkeys():
            if attribute not in constants.VALID_TRANS_ATTRIBUTES:
                badAttributes.add(attribute)
        if badAttributes:
            raise exceptions.InvalidTransitionAttributeError(
                self.machineName, fromStateName, badAttributes)

        # transition event
        event = transDict.get(constants.TRANS_EVENT_ATTRIBUTE)
        if not event:
            raise exceptions.TransitionEventRequiredError(
                machine.name, fromStateName)
        try:
            # attempt to import the value of the event
            self.event = _resolveObject(event, machine.namespace)
        except (exceptions.UnknownModuleError, exceptions.UnknownClassError,
                exceptions.UnknownObjectError):
            # otherwise just use the value from the yaml
            self.event = event
        if not constants.NAME_RE.match(self.event):
            raise exceptions.InvalidTransitionEventNameError(
                self.machineName, fromStateName, self.event)

        # transition name
        self.name = '%s--%s' % (fromStateName, self.event)
        if not self.name:
            raise exceptions.TransitionNameRequiredError(self.machineName)
        if not constants.NAME_RE.match(self.name):
            raise exceptions.InvalidTransitionNameError(
                self.machineName, self.name)

        # transition from state
        if not fromStateName:
            raise exceptions.TransitionFromRequiredError(
                self.machineName, self.name)
        if fromStateName not in machine.states:
            raise exceptions.TransitionUnknownFromStateError(
                self.machineName, self.name, fromStateName)
        self.fromState = machine.states[fromStateName]

        # transition to state
        toStateName = transDict.get(constants.TRANS_TO_ATTRIBUTE)
        if not toStateName:
            raise exceptions.TransitionToRequiredError(self.machineName,
                                                       self.name)
        if toStateName not in machine.states:
            raise exceptions.TransitionUnknownToStateError(
                self.machineName, self.name, toStateName)
        self.toState = machine.states[toStateName]

        # transition namespace
        self.namespace = transDict.get(constants.NAMESPACE_ATTRIBUTE,
                                       machine.namespace)

        # transition task_retry_limit, min_backoff_seconds, max_backoff_seconds, task_age_limit, max_doublings
        # W0612:439:_TransitionConfig.__init__: Unused variable 'default'
        for (constant, attribute, default,
             exception) in TASK_ATTRIBUTES:  # pylint: disable-msg=W0612
            setattr(self, attribute,
                    getattr(machine, attribute))  # default from the machine
            if constant in transDict:
                setattr(self, attribute, transDict[constant])
                try:
                    i = int(getattr(self, attribute))
                    setattr(self, attribute, i)
                except ValueError:
                    raise exception(self.machineName, getattr(self, attribute))

        # if both max_retries and task_retry_limit specified, raise an exception
        if constants.MAX_RETRIES_ATTRIBUTE in transDict and constants.TASK_RETRY_LIMIT_ATTRIBUTE in transDict:
            raise exceptions.MaxRetriesAndTaskRetryLimitMutuallyExclusiveError(
                self.machineName)

        # transition maxRetries
        if constants.MAX_RETRIES_ATTRIBUTE in transDict:
            logging.warning(
                'max_retries is deprecated. Use task_retry_limit instead.')
            self.taskRetryLimit = transDict[constants.MAX_RETRIES_ATTRIBUTE]
            try:
                self.taskRetryLimit = int(self.taskRetryLimit)
            except ValueError:
                raise exceptions.InvalidMaxRetriesError(
                    self.name, self.taskRetryLimit)

        # transition countdown
        self.countdown = transDict.get(constants.TRANS_COUNTDOWN_ATTRIBUTE,
                                       constants.DEFAULT_COUNTDOWN)
        try:
            self.countdown = int(self.countdown)
        except ValueError:
            raise exceptions.InvalidCountdownError(self.countdown,
                                                   self.machineName,
                                                   self.fromState.name)
        if self.countdown and self.toState.fanInPeriod != constants.NO_FAN_IN:
            raise exceptions.UnsupportedConfigurationError(
                self.machineName, self.fromState.name,
                'Countdown cannot be specified on a transition to a fan_in state.'
            )

        # transition specific queue
        self.queueName = transDict.get(constants.QUEUE_NAME_ATTRIBUTE,
                                       machine.queueName)

        # resolve the class for action, if specified
        if constants.TRANS_ACTION_ATTRIBUTE in transDict:
            self.action = _resolveClass(
                transDict[constants.TRANS_ACTION_ATTRIBUTE], self.namespace)()
            if self.fromState.continuation:
                raise exceptions.UnsupportedConfigurationError(
                    self.machineName, self.fromState.name,
                    'Transition actions on transitions from continuation states are not supported.'
                )
            if self.toState.continuation:
                raise exceptions.UnsupportedConfigurationError(
                    self.machineName, self.fromState.name,
                    'Transition actions on transitions to continuation states are not supported.'
                )
            if self.fromState.fanInPeriod != constants.NO_FAN_IN:
                raise exceptions.UnsupportedConfigurationError(
                    self.machineName, self.fromState.name,
                    'Transition actions on transitions from fan_in states are not supported.'
                )
            if self.toState.fanInPeriod != constants.NO_FAN_IN:
                raise exceptions.UnsupportedConfigurationError(
                    self.machineName, self.fromState.name,
                    'Transition actions on transitions to fan_in states are not supported.'
                )
        else:
            self.action = None

        # test for exit actions when transitions to a continuation or a fan_in
        if self.toState.continuation and self.fromState.exit:
            raise exceptions.UnsupportedConfigurationError(
                self.machineName, self.fromState.name,
                'Exit actions on states with a transition to a continuation state are not supported.'
            )
        if self.toState.fanInPeriod != constants.NO_FAN_IN and self.fromState.exit:
            raise exceptions.UnsupportedConfigurationError(
                self.machineName, self.fromState.name,
                'Exit actions on states with a transition to a fan_in state are not supported.'
            )
Ejemplo n.º 2
0
    def __init__(self, stateDict, machine):  # pylint: disable-msg=R0912
        """ Builds a _StateConfig from a dictionary representation. This state is not added to the machine. """

        self.machineName = machine.name

        # state name
        self.name = stateDict.get(constants.STATE_NAME_ATTRIBUTE)
        if not self.name:
            raise exceptions.StateNameRequiredError(self.machineName)
        if not constants.NAME_RE.match(self.name):
            raise exceptions.InvalidStateNameError(self.machineName, self.name)

        # check for bad attributes
        badAttributes = set()
        for attribute in stateDict.iterkeys():
            if attribute not in constants.VALID_STATE_ATTRIBUTES:
                badAttributes.add(attribute)
        if badAttributes:
            raise exceptions.InvalidStateAttributeError(
                self.machineName, self.name, badAttributes)

        self.final = bool(stateDict.get(constants.STATE_FINAL_ATTRIBUTE,
                                        False))

        # state action
        actionName = stateDict.get(constants.STATE_ACTION_ATTRIBUTE)
        if not actionName and not self.final:
            raise exceptions.StateActionRequired(self.machineName, self.name)

        # state namespace, initial state flag, final state flag, continuation flag
        self.namespace = stateDict.get(constants.NAMESPACE_ATTRIBUTE,
                                       machine.namespace)
        self.initial = bool(
            stateDict.get(constants.STATE_INITIAL_ATTRIBUTE, False))
        self.continuation = bool(
            stateDict.get(constants.STATE_CONTINUATION_ATTRIBUTE, False))

        # state fan_in
        self.fanInPeriod = stateDict.get(constants.STATE_FAN_IN_ATTRIBUTE,
                                         constants.NO_FAN_IN)
        try:
            self.fanInPeriod = int(self.fanInPeriod)
        except ValueError:
            raise exceptions.InvalidFanInError(self.machineName, self.name,
                                               self.fanInPeriod)

        # state fan_in_group
        self.fanInGroup = stateDict.get(constants.STATE_FAN_IN_GROUP_ATTRIBUTE,
                                        None)
        # TODO: What makes a valid grouping attribute?
        # if a fan_in_group is specified, make sure this is a fan_in.
        if self.fanInGroup and self.fanInPeriod == constants.NO_FAN_IN:
            raise exceptions.InvalidFanInGroupError(self.machineName,
                                                    self.name, self.fanInGroup)

        # check that a state is not BOTH fan_in and continuation
        if self.continuation and self.fanInPeriod != constants.NO_FAN_IN:
            raise exceptions.FanInContinuationNotSupportedError(
                self.machineName, self.name)

        # state action
        if stateDict.get(constants.STATE_ACTION_ATTRIBUTE):
            self.action = _resolveClass(actionName, self.namespace)()
            if not hasattr(self.action, 'execute'):
                raise exceptions.InvalidActionInterfaceError(
                    self.machineName, self.name)
        else:
            self.action = None

        if self.continuation:
            if not hasattr(self.action, 'continuation'):
                raise exceptions.InvalidContinuationInterfaceError(
                    self.machineName, self.name)
        else:
            if hasattr(self.action, 'continuation'):
                logging.warning(
                    'State\'s action class has a continuation attribute, but the state is '
                    +
                    'not marked as continuation=True. This continuation method will not be '
                    + 'executed. (Machine %s, State %s)', self.machineName,
                    self.name)

        # state entry
        if stateDict.get(constants.STATE_ENTRY_ATTRIBUTE):
            self.entry = _resolveClass(
                stateDict[constants.STATE_ENTRY_ATTRIBUTE], self.namespace)()
            if not hasattr(self.entry, 'execute'):
                raise exceptions.InvalidEntryInterfaceError(
                    self.machineName, self.name)
        else:
            self.entry = None

        # state exit
        if stateDict.get(constants.STATE_EXIT_ATTRIBUTE):
            self.exit = _resolveClass(
                stateDict[constants.STATE_EXIT_ATTRIBUTE], self.namespace)()
            if not hasattr(self.exit, 'execute'):
                raise exceptions.InvalidExitInterfaceError(
                    self.machineName, self.name)
            if self.continuation:
                raise exceptions.UnsupportedConfigurationError(
                    self.machineName, self.name,
                    'Exit actions on continuation states are not supported.')
            if self.fanInPeriod != constants.NO_FAN_IN:
                raise exceptions.UnsupportedConfigurationError(
                    self.machineName, self.name,
                    'Exit actions on fan_in states are not supported.')
        else:
            self.exit = None