rubypython 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
@@ -8,3 +8,4 @@ RubyPython has a growing list of contributors.
8
8
  * Austin Ziegler (halostatue)
9
9
  * Aman Gupta (tmm1)
10
10
  * Ben Doerr (bendoerr)
11
+ * Akzhan Abdulin (azkhan)
@@ -1,3 +1,12 @@
1
+ === 0.6.3 / 2012-09-25
2
+ * Major Enhancements
3
+ * Legacy Mode removed
4
+ * Minor Enhancements
5
+ * Depend on newer versions of FFI
6
+ * Make RubyPython correctly detect python on archlinux. [madjar]
7
+ * Bug Fixes:
8
+ * Fixed some memory leaks, but still looking for others.
9
+
1
10
  === 0.6.2 / 2012-05-24
2
11
  * Bug Fixes:
3
12
  * Fixed a possible namespace collision bug with the FFI library. [Akzhan]
@@ -12,7 +12,6 @@ lib/rubypython.rb
12
12
  lib/rubypython/blankobject.rb
13
13
  lib/rubypython/conversion.rb
14
14
  lib/rubypython/interpreter.rb
15
- lib/rubypython/legacy.rb
16
15
  lib/rubypython/macros.rb
17
16
  lib/rubypython/operators.rb
18
17
  lib/rubypython/pygenerator.rb
@@ -26,7 +25,6 @@ lib/rubypython/type.rb
26
25
  spec/basic_spec.rb
27
26
  spec/callback_spec.rb
28
27
  spec/conversion_spec.rb
29
- spec/legacy_spec.rb
30
28
  spec/pymainclass_spec.rb
31
29
  spec/pyobject_spec.rb
32
30
  spec/python_helpers/basics.py
data/Rakefile CHANGED
@@ -23,7 +23,7 @@ Hoe.spec 'rubypython' do
23
23
  self.readme_file = 'README.rdoc'
24
24
  self.extra_rdoc_files = FileList["*.rdoc"].to_a
25
25
 
26
- self.extra_deps << ['ffi', '~> 1.0.7']
26
+ self.extra_deps << ['ffi', '>= 1.0.7']
27
27
  self.extra_deps << ['blankslate', '>= 2.1.2.3']
28
28
 
29
29
  self.extra_dev_deps << ['rspec', '~> 2.0']
@@ -15,7 +15,7 @@
15
15
  # puts cPickle.dumps("RubyPython is awesome!").rubify
16
16
  # RubyPython.stop
17
17
  module RubyPython
18
- VERSION = '0.6.2'
18
+ VERSION = '0.6.3'
19
19
  end
20
20
 
21
21
  require 'rubypython/blankobject'
@@ -31,63 +31,6 @@ require 'thread'
31
31
 
32
32
  module RubyPython
33
33
  class << self
34
- ##
35
- # :attr_accessor:
36
- # Controls whether RubyPython is operating in <em>Proxy Mode</em> or
37
- # <em>Legacy Mode</em>. This behavioural difference is deprecated as of
38
- # RubyPython 0.6 and will be removed in a subsequent release.
39
- #
40
- # === Proxy Mode
41
- # By default, +legacy_mode+ is +false+, meaning that any object returned
42
- # from a \Python function call will be wrapped in a Ruby-Python proxy
43
- # (an instance of +RubyPyProxy+ or one of its subclasses). This allows
44
- # \Python method calls to be forwarded to the \Python object, even if it
45
- # would otherwise be a native Ruby object.
46
- #
47
- # RubyPython.session do
48
- # string = RubyPython.import 'string'
49
- # ascii_letters = string.ascii_letters
50
- # puts ascii_letters.isalpha # => True
51
- # puts ascii_letters.rubify.isalpha # throws NoMethodError
52
- # end
53
- #
54
- # === Legacy Mode
55
- # If +legacy_mode+ is +true+, RubyPython automatically tries to convert
56
- # returned objects to native Ruby object types. If there is no such
57
- # conversion, the object remains wrapped in +RubyPyProxy+. This
58
- # behaviour is the same as RubyPython 0.2 and earlier. This mode is
59
- # deprecated as of RubyPython 0.6 and will be removed.
60
- #
61
- # RubyPython.legacy_mode = true
62
- # RubyPython.session do
63
- # string = RubyPython.import 'string'
64
- # ascii_letters = string.ascii_letters
65
- # puts ascii_letters.isalpha # throws NoMethodError
66
- # end
67
- def legacy_mode=(value)
68
- warn_legacy_mode_deprecation unless defined? @legacy_mode
69
- @legacy_mode = value
70
- end
71
-
72
- def legacy_mode
73
- unless defined? @legacy_mode
74
- warn_legacy_mode_deprecation
75
- @legacy_mode = nil
76
- end
77
- @legacy_mode
78
- end
79
-
80
- def legacy_mode?
81
- @legacy_mode = nil unless defined? @legacy_mode
82
- @legacy_mode
83
- end
84
- private :legacy_mode?
85
-
86
- def warn_legacy_mode_deprecation
87
- warn "RubyPython's Legacy Mode is deprecated and will be removed after version #{VERSION}."
88
- end
89
- private :warn_legacy_mode_deprecation
90
-
91
34
  ## Starts the \Python interpreter. One of +RubyPython.start+,
92
35
  # RubyPython.session+, or +RubyPython.run+ must be run before using any
93
36
  # \Python code. Returns +true+ if the interpreter was started; +false+
@@ -108,7 +51,7 @@ module RubyPython
108
51
  # p sys.version # => "2.7.1"
109
52
  # RubyPython.stop
110
53
  def start(options = {})
111
- Mutex.new.synchronize do
54
+ RubyPython::Python.synchronize do
112
55
  # Has the Runtime interpreter been defined?
113
56
  if self.const_defined?(:Runtime)
114
57
  # If this constant is defined, then yes it is. Since it is, let's
@@ -124,16 +67,16 @@ module RubyPython
124
67
  raise RubyPython::InvalidInterpreter, "An invalid interpreter was specified."
125
68
  end
126
69
  end
127
-
70
+
128
71
  unless defined? RubyPython::Python.ffi_libraries
129
72
  Runtime.__send__(:infect!, RubyPython::Python)
130
73
  end
131
- end
132
74
 
133
- return false if RubyPython::Python.Py_IsInitialized != 0
134
- RubyPython::Python.Py_Initialize
135
- notify :start
136
- true
75
+ return false if RubyPython::Python.Py_IsInitialized != 0
76
+ RubyPython::Python.Py_Initialize
77
+ notify :start
78
+ true
79
+ end
137
80
  end
138
81
 
139
82
  # Stops the \Python interpreter if it is running. Returns +true+ if the
@@ -141,12 +84,14 @@ module RubyPython
141
84
  # invocation of this method. If you need the values within the \Python
142
85
  # proxy objects, be sure to call +RubyPyProxy#rubify+ on them.
143
86
  def stop
144
- if defined? Python.Py_IsInitialized and Python.Py_IsInitialized != 0
145
- Python.Py_Finalize
146
- notify :stop
147
- true
148
- else
149
- false
87
+ RubyPython::Python.synchronize do
88
+ if defined? Python.Py_IsInitialized and Python.Py_IsInitialized != 0
89
+ Python.Py_Finalize
90
+ notify :stop
91
+ true
92
+ else
93
+ false
94
+ end
150
95
  end
151
96
  end
152
97
 
@@ -11,12 +11,18 @@ module RubyPython::Conversion
11
11
  # Raised when RubyPython does not know how to convert an object from
12
12
  # \Python to Ruby or vice versa.
13
13
  class UnsupportedConversion < Exception; end
14
+ class ConversionError < RuntimeError; end
14
15
 
15
16
  # Convert a Ruby string to a \Python string. Returns an FFI::Pointer to
16
17
  # a PyStringObject.
17
18
  def self.rtopString(rString)
18
19
  size = rString.respond_to?(:bytesize) ? rString.bytesize : rString.size
19
- RubyPython::Python.PyString_FromStringAndSize(rString, size)
20
+ ptr = RubyPython::Python.PyString_FromStringAndSize(rString, size)
21
+ if ptr.null?
22
+ raise ConversionError.new "Python failed to create a string with contents #{rString}"
23
+ else
24
+ ptr
25
+ end
20
26
  end
21
27
 
22
28
  # Convert a Ruby Array to \Python List. Returns an FFI::Pointer to
@@ -24,8 +30,15 @@ module RubyPython::Conversion
24
30
  def self.rtopArrayToList(rArray)
25
31
  size = rArray.length
26
32
  pList = RubyPython::Python.PyList_New size
33
+ if pList.null?
34
+ raise ConversionError.new "Python failed to create list of size #{size}"
35
+ end
27
36
  rArray.each_with_index do |el, i|
28
- RubyPython::Python.PyList_SetItem pList, i, rtopObject(el)
37
+ # PyList_SetItem steals a reference, but rtopObject creates a new reference
38
+ # So we wind up with giving a new reference to the Python interpreter for every
39
+ # object
40
+ ret = RubyPython::Python.PyList_SetItem pList, i, rtopObject(el)
41
+ raise ConversionError.new "Failed to set item #{el} in array conversion" if ret == -1
29
42
  end
30
43
  pList
31
44
  end
@@ -34,8 +47,11 @@ module RubyPython::Conversion
34
47
  # \Python \tuple. Returns an FFI::Pointer to a PyTupleObject.
35
48
  def self.rtopArrayToTuple(rArray)
36
49
  pList = rtopArrayToList(rArray)
37
- pTuple = RubyPython::Python.PySequence_Tuple(pList)
50
+ pTuple = RubyPython::Python.PyList_AsTuple(pList)
38
51
  RubyPython::Python.Py_DecRef(pList)
52
+ if pTuple.null?
53
+ raise Conversion.new "Python failed to convert an intermediate list of #{rArray} to a tuple"
54
+ end
39
55
  pTuple
40
56
  end
41
57
 
@@ -43,29 +59,49 @@ module RubyPython::Conversion
43
59
  # PyDictObject.
44
60
  def self.rtopHash(rHash)
45
61
  pDict = RubyPython::Python.PyDict_New
62
+ if pDict.null?
63
+ raise ConversionError.new "Python failed to create new dict"
64
+ end
46
65
  rHash.each do |k,v|
47
- RubyPython::Python.PyDict_SetItem pDict, rtopObject(k, key = true),
48
- rtopObject(v)
66
+ key = rtopObject(k, :key => true)
67
+ value = rtopObject(v)
68
+
69
+ # PyDict_SetItem INCREFS both the key and the value passed to it.
70
+ # Since rtopObject already gives us a new reference, this is not necessary.
71
+ # Thus, we decref the passed in objects to balancy things out
72
+ if RubyPython::Python.PyDict_SetItem(pDict, key, value) == -1
73
+ raise ConversionError.new "Python failed to set #{key}, #{value} in dict conversion"
74
+ end
75
+
76
+ RubyPython::Python.Py_DecRef key
77
+ RubyPython::Python.Py_DecRef value
49
78
  end
79
+
50
80
  pDict
51
81
  end
52
82
 
53
83
  # Convert a Ruby Fixnum to a \Python Int. Returns an FFI::Pointer to a
54
84
  # PyIntObject.
55
85
  def self.rtopFixnum(rNum)
56
- RubyPython::Python.PyInt_FromLong(rNum)
86
+ num = RubyPython::Python.PyInt_FromLong(rNum)
87
+ raise ConversionError.new "Failed to convert #{rNum}" if num.null?
88
+ num
57
89
  end
58
90
 
59
91
  # Convert a Ruby Bignum to a \Python Long. Returns an FFI::Pointer to a
60
92
  # PyLongObject.
61
93
  def self.rtopBigNum(rNum)
62
- RubyPython::Python.PyLong_FromLong(rNum)
94
+ num = RubyPython::Python.PyLong_FromLong(rNum)
95
+ raise ConversionError.new "Failed to convert #{rNum}" if num.null?
96
+ num
63
97
  end
64
98
 
65
99
  # Convert a Ruby float to a \Python Float. Returns an FFI::Pointer to a
66
100
  # PyFloatObject.
67
101
  def self.rtopFloat(rNum)
68
- RubyPython::Python.PyFloat_FromDouble(rNum)
102
+ num = RubyPython::Python.PyFloat_FromDouble(rNum)
103
+ raise ConversionError.new "Failed to convert #{rNum}" if num.null?
104
+ num
69
105
  end
70
106
 
71
107
  # Returns a \Python False value (equivalent to Ruby's +false+). Returns an
@@ -89,7 +125,7 @@ module RubyPython::Conversion
89
125
  # Convert a Ruby Symbol to a \Python String. Returns an FFI::Pointer to a
90
126
  # PyStringObject.
91
127
  def self.rtopSymbol(rSymbol)
92
- RubyPython::Python.PyString_FromString rSymbol.to_s
128
+ rtopString rSymbol.to_s
93
129
  end
94
130
 
95
131
  # Convert a Ruby Proc to a \Python Function. Returns an FFI::Pointer to a
@@ -115,7 +151,7 @@ module RubyPython::Conversion
115
151
 
116
152
  # This will attempt to convert a Ruby object to an equivalent \Python
117
153
  # native type. Returns an FFI::Pointer to a \Python object (the
118
- # appropriate Py…Object C structure). If the conversion is unsuccessful,
154
+ # appropriate Py_Object C structure). If the conversion is unsuccessful,
119
155
  # will raise UnsupportedConversion.
120
156
  #
121
157
  # [rObj] A native Ruby object.
@@ -151,16 +187,14 @@ module RubyPython::Conversion
151
187
  when Symbol
152
188
  rtopSymbol rObj
153
189
  when Proc, Method
154
- if RubyPython.legacy_mode
155
- raise UnsupportedConversion.new("Callbacks are not supported in Legacy Mode.")
156
- end
157
- rtopFunction rObj
158
- when Method
159
190
  rtopFunction rObj
160
191
  when nil
161
192
  rtopNone
162
193
  when RubyPython::PyObject
194
+ rObj.xIncref
163
195
  rObj.pointer
196
+ when RubyPython::RubyPyProxy
197
+ rtopObject(rObj.pObject, is_key)
164
198
  else
165
199
  raise UnsupportedConversion.new("Unsupported type #{rObj.class} for conversion.")
166
200
  end
@@ -169,6 +203,9 @@ module RubyPython::Conversion
169
203
  # Convert an FFI::Pointer to a \Python String (PyStringObject) to a Ruby
170
204
  # String.
171
205
  def self.ptorString(pString)
206
+ #strPtr is a pointer to a pointer to the internal character array.
207
+ #FFI will free strPtr when we are done but the internal array MUST
208
+ #not be modified
172
209
  strPtr = ::FFI::MemoryPointer.new(:pointer)
173
210
  sizePtr = ::FFI::MemoryPointer.new(:ssize_t)
174
211
 
@@ -196,8 +233,6 @@ module RubyPython::Conversion
196
233
 
197
234
  list_size.times do |i|
198
235
  element = RubyPython::Python.PyList_GetItem(pList, i)
199
- # PyList_GetItem returns borrowed ref
200
- RubyPython::Python.Py_IncRef element
201
236
  rObject = ptorObject(element)
202
237
  rb_array.push rObject
203
238
  end
@@ -226,6 +261,8 @@ module RubyPython::Conversion
226
261
  # Convert an FFI::Pointer to a \Python Tuple (PyTupleObject) to an
227
262
  # instance of RubyPython::Tuple, a subclass of the Ruby Array class.
228
263
  def self.ptorTuple(pTuple)
264
+ #PySequence_List returns a new list. Since we are only using it as a temporary
265
+ #here, we will have to DecRef it once we are done.
229
266
  pList = RubyPython::Python.PySequence_List pTuple
230
267
  rArray = ptorList pList
231
268
  RubyPython::Python.Py_DecRef pList
@@ -243,10 +280,16 @@ module RubyPython::Conversion
243
280
  val = ::FFI::MemoryPointer.new :pointer
244
281
 
245
282
  while RubyPython::Python.PyDict_Next(pDict, pos, key, val) != 0
283
+ #PyDict_Next sets key and val to borrowed references. We do not care
284
+ #if we are able to convert them to native ruby types, but if we wind up
285
+ #wrapping either in a proxy we better IncRef it to make sure it stays
286
+ #around.
246
287
  pKey = key.read_pointer
247
288
  pVal = val.read_pointer
248
289
  rKey = ptorObject(pKey)
249
290
  rVal = ptorObject(pVal)
291
+ RubyPython.Py_IncRef pKey if rKey.kind_of? ::FFI::Pointer
292
+ RubyPython.Py_IncRef pVal if rVal.kind_of? ::FFI::Pointer
250
293
  rb_hash[rKey] = rVal
251
294
  end
252
295
 
@@ -40,6 +40,14 @@ class RubyPython::Interpreter
40
40
  @python_exe = options[:python_exe]
41
41
  # Windows: 'C:\\Python27\python.exe'
42
42
  # Mac OS X: '/usr/bin/
43
+
44
+ # The default interpreter might be python3 on some systems
45
+ rc, majorversion = runpy "import sys; print(sys.version_info[0])"
46
+ if majorversion == "3"
47
+ warn "The python interpreter is python 3, switching to python2"
48
+ @python_exe = "python2"
49
+ end
50
+
43
51
  rc, @python = runpy "import sys; print sys.executable"
44
52
  if rc.exitstatus.nonzero?
45
53
  raise RubyPython::InvalidInterpreter, "An invalid interpreter was specified."
@@ -58,9 +66,10 @@ class RubyPython::Interpreter
58
66
  end
59
67
  else
60
68
  basename = File.basename(@python)
61
-
62
69
  if basename =~ /#{@version}/
63
70
  @version_name = basename
71
+ elsif basename.end_with?("2")
72
+ @version_name = "#{basename[0..-2]}#{@version}"
64
73
  else
65
74
  @version_name = "#{basename}#{@version}"
66
75
  end
@@ -9,9 +9,7 @@ module RubyPython::Operators
9
9
  @@operator ||= RubyPython.import('operator')
10
10
  end
11
11
 
12
- # Creates a method to delegate a binary operation. The result of the
13
- # operation will follow the conversion rules appropriate to the current
14
- # mode of operation as set by {RubyPython.legacy_mode}.
12
+ # Creates a method to delegate a binary operation.
15
13
  # [rname] The name of the Ruby method for this operation. Can be either a
16
14
  # Symbol or a String.
17
15
  # [pname] The name of the \Python magic method to which this method should
@@ -37,10 +35,8 @@ module RubyPython::Operators
37
35
  end
38
36
  end
39
37
 
40
- # Creates a method to delegate a relational operator. The result of the
41
- # operation will follow the conversion rules appropriate to the current
42
- # mode of operation as set by {RubyPython.legacy_mode}. These methods are
43
- # implemented with calls the _operator_ module.
38
+ # Creates a method to delegate a relational operator.
39
+ # These methods are implemented with calls the _operator_ module.
44
40
  # [rname] The name of the Ruby method for this operation. Can be a Symbol
45
41
  # or a String.
46
42
  # [pname] The name of the \Python magic method to which this method should
@@ -27,6 +27,10 @@ class RubyPython::PyObject # :nodoc: all
27
27
  def release(pointer)
28
28
  obj_id = pointer.object_id
29
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
30
34
  if deleted and (RubyPython::Python.Py_IsInitialized != 0)
31
35
  RubyPython::Python.Py_DecRef pointer
32
36
  end
@@ -95,6 +99,7 @@ class RubyPython::PyObject # :nodoc: all
95
99
  # [rbPyAttr] A PyObject wrapper around the value that we wish to set the
96
100
  # attribute to.
97
101
  def setAttr(attrName, rbPyAttr)
102
+ #SetAttrString should incref whatever gets passed to it.
98
103
  RubyPython::Python.PyObject_SetAttrString(@pointer, attrName, rbPyAttr.pointer) != -1
99
104
  end
100
105
 
@@ -119,8 +124,7 @@ class RubyPython::PyObject # :nodoc: all
119
124
  # Decrease the reference count of the wrapped object.
120
125
  def xDecref
121
126
  AutoPyPointer.release(@pointer)
122
- @pointer.free
123
- nil
127
+ @pointer = nil
124
128
  end
125
129
 
126
130
  # Increase the reference count of the wrapped object
@@ -174,59 +178,12 @@ class RubyPython::PyObject # :nodoc: all
174
178
  check != 0
175
179
  end
176
180
 
177
- # Manipulates the supplied PyObject instance such that it is suitable to
178
- # passed to #callObject or #callObjectKeywords. If +rbObject+ is a tuple
179
- # then the argument passed in is returned. If it is a list then the list
180
- # is converted to a tuple. Otherwise returns a tuple with one element:
181
- # +rbObject+.
182
- # [rbObject] The argument to be turned into a Tuple.
183
- def self.makeTuple(rbObject)
184
- pTuple = nil
185
-
186
- if RubyPython::Macros.PyObject_TypeCheck(rbObject.pointer, RubyPython::Python.PyList_Type.to_ptr) != 0
187
- pTuple = RubyPython::Python.PySequence_Tuple(rbObject.pointer)
188
- elsif RubyPython::Macros.PyObject_TypeCheck(rbObject.pointer, RubyPython::Python.PyTuple_Type.to_ptr) != 0
189
- pTuple = rbObject.pointer
190
- else
191
- pTuple = RubyPython::Python.PyTuple_Pack(1, :pointer, rbObject.pointer)
192
- end
193
-
194
- self.new pTuple
195
- end
196
-
197
- # Wraps up the supplied arguments in a \Python List.
198
- def self.newList(*args)
199
- rbList = self.new RubyPython::Python.PyList_New(args.length)
200
-
201
- args.each_with_index do |el, i|
202
- el.xIncref # PyList_SetItem steals references!
203
- RubyPython::Python.PyList_SetItem rbList.pointer, i, el.pointer
204
- end
205
-
206
- rbList
207
- end
208
-
209
- # Converts the supplied arguments to PyObject instances.
210
- def self.convert(*args)
211
- args.map do |arg|
212
- if arg.kind_of? RubyPython::PyObject
213
- arg
214
- elsif arg.kind_of? RubyPython::RubyPyProxy
215
- arg.pObject
216
- else
217
- RubyPython::PyObject.new arg
218
- end
219
- end
220
- end
221
181
 
222
- # Takes an array of wrapped \Python objects and wraps them in a Tuple such
223
- # that they may be passed to #callObject.
224
- # [args] An array of PyObjects; the arguments to be inserted into the
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
225
185
  # Tuple.
226
186
  def self.buildArgTuple(*args)
227
- pList = newList(*args)
228
- pTuple = makeTuple(pList)
229
- pList.xDecref
230
- pTuple
187
+ self.new RubyPython::Conversion.rtopArrayToTuple(args)
231
188
  end
232
189
  end