pycall 0.1.0.alpha.20170224b → 0.1.0.alpha.20170226

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d2a6e3735f767731679b29028417f1c65fd29a34
4
- data.tar.gz: 479fa94df217c1db443950c73e5457fd910a0568
3
+ metadata.gz: ab504049d683e34fa1e325340601d6577a40cd5e
4
+ data.tar.gz: c477cf5937dd0499e50512a4829ad3688d8e34e5
5
5
  SHA512:
6
- metadata.gz: e14d7ebbd21f597a9d9b439532b30a5466d46df36af207ad07151e839ecb5e768eca30dac5c85a717b612facea30a6ad89094bfc168501cd70117e3af443162d
7
- data.tar.gz: 616be33cc87bfae9291dd6ebccb875a41c0c33b97e2a1255d14a9250b3a50540449b37e3e132136171aaa8ad586893367f812dccf43c2a8b73808cbf2fbff718
6
+ metadata.gz: 041fda79cb71ccb7653e442c1831f97b489058adb48159cef581d49174182350047e736192eb5568c6d2c4b61d6e2691e917ccb28f578c2dd5b340d90dca41d3
7
+ data.tar.gz: eb6af8382a0531729aa8ac151d0880e1c7c613441550490fad77e924b26012723833b5ea1aaab75e6ef9a9f1d9d4e99e416ac4c244c155f7c5a2f7b42c4c5d3c
@@ -2,8 +2,6 @@ require 'pycall/import'
2
2
  include PyCall::Import
3
3
 
4
4
  pyimport 'numpy', as: :np
5
- pyimport 'matplotlib.pyplot', as: :plt
6
- pyimport 'matplotlib.colors', as: :mplc
7
5
  pyfrom 'sklearn.cross_validation', import: :train_test_split
8
6
  pyfrom 'sklearn.preprocessing', import: :StandardScaler
9
7
  pyfrom 'sklearn.datasets', import: %i(make_moons make_circles make_classification)
@@ -14,6 +12,13 @@ pyfrom 'sklearn.ensemble', import: %i(RandomForestClassifier AdaBoostClassifier)
14
12
  pyfrom 'sklearn.naive_bayes', import: :GaussianNB
15
13
  pyfrom 'sklearn.discriminant_analysis', import: %i(LinearDiscriminantAnalysis QuadraticDiscriminantAnalysis)
16
14
 
15
+ # FIXME: MacOSX backend is not usable through pycall. I want to fix this issue but the reason is unclear.
16
+ pyimport 'matplotlib', as: :mp
17
+ mp.rcParams[:backend] = 'TkAgg' if mp.rcParams[:backend] == 'MacOSX'
18
+
19
+ pyimport 'matplotlib.pyplot', as: :plt
20
+ pyimport 'matplotlib.colors', as: :mplc
21
+
17
22
  h = 0.02 # step size in the mesh
18
23
 
19
24
  names = [
data/examples/hist.rb CHANGED
@@ -2,6 +2,11 @@ require 'pycall/import'
2
2
  include PyCall::Import
3
3
 
4
4
  pyimport 'numpy', as: 'np'
5
+
6
+ # FIXME: MacOSX backend is not usable through pycall. I want to fix this issue but the reason is unclear.
7
+ pyimport 'matplotlib', as: :mp
8
+ mp.rcParams[:backend] = 'TkAgg' if mp.rcParams[:backend] == 'MacOSX'
9
+
5
10
  pyimport 'matplotlib.mlab', as: 'mlab'
6
11
  pyimport 'matplotlib.pyplot', as: 'plt'
7
12
 
@@ -3,6 +3,11 @@ require 'pycall/import'
3
3
  include PyCall::Import
4
4
 
5
5
  pyimport 'numpy', as: 'np'
6
+
7
+ # FIXME: MacOSX backend is not usable through pycall. I want to fix this issue but the reason is unclear.
8
+ pyimport 'matplotlib', as: :mp
9
+ mp.rcParams[:backend] = 'TkAgg' if mp.rcParams[:backend] == 'MacOSX'
10
+
6
11
  pyimport 'matplotlib.pyplot', as: 'plt'
7
12
 
8
13
  pyfrom 'sklearn.datasets', import: 'fetch_olivetti_faces'
@@ -3,6 +3,11 @@ include PyCall::Import
3
3
 
4
4
  require 'benchmark'
5
5
  pyimport :pandas, as: :pd
6
+
7
+ # FIXME: MacOSX backend is not usable through pycall. I want to fix this issue but the reason is unclear.
8
+ pyimport 'matplotlib', as: :mp
9
+ mp.rcParams[:backend] = 'TkAgg' if mp.rcParams[:backend] == 'MacOSX'
10
+
6
11
  pyimport :seaborn, as: :sns
7
12
  pyimport 'matplotlib.pyplot', as: :plt
8
13
 
@@ -1,5 +1,41 @@
1
1
  module PyCall
2
2
  module Conversions
3
+ @python_type_map = []
4
+
5
+ class TypePair < Struct.new(:pytype, :rbtype)
6
+ def to_a
7
+ [pytype, rbtype]
8
+ end
9
+ end
10
+
11
+ def self.python_type_mapping(pytype, rbtype)
12
+ @python_type_map.each_with_index do |type_pair, index|
13
+ next unless pytype == type_pair.pytype
14
+ type_pair.rbtype = rbtype
15
+ return
16
+ end
17
+ @python_type_map << TypePair.new(pytype, rbtype)
18
+ end
19
+
20
+ def self.to_ruby(pyobj)
21
+ unless pyobj.kind_of? PyObject
22
+ raise
23
+ end
24
+ @python_type_map.each do |tp|
25
+ pytype, rbtype = tp.to_a
26
+ next unless pyobj.kind_of?(pytype)
27
+ case
28
+ when rbtype.kind_of?(Proc)
29
+ return rbtype.(pyobj)
30
+ when rbtype.respond_to?(:from_python)
31
+ return rbtype.from_python(pyobj)
32
+ else
33
+ return rbtype.new(pyobj)
34
+ end
35
+ end
36
+ pyobj
37
+ end
38
+
3
39
  def self.from_ruby(obj)
4
40
  case obj
5
41
  when PyObject
@@ -102,7 +138,7 @@ module PyCall
102
138
  return Conversions.convert_to_string(py_str_ptr).force_encoding(Encoding::UTF_8)
103
139
 
104
140
  when LibPython.PyList_Type
105
- return Conversions.convert_to_array(self)
141
+ return PyCall::List.new(self)
106
142
 
107
143
  when LibPython.PyTuple_Type
108
144
  return Conversions.convert_to_tuple(self)
@@ -114,7 +150,7 @@ module PyCall
114
150
  return PyCall::Set.new(self)
115
151
  end
116
152
 
117
- self
153
+ Conversions.to_ruby(self)
118
154
  end
119
155
  end
120
156
  end
data/lib/pycall/dict.rb CHANGED
@@ -68,7 +68,10 @@ module PyCall
68
68
  end
69
69
 
70
70
  def has_key?(key)
71
- 1 == LibPython.PyDict_Contains(__pyobj__, key).to_ruby
71
+ key = Conversions.from_ruby(key)
72
+ value = LibPython.PyDict_Contains(__pyobj__, key)
73
+ raise PyError.fetch if value == -1
74
+ 1 == value
72
75
  end
73
76
 
74
77
  def default=(val)
data/lib/pycall/eval.rb CHANGED
@@ -7,6 +7,7 @@ module PyCall
7
7
  locals_ptr = maindict_ptr
8
8
  defer_sigint do
9
9
  py_code_ptr = LibPython.Py_CompileString(str, filename, Py_eval_input)
10
+ raise PyError.fetch if py_code_ptr.null?
10
11
  LibPython.PyEval_EvalCode(py_code_ptr, globals_ptr, locals_ptr)
11
12
  end
12
13
  end
@@ -14,8 +15,12 @@ module PyCall
14
15
  class << self
15
16
  private
16
17
 
18
+ def main_module
19
+ @main_module ||= PyCall.import_module("__main__")
20
+ end
21
+
17
22
  def maindict_ptr
18
- LibPython.PyModule_GetDict(PyCall.import_module("__main__"))
23
+ @maindict_ptr ||= LibPython.PyModule_GetDict(main_module)
19
24
  end
20
25
 
21
26
  def defer_sigint
@@ -0,0 +1,40 @@
1
+ require 'pycall'
2
+ require 'iruby'
3
+
4
+ module PyCall
5
+ module IRubyHelper
6
+ private
7
+
8
+ def check_pyobject_respond_to_format_method(obj, method_name)
9
+ return false unless obj.kind_of? PyObject
10
+ return false unless PyCall.hasattr?(obj, method_name)
11
+ PyCall.getattr(obj, method_name).kind_of? PyCall::LibPython.PyMethod_Type
12
+ end
13
+
14
+ def register_pyobject_formatter(format_name, mime, priority_value=0)
15
+ method_name = :"_repr_#{format_name}_"
16
+ match do |obj|
17
+ check_pyobject_respond_to_format_method(obj, method_name)
18
+ end
19
+ priority priority_value
20
+ format mime do |obj|
21
+ PyCall.getattr(obj, method_name).()
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ ::IRuby::Display::Registry.module_eval do
28
+ extend PyCall::IRubyHelper
29
+
30
+ register_pyobject_formatter :html, 'text/html'
31
+ register_pyobject_formatter :markdown, 'text/markdown'
32
+ register_pyobject_formatter :svg, 'image/svg+xml'
33
+ register_pyobject_formatter :png, 'image/png'
34
+ register_pyobject_formatter :jpeg, 'image/jpeg'
35
+ register_pyobject_formatter :latex, 'text/latex'
36
+ register_pyobject_formatter :json, 'application/json'
37
+ register_pyobject_formatter :javascript, 'application/javascript'
38
+ register_pyobject_formatter :pdf, 'application/pdf'
39
+ register_pyobject_formatter :pretty, 'text/plain', -1000
40
+ end
@@ -129,6 +129,7 @@ module PyCall
129
129
  attach_variable :PySet_Type, PyTypeObject
130
130
 
131
131
  attach_variable :PyFunction_Type, PyTypeObject
132
+ attach_variable :PyMethod_Type, PyTypeObject
132
133
 
133
134
  # --- functions ---
134
135
 
@@ -146,8 +147,11 @@ module PyCall
146
147
  attach_function :PyObject_SetItem, [PyObject.by_ref, PyObject.by_ref, PyObject.by_ref], :int
147
148
  attach_function :PyObject_DelItem, [PyObject.by_ref, PyObject.by_ref], :int
148
149
  attach_function :PyObject_Call, [PyObject.by_ref, PyObject.by_ref, PyObject.by_ref], PyObject.by_ref
149
- attach_function :PyObject_IsInstance, [PyObject.by_ref, PyTypeObject.by_ref], :int
150
+ attach_function :PyObject_IsInstance, [PyObject.by_ref, PyObject.by_ref], :int
150
151
  attach_function :PyObject_Dir, [PyObject.by_ref], PyObject.by_ref
152
+ attach_function :PyObject_Repr, [PyObject.by_ref], PyObject.by_ref
153
+ attach_function :PyObject_Str, [PyObject.by_ref], PyObject.by_ref
154
+ attach_function :PyObject_Type, [PyObject.by_ref], PyTypeObject.by_ref
151
155
 
152
156
  # Bool
153
157
 
@@ -237,6 +241,7 @@ module PyCall
237
241
 
238
242
  attach_function :PySequence_Size, [PyObject.by_ref], :ssize_t
239
243
  attach_function :PySequence_GetItem, [PyObject.by_ref, :ssize_t], PyObject.by_ref
244
+ attach_function :PySequence_Contains, [PyObject.by_ref, PyObject.by_ref], :int
240
245
 
241
246
  # Dict
242
247
 
@@ -282,6 +287,7 @@ module PyCall
282
287
 
283
288
  # Error
284
289
 
290
+ attach_function :PyErr_Clear, [], :void
285
291
  attach_function :PyErr_Print, [], :void
286
292
  attach_function :PyErr_Occurred, [], PyObject.by_ref
287
293
  attach_function :PyErr_Fetch, [:pointer, :pointer, :pointer], :void
data/lib/pycall/list.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  module PyCall
2
2
  class List
3
3
  include PyObjectWrapper
4
+ include Enumerable
4
5
 
5
6
  def self.new(init=nil)
6
7
  case init
@@ -47,7 +48,28 @@ module PyCall
47
48
 
48
49
  def include?(value)
49
50
  value = Conversions.from_ruby(value)
50
- LibPython.PyList_Contains(__pyobj__, value).to_ruby
51
+ value = LibPython.PySequence_Contains(__pyobj__, value)
52
+ raise PyError.fetch if value == -1
53
+ 1 == value
54
+ end
55
+
56
+ def ==(other)
57
+ case other
58
+ when Array
59
+ self.to_a == other
60
+ else
61
+ super
62
+ end
63
+ end
64
+
65
+ def each
66
+ return enum_for unless block_given?
67
+ i, n = 0, size
68
+ while i < n
69
+ yield self[i]
70
+ i += 1
71
+ end
72
+ self
51
73
  end
52
74
 
53
75
  def to_a
@@ -17,9 +17,19 @@ module PyCall
17
17
  @type = type
18
18
  @value = value
19
19
  @traceback = traceback
20
- super("#{@type.inspect}: #{PyCall.eval('str').(@value)}")
20
+ super("Error occurred in Python")
21
21
  end
22
22
 
23
23
  attr_reader :type, :value, :traceback
24
+
25
+ def message
26
+ "#{PyObject.new(type.to_ptr)}: #{value}".tap do |msg|
27
+ unless traceback.null?
28
+ if (o = PyCall.format_traceback(traceback))
29
+ msg.concat("\n", *o)
30
+ end
31
+ end
32
+ end
33
+ end
24
34
  end
25
35
  end
@@ -39,7 +39,7 @@ module PyCall
39
39
 
40
40
  def kind_of?(klass)
41
41
  case klass
42
- when PyTypeObject
42
+ when PyObject, PyTypeObject
43
43
  Types.pyisinstance(self, klass)
44
44
  else
45
45
  super
@@ -122,7 +122,16 @@ module PyCall
122
122
  end
123
123
 
124
124
  def to_s
125
- PyCall.str(self)
125
+ s = LibPython.PyObject_Repr(self)
126
+ if s.null?
127
+ LibPython.PyErr_Clear()
128
+ s = LibPython.PyObject_Str(self)
129
+ if s.null?
130
+ LibPython.PyErr_Clear()
131
+ return super
132
+ end
133
+ end
134
+ s.to_ruby
126
135
  end
127
136
 
128
137
  alias inspect to_s
@@ -1,7 +1,8 @@
1
1
  module PyCall
2
2
  module PyObjectWrapper
3
- def initialize(pyobj, pytype)
3
+ def initialize(pyobj, pytype=nil)
4
4
  check_type pyobj, pytype
5
+ pytype ||= LibPython.PyObject_Type(pyobj)
5
6
  @__pyobj__ = pyobj
6
7
  end
7
8
 
@@ -41,7 +42,8 @@ module PyCall
41
42
  private
42
43
 
43
44
  def check_type(pyobj, pytype)
44
- return if pyobj.kind_of?(PyObject) && pyobj.kind_of?(pytype)
45
+ return if pyobj.kind_of?(PyObject)
46
+ return if pytype.nil? || pyobj.kind_of?(pytype)
45
47
  raise TypeError, "the argument must be a PyObject of #{pytype}"
46
48
  end
47
49
  end
data/lib/pycall/types.rb CHANGED
@@ -2,8 +2,8 @@ module PyCall
2
2
  module Types
3
3
  def self.pyisinstance(pyobj, pytype)
4
4
  check_pyobject(pyobj)
5
- pyobj_ptr = pyobj # TODO: fix after introducing PyObject class
6
- LibPython.PyObject_IsInstance(pyobj_ptr, pytype) == 1
5
+ pytype = PyObject.new(pytype.to_ptr) if pytype.kind_of?(PyTypeObject)
6
+ LibPython.PyObject_IsInstance(pyobj, pytype) == 1
7
7
  end
8
8
 
9
9
  class << self
data/lib/pycall/utils.rb CHANGED
@@ -33,6 +33,11 @@ module PyCall
33
33
  @type ||= PyCall.eval('type')
34
34
  @type.(pyobj)
35
35
  end
36
+
37
+ def format_traceback(pyobj)
38
+ @format_tb ||= import_module('traceback').format_tb
39
+ @format_tb.(pyobj)
40
+ end
36
41
  end
37
42
 
38
43
  extend Utils
@@ -1,3 +1,3 @@
1
1
  module PyCall
2
- VERSION = "0.1.0.alpha.20170224b"
2
+ VERSION = "0.1.0.alpha.20170226"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pycall
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.alpha.20170224b
4
+ version: 0.1.0.alpha.20170226
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenta Murata
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-24 00:00:00.000000000 Z
11
+ date: 2017-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -96,6 +96,7 @@ files:
96
96
  - lib/pycall/eval.rb
97
97
  - lib/pycall/import.rb
98
98
  - lib/pycall/init.rb
99
+ - lib/pycall/iruby_helper.rb
99
100
  - lib/pycall/libpython.rb
100
101
  - lib/pycall/list.rb
101
102
  - lib/pycall/pyerror.rb