何らかの奇妙な理由で、ubuntu 12 から ubuntu 14 に切り替えた後、Python コードが機能しなくなりました。データを unpickle できなくなりました。latin1エンコーディングに変換して、データをcouchdbデータベースに保存しました。
latin1 を使用しているのは、これが cPickled バイナリ データを格納し、couchdb データベースから取得するために使用できる唯一のエンコーディングであることを少し前に読んだためです (もうリンクはありません)。json のエンコーディングの問題を回避するためのものです (couchdbkit はバックグラウンドで json を使用します)。
Latin1 は、256 文字を 256 文字にマップすることになっていましたが、これは正確にバイト単位です。現在、システムのアップグレード後、Python は有効な値が 128 個しかないかのように文句を言い、UnicodeDecodeError をスローするようです (以下を参照)。
- 古いpythonバージョンは2.7.3でした
- 古いcouchdbバージョン1.6.1
古いcouchdbkitは0.5.7でした
新しいpythonバージョンは2.7.6です
- 新しいcouchdbバージョン1.6.1(変更なし)
- 新しいcouchdbkitは0.6.5です
これらすべての詳細が必要かどうかはわかりませんが、私が使用するいくつかの宣言を次に示します。
#deals with all the errors when saving an item
def saveitem(item):
item.set_db(self.db)
item["_id"] = key
error = True
while error:
try:
item.save()
error = False
except ResourceConflict:
try:
item = DBEntry.get_or_create(key)
except ResourceConflict:
pass
except (NoMoreData) as e:
print "CouchDB.set.saveitem: NoMoreData error, retrying...", str(e)
except (RequestError) as e:
print "CouchDB.set.saveitem: RequestError error. retrying...", str(e)
#deals with most of what could go wrong when adding an attachment
def addattachment(item, content, name = "theattachment"):
key = item["_id"]
error = True
while error:
try:
item.put_attachment(content = content, name = name) #, content_type = "application/octet-stream"
error = False
except ResourceConflict:
try:
item = DBEntry.get_or_create(key)
except ResourceConflict:
print "addattachment ResourceConflict, retrying..."
except NoMoreData:
print "addattachment NoMoreData, retrying..."
except (NoMoreData) as e:
print key, ": no more data exception, wating 1 sec and retrying... -> ", str(e)
time.sleep(1)
item = DBEntry.get_or_create(key)
except (IOError) as e:
print "addattachment IOError:", str(e), "repeating..."
item = DBEntry.get_or_create(key)
except (KeyError) as e:
print "addattachment error:", str(e), "repeating..."
try:
item = DBEntry.get_or_create(key)
except ResourceConflict:
pass
except (NoMoreData) as e:
pass
次に、次のように保存します。
pickled = cPickle.dumps(obj = value, protocol = 2)
pickled = pickled.decode('latin1')
item = DBEntry(content={"seeattachment": True, "ispickled" : True},
creationtm=datetime.datetime.utcnow(),lastaccesstm=datetime.datetime.utcnow())
item = saveitem(item)
addattachment(item, pickled)
そして、これが私が開梱する方法です。データは ubuntu 12 で書き込まれました。ubuntu 14 で解凍できません:
def unpackValue(self, value, therawkey):
if value is None: return None
originalval = value
value = value["content"]
result = None
if value.has_key("realcontent"):
result = value["realcontent"]
elif value.has_key("seeattachment"):
if originalval.has_key("_attachments"):
if originalval["_attachments"].has_key("theattachment"):
if originalval["_attachments"]["theattachment"].has_key("data"):
result = originalval["_attachments"]["theattachment"]["data"]
result = base64.b64decode(result)
else:
print "unpackvalue: no data in attachment. Here is how it looks like:"
print originalval["_attachments"]["theattachment"].iteritems()
else:
error = True
while error:
try:
result = self.db.fetch_attachment(therawkey, "theattachment")
error = False
except ResourceConflict:
print "could not get attachment for", therawkey, "retrying..."
time.sleep(1)
except ResourceNotFound:
self.delete(key = therawkey, rawkey = True)
return None
if value["ispickled"]:
result = cPickle.loads(result.encode('latin1'))
else:
result = value
if isinstance(result, unicode): result = result.encode("utf8")
return result
行result = cPickle.loads(result.encode('latin1'))
は ubuntu 12 では成功しますが、ubuntu 14 では失敗します。次のエラー:
UnicodeDecodeError: 'ascii' コーデックは位置 0 のバイト 0xc2 をデコードできません: 序数が範囲外です (128)
ubuntu 12でそのエラーは発生しませんでした!
新しいバージョンのcouchdbkitとpythonを維持しながら、ubuntu 14でデータを読み取るにはどうすればよいですか? それはバージョン管理の問題ですか?なぜそのエラーが発生するのですか?