rubypython 0.3.2 → 0.5.0
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.
- data/.autotest +3 -0
- data/.gemtest +0 -0
- data/.gitignore +13 -0
- data/.hgignore +14 -0
- data/.hgtags +7 -0
- data/.rspec +1 -1
- data/Contributors.rdoc +9 -0
- data/History.rdoc +148 -0
- data/{License.txt → License.rdoc} +7 -1
- data/Manifest.txt +15 -10
- data/PostInstall.txt +11 -4
- data/README.rdoc +272 -0
- data/Rakefile +107 -22
- data/autotest/discover.rb +1 -0
- data/lib/rubypython.rb +214 -120
- data/lib/rubypython/blankobject.rb +16 -14
- data/lib/rubypython/conversion.rb +242 -173
- data/lib/rubypython/legacy.rb +30 -31
- data/lib/rubypython/macros.rb +43 -34
- data/lib/rubypython/operators.rb +103 -101
- data/lib/rubypython/options.rb +41 -44
- data/lib/rubypython/pygenerator.rb +61 -0
- data/lib/rubypython/pymainclass.rb +46 -29
- data/lib/rubypython/pyobject.rb +193 -177
- data/lib/rubypython/python.rb +189 -176
- data/lib/rubypython/pythonerror.rb +54 -63
- data/lib/rubypython/pythonexec.rb +123 -0
- data/lib/rubypython/rubypyproxy.rb +213 -137
- data/lib/rubypython/type.rb +20 -0
- data/spec/basic_spec.rb +50 -0
- data/spec/callback_spec.rb +7 -17
- data/spec/conversion_spec.rb +7 -21
- data/spec/legacy_spec.rb +1 -16
- data/spec/pymainclass_spec.rb +6 -15
- data/spec/pyobject_spec.rb +39 -64
- data/spec/python_helpers/basics.py +20 -0
- data/spec/python_helpers/objects.py +24 -20
- data/spec/pythonerror_spec.rb +5 -17
- data/spec/refcnt_spec.rb +4 -10
- data/spec/rubypyclass_spec.rb +1 -11
- data/spec/rubypyproxy_spec.rb +45 -54
- data/spec/rubypython_spec.rb +45 -57
- data/spec/spec_helper.rb +49 -33
- metadata +87 -63
- data.tar.gz.sig +0 -0
- data/History.markdown +0 -97
- data/README.markdown +0 -105
- data/lib/rubypython/core_ext/string.rb +0 -7
- data/lib/rubypython/version.rb +0 -9
- data/spec/python_helpers/objects.pyc +0 -0
- metadata.gz.sig +0 -0
data/lib/rubypython/python.rb
CHANGED
@@ -1,185 +1,198 @@
|
|
1
1
|
require 'ffi'
|
2
|
-
require 'open3'
|
3
2
|
require 'rubypython/options'
|
3
|
+
require 'rubypython/pythonexec'
|
4
4
|
|
5
5
|
module RubyPython
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
PYTHON_EXE = RubyPython.options[:python_exe] || 'python'
|
15
|
-
# This much we can assume works without anything special at all.
|
16
|
-
PYTHON_VERSION = Open3.popen3("#{PYTHON_EXE} --version") { |i,o,e| e.read }.chomp.split[1].to_f
|
17
|
-
PYTHON_NAME = "python#{PYTHON_VERSION}"
|
18
|
-
LIB_NAME = "#{FFI::Platform::LIBPREFIX}#{PYTHON_NAME}"
|
19
|
-
LIB_EXT = FFI::Platform::LIBSUFFIX
|
20
|
-
PYTHON_SYS_PREFIX = %x{#{PYTHON_NAME} -c "import sys; print(sys.prefix)"}.chomp
|
21
|
-
|
22
|
-
# Here's where we run into problems, as not everything works quite the
|
23
|
-
# way we expect it to.
|
24
|
-
#
|
25
|
-
# The default libname will be something like libpython2.6.so (or .dylib)
|
26
|
-
# or maybe even python2.6.dll on Windows.
|
27
|
-
libname = "#{LIB_NAME}.#{LIB_EXT}"
|
28
|
-
|
29
|
-
# We may need to look in multiple locations for Python, so let's build
|
30
|
-
# this as an array.
|
31
|
-
locations = [ File.join(PYTHON_SYS_PREFIX, "lib", libname) ]
|
32
|
-
|
33
|
-
if FFI::Platform.mac?
|
34
|
-
# On the Mac, let's add a special case that has even a different
|
35
|
-
# libname. This may not be fully useful on future versions of OS X,
|
36
|
-
# but it should work on 10.5 and 10.6. Even if it doesn't, the next
|
37
|
-
# step will (/usr/lib/libpython<version>.dylib is a symlink to the
|
38
|
-
# correct location).
|
39
|
-
locations << File.join(PYTHON_SYS_PREFIX, "Python")
|
40
|
-
# Let's also look in the location that was originally set in this
|
41
|
-
# library:
|
42
|
-
File.join(PYTHON_SYS_PREFIX, "lib", "#{PYTHON_NAME}", "config",
|
43
|
-
libname)
|
44
|
-
end
|
45
|
-
|
46
|
-
if FFI::Platform.unix?
|
47
|
-
# On Unixes, let's look in alternative places, too. Just in case.
|
48
|
-
locations << File.join("/opt/local/lib", libname)
|
49
|
-
locations << File.join("/opt/lib", libname)
|
50
|
-
locations << File.join("/usr/local/lib", libname)
|
51
|
-
locations << File.join("/usr/lib", libname)
|
52
|
-
end
|
53
|
-
|
54
|
-
# Get rid of redundant locations.
|
55
|
-
locations.uniq!
|
56
|
-
|
57
|
-
dyld_flags = FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL
|
58
|
-
exceptions = []
|
59
|
-
|
60
|
-
locations.each do |location|
|
61
|
-
begin
|
62
|
-
@ffi_libs = [ FFI::DynamicLibrary.open(location, dyld_flags) ]
|
63
|
-
LIB = location
|
64
|
-
break
|
65
|
-
rescue LoadError => ex
|
66
|
-
@ffi_libs = nil
|
67
|
-
exceptions << ex
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
raise exceptions.first if @ffi_libs.nil?
|
72
|
-
|
73
|
-
#The class is a little bit of a hack to extract the address of global
|
74
|
-
#structs. If someone knows a better way please let me know.
|
75
|
-
class DummyStruct < FFI::Struct
|
76
|
-
layout :dummy_var, :int
|
77
|
-
end
|
78
|
-
|
79
|
-
#Python interpreter startup and shutdown
|
80
|
-
attach_function :Py_IsInitialized, [], :int
|
81
|
-
attach_function :Py_Initialize, [], :void
|
82
|
-
attach_function :Py_Finalize, [], :void
|
83
|
-
|
84
|
-
#Module methods
|
85
|
-
attach_function :PyImport_ImportModule, [:string], :pointer
|
86
|
-
|
87
|
-
#Object Methods
|
88
|
-
attach_function :PyObject_HasAttrString, [:pointer, :string], :int
|
89
|
-
attach_function :PyObject_GetAttrString, [:pointer, :string], :pointer
|
90
|
-
attach_function :PyObject_SetAttrString, [:pointer, :string, :pointer], :int
|
91
|
-
|
92
|
-
attach_function :PyObject_Compare, [:pointer, :pointer], :int
|
93
|
-
|
94
|
-
attach_function :PyObject_CallObject, [:pointer, :pointer], :pointer
|
95
|
-
attach_function :PyCallable_Check, [:pointer], :int
|
96
|
-
|
97
|
-
###Python To Ruby Conversion
|
98
|
-
#String Methods
|
99
|
-
attach_function :PyString_AsString, [:pointer], :string
|
100
|
-
attach_function :PyString_FromString, [:string], :pointer
|
101
|
-
|
102
|
-
#List Methods
|
103
|
-
attach_function :PyList_GetItem, [:pointer, :int], :pointer
|
104
|
-
attach_function :PyList_Size, [:pointer], :int
|
105
|
-
attach_function :PyList_New, [:int], :pointer
|
106
|
-
attach_function :PyList_SetItem, [:pointer, :int, :pointer], :void
|
107
|
-
|
108
|
-
#Integer Methods
|
109
|
-
attach_function :PyInt_AsLong, [:pointer], :long
|
110
|
-
attach_function :PyInt_FromLong, [:long], :pointer
|
111
|
-
|
112
|
-
attach_function :PyLong_AsLong, [:pointer], :long
|
113
|
-
attach_function :PyLong_FromLong, [:pointer], :long
|
114
|
-
|
115
|
-
#Float Methods
|
116
|
-
attach_function :PyFloat_AsDouble, [:pointer], :double
|
117
|
-
attach_function :PyFloat_FromDouble, [:double], :pointer
|
118
|
-
|
119
|
-
#Tuple Methods
|
120
|
-
attach_function :PySequence_List, [:pointer], :pointer
|
121
|
-
attach_function :PySequence_Tuple, [:pointer], :pointer
|
122
|
-
attach_function :PyTuple_Pack, [:int, :varargs], :pointer
|
123
|
-
|
124
|
-
#Dict/Hash Methods
|
125
|
-
attach_function :PyDict_Next, [:pointer, :pointer, :pointer, :pointer], :int
|
126
|
-
attach_function :PyDict_New, [], :pointer
|
127
|
-
attach_function :PyDict_SetItem, [:pointer, :pointer, :pointer], :int
|
128
|
-
attach_function :PyDict_Contains, [:pointer, :pointer], :int
|
129
|
-
attach_function :PyDict_GetItem, [:pointer, :pointer], :pointer
|
130
|
-
|
131
|
-
#Function Constants
|
132
|
-
METH_VARARGS = 1
|
133
|
-
attach_function :PyCFunction_New, [:pointer, :pointer], :pointer
|
134
|
-
callback :PyCFunction, [:pointer, :pointer], :pointer
|
135
|
-
|
136
|
-
#Error Methods
|
137
|
-
attach_function :PyErr_Fetch, [:pointer, :pointer, :pointer], :void
|
138
|
-
attach_function :PyErr_Occurred, [], :pointer
|
139
|
-
attach_function :PyErr_Clear, [], :void
|
140
|
-
|
141
|
-
#Reference Counting
|
142
|
-
attach_function :Py_IncRef, [:pointer], :void
|
143
|
-
attach_function :Py_DecRef, [:pointer], :void
|
144
|
-
|
145
|
-
#Type Objects
|
146
|
-
attach_variable :PyString_Type, DummyStruct.by_value
|
147
|
-
attach_variable :PyList_Type, DummyStruct.by_value
|
148
|
-
attach_variable :PyInt_Type, DummyStruct.by_value
|
149
|
-
attach_variable :PyLong_Type, DummyStruct.by_value
|
150
|
-
attach_variable :PyFloat_Type, DummyStruct.by_value
|
151
|
-
attach_variable :PyTuple_Type, DummyStruct.by_value
|
152
|
-
attach_variable :PyDict_Type, DummyStruct.by_value
|
153
|
-
attach_variable :PyFunction_Type, DummyStruct.by_value
|
154
|
-
attach_variable :PyCFunction_Type, DummyStruct.by_value
|
155
|
-
attach_variable :PyMethod_Type, DummyStruct.by_value
|
156
|
-
attach_variable :PyType_Type, DummyStruct.by_value
|
157
|
-
attach_variable :PyClass_Type, DummyStruct.by_value
|
158
|
-
|
159
|
-
attach_variable :Py_TrueStruct, :_Py_TrueStruct, DummyStruct.by_value
|
160
|
-
attach_variable :Py_ZeroStruct, :_Py_ZeroStruct, DummyStruct.by_value
|
161
|
-
attach_variable :Py_NoneStruct, :_Py_NoneStruct, DummyStruct.by_value
|
162
|
-
|
163
|
-
#This is an implementation of the basic structure of a Python PyObject
|
164
|
-
#struct. The C struct is actually much larger, but since we only access
|
165
|
-
#the first two data members via FFI and always deal with struct pointers
|
166
|
-
#there is no need to mess around with the rest of the object.
|
167
|
-
class PyObjectStruct < FFI::Struct
|
168
|
-
layout :ob_refcnt, :int,
|
169
|
-
:ob_type, :pointer
|
170
|
-
end
|
171
|
-
|
172
|
-
#This struct is used when defining Python methods.
|
173
|
-
class PyMethodDef < FFI::Struct
|
174
|
-
layout :ml_name, :pointer,
|
175
|
-
:ml_meth, :PyCFunction,
|
176
|
-
:ml_flags, :int,
|
177
|
-
:ml_doc, :pointer
|
178
|
-
end
|
6
|
+
unless defined? PYTHON_RB
|
7
|
+
PYTHON_RB = __FILE__
|
8
|
+
PYTHON_RB.freeze
|
9
|
+
end
|
10
|
+
|
11
|
+
module Python; end
|
12
|
+
end
|
179
13
|
|
14
|
+
if RubyPython.load_ffi?
|
15
|
+
# This module provides access to the \Python C API functions via the Ruby
|
16
|
+
# FFI gem.
|
17
|
+
#
|
18
|
+
# === Documentation
|
19
|
+
# * {Python C API}[http://docs.python.org/c-api/]
|
20
|
+
# * {Ruby FFI}[http://rdoc.info/projects/ffi/ffi]
|
21
|
+
module RubyPython::Python # :nodoc: all
|
22
|
+
extend FFI::Library
|
23
|
+
|
24
|
+
EXEC = RubyPython::PythonExec.new(RubyPython.options[:python_exe])
|
25
|
+
|
26
|
+
PYTHON_LIB = EXEC.library
|
27
|
+
# FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL
|
28
|
+
ffi_lib_flags :lazy, :global
|
29
|
+
ffi_lib EXEC.library
|
30
|
+
|
31
|
+
# The class is a little bit of a hack to extract the address of global
|
32
|
+
# structs. If someone knows a better way please let me know.
|
33
|
+
class DummyStruct < FFI::Struct # :nodoc:
|
34
|
+
layout :dummy_var, :int
|
180
35
|
end
|
181
36
|
|
182
|
-
|
183
|
-
|
37
|
+
PY_FILE_INPUT = 257
|
38
|
+
PY_EVAL_INPUT = 258
|
39
|
+
|
40
|
+
# Function methods & constants
|
41
|
+
METH_VARARGS = 0x0001
|
42
|
+
attach_function :PyCFunction_New, [:pointer, :pointer], :pointer
|
43
|
+
callback :PyCFunction, [:pointer, :pointer], :pointer
|
44
|
+
|
45
|
+
attach_function :PyRun_String, [:string, :int, :pointer, :pointer], :pointer
|
46
|
+
attach_function :PyRun_SimpleString, [:string], :pointer
|
47
|
+
attach_function :Py_CompileString, [:string, :string, :int], :pointer
|
48
|
+
attach_function :PyEval_EvalCode, [:pointer, :pointer, :pointer], :pointer
|
49
|
+
attach_function :PyErr_SetString, [:pointer, :string], :void
|
50
|
+
|
51
|
+
# Python interpreter startup and shutdown
|
52
|
+
attach_function :Py_IsInitialized, [], :int
|
53
|
+
attach_function :Py_Initialize, [], :void
|
54
|
+
attach_function :Py_Finalize, [], :void
|
55
|
+
|
56
|
+
# Module methods
|
57
|
+
attach_function :PyImport_ImportModule, [:string], :pointer
|
58
|
+
|
59
|
+
# Object Methods
|
60
|
+
attach_function :PyObject_HasAttrString, [:pointer, :string], :int
|
61
|
+
attach_function :PyObject_GetAttrString, [:pointer, :string], :pointer
|
62
|
+
attach_function :PyObject_SetAttrString, [:pointer, :string, :pointer], :int
|
63
|
+
attach_function :PyObject_Dir, [:pointer], :pointer
|
64
|
+
|
65
|
+
attach_function :PyObject_Compare, [:pointer, :pointer], :int
|
66
|
+
|
67
|
+
attach_function :PyObject_Call, [:pointer, :pointer, :pointer], :pointer
|
68
|
+
attach_function :PyObject_CallObject, [:pointer, :pointer], :pointer
|
69
|
+
attach_function :PyCallable_Check, [:pointer], :int
|
70
|
+
|
71
|
+
### Python To Ruby Conversion
|
72
|
+
# String Methods
|
73
|
+
attach_function :PyString_AsString, [:pointer], :string
|
74
|
+
attach_function :PyString_FromString, [:string], :pointer
|
75
|
+
attach_function :PyString_AsStringAndSize, [:pointer, :pointer, :pointer], :int
|
76
|
+
attach_function :PyString_FromStringAndSize, [:buffer_in, :ssize_t], :pointer
|
77
|
+
|
78
|
+
# List Methods
|
79
|
+
attach_function :PyList_GetItem, [:pointer, :int], :pointer
|
80
|
+
attach_function :PyList_Size, [:pointer], :int
|
81
|
+
attach_function :PyList_New, [:int], :pointer
|
82
|
+
attach_function :PyList_SetItem, [:pointer, :int, :pointer], :void
|
83
|
+
|
84
|
+
# Integer Methods
|
85
|
+
attach_function :PyInt_AsLong, [:pointer], :long
|
86
|
+
attach_function :PyInt_FromLong, [:long], :pointer
|
87
|
+
|
88
|
+
attach_function :PyLong_AsLong, [:pointer], :long
|
89
|
+
attach_function :PyLong_FromLong, [:pointer], :long
|
90
|
+
|
91
|
+
# Float Methods
|
92
|
+
attach_function :PyFloat_AsDouble, [:pointer], :double
|
93
|
+
attach_function :PyFloat_FromDouble, [:double], :pointer
|
94
|
+
|
95
|
+
# Tuple Methods
|
96
|
+
attach_function :PySequence_List, [:pointer], :pointer
|
97
|
+
attach_function :PySequence_Tuple, [:pointer], :pointer
|
98
|
+
attach_function :PyTuple_Pack, [:int, :varargs], :pointer
|
99
|
+
|
100
|
+
# Dict/Hash Methods
|
101
|
+
attach_function :PyDict_Next, [:pointer, :pointer, :pointer, :pointer], :int
|
102
|
+
attach_function :PyDict_New, [], :pointer
|
103
|
+
attach_function :PyDict_SetItem, [:pointer, :pointer, :pointer], :int
|
104
|
+
attach_function :PyDict_Contains, [:pointer, :pointer], :int
|
105
|
+
attach_function :PyDict_GetItem, [:pointer, :pointer], :pointer
|
106
|
+
|
107
|
+
# Error Methods
|
108
|
+
attach_variable :PyExc_Exception, DummyStruct.by_ref
|
109
|
+
attach_variable :PyExc_StopIteration, DummyStruct.by_ref
|
110
|
+
attach_function :PyErr_SetNone, [:pointer], :void
|
111
|
+
attach_function :PyErr_Fetch, [:pointer, :pointer, :pointer], :void
|
112
|
+
attach_function :PyErr_Occurred, [], :pointer
|
113
|
+
attach_function :PyErr_Clear, [], :void
|
114
|
+
|
115
|
+
# Reference Counting
|
116
|
+
attach_function :Py_IncRef, [:pointer], :void
|
117
|
+
attach_function :Py_DecRef, [:pointer], :void
|
118
|
+
|
119
|
+
# Type Objects
|
120
|
+
# attach_variable :PyBaseObject_Type, DummyStruct.by_value # built-in 'object'
|
121
|
+
# attach_variable :PyBaseString_Type, DummyStruct.by_value
|
122
|
+
# attach_variable :PyBool_Type, DummyStruct.by_value
|
123
|
+
# attach_variable :PyBuffer_Type, DummyStruct.by_value
|
124
|
+
# attach_variable :PyByteArrayIter_Type, DummyStruct.by_value
|
125
|
+
# attach_variable :PyByteArray_Type, DummyStruct.by_value
|
126
|
+
attach_variable :PyCFunction_Type, DummyStruct.by_value
|
127
|
+
# attach_variable :PyCObject_Type, DummyStruct.by_value
|
128
|
+
# attach_variable :PyCallIter_Type, DummyStruct.by_value
|
129
|
+
# attach_variable :PyCapsule_Type, DummyStruct.by_value
|
130
|
+
# attach_variable :PyCell_Type, DummyStruct.by_value
|
131
|
+
# attach_variable :PyClassMethod_Type, DummyStruct.by_value
|
132
|
+
attach_variable :PyClass_Type, DummyStruct.by_value
|
133
|
+
# attach_variable :PyCode_Type, DummyStruct.by_value
|
134
|
+
# attach_variable :PyComplex_Type, DummyStruct.by_value
|
135
|
+
# attach_variable :PyDictItems_Type, DummyStruct.by_value
|
136
|
+
# attach_variable :PyDictIterItem_Type, DummyStruct.by_value
|
137
|
+
# attach_variable :PyDictIterKey_Type, DummyStruct.by_value
|
138
|
+
# attach_variable :PyDictIterValue_Type, DummyStruct.by_value
|
139
|
+
# attach_variable :PyDictKeys_Type, DummyStruct.by_value
|
140
|
+
# attach_variable :PyDictProxy_Type, DummyStruct.by_value
|
141
|
+
# attach_variable :PyDictValues_Type, DummyStruct.by_value
|
142
|
+
attach_variable :PyDict_Type, DummyStruct.by_value
|
143
|
+
# attach_variable :PyEllipsis_Type, DummyStruct.by_value
|
144
|
+
# attach_variable :PyEnum_Type, DummyStruct.by_value
|
145
|
+
# attach_variable :PyFile_Type, DummyStruct.by_value
|
146
|
+
attach_variable :PyFloat_Type, DummyStruct.by_value
|
147
|
+
# attach_variable :PyFrame_Type, DummyStruct.by_value
|
148
|
+
# attach_variable :PyFrozenSet_Type, DummyStruct.by_value
|
149
|
+
attach_variable :PyFunction_Type, DummyStruct.by_value
|
150
|
+
# attach_variable :PyGen_Type, DummyStruct.by_value
|
151
|
+
# attach_variable :PyGetSetDescr_Type, DummyStruct.by_value
|
152
|
+
# attach_variable :PyInstance_Type, DummyStruct.by_value
|
153
|
+
attach_variable :PyInt_Type, DummyStruct.by_value
|
154
|
+
attach_variable :PyList_Type, DummyStruct.by_value
|
155
|
+
attach_variable :PyLong_Type, DummyStruct.by_value
|
156
|
+
# attach_variable :PyMemberDescr_Type, DummyStruct.by_value
|
157
|
+
# attach_variable :PyMemoryView_Type, DummyStruct.by_value
|
158
|
+
attach_variable :PyMethod_Type, DummyStruct.by_value
|
159
|
+
# attach_variable :PyModule_Type, DummyStruct.by_value
|
160
|
+
# attach_variable :PyNullImporter_Type, DummyStruct.by_value
|
161
|
+
# attach_variable :PyProperty_Type, DummyStruct.by_value
|
162
|
+
# attach_variable :PyRange_Type, DummyStruct.by_value
|
163
|
+
# attach_variable :PyReversed_Type, DummyStruct.by_value
|
164
|
+
# attach_variable :PySTEntry_Type, DummyStruct.by_value
|
165
|
+
# attach_variable :PySeqIter_Type, DummyStruct.by_value
|
166
|
+
# attach_variable :PySet_Type, DummyStruct.by_value
|
167
|
+
# attach_variable :PySlice_Type, DummyStruct.by_value
|
168
|
+
# attach_variable :PyStaticMethod_Type, DummyStruct.by_value
|
169
|
+
attach_variable :PyString_Type, DummyStruct.by_value
|
170
|
+
# attach_variable :PySuper_Type, DummyStruct.by_value # built-in 'super'
|
171
|
+
# attach_variable :PyTraceBack_Type, DummyStruct.by_value
|
172
|
+
attach_variable :PyTuple_Type, DummyStruct.by_value
|
173
|
+
attach_variable :PyType_Type, DummyStruct.by_value
|
174
|
+
# attach_variable :PyUnicode_Type, DummyStruct.by_value
|
175
|
+
# attach_variable :PyWrapperDescr_Type, DummyStruct.by_value
|
176
|
+
|
177
|
+
attach_variable :Py_TrueStruct, :_Py_TrueStruct, DummyStruct.by_value
|
178
|
+
attach_variable :Py_ZeroStruct, :_Py_ZeroStruct, DummyStruct.by_value
|
179
|
+
attach_variable :Py_NoneStruct, :_Py_NoneStruct, DummyStruct.by_value
|
180
|
+
|
181
|
+
# This is an implementation of the basic structure of a Python PyObject
|
182
|
+
# struct. The C struct is actually much larger, but since we only access
|
183
|
+
# the first two data members via FFI and always deal with struct
|
184
|
+
# pointers there is no need to mess around with the rest of the object.
|
185
|
+
class PyObjectStruct < FFI::Struct
|
186
|
+
layout :ob_refcnt, :ssize_t,
|
187
|
+
:ob_type, :pointer
|
188
|
+
end
|
189
|
+
|
190
|
+
# This struct is used when defining Python methods.
|
191
|
+
class PyMethodDef < FFI::Struct
|
192
|
+
layout :ml_name, :pointer,
|
193
|
+
:ml_meth, :PyCFunction,
|
194
|
+
:ml_flags, :int,
|
195
|
+
:ml_doc, :pointer
|
196
|
+
end
|
184
197
|
end
|
185
198
|
end
|
@@ -1,78 +1,69 @@
|
|
1
1
|
require 'rubypython/python'
|
2
2
|
require 'rubypython/macros'
|
3
3
|
|
4
|
+
# Raised when an error occurs in the \Python interpreter.
|
5
|
+
class RubyPython::PythonError < RuntimeError
|
6
|
+
# Creates the PythonError.
|
7
|
+
# [typeName] The class name of the \Python error.
|
8
|
+
# [msg] The message attached to the \Python error.
|
9
|
+
def initialize(typeName, msg)
|
10
|
+
@type = typeName
|
11
|
+
super([typeName, msg].join(': '))
|
12
|
+
end
|
4
13
|
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@type = typeName
|
14
|
-
super([typeName, msg].join(': '))
|
15
|
-
end
|
16
|
-
|
17
|
-
#This method should be called when an error has occured in the
|
18
|
-
#Python interpreter. This acts as factory function for PythonError
|
19
|
-
#objects. The function fetchs calls {fetch} to get the error
|
20
|
-
#information from the Python interpreter and uses this to build
|
21
|
-
#a PythonError object. It then calls {clear} to clear the error
|
22
|
-
#flag of the python interpreter
|
23
|
-
#@return [PythonError] an error enscapsulating the Python error
|
24
|
-
def self.handle_error
|
25
|
-
rbType, rbValue, rbTraceback = fetch()
|
26
|
-
|
27
|
-
if not rbValue.null?
|
28
|
-
msg = rbValue.getAttr("__str__").callObject PyObject.buildArgTuple
|
29
|
-
msg = msg.rubify
|
30
|
-
else
|
31
|
-
msg = nil
|
32
|
-
end
|
33
|
-
|
34
|
-
#Decrease the reference count. This will happen anyway when they go
|
35
|
-
#out of scope but might as well.
|
36
|
-
rbValue.xDecref
|
37
|
-
rbTraceback.xDecref
|
38
|
-
pyName = rbType.getAttr("__name__")
|
14
|
+
# This method should be called when an error has occurred in the \Python
|
15
|
+
# interpreter. This acts as factory function for PythonError objects. The
|
16
|
+
# function fetches calls +#fetch+ to get the error information from the
|
17
|
+
# \Python interpreter and uses this to build a PythonError object. It then
|
18
|
+
# calls +#clear to clear the error flag in the python interpreter. After
|
19
|
+
# the error flag has been cleared, the PythonError object is returned.
|
20
|
+
def self.handle_error
|
21
|
+
rbType, rbValue, rbTraceback = fetch()
|
39
22
|
|
40
|
-
|
41
|
-
|
42
|
-
|
23
|
+
if not rbValue.null?
|
24
|
+
msg = rbValue.getAttr("__str__").callObject RubyPython::PyObject.buildArgTuple
|
25
|
+
msg = msg.rubify
|
26
|
+
else
|
27
|
+
msg = nil
|
28
|
+
end
|
43
29
|
|
44
|
-
|
30
|
+
# Decrease the reference count. This will happen anyway when they go out
|
31
|
+
# of scope but might as well.
|
32
|
+
rbValue.xDecref
|
33
|
+
rbTraceback.xDecref
|
34
|
+
pyName = rbType.getAttr("__name__")
|
45
35
|
|
46
|
-
|
47
|
-
|
36
|
+
rbType.xDecref
|
37
|
+
rbName = pyName.rubify
|
38
|
+
pyName.xDecref
|
48
39
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
# error respectively.
|
53
|
-
def self.fetch
|
54
|
-
typePointer = FFI::MemoryPointer.new :pointer
|
55
|
-
valuePointer = FFI::MemoryPointer.new :pointer
|
56
|
-
tracebackPointer = FFI::MemoryPointer.new :pointer
|
40
|
+
RubyPython::PythonError.clear
|
41
|
+
RubyPython::PythonError.new(rbName, msg)
|
42
|
+
end
|
57
43
|
|
58
|
-
|
44
|
+
# A wrapper to the \Python C API +PyErr_Fetch+ function. Returns an array
|
45
|
+
# with three PyObject instances, representing the Type, the Value, and the
|
46
|
+
# stack trace of the Python error.
|
47
|
+
def self.fetch
|
48
|
+
typePointer = FFI::MemoryPointer.new :pointer
|
49
|
+
valuePointer = FFI::MemoryPointer.new :pointer
|
50
|
+
tracebackPointer = FFI::MemoryPointer.new :pointer
|
59
51
|
|
60
|
-
|
61
|
-
rbValue = PyObject.new valuePointer.read_pointer
|
62
|
-
rbTraceback = PyObject.new tracebackPointer.read_pointer
|
63
|
-
[rbType, rbValue, rbTraceback]
|
64
|
-
end
|
52
|
+
RubyPython::Python.PyErr_Fetch typePointer, valuePointer, tracebackPointer
|
65
53
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
54
|
+
rbType = RubyPython::PyObject.new typePointer.read_pointer
|
55
|
+
rbValue = RubyPython::PyObject.new valuePointer.read_pointer
|
56
|
+
rbTraceback = RubyPython::PyObject.new tracebackPointer.read_pointer
|
57
|
+
[rbType, rbValue, rbTraceback]
|
58
|
+
end
|
70
59
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
60
|
+
# Determines whether an error has occurred in the \Python interpreter.
|
61
|
+
def self.error?
|
62
|
+
!RubyPython::Python.PyErr_Occurred.null?
|
63
|
+
end
|
76
64
|
|
65
|
+
# Resets the \Python interpreter error flag
|
66
|
+
def self.clear
|
67
|
+
RubyPython::Python.PyErr_Clear
|
77
68
|
end
|
78
69
|
end
|