2016-08-17 13 views
0

でJSONシリアル化可能ではないエラーが原因私は、Amazon AWSラムダサービスでのPythonの使用方法を学んでいます。私はS3オブジェクトから文字を読み込み、別のS3オブジェクトに書き込もうとしています。私は地元のtmpファイルにS3オブジェクトをコピーすることができます実現が、可能であれば、私は、ローカルコピーの段階なしで、スクリプト、プロセスおよび出力にS3入力「ストリーム」にしたかったです。私はこれの解決策を示唆するこのStackOverFlow(二番目の答え)のコードを使用しています。Pythonの収量 "文LAMBDA AWSのテストケース

このコードは、エラー「発電機は能登JSONシリアル化可能である」投げるために私のそれ以外の作業スクリプトを引き起こしている2つの「収量()」ステートメントが含まれています。 "yield()"ステートメントがこのエラーをスローする理由を理解しようとしています。これはラムダ環境の制限ですか、これはシリアル化の問題を作成している私のコードに固有のものです。 (S3ファイルオブジェクトを使用していると思われますか?)

は、ここで私はラムダで実行する私のコードです。私が2つのyield文をコメントアウトすると、それは実行されますが、出力ファイルは空です。

from __future__ import print_function 

import json 
import urllib 
import uuid 
import boto3 
import re 

print('Loading IO function') 

s3 = boto3.client('s3') 


def lambda_handler(event, context): 
    print("Received event: " + json.dumps(event, indent=2)) 

# Get the object from the event and show its content type 
inbucket = event['Records'][0]['s3']['bucket']['name'] 
outbucket = "outlambda" 
inkey  = urllib.unquote_plus(event['Records'][0]['s3']['object']['key'].encode('utf8')) 
outkey = "out" + inkey 
try: 
    infile = s3.get_object(Bucket=inbucket, Key=inkey) 

except Exception as e: 
    print(e) 
    print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(inkey, bucket)) 
    raise e 

    tmp_path = '/tmp/{}{}'.format(uuid.uuid4(), "tmp.txt") 
# upload_path = '/tmp/resized-{}'.format(key) 

    with open(tmp_path,'w') as out: 
     unfinished_line = '' 
     for byte in infile: 
      byte = unfinished_line + byte 
      #split on whatever, or use a regex with re.split() 
      lines = byte.split('\n') 
      unfinished_line = lines.pop() 
      for line in lines: 
        out.write(line) 
        yield line   # This line causes JSON error if uncommented 
      yield unfinished_line # This line causes JSON error if uncommented 
    # 
    # Upload the file to S3 
    # 
    tmp = open(tmp_path,"r") 
    try: 
     outfile = s3.put_object(Bucket=outbucket,Key=outkey,Body=tmp) 
    except Exception as e: 
     print(e) 
     print('Error putting object {} from bucket {} Body {}. Make sure they exist and your bucket is in the same region as this function.'.format(outkey, outbucket,"tmp.txt")) 
     raise e 

    tmp.close() 
+0

あなたはコードが正しくフォーマットされていますか?具体的には、 'with open'ブロックは実際に例外処理コード内にありますか? – FujiApple

+0

ありがとう、私はこのコードでいくつかの他の重要な問題を発見しました。私もそれを見ていきます。 (それを逃した)。 –

答えて

2

機能はyieldを含むラムダハンドラは、必要に応じて、JSON-シリアライズ値を返すfunctionする必要があるのに対し、実際generatorあります。私が求めていた特定のポイントに答えるためのレイ市に

+0

これは非常に意味があります。関数呼び出しをカプセル化すれば、それを機能させることができるはずです。 –

0

感謝。 元のコードで誤ったコーディングミスを指摘してくれたFujiAppleにも感謝します。 私は、出力ファイルをコピーして出力するように見えるyieldを使わずにソリューションを開発することができました。しかしLei ShiとFujiApplesのコメントでは、そのコードを変更して、ラムダハンドラによって呼び出されるサブ関数を生成することができました。これはジェネレータである可能性があります。

from __future__ import print_function 

import json 
import urllib 
import uuid 
import boto3 
import re 
print('Loading IO function') 

s3 = boto3.client('s3') 

def processFile(inbucket,inkey,outbucket,outkey): 
    try: 
     infile = s3.get_object(Bucket=inbucket, Key=inkey) 

    except Exception as e: 
     print(e) 
     print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(inkey, bucket)) 
     raise e 

    inbody = infile['Body'] 
    tmp_path = '/tmp/{}{}'.format(uuid.uuid4(), "tmp.txt") 
# upload_path = '/tmp/resized-{}'.format(key) 

    with open(tmp_path,'w') as out: 
     unfinished_line = '' 
     bytes=inbody.read(4096) 
     while(bytes): 
      bytes = unfinished_line + bytes 
      #split on whatever, or use a regex with re.split() 
      lines = bytes.split('\n') 
      print ("bytes %s" % bytes) 
      unfinished_line = lines.pop() 
      for line in lines: 
        print ("line %s" % line) 
        out.write(line) 
        yield line  # if this line is commented out uncomment the  unfinished line if() clause below 
      bytes=inbody.read(4096) 
#  if(unfinished_line): 
#     out.write(unfinished_line) 
    # 
    # Upload the file to S3 
    # 
    tmp = open(tmp_path,"r") 
    try: 
     outfile = s3.put_object(Bucket=outbucket,Key=outkey,Body=tmp) 
    except Exception as e: 
     print(e) 
     print('Error putting object {} from bucket {} Body {}. Make sure they exist and your bucket is in the same region as this function.'.format(outkey, outbucket,"tmp.txt")) 
     raise e 

    tmp.close() 

def lambda_handler(event, context): 
    print("Received event: " + json.dumps(event, indent=2)) 

    # Get the object from the event and show its content type 
    inbucket = event['Records'][0]['s3']['bucket']['name'] 
    outbucket = "outlambda" 
    inkey  = urllib.unquote_plus(event['Records'][0]['s3']['object'] ['key'].encode('utf8')) 
    outkey = "out" + inkey 

    processFile(inbucket,inkey,outbucket,outkey) 

サブジェネレータ機能でyieldを使用するソリューションを投稿しています。 "yield"がなければ、コードは最後の行を逃します。これは、if節でコメントアウトされています。