python3.5でpyobjcのコードを動かそうとしたら Symbol not found: _PyObject_REPR
はじめに
python3.5でpyobjcのコードを動かそうとした際に、以下のようなエラーが出てしまっていた。
Symbol not found: _PyObject_REPR
結論からいうとパッケージが古かったので更新した。(3.0.4 -> 3.1.1)
stack overflowで該当する質問
- python - Symbol not found: _PyObject_REPR when calling pyobjc function, Python3.5.1 - Stack Overflow
現在の状態
個人的にmacportsを使っている。
$ port installed | grep pyobjc py35-pyobjc @3.0.4_0 (active) py35-pyobjc-cocoa @3.0.4_0 (active)
portfileの書き換え
pypiを見たら最新は3.1.1だったのでそれを使うように書き換える。pipで単にインストールしても良いけれど。拡張ライブラリが含まれたようなものはその環境固有の方法で管理したほうが良い気がしている。
ここに書いてある作業に従ってportfileを書き換えれば良い
$ cd `port dir py35-pyobjc-cocoa` $ sudo cp -p Portfile Portfile.orig # versionの書き換え $ sudo port edit py35-pyobjc-cocoa $ sudo port -d checksum py35-pyobjc-cocoa # distのchecksumの方に書き換える $ sudo port edit py35-pyobjc-cocoa $ sudo port -d install py35-pyobjc-cocoa $ cd `port dir py35-pyobjc` $ sudo cp -p Portfile Portfile.orig # versionの書き換え $ sudo port edit py35-pyobjc $ sudo port -d checksum py35-pyobjc $ sudo port -d livecheck py35-pyobjc # distのchecksumの方に書き換える $ sudo port edit py35-pyobjc $ sudo port -d install py35-pyobjc
portfileを書き換えたらインストールする。
versionの書き換え
3.0.4 -> 3.1.1
checksumの書き換え
checksumを実行してわざと失敗させて新しいchecksumの値を取るのが便利。以下のような出力からDistfile ... の部分を取り出す。
Portfile checksum: pyobjc-core-3.1.1.tar.gz rmd160 12ee6d8132c59420c768dafdb2ee73f17ea97cc1 Distfile checksum: pyobjc-core-3.1.1.tar.gz rmd160 20a806aed2a7396ca86ca680060947ff6b48eccb DEBUG: Calculated (sha256) is 07c4e9c4fa5bec881cd86bf1b7dbcdb306b16567b490d06fa538c0d1b2677d2e Error: Checksum (sha256) mismatch for pyobjc-core-3.1.1.tar.gz Portfile checksum: pyobjc-core-3.1.1.tar.gz sha256 a4708886ff7844ff7537c60d14e903014a90b3e3cdbad5e717acfcbe150768b7 Distfile checksum: pyobjc-core-3.1.1.tar.gz sha256 07c4e9c4fa5bec881cd86bf1b7dbcdb306b16567b490d06fa538c0d1b2677d2e
結果
$ port installed | grep pyobjc py35-pyobjc @3.0.4_0 py35-pyobjc @3.1.1_0 (active) py35-pyobjc-cocoa @3.0.4_0 py35-pyobjc-cocoa @3.1.1_0 (active)
hello worldが動くようになった。
goのtext/templateでprivateなattributeを出力しようとするとエラーになるという話
goのtext/templateでprivateなattributeを出力しようとすると、エラーになるという話を知らなかった。
全部public
例えば、以下はOK
type User struct { Name string Message string } type V map[string]interface{} func main() { const tmpl = `{{.user.Name}}: {{.user.Message}}` tpl := template.Must(template.New("mytemplate").Parse(tmpl)) user := User{Name: "foo", Message: "hello world"} if err := tpl.Execute(os.Stdout, V{"user": user}); err != nil { fmt.Println(err) } }
一部privateに
これを以下の様にする
@@ -7,19 +7,20 @@ ) type User struct { - Name string + name string Message string } type V map[string]interface{} func main() { - const tmpl = `{{.user.Name}}: {{.user.Message}}` + const tmpl = `{{.user.name}}: {{.user.Message}}` tpl := template.Must(template.New("mytemplate").Parse(tmpl)) - user := User{Name: "foo", Message: "hello world"} + user := User{name: "foo", Message: "hello world"}
User.Name
を User.name
にした。
するとエラーになる。
$ go run xxx.go template: mytemplate:1:7: executing "mytemplate" at <.user.name>: name is an unexported field of struct type interface {}
実際のところドキュメントに書いてあった
template - The Go Programming Language
Template is the representation of a parsed template. The *parse.Tree field is exported only for use by html/template and should be treated as unexported by all other clie
exported/unexportedチェックしているところ
単純に、template部分は別パッケージという扱いで非公開のメンバーにアクセスしようとしたからエラーということっぽい。 reflectionを使っているしruntime時にしかわからないのでruntime error。
text/template/exec.go の以下の部分で
func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value { // snip... switch receiver.Kind() { case reflect.Struct: tField, ok := receiver.Type().FieldByName(fieldName) if ok { // snip... if tField.PkgPath != "" { // field is unexported s.errorf("%s is an unexported field of struct type %s", fieldName, typ) }
tFieldは StructField型
reflect/type.go
// A StructField describes a single field in a struct. type StructField struct { // Name is the field name. Name string // PkgPath is the package path that qualifies a lower case (unexported) // field name. It is empty for upper case (exported) field names. // See https://golang.org/ref/spec#Uniqueness_of_identifiers PkgPath string Type Type // field type Tag StructTag // field tag string Offset uintptr // offset within struct, in bytes Index []int // index sequence for Type.FieldByIndex Anonymous bool // is an embedded field }
reflect/type.go のあたりでexportされていないfieldに対してはpkgPathを設定しているという感じになっているので。確かにexportedかどうかの判別に使えそう。
func (t *structType) Field(i int) (f StructField) { // snip.. if !p.name.isExported() { // Fields never have an import path in their name. f.PkgPath = t.pkgPath.name() } }