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.
- 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
|