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, initDict, rootUrl=None): """ Configures the basic attributes of a machine. States and transitions are not handled here, but are added by an external client. """ # machine name self.name = initDict.get(constants.MACHINE_NAME_ATTRIBUTE) if not self.name: raise exceptions.MachineNameRequiredError() if not constants.NAME_RE.match(self.name): raise exceptions.InvalidMachineNameError(self.name) # check for bad attributes badAttributes = set() for attribute in initDict.iterkeys(): if attribute not in constants.VALID_MACHINE_ATTRIBUTES: badAttributes.add(attribute) if badAttributes: raise exceptions.InvalidMachineAttributeError( self.name, badAttributes) # machine queue, namespace self.queueName = initDict.get(constants.QUEUE_NAME_ATTRIBUTE, constants.DEFAULT_QUEUE_NAME) self.namespace = initDict.get(constants.NAMESPACE_ATTRIBUTE) # logging self.logging = initDict.get(constants.MACHINE_LOGGING_NAME_ATTRIBUTE, constants.LOGGING_DEFAULT) if self.logging not in constants.VALID_LOGGING_VALUES: raise exceptions.InvalidLoggingError(self.name, self.logging) # machine task_retry_limit, min_backoff_seconds, max_backoff_seconds, task_age_limit, max_doublings for (constant, attribute, default, exception) in TASK_ATTRIBUTES: setattr(self, attribute, default) if constant in initDict: setattr(self, attribute, initDict[constant]) try: i = int(getattr(self, attribute)) setattr(self, attribute, i) except ValueError: raise exception(self.name, getattr(self, attribute)) # if both max_retries and task_retry_limit specified, raise an exception if constants.MAX_RETRIES_ATTRIBUTE in initDict and constants.TASK_RETRY_LIMIT_ATTRIBUTE in initDict: raise exceptions.MaxRetriesAndTaskRetryLimitMutuallyExclusiveError( self.name) # machine max_retries - sets taskRetryLimit internally if constants.MAX_RETRIES_ATTRIBUTE in initDict: logging.warning( 'max_retries is deprecated. Use task_retry_limit instead.') self.taskRetryLimit = initDict[constants.MAX_RETRIES_ATTRIBUTE] try: self.taskRetryLimit = int(self.taskRetryLimit) except ValueError: raise exceptions.InvalidMaxRetriesError( self.name, self.taskRetryLimit) self.states = {} self.transitions = {} self.initialState = None self.finalStates = [] # context types self.contextTypes = initDict.get( constants.MACHINE_CONTEXT_TYPES_ATTRIBUTE, {}) for contextName, contextType in self.contextTypes.iteritems(): self.contextTypes[contextName] = _resolveClass( contextType, self.namespace) self.rootUrl = rootUrl if not self.rootUrl: self.rootUrl = constants.DEFAULT_ROOT_URL elif not rootUrl.endswith('/'): self.rootUrl += '/'