lokeshh_rubypython 0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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