rubypython 0.6.2 → 0.6.3

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