lokeshh_rubypython 0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.autotest +3 -0
- data/.gitignore +18 -0
- data/.hgignore +20 -0
- data/.hgtags +12 -0
- data/.rspec +2 -0
- data/Contributors.rdoc +11 -0
- data/History.rdoc +214 -0
- data/License.rdoc +26 -0
- data/Manifest.txt +46 -0
- data/PostInstall.txt +16 -0
- data/README.rdoc +272 -0
- data/Rakefile +118 -0
- data/autotest/discover.rb +1 -0
- data/lib/rubypython/blankobject.rb +23 -0
- data/lib/rubypython/conversion.rb +332 -0
- data/lib/rubypython/interpreter.rb +262 -0
- data/lib/rubypython/macros.rb +56 -0
- data/lib/rubypython/operators.rb +120 -0
- data/lib/rubypython/pygenerator.rb +61 -0
- data/lib/rubypython/pymainclass.rb +80 -0
- data/lib/rubypython/pyobject.rb +189 -0
- data/lib/rubypython/python.rb +199 -0
- data/lib/rubypython/pythonerror.rb +80 -0
- data/lib/rubypython/rubypyproxy.rb +328 -0
- data/lib/rubypython/tuple.rb +10 -0
- data/lib/rubypython/type.rb +20 -0
- data/lib/rubypython.rb +229 -0
- data/spec/basic_spec.rb +50 -0
- data/spec/callback_spec.rb +53 -0
- data/spec/conversion_spec.rb +68 -0
- data/spec/pymainclass_spec.rb +24 -0
- data/spec/pyobject_spec.rb +202 -0
- data/spec/python_helpers/basics.py +23 -0
- data/spec/python_helpers/errors.py +2 -0
- data/spec/python_helpers/objects.py +48 -0
- data/spec/pythonerror_spec.rb +52 -0
- data/spec/refcnt_spec.rb +98 -0
- data/spec/rubypyclass_spec.rb +10 -0
- data/spec/rubypyproxy_spec.rb +261 -0
- data/spec/rubypython_spec.rb +59 -0
- data/spec/spec_helper.rb +71 -0
- data/website/index.rhtml +36 -0
- data/website/robots.txt +5 -0
- data/website/stylesheets/960.css +549 -0
- data/website/stylesheets/border-radius.htc +143 -0
- data/website/stylesheets/screen.css +132 -0
- 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
|