示例#1
0
def _next_and_end(cls: "StateMirror") -> "StateMirror":
    """Add "Next" and "End" parameters to the class.
    Also adds the "then()" and "end()" helper methods.
    """
    def _validate_next(instance, attribute: attr.Attribute, value: Any):
        if value is not None and instance.End is not None:
            raise ValueError("Only one of 'Next' and 'End' is allowed")

    cls.Next = RHODES_ATTRIB(validator=(optional(instance_of(str)),
                                        _validate_next))
    cls.__doc__ = docstring_with_param(
        cls, "Next", description="The state that will follow this state")

    def _validate_end(instance, attribute: attr.Attribute, value: Any):
        if value is not None and instance.Next is not None:
            raise ValueError("Only one of 'Next' and 'End' is allowed")

        if value is not None and value is not True:
            raise ValueError("If 'End' is set, value must be True")

    cls.End = RHODES_ATTRIB(validator=(optional(instance_of(bool)),
                                       _validate_end))
    cls.__doc__ = docstring_with_param(
        cls, "End", bool, description="This state is a terminal state")

    def _then(instance, next_state):
        """Set the next state in this state machine."""

        if instance.End is not None:
            raise InvalidDefinitionError(
                f"Cannot set state transition. State {instance.title!r} already has an end condition."
            )

        if instance.Next is not None:
            raise InvalidDefinitionError(
                f"Cannot set state transition. State {instance.title!r} already has a state transition."
            )

        instance.member_of.add_state(next_state)
        # TODO: set reference rather than extracting name
        instance.Next = next_state.title
        return next_state

    cls.then = _then

    def _end(instance):
        """Make this state a terminal state."""

        if instance.Next is not None:
            raise InvalidDefinitionError(
                "Cannot set end condition."
                f"State {instance.title!r} already has a state transition.")

        instance.End = True

        return instance

    cls.end = _end

    return cls
示例#2
0
def task_type(cls: "StateMirror") -> "StateMirror":
    """Add common parameters used by all "Task" types."""

    cls = state(cls)
    cls = _next_and_end(cls)
    cls = _input_output(cls)
    cls = _result_path(cls)
    cls = _catch_retry(cls)

    def _validate_positive_value(instance, attribute: attr.Attribute,
                                 value: int):
        if value is not None and not value > 0:
            raise ValueError(
                f"{instance.__class__.__name__} parameter '{attribute.name}' value must be positive"
            )

    # default=99999999
    cls.TimeoutSeconds = RHODES_ATTRIB(validator=(optional(instance_of(int)),
                                                  _validate_positive_value))
    cls.__doc__ = docstring_with_param(
        cls,
        "TimeoutSeconds",
        int,
        description="Maximum time that this state is allowed to run")

    cls.HeartbeatSeconds = RHODES_ATTRIB(validator=(optional(instance_of(int)),
                                                    _validate_positive_value))
    cls.__doc__ = docstring_with_param(
        cls,
        "HeartbeatSeconds",
        int,
        description=
        "Maximum time allowed between heartbeat responses from state")

    return cls
示例#3
0
def _input_output(cls: "StateMirror") -> "StateMirror":
    """Add the "InputPath" and "OutputPath" parameters to the class."""

    cls.InputPath = RHODES_ATTRIB(default=JsonPath("$"),
                                  validator=optional(instance_of(JsonPath)),
                                  converter=convert_to_json_path)
    cls.__doc__ = docstring_with_param(
        cls,
        "InputPath",
        JsonPath,
        description=
        "The portion of the state input data to be used as input for the state",
        default=JsonPath("$"),
    )

    cls.OutputPath = RHODES_ATTRIB(default=JsonPath("$"),
                                   validator=optional(instance_of(JsonPath)),
                                   converter=convert_to_json_path)
    cls.__doc__ = docstring_with_param(
        cls,
        "OutputPath",
        JsonPath,
        description=
        "The portion of the state input data to be passed to the next state",
        default=JsonPath("$"),
    )

    return cls
示例#4
0
def _catch_retry(cls: "StateMirror") -> "StateMirror":
    """Add the "Catch" and "Retry" parameters to the class."""
    cls.Retry = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(cls, "Retry")

    cls.Catch = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(cls, "Catch")

    return cls
示例#5
0
def state(cls: "StateMirror") -> "StateMirror":
    """Add common parameters used by all states."""

    cls.__doc__ = docstring_with_param(
        cls, "title", str, description="Name of state in state machine")

    cls.__doc__ = docstring_with_param(
        cls,
        "Comment",
        str,
        description="Human-readable description of the state",
        default="")

    return cls
示例#6
0
def _number(cls):
    cls = _single(cls)

    def _numeric_converter(value) -> Decimal:
        if isinstance(value, Decimal):
            return value

        return Decimal(str(value))

    def _value_serializer(instance) -> float:
        return float(instance.Value)

    # TODO: Note that for interoperability,
    #  numeric comparisons should not be assumed to work
    #  with values outside the magnitude or precision
    #  representable using the IEEE 754-2008 “binary64” data type.
    #  In particular,
    #  integers outside of the range [-(253)+1, (253)-1]
    #  might fail to compare in the expected way.
    cls.Value = RHODES_ATTRIB(validator=instance_of(Decimal),
                              converter=_numeric_converter)
    cls.__doc__ = docstring_with_param(
        cls, "Value", description="The value to which to compare ``Variable``")

    cls._serialized_value = _value_serializer

    return cls
示例#7
0
def _endpoint_name(cls: StateMirror) -> StateMirror:
    cls.EndpointName = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(cls,
                                       "EndpointName",
                                       description="The name of the endpoint.")

    return cls
示例#8
0
def _endpoint_config_name(cls: StateMirror) -> StateMirror:
    cls.EndpointConfigName = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "EndpointConfigName",
        description="The name of an endpoint configuration.")

    return cls
示例#9
0
def _multi(cls):
    cls.Rules = RHODES_ATTRIB(validator=_validate_multi_subrules)
    cls.__doc__ = docstring_with_param(
        cls,
        "Rules",
        description="One or more :class:`ChoiceRule` to evaluate for this rule"
    )

    cls.Next = RHODES_ATTRIB(validator=optional(instance_of(str)))
    cls.__doc__ = docstring_with_param(
        cls,
        "Next",
        description=
        "The state to which to continue if this rule evaluates as true")

    cls.to_dict = _multi_to_dict

    return cls
示例#10
0
def _single(cls):
    cls.Variable = RHODES_ATTRIB(validator=instance_of(VariablePath),
                                 converter=_convert_to_variable_path)
    cls.__doc__ = docstring_with_param(
        cls,
        "Variable",
        VariablePath,
        description="Path to value in state input that will be evaluated")

    cls.Next = RHODES_ATTRIB(validator=optional(instance_of(str)))
    cls.__doc__ = docstring_with_param(
        cls,
        "Next",
        description=
        "The state to which to continue if this rule evaluates as true")

    cls.to_dict = _single_to_dict

    return cls
示例#11
0
def _ddb_key(cls: StateMirror) -> StateMirror:
    cls.Key = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "Key",
        description=
        ("A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve."
         ),
    )

    return cls
示例#12
0
def _bool(cls):
    cls = _single(cls)

    cls.Value = RHODES_ATTRIB(validator=instance_of(bool))
    cls.__doc__ = docstring_with_param(
        cls,
        "Value",
        bool,
        description="The value to which to compare ``Variable``")

    return cls
示例#13
0
def _parameters(cls: "StateMirror") -> "StateMirror":
    """Add the "Parameters" parameter to the class."""
    cls.Parameters = RHODES_ATTRIB(validator=optional(instance_of(Parameters)))
    cls.__doc__ = docstring_with_param(
        cls,
        "Parameters",
        Parameters,
        description=
        "Additional parameters for Step Functions to provide to connected resource",
    )

    return cls
示例#14
0
def _tags(cls: StateMirror) -> StateMirror:
    cls.Tags = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "Tags",
        description=
        ("An array of key-value pairs. "
         "For more information, see Using Cost Allocation Tagsin the AWS Billing and Cost Management User Guide."
         ),
    )

    return cls
示例#15
0
    def _decorate(cls: StateMirror) -> StateMirror:
        cls = task_type(cls)

        cls.Pattern = RHODES_ATTRIB(default=options[0], validator=in_(options))
        cls.__doc__ = docstring_with_param(
            cls,
            "Pattern",
            IntegrationPattern,
            description="Step Functions integration pattern",
            default=options[0])

        def to_dict(instance) -> Dict:
            """Serialize state as a dictionary."""
            for required in instance._required_fields:
                require_field(instance=instance, required_value=required)

            task = instance._build_task()
            return task.to_dict()

        cls.to_dict = to_dict

        def _build_task(instance) -> Task:
            task_fields = [field.name for field in attr.fields(Task)]
            field_name_blacklist = ("Pattern", )
            resource_name = instance._resource_name.value + instance.Pattern.value

            task_kwargs = {}
            parameters_kwargs = {}

            for field in attr.fields(type(instance)):
                if field.name in field_name_blacklist or field.name.startswith(
                        "_"):
                    continue

                value = getattr(instance, field.name)
                if value is None:
                    continue

                if field.name in task_fields and field.name != "Parameters":
                    task_kwargs[field.name] = value
                else:
                    parameters_kwargs[field.name] = value

            params = Parameters(**parameters_kwargs)
            return Task(Parameters=params,
                        Resource=resource_name,
                        **task_kwargs)

        cls._build_task = _build_task

        return cls
示例#16
0
def _result_path(cls: "StateMirror") -> "StateMirror":
    """Add the "ResultPath" parameter to the class."""
    cls.ResultPath = RHODES_ATTRIB(default=JsonPath("$"),
                                   validator=optional(instance_of(JsonPath)),
                                   converter=convert_to_json_path)
    cls.__doc__ = docstring_with_param(
        cls,
        "ResultPath",
        JsonPath,
        description=
        "Where in the state input data to place the results of this state",
        default=JsonPath("$"),
    )

    return cls
示例#17
0
def _timestamp(cls):
    cls = _single(cls)

    def _datetime_validator(instance, attribute, value):
        if value.tzinfo is None:
            raise ValueError(
                f"'{attribute.name}' must have a 'tzinfo' value set.")

    def _value_serializer(instance):
        return instance.Value.isoformat()

    cls.Value = RHODES_ATTRIB(
        validator=[instance_of(datetime), _datetime_validator])
    cls.__doc__ = docstring_with_param(
        cls,
        "Value",
        datetime,
        description="The value to which to compare ``Variable``")

    cls._serialized_value = _value_serializer

    return cls
示例#18
0
def _ddb_table_name(cls: StateMirror) -> StateMirror:
    cls.TableName = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls, "TableName", description="The table to interact with")

    return cls
示例#19
0
def _ddb_write_attributes(cls: StateMirror) -> StateMirror:
    cls.ConditionalOperator = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "ConditionalOperator",
        description=
        ("This is a legacy parameter. "
         "Use ConditionExpression instead. "
         "For more information, see ConditionalOperator in the Amazon DynamoDB Developer Guide."
         ),
    )

    cls.ConditionExpression = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "ConditionExpression",
        description=
        "A condition that must be satisfied in order for a conditional operation to succeed.",
    )

    cls.Expected = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "Expected",
        description=
        ("This is a legacy parameter. "
         "Use ConditionExpression instead. "
         "For more information, see Expected in the Amazon DynamoDB Developer Guide."
         ),
    )

    cls.ExpressionAttributeNames = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "ExpressionAttributeNames",
        description=
        "One or more substitution tokens for attribute names in an expression.",
    )

    cls.ExpressionAttributeValues = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "ExpressionAttributeValues",
        description=
        "One or more values that can be substituted in an expression.")

    cls.ReturnConsumedCapacity = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "ReturnConsumedCapacity",
        description=
        ("Determines the level of detail about provisioned throughput consumption that is returned in the response"
         ),
    )

    cls.ReturnItemCollectionMetrics = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "ReturnItemCollectionMetrics",
        description="Determines whether item collection metrics are returned.")

    cls.ReturnValues = RHODES_ATTRIB()
    cls.__doc__ = docstring_with_param(
        cls,
        "ReturnValues",
        description=(
            "Use ReturnValues if you want to get the item attributes "
            "as they appeared before they were updated with the request."),
    )

    return cls