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.' )
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