text: # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  # SPDX-License-Identifier: Apache-2.0
  
  """
  An AWS Lambda handler that receives an Amazon S3 batch event. The handler unpacks the
  event and applies the specified revision to the specified object.
  """
  
  # snippet-start:[s3.python.lambda.revise_stanza]
  import logging
  from urllib import parse
  import boto3
  from botocore.exceptions import ClientError
  
  logger = logging.getLogger(__name__)
  logger.setLevel('INFO')
  
  s3 = boto3.resource('s3')
  
  
  def lambda_handler(event, context):
      """
      Applies the specified revision to the specified object.
  
      :param event: The Amazon S3 batch event that contains the ID of the object to
                    revise and the revision type to apply.
      :param context: Context about the event.
      :return: A result structure that Amazon S3 uses to interpret the result of the
               operation.
      """
      # Parse job parameters from Amazon S3 batch operations
      invocation_id = event['invocationId']
      invocation_schema_version = event['invocationSchemaVersion']
  
      results = []
      result_code = None
      result_string = None
  
      task = event['tasks'][0]
      task_id = task['taskId']
      # The revision type is packed with the object key as a pipe-delimited string.
      obj_key, revision = \
          parse.unquote(task['s3Key'], encoding='utf-8').split('|')
      bucket_name = task['s3BucketArn'].split(':')[-1]
  
      logger.info("Got task: apply revision %s to %s.", revision, obj_key)
  
      try:
          stanza_obj = s3.Bucket(bucket_name).Object(obj_key)
          stanza = stanza_obj.get()['Body'].read().decode('utf-8')
          if revision == 'lower':
              stanza = stanza.lower()
          elif revision == 'upper':
              stanza = stanza.upper()
          elif revision == 'reverse':
              stanza = stanza[::-1]
          elif revision == 'delete':
              pass
          else:
              raise TypeError(f"Can't handle revision type '{revision}'.")
  
          if revision == 'delete':
              stanza_obj.delete()
              result_string = f"Deleted stanza {stanza_obj.key}."
          else:
              stanza_obj.put(Body=bytes(stanza, 'utf-8'))
              result_string = f"Applied revision type '{revision}' to " \
                              f"stanza {stanza_obj.key}."
  
          logger.info(result_string)
          result_code = 'Succeeded'
      except ClientError as error:
          if error.response['Error']['Code'] == 'NoSuchKey':
              result_code = 'Succeeded'
              result_string = f"Stanza {obj_key} not found, assuming it was deleted " \
                              f"in an earlier revision."
              logger.info(result_string)
          else:
              result_code = 'PermanentFailure'
              result_string = f"Got exception when applying revision type '{revision}' " \
                              f"to {obj_key}: {error}."
              logger.exception(result_string)
      finally:
          results.append({
              'taskId': task_id,
              'resultCode': result_code,
              'resultString': result_string
          })
      return {
          'invocationSchemaVersion': invocation_schema_version,
          'treatMissingKeysAs': 'PermanentFailure',
          'invocationId': invocation_id,
          'results': results
      }
  # snippet-end:[s3.python.lambda.revise_stanza]
  