{ "cells": [ { "cell_type": "markdown", "source": [ "# Quick Start\n", "\n", "In this tutorial, let's learn how to use [aws_stepfunction](https://pypi.org/project/aws-stepfunction/) library to create / deploy / execute / delete an AWS StepFunction." ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "markdown", "source": [ "## The test Lambda Function\n", "\n", "First, let's create a simple lambda function for testing. The logic is to json encode the input event and just return. This lambda function has 30 % chance to fail. The lambda execution won't fail, however, it returns an 400 HTTP status code." ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 4, "outputs": [], "source": [ "# content of lambda_handler.py\n", "\n", "import json\n", "import random\n", "\n", "def lambda_handler(event, context):\n", " if random.randint(1, 100) <= 70:\n", " return {\n", " \"statusCode\": 200,\n", " \"body\": json.dumps(event),\n", " }\n", " else:\n", " return {\n", " \"statusCode\": 400,\n", " \"body\": \"failed!\"\n", " }" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "Sample input output" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 7, "outputs": [ { "data": { "text/plain": "{'statusCode': 200, 'body': '{\"message\": \"hello world\"}'}" }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# succeed\n", "lambda_handler({\"message\": \"hello world\"}, None)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "code", "execution_count": 17, "outputs": [ { "data": { "text/plain": "{'statusCode': 400, 'body': 'failed!'}" }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# fail\n", "lambda_handler({\"message\": \"hello world\"}, None)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "## Create a Step Function\n", "\n", "Now let's learn the power of [aws_stepfunction](https://pypi.org/project/aws-stepfunction/) library." ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 1, "outputs": [ { "data": { "text/plain": "\u001B[1;35mWorkflow\u001B[0m\u001B[1m(\u001B[0m\n \u001B[33mid\u001B[0m=\u001B[32m'Workflow-1a98433'\u001B[0m,\n \u001B[33mcomment\u001B[0m=\u001B[32m'The power of aws_stepfunction library!'\u001B[0m,\n \u001B[33mversion\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33mtimeout_seconds\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33m_start_at\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33m_states\u001B[0m=\u001B[1;35mOrderedDict\u001B[0m\u001B[1m(\u001B[0m\u001B[1m)\u001B[0m,\n \u001B[33m_started\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n \u001B[33m_previous_state\u001B[0m=\u001B[3;35mNone\u001B[0m\n\u001B[1m)\u001B[0m\n", "text/html": "
Workflow(\n    id='Workflow-1a98433',\n    comment='The power of aws_stepfunction library!',\n    version=None,\n    timeout_seconds=None,\n    _start_at=None,\n    _states=OrderedDict(),\n    _started=False,\n    _previous_state=None\n)\n
\n" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# ------------------------------------------------------------------------------\n", "# Step 1. import, preparation\n", "# ------------------------------------------------------------------------------\\\n", "# Import the \"aws_stepfunction\" library,\n", "# all public API can be accessed from the \"sfn\" namespace\n", "import aws_stepfunction as sfn\n", "from boto_session_manager import BotoSesManager\n", "from rich import print # for pretty print\n", "\n", "# Create a boto3 session manager object\n", "# the credential you are using should have STS.get_caller_identity permission\n", "# it is for getting the AWS Account ID information\n", "bsm = BotoSesManager(\n", " profile_name=\"aws_data_lab_sanhe_us_east_1\",\n", " region_name=\"us-east-1\",\n", ")\n", "\n", "# You could tell the task context about the aws_account_id and aws_region\n", "# then you can only need to provide lambda function name without the full ARN.\n", "sfn.task_context.aws_account_id = bsm.aws_account_id\n", "sfn.task_context.aws_region = bsm.aws_region\n", "\n", "# Declare a workflow object\n", "workflow = sfn.Workflow(\n", " comment=\"The power of aws_stepfunction library!\", # put random comment here\n", ")\n", "print(workflow)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "code", "execution_count": 2, "outputs": [ { "data": { "text/plain": "\u001B[1;35mTask\u001B[0m\u001B[1m(\u001B[0m\n \u001B[33mcomment\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33mnext\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33mend\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33minput_path\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33moutput_path\u001B[0m=\u001B[32m'$.Payload'\u001B[0m,\n \u001B[33mparameters\u001B[0m=\u001B[1m{\u001B[0m\n \u001B[32m'Payload.$'\u001B[0m: \u001B[32m'$'\u001B[0m,\n \u001B[32m'FunctionName'\u001B[0m: \u001B[32m'arn:aws:lambda:us-east-1:669508176277:stepfunction_quick_start'\u001B[0m\n \u001B[1m}\u001B[0m,\n \u001B[33mresult_selector\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n \u001B[33mresult_path\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33mretry\u001B[0m=\u001B[1m[\u001B[0m\n \u001B[1;35mRetry\u001B[0m\u001B[1m(\u001B[0m\n \u001B[33merror_equals\u001B[0m=\u001B[1m[\u001B[0m\u001B[32m'Lambda.ServiceException'\u001B[0m, \u001B[32m'Lambda.AWSLambdaException'\u001B[0m, \u001B[32m'Lambda.SdkClientException'\u001B[0m\u001B[1m]\u001B[0m,\n \u001B[33minterval_seconds\u001B[0m=\u001B[1;36m2\u001B[0m,\n \u001B[33mbackoff_rate\u001B[0m=\u001B[1;36m2\u001B[0m,\n \u001B[33mmax_attempts\u001B[0m=\u001B[1;36m3\u001B[0m\n \u001B[1m)\u001B[0m\n \u001B[1m]\u001B[0m,\n \u001B[33mcatch\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n \u001B[33mid\u001B[0m=\u001B[32m'Task-1824cda'\u001B[0m,\n \u001B[33mtype\u001B[0m=\u001B[32m'Task'\u001B[0m,\n \u001B[33mresource\u001B[0m=\u001B[32m'arn:aws:states:::lambda:invoke'\u001B[0m,\n \u001B[33mtimeout_seconds_path\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33mtimeout_seconds\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33mheartbeat_seconds_path\u001B[0m=\u001B[3;35mNone\u001B[0m,\n \u001B[33mheartbeat_seconds\u001B[0m=\u001B[3;35mNone\u001B[0m\n\u001B[1m)\u001B[0m\n", "text/html": "
Task(\n    comment=None,\n    next=None,\n    end=None,\n    input_path=None,\n    output_path='$.Payload',\n    parameters={\n        'Payload.$': '$',\n        'FunctionName': 'arn:aws:lambda:us-east-1:669508176277:stepfunction_quick_start'\n    },\n    result_selector={},\n    result_path=None,\n    retry=[\n        Retry(\n            error_equals=['Lambda.ServiceException', 'Lambda.AWSLambdaException', 'Lambda.SdkClientException'],\n            interval_seconds=2,\n            backoff_rate=2,\n            max_attempts=3\n        )\n    ],\n    catch=[],\n    id='Task-1824cda',\n    type='Task',\n    resource='arn:aws:states:::lambda:invoke',\n    timeout_seconds_path=None,\n    timeout_seconds=None,\n    heartbeat_seconds_path=None,\n    heartbeat_seconds=None\n)\n
\n" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": "\u001B[1;35mSucceed\u001B[0m\u001B[1m(\u001B[0m\u001B[33mcomment\u001B[0m=\u001B[3;35mNone\u001B[0m, \u001B[33minput_path\u001B[0m=\u001B[3;35mNone\u001B[0m, \u001B[33moutput_path\u001B[0m=\u001B[3;35mNone\u001B[0m, \u001B[33mid\u001B[0m=\u001B[32m'Succeed-4c067dd'\u001B[0m, \u001B[33mtype\u001B[0m=\u001B[32m'Succeed'\u001B[0m\u001B[1m)\u001B[0m\n", "text/html": "
Succeed(comment=None, input_path=None, output_path=None, id='Succeed-4c067dd', type='Succeed')\n
\n" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": "\u001B[1;35mFail\u001B[0m\u001B[1m(\u001B[0m\u001B[33mcomment\u001B[0m=\u001B[3;35mNone\u001B[0m, \u001B[33mid\u001B[0m=\u001B[32m'Fail-a6fa70c'\u001B[0m, \u001B[33mtype\u001B[0m=\u001B[32m'Fail'\u001B[0m, \u001B[33mcause\u001B[0m=\u001B[3;35mNone\u001B[0m, \u001B[33merror\u001B[0m=\u001B[3;35mNone\u001B[0m\u001B[1m)\u001B[0m\n", "text/html": "
Fail(comment=None, id='Fail-a6fa70c', type='Fail', cause=None, error=None)\n
\n" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# ------------------------------------------------------------------------------\n", "# Step 2. Define some tasks and states\n", "# ------------------------------------------------------------------------------\n", "# There are some helper functions to create common task.\n", "# These helper functions are just the equivalent of\n", "# The widget in Step Function Visual Editor\n", "\n", "# define a lambda function invoke task\n", "task_invoke_lambda = sfn.actions.lambda_invoke(func_name=\"stepfunction_quick_start\")\n", "\n", "# define a succeed state\n", "succeed = sfn.Succeed()\n", "\n", "# define a fail state\n", "fail = sfn.Fail()\n", "\n", "print(task_invoke_lambda)\n", "print(succeed)\n", "print(fail)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "code", "execution_count": 3, "outputs": [ { "data": { "text/plain": "\u001B[1m{\u001B[0m\n \u001B[32m'StartAt'\u001B[0m: \u001B[32m'Task-1824cda'\u001B[0m,\n \u001B[32m'Comment'\u001B[0m: \u001B[32m'The power of aws_stepfunction library!'\u001B[0m,\n \u001B[32m'States'\u001B[0m: \u001B[1m{\u001B[0m\n \u001B[32m'Task-1824cda'\u001B[0m: \u001B[1m{\u001B[0m\n \u001B[32m'Type'\u001B[0m: \u001B[32m'Task'\u001B[0m,\n \u001B[32m'Resource'\u001B[0m: \u001B[32m'arn:aws:states:::lambda:invoke'\u001B[0m,\n \u001B[32m'Next'\u001B[0m: \u001B[32m'Choice-by-Task-1824cda'\u001B[0m,\n \u001B[32m'Parameters'\u001B[0m: \u001B[1m{\u001B[0m\n \u001B[32m'Payload.$'\u001B[0m: \u001B[32m'$'\u001B[0m,\n \u001B[32m'FunctionName'\u001B[0m: \u001B[32m'arn:aws:lambda:us-east-1:669508176277:stepfunction_quick_start'\u001B[0m\n \u001B[1m}\u001B[0m,\n \u001B[32m'OutputPath'\u001B[0m: \u001B[32m'$.Payload'\u001B[0m,\n \u001B[32m'Retry'\u001B[0m: \u001B[1m[\u001B[0m\n \u001B[1m{\u001B[0m\n \u001B[32m'ErrorEquals'\u001B[0m: \u001B[1m[\u001B[0m\n \u001B[32m'Lambda.ServiceException'\u001B[0m,\n \u001B[32m'Lambda.AWSLambdaException'\u001B[0m,\n \u001B[32m'Lambda.SdkClientException'\u001B[0m\n \u001B[1m]\u001B[0m,\n \u001B[32m'IntervalSeconds'\u001B[0m: \u001B[1;36m2\u001B[0m,\n \u001B[32m'BackoffRate'\u001B[0m: \u001B[1;36m2\u001B[0m,\n \u001B[32m'MaxAttempts'\u001B[0m: \u001B[1;36m3\u001B[0m\n \u001B[1m}\u001B[0m\n \u001B[1m]\u001B[0m\n \u001B[1m}\u001B[0m,\n \u001B[32m'Choice-by-Task-1824cda'\u001B[0m: \u001B[1m{\u001B[0m\n \u001B[32m'Type'\u001B[0m: \u001B[32m'Choice'\u001B[0m,\n \u001B[32m'Choices'\u001B[0m: \u001B[1m[\u001B[0m\n \u001B[1m{\u001B[0m\u001B[32m'Not'\u001B[0m: \u001B[1m{\u001B[0m\u001B[32m'Variable'\u001B[0m: \u001B[32m'$.body'\u001B[0m, \u001B[32m'StringEquals'\u001B[0m: \u001B[32m'failed!'\u001B[0m\u001B[1m}\u001B[0m, \u001B[32m'Next'\u001B[0m: \u001B[32m'Succeed-4c067dd'\u001B[0m\u001B[1m}\u001B[0m,\n \u001B[1m{\u001B[0m\u001B[32m'Variable'\u001B[0m: \u001B[32m'$.body'\u001B[0m, \u001B[32m'StringEquals'\u001B[0m: \u001B[32m'failed!'\u001B[0m, \u001B[32m'Next'\u001B[0m: \u001B[32m'Fail-a6fa70c'\u001B[0m\u001B[1m}\u001B[0m\n \u001B[1m]\u001B[0m\n \u001B[1m}\u001B[0m,\n \u001B[32m'Succeed-4c067dd'\u001B[0m: \u001B[1m{\u001B[0m\u001B[32m'Type'\u001B[0m: \u001B[32m'Succeed'\u001B[0m\u001B[1m}\u001B[0m,\n \u001B[32m'Fail-a6fa70c'\u001B[0m: \u001B[1m{\u001B[0m\u001B[32m'Type'\u001B[0m: \u001B[32m'Fail'\u001B[0m\u001B[1m}\u001B[0m\n \u001B[1m}\u001B[0m\n\u001B[1m}\u001B[0m\n", "text/html": "
{\n    'StartAt': 'Task-1824cda',\n    'Comment': 'The power of aws_stepfunction library!',\n    'States': {\n        'Task-1824cda': {\n            'Type': 'Task',\n            'Resource': 'arn:aws:states:::lambda:invoke',\n            'Next': 'Choice-by-Task-1824cda',\n            'Parameters': {\n                'Payload.$': '$',\n                'FunctionName': 'arn:aws:lambda:us-east-1:669508176277:stepfunction_quick_start'\n            },\n            'OutputPath': '$.Payload',\n            'Retry': [\n                {\n                    'ErrorEquals': [\n                        'Lambda.ServiceException',\n                        'Lambda.AWSLambdaException',\n                        'Lambda.SdkClientException'\n                    ],\n                    'IntervalSeconds': 2,\n                    'BackoffRate': 2,\n                    'MaxAttempts': 3\n                }\n            ]\n        },\n        'Choice-by-Task-1824cda': {\n            'Type': 'Choice',\n            'Choices': [\n                {'Not': {'Variable': '$.body', 'StringEquals': 'failed!'}, 'Next': 'Succeed-4c067dd'},\n                {'Variable': '$.body', 'StringEquals': 'failed!', 'Next': 'Fail-a6fa70c'}\n            ]\n        },\n        'Succeed-4c067dd': {'Type': 'Succeed'},\n        'Fail-a6fa70c': {'Type': 'Fail'}\n    }\n}\n
\n" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# ------------------------------------------------------------------------------\n", "# Step 3. Orchestrate the Workflow\n", "# ------------------------------------------------------------------------------\n", "# We use this \"Human-language alike\", \"Pythonic\", \"Objective Oriented\"\n", "# \"Auto-complete empowered\" code pattern to create a human-readable workflow\n", "(\n", " workflow.start(task_invoke_lambda)\n", " .choice([\n", " # choice 1, succeed case\n", " ( # define condition\n", " sfn.not_(sfn.Var(\"$.body\").string_equals(\"failed!\"))\n", " # define next action\n", " .next_then(succeed)\n", " ),\n", " # choice 2, fail case\n", " (\n", " # define condition\n", " sfn.Var(\"$.body\").string_equals(\"failed!\")\n", " # define next action\n", " .next_then(fail)\n", " ),\n", " ])\n", ")\n", "\n", "print(workflow.serialize())" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "code", "execution_count": 4, "outputs": [ { "data": { "text/plain": "arn:aws:states:us-east-\u001B[1;92m1:6695\u001B[0m08176277:stateMachine:stepfunction_quick_start\n", "text/html": "
arn:aws:states:us-east-1:669508176277:stateMachine:stepfunction_quick_start\n
\n" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": "\u001B[4;94mhttps://us-east-1.console.aws.amazon.com/states/home?\u001B[0m\u001B[4;94mregion\u001B[0m\u001B[4;94m=\u001B[0m\u001B[4;94mus\u001B[0m\u001B[4;94m-east-1#/statemachines/view/arn:aws:states:us-east-1:\u001B[0m\n\u001B[4;94m669508176277:stateMachine:stepfunction_quick_start\u001B[0m\n", "text/html": "
https://us-east-1.console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:\n669508176277:stateMachine:stepfunction_quick_start\n
\n" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# ------------------------------------------------------------------------------\n", "# Step 4. Declare an instance of AWS State Machine for AWS console\n", "# ------------------------------------------------------------------------------\n", "# This is the metadata of the concrete AWS State Machine resource\n", "state_machine = sfn.StateMachine(\n", " name=\"stepfunction_quick_start\",\n", " workflow=workflow,\n", " role_arn=\"arn:aws:iam::669508176277:role/state-machine-role\",\n", ")\n", "print(state_machine.get_state_machine_arn(bsm))\n", "print(state_machine.get_state_machine_console_url(bsm))" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "code", "execution_count": 5, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "deploy state machine to 'arn:aws:states:us-east-1:669508176277:stateMachine:stepfunction_quick_start' ...\n", " not exists, create state machine ...\n", " done, preview at: https://us-east-1.console.aws.amazon.com/states/home?region=us-east-1#/visual-editor?stateMachineArn=arn:aws:states:us-east-1:669508176277:stateMachine:stepfunction_quick_start\n" ] }, { "data": { "text/plain": "{'stateMachineArn': 'arn:aws:states:us-east-1:669508176277:stateMachine:stepfunction_quick_start',\n 'creationDate': datetime.datetime(2022, 8, 5, 19, 23, 49, 785000, tzinfo=tzlocal()),\n 'ResponseMetadata': {'RequestId': 'df4a6cf2-3448-4bb0-9e7d-c06a28622de2',\n 'HTTPStatusCode': 200,\n 'HTTPHeaders': {'x-amzn-requestid': 'df4a6cf2-3448-4bb0-9e7d-c06a28622de2',\n 'date': 'Fri, 05 Aug 2022 23:23:49 GMT',\n 'content-type': 'application/x-amz-json-1.0',\n 'content-length': '129'},\n 'RetryAttempts': 0},\n '_deploy_action': 'create'}" }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ------------------------------------------------------------------------------\n", "# Step 5. Deploy / Execute / Delete State Machine\n", "# ------------------------------------------------------------------------------\n", "# deploy (create / update)\n", "state_machine.deploy(bsm)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "![](./deploy.png)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 6, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "execute state machine 'arn:aws:states:us-east-1:669508176277:stateMachine:stepfunction_quick_start'\n", " preview at: https://us-east-1.console.aws.amazon.com/states/home?region=us-east-1#/executions/details/arn:aws:states:us-east-1:669508176277:execution:stepfunction_quick_start:8f26d437-1806-498f-941a-447b390ccdac\n" ] }, { "data": { "text/plain": "{'executionArn': 'arn:aws:states:us-east-1:669508176277:execution:stepfunction_quick_start:8f26d437-1806-498f-941a-447b390ccdac',\n 'startDate': datetime.datetime(2022, 8, 5, 19, 24, 14, 476000, tzinfo=tzlocal()),\n 'ResponseMetadata': {'RequestId': '14025e4c-5ac3-4e7b-87ae-2eff8dc7cd9b',\n 'HTTPStatusCode': 200,\n 'HTTPHeaders': {'x-amzn-requestid': '14025e4c-5ac3-4e7b-87ae-2eff8dc7cd9b',\n 'date': 'Fri, 05 Aug 2022 23:24:14 GMT',\n 'content-type': 'application/x-amz-json-1.0',\n 'content-length': '157'},\n 'RetryAttempts': 0}}" }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# execute state machine with custom payload\n", "state_machine.execute(bsm, payload={\"name\": \"alice\"})" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "\"\"" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": 7, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "delete state machine 'arn:aws:states:us-east-1:669508176277:stateMachine:stepfunction_quick_start'\n", " done, exam at: https://us-east-1.console.aws.amazon.com/states/home?region=us-east-1#/statemachines/view/arn:aws:states:us-east-1:669508176277:stateMachine:stepfunction_quick_start\n" ] }, { "data": { "text/plain": "{'ResponseMetadata': {'RequestId': '16346f8e-6341-4c1d-a174-f9107a0e5c27',\n 'HTTPStatusCode': 200,\n 'HTTPHeaders': {'x-amzn-requestid': '16346f8e-6341-4c1d-a174-f9107a0e5c27',\n 'date': 'Fri, 05 Aug 2022 23:25:53 GMT',\n 'content-type': 'application/x-amz-json-1.0',\n 'content-length': '2'},\n 'RetryAttempts': 0}}" }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# delete state machine\n", "state_machine.delete(bsm)" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } }, { "cell_type": "markdown", "source": [ "## Summary\n", "\n", "The objective of [aws_stepfunction](https://pypi.org/project/aws-stepfunction/) library is to provide developer a \"smooth\", \"interruption free\", \"enjoyable\" development experience. The orchestration code itself is just like human-language, and tells the story without any comments.\n", "\n", "In addition, the API and type hint are designed for static check and auto-complete. If you use any modern IDE / Code Editor like PyCharm, VSCode, Sublime, Eclipse, the learning curve should be minimal and the IDE will tell you all the syntax you need for coding.\n", "\n", "\"\"\n", "\"\"\n", "\"\"\n", "\"\"" ], "metadata": { "collapsed": false, "pycharm": { "name": "#%% md\n" } } }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [], "metadata": { "collapsed": false, "pycharm": { "name": "#%%\n" } } } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 0 }