Ver código fonte

Expanded definitions

Min 4 anos atrás
pai
commit
30237cacc9
5 arquivos alterados com 274 adições e 6 exclusões
  1. 4 0
      exception.go
  2. 8 0
      import.go
  3. 40 0
      object.go
  4. 4 3
      path.go
  5. 218 3
      primitive.go

+ 4 - 0
exception.go

@@ -80,3 +80,7 @@ func (self *Exception) Error() string {
 		return "malformed Python exception"
 	}
 }
+
+func ClearException() {
+	C.PyErr_Clear()
+}

+ 8 - 0
import.go

@@ -23,3 +23,11 @@ func Import(name string) (*Reference, error) {
 		return nil, GetError()
 	}
 }
+
+func ReloadModule(module *Reference) (*Reference, error) {
+	if module_ := C.PyImport_ReloadModule(module.Object); module != nil {
+		return NewReference(module_), nil
+	} else {
+		return nil, GetError()
+	}
+}

+ 40 - 0
object.go

@@ -47,6 +47,14 @@ func (self *Reference) Str() (*Reference, error) {
 	}
 }
 
+func (self *Reference) HasAttr(name string) bool {
+	name_ := C.CString(name)
+	defer C.free(unsafe.Pointer(name_))
+
+	res := C.PyObject_HasAttrString(self.Object, name_)
+	return res == 1
+}
+
 func (self *Reference) GetAttr(name string) (*Reference, error) {
 	name_ := C.CString(name)
 	defer C.free(unsafe.Pointer(name_))
@@ -58,6 +66,32 @@ func (self *Reference) GetAttr(name string) (*Reference, error) {
 	}
 }
 
+func (self *Reference) GetAttrDict() map[string]*Reference {
+	obj := C.PyObject_GenericGetDict(self.Object, nil)
+	defer C.Py_DecRef(obj)
+	dict := make(map[string]*Reference)
+	keys := C.PyDict_Keys(obj)
+
+	//if HasException() {
+	//	fmt.Printf("%v\n", GetError())
+	//	return dict
+	//}
+	defer C.Py_DecRef(keys)
+	iterator := C.PyObject_GetIter(keys)
+	defer C.Py_DecRef(iterator)
+
+	for {
+		key := C.PyIter_Next(iterator);
+		if key == nil { break }
+		value := C.PyDict_GetItem(obj, key)
+		if value == nil { continue }
+		keyRef := NewReference(key)
+		dict[keyRef.String()] = NewReference(value)
+		keyRef.Release()
+	}
+	return dict
+}
+
 func (self *Reference) SetAttr(name string, reference *Reference) error {
 	name_ := C.CString(name)
 	defer C.free(unsafe.Pointer(name_))
@@ -69,6 +103,12 @@ func (self *Reference) SetAttr(name string, reference *Reference) error {
 	}
 }
 
+func (self *Reference) SetAttrI(name string, primite interface{}) error {
+	value, err := NewPrimitiveReference(primite)
+	if err != nil { return err }
+	return self.SetAttr(name, value)
+}
+
 func (self *Reference) Call(args ...interface{}) (*Reference, error) {
 	if args_, err := NewTuple(args...); err == nil {
 		if kw, err := NewDict(); err == nil {

+ 4 - 3
path.go

@@ -3,25 +3,26 @@ package python
 import (
 	"os"
 	"path/filepath"
+	"strings"
 )
 
 const PYTHONPATH = "PYTHONPATH"
 
 func SetPythonPath(path ...string) {
-	path_ := filepath.Join(path...)
+	path_ := strings.Join(path, string(filepath.ListSeparator))
 	os.Setenv(PYTHONPATH, path_)
 }
 
 func AppendPythonPath(path ...string) {
 	path_ := filepath.SplitList(os.Getenv(PYTHONPATH))
 	path_ = append(path_, path...)
-	path__ := filepath.Join(path_...)
+	path__ := strings.Join(path_, string(filepath.ListSeparator))
 	os.Setenv(PYTHONPATH, path__)
 }
 
 func PrependPythonPath(path ...string) {
 	path_ := filepath.SplitList(os.Getenv(PYTHONPATH))
 	path_ = append(path, path_...)
-	path__ := filepath.Join(path_...)
+	path__ := strings.Join(path_, string(filepath.ListSeparator))
 	os.Setenv(PYTHONPATH, path__)
 }

+ 218 - 3
primitive.go

@@ -47,10 +47,81 @@ func NewPrimitiveReference(value interface{}) (*Reference, error) {
 	case []byte:
 		return NewBytes(value_)
 	}
+	return nil, fmt.Errorf("unsupported type: %s", value)
+}
 
-	return nil, fmt.Errorf("unsupported primitive: %s", value)
+func (self *Reference) ToInterface(recurse int) (interface{}, error) {
+	if self.IsLong() {
+		return self.ToInt64()
+	}
+	if self.IsUnicode() {
+		return self.ToString()
+	}
+	if self.IsBool() {
+		return self.ToBool(), nil
+	}
+	if self.IsNone() {
+		return nil, nil
+	}
+	if self.IsFloat() {
+		return self.ToFloat64()
+	}
+	if self.IsBytes() {
+		return self.ToBytes()
+	}
+	if self.IsByteArray() {
+		return self.ByteArrayToBytes()
+	}
+	if self.IsDict() {
+		if recurse <= 0 {
+			return nil, fmt.Errorf("reached recursion limit")
+		}
+		mapValue := make(map[interface{}]interface{})
+
+		dict, err := self.ToMap()
+		if err != nil { return mapValue, err }
+
+		errorNum := 0
+		for key, val := range dict {
+			keyValue, err1 := key.ToInterface(recurse-1)
+			valValue, err2 := val.ToInterface(recurse-1)
+			key.Release()
+			val.Release()
+			if err1 == nil && err2 == nil {
+				mapValue[keyValue] = valValue
+			} else {
+				errorNum ++
+			}
+		}
+		if errorNum > 0 {
+			return mapValue, fmt.Errorf("failed to convert %d primitives from dictionary", errorNum)
+		}
+		return mapValue, nil
+	}
+	if self.IsList() {
+		if recurse <= 0 {
+			return nil, fmt.Errorf("reached recursion limit")
+		}
+		pyList, err := self.ToList()
+		if err != nil { return nil, err }
+		goList := make([]interface{}, len(pyList))
+
+		errorNum := 0
+		for i, item := range pyList {
+			if goList[i], err = item.ToInterface(recurse-1); err != nil {
+				errorNum ++
+			}
+			item.Release()
+		}
+		if errorNum > 0 {
+			return goList, fmt.Errorf("failed to convert %d primitives from list", errorNum)
+		}
+		return goList, nil
+	}
+	return nil, fmt.Errorf("unsupported primitive: %s", self.String())
 }
 
+
 //
 // None
 //
@@ -66,6 +137,10 @@ var BoolType = NewType(&C.PyBool_Type)
 var True = NewReference(C.Py_True)
 var False = NewReference(C.Py_False)
 
+func (self *Reference) IsNone() bool {
+	return self.Object == C.Py_None
+}
+
 func (self *Reference) IsBool() bool {
 	return self.Type().IsSubtype(BoolType)
 }
@@ -100,10 +175,10 @@ func (self *Reference) IsLong() bool {
 }
 
 func (self *Reference) ToInt64() (int64, error) {
-	if long := C.PyLong_AsLong(self.Object); !HasException() {
+	if long := C.PyLong_AsLongLong(self.Object); !HasException() {
 		return int64(long), nil
 	} else {
-		return 0, GetError()
+		return int64(long), GetError()
 	}
 }
 
@@ -257,6 +332,54 @@ func (self *Reference) SetListItem(index int, item *Reference) error {
 	}
 }
 
+func (self *Reference) ToList() ([]*Reference, error) {
+	var listLen int
+	if listLen = int(C.PyList_Size(self.Object)); HasException() {
+		return nil, GetError()
+	}
+	goList := make([]*Reference, listLen)
+	for i := 0; i < listLen; i++ {
+		index := C.long(int64(i))
+		if item := C.PyList_GetItem(self.Object, index); item != nil {
+			goList[i] = NewReference(item)
+		}
+	}
+	return goList, nil
+}
+
+func (self *Reference) Iteratable() bool {
+	return int(C.PyIter_Check(self.Object)) == 1
+}
+
+func (self *Reference) Iterate(next <-chan bool) (<-chan *Reference, error) {
+	iterator := C.PyObject_GetIter(self.Object)
+	if iterator == nil || HasException() {
+		return nil, GetError()
+	}
+	ch := make(chan *Reference, 1)
+	go func() {
+		defer close(ch)
+		defer C.Py_DecRef(iterator)
+		forLoop:
+		for ;; {
+			if <- next {
+				item := C.PyIter_Next(iterator);
+				if item == nil { break }
+				pyItem := NewReference(item)
+				select {
+				case ch <- pyItem:
+				default:
+					pyItem.Release()
+					break forLoop
+				}
+			} else {
+				break
+			}
+		}
+	}()
+	return ch, nil
+}
+
 //
 // Dict
 //
@@ -284,6 +407,80 @@ func (self *Reference) SetDictItem(key *Reference, value *Reference) error {
 	}
 }
 
+func (self *Reference) DictContains(key *Reference) (bool, error) {
+	res := C.PyDict_Contains(self.Object, key.Object)
+	if res == -1 {
+		return false, GetError()
+	}
+	return res == 1, nil
+}
+
+func (self *Reference) DictContainsString(key string) (bool, error) {
+	keyObj, err := NewUnicode(key)
+	if err != nil {
+		return false, err
+	}
+	defer keyObj.Release()
+	res := C.PyDict_Contains(self.Object, keyObj.Object)
+	if res == -1 {
+		return false, GetError()
+	}
+	return res == 1, nil
+}
+
+func (self *Reference) GetDictItemString(key string) *Reference {
+	value_ := C.CString(key)
+	defer C.free(unsafe.Pointer(value_))
+
+	if obj := C.PyDict_GetItemString(self.Object, value_); obj != nil {
+		return NewReference(obj)
+	}
+	return nil
+}
+
+func (self *Reference) GetDictItem(key *Reference) *Reference {
+	if obj := C.PyDict_GetItem(self.Object, key.Object); obj != nil {
+		return NewReference(obj)
+	}
+	return nil
+}
+
+func (self *Reference) DeleteDictItem(key *Reference) error {
+	if ret := C.PyDict_DelItem(self.Object, key.Object); ret != 0 {
+		return GetError()
+	}
+	return nil
+}
+
+func (self *Reference) DeleteDictItemString(key string) error {
+	value_ := C.CString(key)
+	defer C.free(unsafe.Pointer(value_))
+
+	if ret := C.PyDict_DelItemString(self.Object, value_); ret != 0 {
+		return GetError()
+	}
+	return nil
+}
+
+func (self *Reference) ToMap() (map[*Reference]*Reference, error) {
+	keys := C.PyDict_Keys(self.Object)
+	if HasException() {
+		return nil, GetError()
+	}
+	defer C.Py_DecRef(keys)
+	iterator := C.PyObject_GetIter(keys)
+	defer C.Py_DecRef(iterator)
+	dict := make(map[*Reference]*Reference)
+	for {
+		key := C.PyIter_Next(iterator);
+		if key == nil { break }
+		value := C.PyDict_GetItem(self.Object, key)
+		if value == nil { continue }
+		dict[NewReference(key)] = NewReference(value)
+	}
+	return dict, nil
+}
+
 //
 // Set (mutable)
 //
@@ -398,3 +595,21 @@ func (self *Reference) AccessByteArray() (unsafe.Pointer, int, error) {
 		return nil, 0, GetError()
 	}
 }
+
+//
+//  Object
+//
+
+//var ObjectType = NewType(&C.PyObject_Type)
+//
+//func (self *Reference) IsObject() bool {
+//	return self.Type().IsSubtype(ObjectType)
+//}
+
+func (self *Reference) IsInstance(cls *Reference) (bool, error) {
+	inst := int64(C.PyObject_IsInstance(self.Object, cls.Object))
+	if HasException() {
+		return false, GetError()
+	}
+	return inst == 1, nil
+}