カテゴリー別アーカイブ: プログラム

GAE pythonでのランダムな「AttributeError: ‘~’ object has no attribute ‘~’」の原因

GoogleAppEngine(GAE)のpythonでハマったのでメモ。
具体的には以下のエラーが出た。

AttributeError: ‘~’ object has no attribute ‘=’

~のところには、自分で設定した名前が入る。
このエラーが出るだけなら、単純なんだけど、名前の間違いとか、データが入っていないとかは無くて、それでもなぜかエラーが出たり出なかったりする。この出たり出なかったりという反応の仕方をするので解決に時間がかかった。完璧に100%エラーが出るなら原因は特定しやすいんだけど。

具体的には以下の様な使い方をしていた。

class datax(ndb.Model):
cat = ndb.IntegerProperty()

まず上の用に設定して、以下のようにデータを取り出す。

q = datax.query()
qry2 = q.filter(~)
qry3 = qry2.order(-~)
qry4 = qry3.fetch(1)
datay = qry4[0].cat

~の部分は省略。
この時に、上記のAttributeErrorが出たり出なかったりした。いろいろ試して最後やっと解決したけど、原因は

class datax(ndb.Model):
cat = ndb.IntegerProperty()

の部分だった。class datax(ndb.Model)というのは実際には、

class datax(ndb.Model):
cat = ndb.IntegerProperty()
dog = ndb.IntegerProperty()
bird = ndb.IntegerProperty()
frog = ndb.IntegerProperty()

なんだけど、このファイル内で使うのは、

cat = ndb.IntegerProperty()

だけだったから、

class datax(ndb.Model):
cat = ndb.IntegerProperty()

ファイル内をスッキリさせるために、上記のように使うものだけ入れて書いていた。最初試しに省略したら、普通に問題なく動いたので、これでいいんだと思い込んでいた。で、上記の部分を全ファイル省略せずに書くようにしたら、エラーが完璧に0になった。どういう仕組でエラーが出たり出なかったりしていたのかはわからないけどもとりあえず解決して良かった。

Google App EngineのデータベースNDBのProperty Optionsについて。

Google App Engineのpythonでデータを出し入れするときには、NDBというデータベースをMYSQLの代わりに使う。
NDBのProperty(データ)にはオプション設定がいろいろ用意してあるんだけど、今までオプション設定の必要性を感じたことがなかった。
ところが、NDBからデータを利用するときに、エラーが出ることがあって、エラーを避けるために、データを取り出すときではなくて、入れる段階で処理すると楽だなと思い、そういえばオプション設定があったな、と思い出し、グーグルのマニュアルを見てみると便利そうなものがたくさん用意されていた。

ndb.IntegerProperty(required=True)

みたいに、requiredを設定すると、値が必ず入っていないとダメなので、取り出す時にデータが入ってなくてエラーが出るということを避けられる。ということがやっとわかった。

PythonのNDB Asynchronous(非同期)での@ndb.toplevelの使い方

Google App EngineでNDB Asynchronousを使うときに@ndb.toplevelというのが出てきた。

class MyRequestHandler(webapp2.RequestHandler):
@ndb.toplevel
def get(self):
acct = Account.get_by_id(users.get_current_user().user_id())
acct.view_counter += 1
acct.put_async() # Ignoring the Future this returns
# …read something else from Datastore…
template.render(…)

マニュアルのサンプルコードがこれで、最初は何のことかチンプンカンプンだった。
一晩寝て次の日になってやっとわかってきて
async()は、複数のことを同時にできるから、例えば、100個の命令を同時に出して、まだ全部の命令が完了していないのに
次の命令、サンプルだとtemplate.render(…)が実行されてしまうと、async()のまだ終わってないのに、次の段階に進んでしまい永遠に
async()の内容が完了しないままになることがあるかもしれない。そこで登場するのが@ndb.toplevelで、これをつけると、async()が完了するまで待ってくれる、ということらしい。

Google Cloud StorageにPythonでデータのやり取りをする

何をしたいかというと、GCS(Google Cloud Storage)にプログラムでデータを放り込んだり取り出したりしたい。

最初は、Blobstoreという物を使おうと思い調べていたけど、グーグルのマニュアルに、プログラムでBlobstoreへ書き込む機能はもうじきなくなるので、GCS(Google Cloud Storage)の方をおすすめする、みたいなことが書いてあったので、GCSの方を使うことにした。

使うのはpythonで、GCS(Google Cloud Storage)とやりとりするためには、Google Cloud Storage Python Client Libraryというのを使う必要があるらしく、まずはこのファイルをダウンロードしてインストール。インストールと言っても、、そのライブラリーのcloudstorageというフォルダがあれば、それをアプリと同じフォルダ(最初階層を間違えてエラーが出た)に置くだけで使えるようになった。

あとは、

import cloudstorage as gcs

でライブラリーを読み込んで、

g_file = gcs.open(filename,’w’,content_type=”,retry_params=write_retry_params)
g_file.write(testfile)
g_file.close()

とするだけでOKだった、予想以上に簡単。
filenameは固有のbucketの後は自分で好きに決めれてサブディレクトリみたいに、表面上は/a/b/c/catと整理しやすくできるみたい。
testfileに書き込む内容を入れる。
‘w’は書き込みモードで読み込むときはrにする。content_typeは自由に決めれることができるので書き込むファイルに合わせる。retry_paramsは良くわからないけど、書き込みに失敗した時に、どういう対応をするのか決めるっぽい。

次に、writeで書き込んで、closeで終わり。

書き込んだファイルを読み込む場合は、固有のbucketの後に、自分で決めたファイル名をつなげたURLにアクセスすると表示できる。
ブラウザで操作できるディベロッパーコンソールから書き込んだファイルの確認や削除、一般公開のON,OFFの設定や公開するときのURLの確認等もできた。

Google Cloud Storage Pythonを使ってみる

グーグルがやってるクラウドサービスというのを試しに使って見てるが、まだ良くわからないところが多い。

基本の単語からわからなくて、取り敢えず、データを収める場所がバケットで、収めるデータをオブジェクトというらしい。

面白いなと思ったのは、サブディレクトリの仕組みで
例えば、
animal/sea/fish
というサブディレクトリの構造らしきものがあったとして(これをバケットというらしい)、実際は、animalの下にseaフォルダがあって、そこにfishというファイルがあるんではなくて
たんに、fishというファイルにanimal/sea/fishという名前が付いているだけということらしい。

グーグルのクラウドサービスを見るとなんでも用意されてるので、ほんとできるだけ自前でやらずに用意されているものを上手に組み合わせてどう利用するかが大切だなぁと思った。