lokeshh_rubypython 0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +3 -0
  3. data/.gitignore +18 -0
  4. data/.hgignore +20 -0
  5. data/.hgtags +12 -0
  6. data/.rspec +2 -0
  7. data/Contributors.rdoc +11 -0
  8. data/History.rdoc +214 -0
  9. data/License.rdoc +26 -0
  10. data/Manifest.txt +46 -0
  11. data/PostInstall.txt +16 -0
  12. data/README.rdoc +272 -0
  13. data/Rakefile +118 -0
  14. data/autotest/discover.rb +1 -0
  15. data/lib/rubypython/blankobject.rb +23 -0
  16. data/lib/rubypython/conversion.rb +332 -0
  17. data/lib/rubypython/interpreter.rb +262 -0
  18. data/lib/rubypython/macros.rb +56 -0
  19. data/lib/rubypython/operators.rb +120 -0
  20. data/lib/rubypython/pygenerator.rb +61 -0
  21. data/lib/rubypython/pymainclass.rb +80 -0
  22. data/lib/rubypython/pyobject.rb +189 -0
  23. data/lib/rubypython/python.rb +199 -0
  24. data/lib/rubypython/pythonerror.rb +80 -0
  25. data/lib/rubypython/rubypyproxy.rb +328 -0
  26. data/lib/rubypython/tuple.rb +10 -0
  27. data/lib/rubypython/type.rb +20 -0
  28. data/lib/rubypython.rb +229 -0
  29. data/spec/basic_spec.rb +50 -0
  30. data/spec/callback_spec.rb +53 -0
  31. data/spec/conversion_spec.rb +68 -0
  32. data/spec/pymainclass_spec.rb +24 -0
  33. data/spec/pyobject_spec.rb +202 -0
  34. data/spec/python_helpers/basics.py +23 -0
  35. data/spec/python_helpers/errors.py +2 -0
  36. data/spec/python_helpers/objects.py +48 -0
  37. data/spec/pythonerror_spec.rb +52 -0
  38. data/spec/refcnt_spec.rb +98 -0
  39. data/spec/rubypyclass_spec.rb +10 -0
  40. data/spec/rubypyproxy_spec.rb +261 -0
  41. data/spec/rubypython_spec.rb +59 -0
  42. data/spec/spec_helper.rb +71 -0
  43. data/website/index.rhtml +36 -0
  44. data/website/robots.txt +5 -0
  45. data/website/stylesheets/960.css +549 -0
  46. data/website/stylesheets/border-radius.htc +143 -0
  47. data/website/stylesheets/screen.css +132 -0
  48. metadata +297 -0
@@ -0,0 +1,189 @@
1
+ require 'rubypython/python'
2
+ require 'rubypython/macros'
3
+ require 'rubypython/conversion'
4
+ require 'ffi'
5
+
6
+ # This object is an opaque wrapper around the C Py…Object types used by the
7
+ # \Python C API.
8
+ #
9
+ # This class is *only* for RubyPython internal use.
10
+ class RubyPython::PyObject # :nodoc: all
11
+ # This class wraps C <tt>Py…Object</tt>s so that the RubyPython::Python
12
+ # reference count is automatically decreased when the Ruby object
13
+ # referencing them goes out of scope.
14
+ class AutoPyPointer < ::FFI::AutoPointer # :nodoc:
15
+ class << self
16
+ # Keeps track of which objects are associated with the currently
17
+ # running RubyPython::Python interpreter, so that RubyPython knows not
18
+ # to try to decrease the reference counts of the others when garbage
19
+ # collecting.
20
+ attr_accessor :current_pointers
21
+
22
+ # When used along with the FFI Library method is executed whenever a
23
+ # pointer is garbage collected so that cleanup can be done. In our
24
+ # case we decrease the reference count of the held pointer as long as
25
+ # the object is still good. There is really no reason the end-user
26
+ # would need to the use this method directly.
27
+ def release(pointer)
28
+ obj_id = pointer.object_id
29
+ deleted = @current_pointers.delete(obj_id)
30
+ if pointer.null?
31
+ puts "Warning: Trying to DecRef NULL pointer" if RubyPython::Python.Py_IsInitialized != 0
32
+ return
33
+ end
34
+ if deleted and (RubyPython::Python.Py_IsInitialized != 0)
35
+ RubyPython::Python.Py_DecRef pointer
36
+ end
37
+ end
38
+
39
+ # Called by RubyPython when the interpreter is started or stopped so
40
+ # that the necessary preparation or cleanup can be done. For internal
41
+ # use only.
42
+ def python_interpreter_update(status)
43
+ case status
44
+ when :stop
45
+ current_pointers.clear
46
+ end
47
+ end
48
+ private :python_interpreter_update
49
+ end
50
+
51
+ self.current_pointers = {}
52
+ end
53
+
54
+ # The AutoPyPointer object which represents the RubyPython::Python
55
+ # Py…Object.
56
+ attr_reader :pointer
57
+
58
+ # [rObject] FFI Pointer objects passed into the constructor are wrapped in
59
+ # an AutoPyPointer and assigned to the +#pointer+ attribute. Other objects
60
+ # are converted, if possible, from their Ruby types to their \Python types
61
+ # and wrapped in an AutoPyPointer. The conversion is done with
62
+ # +RubyPython::Conversion.rtopObject+.
63
+ def initialize(rObject)
64
+ if rObject.kind_of? ::FFI::AutoPointer
65
+ new_pointer = ::FFI::Pointer.new rObject
66
+ @pointer = AutoPyPointer.new new_pointer
67
+ xIncref
68
+ elsif rObject.kind_of? ::FFI::Pointer
69
+ @pointer = AutoPyPointer.new rObject
70
+ else
71
+ @pointer = AutoPyPointer.new RubyPython::Conversion.rtopObject(rObject)
72
+ end
73
+ AutoPyPointer.current_pointers[@pointer.object_id] = true
74
+ end
75
+
76
+ # Attempts to convert the wrapped object to a native ruby type. Returns
77
+ # either the Ruby object or the unmodified \Python object.
78
+ def rubify
79
+ RubyPython::Conversion.ptorObject @pointer
80
+ end
81
+
82
+ # Tests whether the wrapped \Python object has a given attribute. Returns
83
+ # +true+ if the attribute exists.
84
+ # [attrName] The name of the attribute to look up.
85
+ def hasAttr(attrName)
86
+ RubyPython::Python.PyObject_HasAttrString(@pointer, attrName) == 1
87
+ end
88
+
89
+ # Retrieves an object from the wrapped \Python object.
90
+ # [attrName] The name of the attribute to fetch.
91
+ def getAttr(attrName)
92
+ pyAttr = RubyPython::Python.PyObject_GetAttrString(@pointer, attrName)
93
+ self.class.new pyAttr
94
+ end
95
+
96
+ # Sets an attribute of the wrapped \Python object. Returns +true+ if the
97
+ # attribute was successfully set.
98
+ # [attrName] The name of the attribute to set.
99
+ # [rbPyAttr] A PyObject wrapper around the value that we wish to set the
100
+ # attribute to.
101
+ def setAttr(attrName, rbPyAttr)
102
+ #SetAttrString should incref whatever gets passed to it.
103
+ RubyPython::Python.PyObject_SetAttrString(@pointer, attrName, rbPyAttr.pointer) != -1
104
+ end
105
+
106
+ # Calls the wrapped \Python object with the supplied arguments and keyword
107
+ # arguments. Returns a PyObject wrapper around the returned object, which
108
+ # may be +NULL+.
109
+ # [rbPyArgs] A PyObject wrapping a Tuple of the supplied arguments.
110
+ # [rbPyKeywords] A PyObject wrapping a Dict of keyword arguments.
111
+ def callObjectKeywords(rbPyArgs, rbPyKeywords)
112
+ pyReturn = RubyPython::Python.PyObject_Call(@pointer, rbPyArgs.pointer, rbPyKeywords.pointer)
113
+ self.class.new pyReturn
114
+ end
115
+
116
+ # Calls the wrapped \Python object with the supplied arguments. Returns a
117
+ # PyObject wrapper around the returned object, which may be +NULL+.
118
+ # [rbPyArgs] A PyObject wrapping a Tuple of the supplied arguments.
119
+ def callObject(rbPyArgs)
120
+ pyReturn = RubyPython::Python.PyObject_CallObject(@pointer, rbPyArgs.pointer)
121
+ self.class.new pyReturn
122
+ end
123
+
124
+ # Decrease the reference count of the wrapped object.
125
+ def xDecref
126
+ AutoPyPointer.release(@pointer)
127
+ @pointer = nil
128
+ end
129
+
130
+ # Increase the reference count of the wrapped object
131
+ def xIncref
132
+ RubyPython::Python.Py_IncRef @pointer
133
+ nil
134
+ end
135
+
136
+ # Tests whether the wrapped object is +NULL+.
137
+ def null?
138
+ @pointer.null?
139
+ end
140
+
141
+ # Performs a compare on two Python objects. Returns a value similar to
142
+ # that of the spaceship operator (<=>).
143
+ def cmp(other)
144
+ RubyPython::Python.PyObject_Compare @pointer, other.pointer
145
+ end
146
+
147
+ # Tests whether the wrapped object is a function or a method. This is not
148
+ # the same as #callable? as many other \Python objects are callable.
149
+ def function_or_method?
150
+ check = RubyPython::Macros.PyObject_TypeCheck(@pointer, [
151
+ RubyPython::Python.PyFunction_Type.to_ptr,
152
+ RubyPython::Python.PyCFunction_Type.to_ptr,
153
+ RubyPython::Python.PyMethod_Type.to_ptr
154
+ ])
155
+ check != 0
156
+ end
157
+
158
+ # Is the wrapped object callable?
159
+ def callable?
160
+ RubyPython::Python.PyCallable_Check(@pointer) != 0
161
+ end
162
+
163
+ # Returns the 'directory' of the RubyPython::Python object; similar to #methods in
164
+ # Ruby.
165
+ def dir
166
+ return self.class.new(RubyPython::Python.PyObject_Dir(@pointer)).rubify.map do |x|
167
+ x.to_sym
168
+ end
169
+ end
170
+
171
+ # Tests whether the wrapped object is a RubyPython::Python class (both new
172
+ # and old style).
173
+ def class?
174
+ check = RubyPython::Macros.PyObject_TypeCheck(@pointer, [
175
+ RubyPython::Python.PyClass_Type.to_ptr,
176
+ RubyPython::Python.PyType_Type.to_ptr
177
+ ])
178
+ check != 0
179
+ end
180
+
181
+
182
+ # Takes an array of objects, converting them to \Python objects if necessary,
183
+ # and wraps them in a Tuple such that they may be passed to #callObject.
184
+ # [args] An array; the arguments to be inserted into the
185
+ # Tuple.
186
+ def self.buildArgTuple(*args)
187
+ self.new RubyPython::Conversion.rtopArrayToTuple(args)
188
+ end
189
+ end
@@ -0,0 +1,199 @@
1
+ require 'ffi'
2
+ require 'thread'
3
+ require 'rubypython/interpreter'
4
+
5
+ module RubyPython
6
+ # This module will hold the loaded RubyPython interpreter.
7
+ module Python #:nodoc: all
8
+ @lock = Mutex.new
9
+
10
+ def self.synchronize(&block)
11
+ @lock.synchronize(&block)
12
+ end
13
+ end
14
+ end
15
+
16
+ class RubyPython::Interpreter
17
+ # Infects the provided module with the Python FFI. Once a single module
18
+ # has been infected, the #infect! method is removed from
19
+ # RubyPython::Interpreter.
20
+ def infect!(mod)
21
+ self.class.class_eval do
22
+ undef :infect!
23
+ end
24
+
25
+ mod.extend ::FFI::Library
26
+ # FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL
27
+ mod.ffi_lib_flags :lazy, :global
28
+ mod.ffi_lib self.library
29
+
30
+ # This class is a little bit of a hack to extract the address of
31
+ # global structs. If someone knows a better way please let me know.
32
+ mod.module_eval do
33
+ self.const_set :DummyStruct, Class.new(::FFI::Struct)
34
+ self::DummyStruct.layout :dummy_var, :int
35
+
36
+ self.const_set(:PY_FILE_INPUT, 257)
37
+ self.const_set(:PY_EVAL_INPUT, 258)
38
+ self.const_set(:METH_VARARGS, 0x0001)
39
+
40
+ # Function methods & constants
41
+ attach_function :PyCFunction_New, [:pointer, :pointer], :pointer
42
+ callback :PyCFunction, [:pointer, :pointer], :pointer
43
+
44
+ attach_function :PyRun_String, [:string, :int, :pointer, :pointer], :pointer
45
+ attach_function :PyRun_SimpleString, [:string], :pointer
46
+ attach_function :Py_CompileString, [:string, :string, :int], :pointer
47
+ attach_function :PyEval_EvalCode, [:pointer, :pointer, :pointer], :pointer
48
+ attach_function :PyErr_SetString, [:pointer, :string], :void
49
+
50
+ # Python interpreter startup and shutdown
51
+ attach_function :Py_IsInitialized, [], :int
52
+ attach_function :Py_Initialize, [], :void
53
+ attach_function :Py_Finalize, [], :void
54
+
55
+ # Module methods
56
+ attach_function :PyImport_ImportModule, [:string], :pointer
57
+
58
+ # Object Methods
59
+ attach_function :PyObject_HasAttrString, [:pointer, :string], :int
60
+ attach_function :PyObject_GetAttrString, [:pointer, :string], :pointer
61
+ attach_function :PyObject_SetAttrString, [:pointer, :string, :pointer], :int
62
+ attach_function :PyObject_Dir, [:pointer], :pointer
63
+
64
+ attach_function :PyObject_Compare, [:pointer, :pointer], :int
65
+
66
+ attach_function :PyObject_Call, [:pointer, :pointer, :pointer], :pointer
67
+ attach_function :PyObject_CallObject, [:pointer, :pointer], :pointer
68
+ attach_function :PyCallable_Check, [:pointer], :int
69
+
70
+ ### Python To Ruby Conversion
71
+ # String Methods
72
+ attach_function :PyString_AsString, [:pointer], :string
73
+ attach_function :PyString_FromString, [:string], :pointer
74
+ attach_function :PyString_AsStringAndSize, [:pointer, :pointer, :pointer], :int
75
+ attach_function :PyString_FromStringAndSize, [:buffer_in, :ssize_t], :pointer
76
+
77
+ # List Methods
78
+ attach_function :PyList_GetItem, [:pointer, :int], :pointer
79
+ attach_function :PyList_Size, [:pointer], :int
80
+ attach_function :PyList_New, [:int], :pointer
81
+ attach_function :PyList_SetItem, [:pointer, :int, :pointer], :void
82
+
83
+ # Integer Methods
84
+ attach_function :PyInt_AsLong, [:pointer], :long
85
+ attach_function :PyInt_FromLong, [:long], :pointer
86
+
87
+ attach_function :PyLong_AsLong, [:pointer], :long
88
+ attach_function :PyLong_FromLongLong, [:long_long], :pointer
89
+
90
+ # Float Methods
91
+ attach_function :PyFloat_AsDouble, [:pointer], :double
92
+ attach_function :PyFloat_FromDouble, [:double], :pointer
93
+
94
+ # Tuple Methods
95
+ attach_function :PySequence_List, [:pointer], :pointer
96
+ attach_function :PyList_AsTuple, [:pointer], :pointer
97
+ attach_function :PyTuple_Pack, [:int, :varargs], :pointer
98
+
99
+ # Dict/Hash Methods
100
+ attach_function :PyDict_Next, [:pointer, :pointer, :pointer, :pointer], :int
101
+ attach_function :PyDict_New, [], :pointer
102
+ attach_function :PyDict_SetItem, [:pointer, :pointer, :pointer], :int
103
+ attach_function :PyDict_Contains, [:pointer, :pointer], :int
104
+ attach_function :PyDict_GetItem, [:pointer, :pointer], :pointer
105
+
106
+ # Error Methods
107
+ attach_variable :PyExc_Exception, self::DummyStruct.by_ref
108
+ attach_variable :PyExc_StopIteration, self::DummyStruct.by_ref
109
+ attach_function :PyErr_SetNone, [:pointer], :void
110
+ attach_function :PyErr_Fetch, [:pointer, :pointer, :pointer], :void
111
+ attach_function :PyErr_Occurred, [], :pointer
112
+ attach_function :PyErr_Clear, [], :void
113
+
114
+ # Reference Counting
115
+ attach_function :Py_IncRef, [:pointer], :void
116
+ attach_function :Py_DecRef, [:pointer], :void
117
+
118
+ # Type Objects
119
+ # attach_variable :PyBaseObject_Type, self::DummyStruct.by_value # built-in 'object'
120
+ # attach_variable :PyBaseString_Type, self::DummyStruct.by_value
121
+ # attach_variable :PyBool_Type, self::DummyStruct.by_value
122
+ # attach_variable :PyBuffer_Type, self::DummyStruct.by_value
123
+ # attach_variable :PyByteArrayIter_Type, self::DummyStruct.by_value
124
+ # attach_variable :PyByteArray_Type, self::DummyStruct.by_value
125
+ attach_variable :PyCFunction_Type, self::DummyStruct.by_value
126
+ # attach_variable :PyCObject_Type, self::DummyStruct.by_value
127
+ # attach_variable :PyCallIter_Type, self::DummyStruct.by_value
128
+ # attach_variable :PyCapsule_Type, self::DummyStruct.by_value
129
+ # attach_variable :PyCell_Type, self::DummyStruct.by_value
130
+ # attach_variable :PyClassMethod_Type, self::DummyStruct.by_value
131
+ attach_variable :PyClass_Type, self::DummyStruct.by_value
132
+ # attach_variable :PyCode_Type, self::DummyStruct.by_value
133
+ # attach_variable :PyComplex_Type, self::DummyStruct.by_value
134
+ # attach_variable :PyDictItems_Type, self::DummyStruct.by_value
135
+ # attach_variable :PyDictIterItem_Type, self::DummyStruct.by_value
136
+ # attach_variable :PyDictIterKey_Type, self::DummyStruct.by_value
137
+ # attach_variable :PyDictIterValue_Type, self::DummyStruct.by_value
138
+ # attach_variable :PyDictKeys_Type, self::DummyStruct.by_value
139
+ # attach_variable :PyDictProxy_Type, self::DummyStruct.by_value
140
+ # attach_variable :PyDictValues_Type, self::DummyStruct.by_value
141
+ attach_variable :PyDict_Type, self::DummyStruct.by_value
142
+ # attach_variable :PyEllipsis_Type, self::DummyStruct.by_value
143
+ # attach_variable :PyEnum_Type, self::DummyStruct.by_value
144
+ # attach_variable :PyFile_Type, self::DummyStruct.by_value
145
+ attach_variable :PyFloat_Type, self::DummyStruct.by_value
146
+ # attach_variable :PyFrame_Type, self::DummyStruct.by_value
147
+ # attach_variable :PyFrozenSet_Type, self::DummyStruct.by_value
148
+ attach_variable :PyFunction_Type, self::DummyStruct.by_value
149
+ # attach_variable :PyGen_Type, self::DummyStruct.by_value
150
+ # attach_variable :PyGetSetDescr_Type, self::DummyStruct.by_value
151
+ # attach_variable :PyInstance_Type, self::DummyStruct.by_value
152
+ attach_variable :PyInt_Type, self::DummyStruct.by_value
153
+ attach_variable :PyList_Type, self::DummyStruct.by_value
154
+ attach_variable :PyLong_Type, self::DummyStruct.by_value
155
+ # attach_variable :PyMemberDescr_Type, self::DummyStruct.by_value
156
+ # attach_variable :PyMemoryView_Type, self::DummyStruct.by_value
157
+ attach_variable :PyMethod_Type, self::DummyStruct.by_value
158
+ # attach_variable :PyModule_Type, self::DummyStruct.by_value
159
+ # attach_variable :PyNullImporter_Type, self::DummyStruct.by_value
160
+ # attach_variable :PyProperty_Type, self::DummyStruct.by_value
161
+ # attach_variable :PyRange_Type, self::DummyStruct.by_value
162
+ # attach_variable :PyReversed_Type, self::DummyStruct.by_value
163
+ # attach_variable :PySTEntry_Type, self::DummyStruct.by_value
164
+ # attach_variable :PySeqIter_Type, self::DummyStruct.by_value
165
+ # attach_variable :PySet_Type, self::DummyStruct.by_value
166
+ # attach_variable :PySlice_Type, self::DummyStruct.by_value
167
+ # attach_variable :PyStaticMethod_Type, self::DummyStruct.by_value
168
+ attach_variable :PyString_Type, self::DummyStruct.by_value
169
+ # attach_variable :PySuper_Type, self::DummyStruct.by_value # built-in 'super'
170
+ # attach_variable :PyTraceBack_Type, self::DummyStruct.by_value
171
+ attach_variable :PyTuple_Type, self::DummyStruct.by_value
172
+ attach_variable :PyType_Type, self::DummyStruct.by_value
173
+ # attach_variable :PyUnicode_Type, self::DummyStruct.by_value
174
+ # attach_variable :PyWrapperDescr_Type, self::DummyStruct.by_value
175
+
176
+ attach_variable :Py_TrueStruct, :_Py_TrueStruct, self::DummyStruct.by_value
177
+ attach_variable :Py_ZeroStruct, :_Py_ZeroStruct, self::DummyStruct.by_value
178
+ attach_variable :Py_NoneStruct, :_Py_NoneStruct, self::DummyStruct.by_value
179
+
180
+ # This is an implementation of the basic structure of a Python PyObject
181
+ # struct. The C struct is actually much larger, but since we only access
182
+ # the first two data members via FFI and always deal with struct
183
+ # pointers there is no need to mess around with the rest of the object.
184
+ self.const_set :PyObjectStruct, Class.new(::FFI::Struct)
185
+ self::PyObjectStruct.layout :ob_refcnt, :ssize_t,
186
+ :ob_type, :pointer
187
+
188
+ # This struct is used when defining Python methods.
189
+ self.const_set :PyMethodDef, Class.new(::FFI::Struct)
190
+ self::PyMethodDef.layout :ml_name, :pointer,
191
+ :ml_meth, :PyCFunction,
192
+ :ml_flags, :int,
193
+ :ml_doc, :pointer
194
+ end
195
+
196
+ end
197
+
198
+ private :infect!
199
+ end
@@ -0,0 +1,80 @@
1
+ require 'rubypython/python'
2
+ require 'rubypython/macros'
3
+
4
+ # Raised when an error occurs in the \Python interpreter.
5
+ class RubyPython::PythonError < RuntimeError
6
+ # The \Python traceback object associated with this error. This will be
7
+ # a RubyPython::RubyPyProxy object.
8
+ attr_reader :traceback
9
+
10
+ # Creates the PythonError.
11
+ # [typeName] The class name of the \Python error.
12
+ # [msg] The message attached to the \Python error.
13
+ # [traceback] The traceback, if any, associated with the \Python error.
14
+ def initialize(typeName, msg, traceback = nil)
15
+ @type = typeName
16
+ @traceback = traceback
17
+ super([typeName, msg].join(': '))
18
+ end
19
+
20
+ # This method should be called when an error has occurred in the \Python
21
+ # interpreter. This acts as factory function for PythonError objects. The
22
+ # function fetches calls +#fetch+ to get the error information from the
23
+ # \Python interpreter and uses this to build a PythonError object. It then
24
+ # calls +#clear to clear the error flag in the python interpreter. After
25
+ # the error flag has been cleared, the PythonError object is returned.
26
+ def self.handle_error
27
+ rbType, rbValue, rbTraceback = fetch()
28
+
29
+ if not rbValue.null?
30
+ msg = rbValue.getAttr("__str__").callObject RubyPython::PyObject.buildArgTuple
31
+ msg = msg.rubify
32
+ else
33
+ msg = nil
34
+ end
35
+
36
+ if not rbTraceback.null?
37
+ traceback = RubyPython::RubyPyProxy.new rbTraceback
38
+ else
39
+ traceback = nil
40
+ end
41
+
42
+ # Decrease the reference count. This will happen anyway when they go out
43
+ # of scope but might as well.
44
+ rbValue.xDecref if not rbValue.null?
45
+ pyName = rbType.getAttr("__name__")
46
+
47
+ rbType.xDecref
48
+ rbName = pyName.rubify
49
+ pyName.xDecref
50
+
51
+ RubyPython::PythonError.clear
52
+ RubyPython::PythonError.new(rbName, msg, traceback)
53
+ end
54
+
55
+ # A wrapper to the \Python C API +PyErr_Fetch+ function. Returns an array
56
+ # with three PyObject instances, representing the Type, the Value, and the
57
+ # stack trace of the Python error.
58
+ def self.fetch
59
+ typePointer = ::FFI::MemoryPointer.new :pointer
60
+ valuePointer = ::FFI::MemoryPointer.new :pointer
61
+ tracebackPointer = ::FFI::MemoryPointer.new :pointer
62
+
63
+ RubyPython::Python.PyErr_Fetch typePointer, valuePointer, tracebackPointer
64
+
65
+ rbType = RubyPython::PyObject.new typePointer.read_pointer
66
+ rbValue = RubyPython::PyObject.new valuePointer.read_pointer
67
+ rbTraceback = RubyPython::PyObject.new tracebackPointer.read_pointer
68
+ [rbType, rbValue, rbTraceback]
69
+ end
70
+
71
+ # Determines whether an error has occurred in the \Python interpreter.
72
+ def self.error?
73
+ !RubyPython::Python.PyErr_Occurred.null?
74
+ end
75
+
76
+ # Resets the \Python interpreter error flag
77
+ def self.clear
78
+ RubyPython::Python.PyErr_Clear
79
+ end
80
+ end