Module: PyCall::Conversions

Defined in:
lib/pycall/conversion.rb

Defined Under Namespace

Classes: TypePair

Class Method Summary collapse

Class Method Details

.convert_to_array(py_obj, force_list: true, array_class: Array) ⇒ Object



153
154
155
156
157
158
159
160
161
# File 'lib/pycall/conversion.rb', line 153

def self.convert_to_array(py_obj, force_list: true, array_class: Array)
  case
  when force_list || py_obj.kind_of?(LibPython.PyList_Type)
    len = LibPython.PySequence_Size(py_obj)
    array_class.new(len) do |i|
      LibPython.PySequence_GetItem(py_obj, i).to_ruby
    end
  end
end

.convert_to_boolean(py_obj) ⇒ Object



123
124
125
# File 'lib/pycall/conversion.rb', line 123

def self.convert_to_boolean(py_obj)
  0 != LibPython.PyInt_AsSsize_t(py_obj)
end

.convert_to_complex(py_obj) ⇒ Object



135
136
137
138
139
# File 'lib/pycall/conversion.rb', line 135

def self.convert_to_complex(py_obj)
  real = LibPython.PyComplex_RealAsDouble(py_obj)
  imag = LibPython.PyComplex_ImagAsDouble(py_obj)
  Complex(real, imag)
end

.convert_to_float(py_obj) ⇒ Object



131
132
133
# File 'lib/pycall/conversion.rb', line 131

def self.convert_to_float(py_obj)
  LibPython.PyFloat_AsDouble(py_obj)
end

.convert_to_integer(py_obj) ⇒ Object



127
128
129
# File 'lib/pycall/conversion.rb', line 127

def self.convert_to_integer(py_obj)
  LibPython.PyInt_AsSsize_t(py_obj)
end

.convert_to_string(py_obj) ⇒ Object



141
142
143
144
145
146
147
148
149
150
151
# File 'lib/pycall/conversion.rb', line 141

def self.convert_to_string(py_obj)
  FFI::MemoryPointer.new(:string) do |str_ptr|
    FFI::MemoryPointer.new(:int) do |len_ptr|
      res = LibPython.PyString_AsStringAndSize(py_obj, str_ptr, len_ptr)
      return nil if res == -1  # FIXME: error

      len = len_ptr.get(:int, 0)
      return str_ptr.get_pointer(0).read_string(len)
    end
  end
end

.convert_to_tuple(py_obj) ⇒ Object



163
164
165
# File 'lib/pycall/conversion.rb', line 163

def self.convert_to_tuple(py_obj)
  PyCall::Tuple.new(py_obj)
end

.each_type_pairObject



11
12
13
14
15
16
17
18
# File 'lib/pycall/conversion.rb', line 11

def self.each_type_pair
  i, n = 1, @python_type_map.length
  while i <= n
    yield @python_type_map[n - i]
    i += 1
  end
  self
end

.from_ruby(obj) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/pycall/conversion.rb', line 92

def self.from_ruby(obj)
  case obj
  when LibPython::PyObjectStruct
    obj
  when PyObject, PyObjectWrapper
    obj.__pyobj__
  when TrueClass, FalseClass
    LibPython.PyBool_FromLong(obj ? 1 : 0)
  when Integer
    LibPython.PyInt_FromSsize_t(obj)
  when Float
    LibPython.PyFloat_FromDouble(obj)
  when String
    if obj.encoding != Encoding::BINARY && (PyCall.unicode_literals? || !obj.ascii_only?)
      obj = obj.encode(Encoding::UTF_8) if obj.encoding != Encoding::UTF_8
      return LibPython.PyUnicode_DecodeUTF8(obj, obj.bytesize, nil)
    end
    LibPython.PyString_FromStringAndSize(obj, obj.bytesize)
  when Symbol
    from_ruby(obj.to_s)
  when Array
    PyCall::List.new(obj).__pyobj__
  when Hash
    PyCall::Dict.new(obj).__pyobj__
  when Proc
    PyCall.wrap_ruby_callable(obj)
  else
    PyCall.None
  end
end

.python_type_mapping(pytype, rbtype) ⇒ Object



20
21
22
23
24
25
26
27
# File 'lib/pycall/conversion.rb', line 20

def self.python_type_mapping(pytype, rbtype)
  each_type_pair do |type_pair|
    next unless pytype == type_pair.pytype
    type_pair.rbtype = rbtype
    return
  end
  @python_type_map << TypePair.new(pytype, rbtype)
end

.to_ruby(pyptr) ⇒ Object

Convert a PyCall::PyObjectStruct object to a Ruby object

Parameters:

  • pyptr (PyCall::PyObjectStruct)

    a PyObjectStruct object.

Returns:

  • a Ruby object converted from ‘pyptr`.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/pycall/conversion.rb', line 34

def self.to_ruby(pyptr)
  return nil if pyptr.null? || PyCall.none?(pyptr)

  case
  when PyCall::Types.pyisinstance(pyptr, LibPython.PyType_Type)
    return TypeObject.new(pyptr)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyBool_Type)
    return Conversions.convert_to_boolean(pyptr)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyInt_Type)
    return Conversions.convert_to_integer(pyptr)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyLong_Type)
    # TODO: should make Bignum

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyFloat_Type)
    return Conversions.convert_to_float(pyptr)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyComplex_Type)
    return Conversions.convert_to_complex(pyptr)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyString_Type)
    return Conversions.convert_to_string(pyptr)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyUnicode_Type)
    py_str_ptr = LibPython.PyUnicode_AsUTF8String(pyptr)
    return Conversions.convert_to_string(py_str_ptr).force_encoding(Encoding::UTF_8)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyList_Type)
    return PyCall::List.new(pyptr)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyTuple_Type)
    return Conversions.convert_to_tuple(pyptr)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PyDict_Type)
    return PyCall::Dict.new(pyptr)

  when PyCall::Types.pyisinstance(pyptr, LibPython.PySet_Type)
    return PyCall::Set.new(pyptr)
  end

  pyobj = PyObject.new(pyptr)
  each_type_pair do |tp|
    pytype, rbtype = tp.to_a
    next unless pyobj.kind_of?(pytype)
    case
    when rbtype.kind_of?(Proc)
      return rbtype.(pyobj)
    when rbtype.respond_to?(:from_python)
      return rbtype.from_python(pyobj)
    else
      return rbtype.new(pyobj)
    end
  end
  pyobj
end