AWS Cognito User Migration Lambda in Python

We've been tasked with switching our login system from an in-app system to something leveraging AWS Cognito. Doing so requires a migration step which, when done fully through AWS requires some hoops (including an AWS Lambda where the example provided from AWS is a NodeJS Lambda (where we prefer Python Lambdas) so I spent some time rewriting it and thought I'd share for those that are interested.

Here's the source of the Python Lambda:

def handler(event, context):
    if event['triggerSource'] == "UserMigration_Authentication":
        user = {} # Fetch your user somehow here

        # attributes may be set on the object here
        event['response']['userAttributes'] = {
            "email": "",
            "email_verified": "true"
        }

        event['response']['finalUserStatus'] = "CONFIRMED"
        event['response']['messageAction'] = "SUPPRESS"

        return event

    elif event['triggerSource'] == "UserMigration_ForgotPassword":
        user = {} # Fetch your user somehow here

        event['response']['userAttributes'] = {
            "email": "",
            # required to enable password-reset code to be sent to user
            "email_verified": "true"
        }
        event['response']['messageAction'] = "SUPPRESS"

        return event
    else:
        # Return error to Amazon Cognito
        return fail("Bad triggerSource " + event['triggerSource'])

def fail(message):
    return {"errorType":"Error","errorMessage":message}

Additionally, an example of the data that's being provided to the Lambda from Cognito if someone wants to use it for writing tests:

{
  "version": "1",
  "triggerSource": "UserMigration_Authentication",
  "region": "us-east-1",
  "userPoolId": "user-pool-id",
  "userName": "glen@dp.cx",
  "callerContext": {
    "awsSdkVersion": "sdk-version",
    "clientId": "client-id"
  },
  "request": {
    "password": "correct-horse-battery-staple",
    "validationData": {
    },
    "userAttributes": null
  },
  "response": {
    "userAttributes": null,
    "forceAliasCreation": null,
    "finalUserStatus": null,
    "messageAction": null,
    "desiredDeliveryMediums": null
  }
}

And all values provided in the ClientMetadata will be passed in the .request.validationData field in the provided json. The overall structure provided by this json is accurate (as of post date); data may obviously be different based on submission.