pycall 1.0.1-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +41 -0
  5. data/CHANGES.md +39 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +91 -0
  9. data/Rakefile +29 -0
  10. data/appveyor.yml +138 -0
  11. data/bin/console +10 -0
  12. data/bin/guard +17 -0
  13. data/bin/rspec +17 -0
  14. data/bin/runner +6 -0
  15. data/bin/setup +8 -0
  16. data/config/Guardfile +30 -0
  17. data/docker/Dockerfile +191 -0
  18. data/docker/Gemfile +12 -0
  19. data/docker/README.md +22 -0
  20. data/examples/classifier_comparison.rb +135 -0
  21. data/examples/datascience_rb_20170519.ipynb +4836 -0
  22. data/examples/hist.rb +32 -0
  23. data/examples/notebooks/classifier_comparison.ipynb +226 -0
  24. data/examples/notebooks/forest_importances.ipynb +238 -0
  25. data/examples/notebooks/iruby_integration.ipynb +183 -0
  26. data/examples/notebooks/lorenz_attractor.ipynb +214 -0
  27. data/examples/notebooks/polar_axes.ipynb +209 -0
  28. data/examples/notebooks/sum_benchmarking.ipynb +374 -0
  29. data/examples/notebooks/xkcd_style.ipynb +149 -0
  30. data/examples/plot_forest_importances_faces.rb +46 -0
  31. data/examples/sum_benchmarking.rb +49 -0
  32. data/ext/pycall/extconf.rb +3 -0
  33. data/ext/pycall/gc.c +74 -0
  34. data/ext/pycall/libpython.c +217 -0
  35. data/ext/pycall/pycall.c +2184 -0
  36. data/ext/pycall/pycall_internal.h +700 -0
  37. data/ext/pycall/range.c +69 -0
  38. data/ext/pycall/ruby_wrapper.c +432 -0
  39. data/lib/2.1/pycall.so +0 -0
  40. data/lib/2.2/pycall.so +0 -0
  41. data/lib/2.3/pycall.so +0 -0
  42. data/lib/2.4/pycall.so +0 -0
  43. data/lib/pycall/conversion.rb +173 -0
  44. data/lib/pycall/dict.rb +48 -0
  45. data/lib/pycall/error.rb +10 -0
  46. data/lib/pycall/gc_guard.rb +84 -0
  47. data/lib/pycall/import.rb +120 -0
  48. data/lib/pycall/init.rb +55 -0
  49. data/lib/pycall/iruby_helper.rb +40 -0
  50. data/lib/pycall/libpython/finder.rb +170 -0
  51. data/lib/pycall/libpython/pyobject_struct.rb +30 -0
  52. data/lib/pycall/libpython/pytypeobject_struct.rb +273 -0
  53. data/lib/pycall/libpython.rb +12 -0
  54. data/lib/pycall/list.rb +45 -0
  55. data/lib/pycall/pretty_print.rb +9 -0
  56. data/lib/pycall/pyerror.rb +30 -0
  57. data/lib/pycall/pyobject_wrapper.rb +212 -0
  58. data/lib/pycall/python/PyCall/__init__.py +1 -0
  59. data/lib/pycall/python/PyCall/six.py +23 -0
  60. data/lib/pycall/python/investigator.py +7 -0
  61. data/lib/pycall/pytypeobject_wrapper.rb +90 -0
  62. data/lib/pycall/set.rb +19 -0
  63. data/lib/pycall/slice.rb +8 -0
  64. data/lib/pycall/tuple.rb +46 -0
  65. data/lib/pycall/version.rb +3 -0
  66. data/lib/pycall/wrapper_object_cache.rb +61 -0
  67. data/lib/pycall.rb +91 -0
  68. data/pycall.gemspec +40 -0
  69. data/tasks/docker.rake +21 -0
  70. data/tasks/pycall.rake +7 -0
  71. metadata +228 -0
@@ -0,0 +1,273 @@
1
+ require 'pycall/libpython/pyobject_struct'
2
+
3
+ module PyCall
4
+ module LibPython
5
+ # types:
6
+ T_SHORT = 0
7
+ T_INT = 1
8
+ T_LONG = 2
9
+ T_FLOAT = 3
10
+ T_DOUBLE = 4
11
+ T_STRING = 5
12
+ T_OBJECT = 6
13
+ T_CHAR = 7
14
+ T_BYTE = 8
15
+ T_UBYTE = 9
16
+ T_USHORT = 10
17
+ T_UINT = 11
18
+ T_ULONG = 12
19
+ T_STRING_INPLACE = 13
20
+ T_BOOL = 14
21
+ T_OBJECT_EX = 16
22
+ T_LONGLONG = 17 # added in Python 2.5
23
+ T_ULONGLONG = 18 # added in Python 2.5
24
+ T_PYSSIZET = 19 # added in Python 2.6
25
+ T_NONE = 20 # added in Python 3.0
26
+
27
+ # flags:
28
+ READONLY = 1
29
+ READ_RESTRICTED = 2
30
+ PY_WRITE_RESTRICTED = 4
31
+ RESTRICTED = (READ_RESTRICTED | PY_WRITE_RESTRICTED)
32
+
33
+ # Python 2.7
34
+ Py_TPFLAGS_HAVE_GETCHARBUFFER = 0x00000001<<0
35
+ Py_TPFLAGS_HAVE_SEQUENCE_IN = 0x00000001<<1
36
+ Py_TPFLAGS_GC = 0 # was sometimes (0x00000001<<2) in Python <= 2.1
37
+ Py_TPFLAGS_HAVE_INPLACEOPS = 0x00000001<<3
38
+ Py_TPFLAGS_CHECKTYPES = 0x00000001<<4
39
+ Py_TPFLAGS_HAVE_RICHCOMPARE = 0x00000001<<5
40
+ Py_TPFLAGS_HAVE_WEAKREFS = 0x00000001<<6
41
+ Py_TPFLAGS_HAVE_ITER = 0x00000001<<7
42
+ Py_TPFLAGS_HAVE_CLASS = 0x00000001<<8
43
+ Py_TPFLAGS_HAVE_INDEX = 0x00000001<<17
44
+ Py_TPFLAGS_HAVE_NEWBUFFER = 0x00000001<<21
45
+ Py_TPFLAGS_STRING_SUBCLASS = 0x00000001<<27
46
+
47
+ # Python 3.0+ has only these:
48
+ Py_TPFLAGS_HEAPTYPE = 0x00000001<<9
49
+ Py_TPFLAGS_BASETYPE = 0x00000001<<10
50
+ Py_TPFLAGS_READY = 0x00000001<<12
51
+ Py_TPFLAGS_READYING = 0x00000001<<13
52
+ Py_TPFLAGS_HAVE_GC = 0x00000001<<14
53
+ Py_TPFLAGS_HAVE_VERSION_TAG = 0x00000001<<18
54
+ Py_TPFLAGS_VALID_VERSION_TAG = 0x00000001<<19
55
+ Py_TPFLAGS_IS_ABSTRACT = 0x00000001<<20
56
+ Py_TPFLAGS_INT_SUBCLASS = 0x00000001<<23
57
+ Py_TPFLAGS_LONG_SUBCLASS = 0x00000001<<24
58
+ Py_TPFLAGS_LIST_SUBCLASS = 0x00000001<<25
59
+ Py_TPFLAGS_TUPLE_SUBCLASS = 0x00000001<<26
60
+ Py_TPFLAGS_BYTES_SUBCLASS = 0x00000001<<27
61
+ Py_TPFLAGS_UNICODE_SUBCLASS = 0x00000001<<28
62
+ Py_TPFLAGS_DICT_SUBCLASS = 0x00000001<<29
63
+ Py_TPFLAGS_BASE_EXC_SUBCLASS = 0x00000001<<30
64
+ Py_TPFLAGS_TYPE_SUBCLASS = 0x00000001<<31
65
+
66
+ # only use this if we have the stackless extension
67
+ Py_TPFLAGS_HAVE_STACKLESS_EXTENSION_ = 0x00000003<<15
68
+
69
+ class PyMethodDef < FFI::Struct
70
+ layout ml_name: :string,
71
+ ml_meth: :pointer,
72
+ ml_flags: :int,
73
+ ml_doc: :string # may be NULL
74
+
75
+ def initialize(*args)
76
+ case args.length
77
+ when 3, 4
78
+ name, meth, flags, doc = *args
79
+ super()
80
+ self.ml_name = name
81
+ self[:ml_meth] = meth
82
+ self[:ml_flags] = flags
83
+ self.ml_doc = doc
84
+ else
85
+ super
86
+ end
87
+ end
88
+
89
+ def ml_name=(str)
90
+ @saved_name = FFI::MemoryPointer.from_string(str || '')
91
+ self.pointer.put_pointer(offset_of(:ml_name), @saved_name)
92
+ end
93
+
94
+ def ml_doc=(str)
95
+ @saved_doc = FFI::MemoryPointer.from_string(str || '')
96
+ self.pointer.put_pointer(offset_of(:ml_name), @saved_doc)
97
+ end
98
+ end
99
+
100
+ # ml_flags should be one of:
101
+ METH_VARARGS = 0x0001 # args are a tuple of arguments
102
+ METH_KEYWORDS = 0x0002 # two arguments: the varargs and the kwargs
103
+ METH_NOARGS = 0x0004 # no arguments (NULL argument pointer)
104
+ METH_O = 0x0008 # single argument (not wrapped in tuple)
105
+
106
+ # not sure when these are needed:
107
+ METH_CLASS = 0x0010 # for class methods
108
+ METH_STATIC = 0x0020 # for static methods
109
+
110
+ class PyGetSetDef < FFI::Struct
111
+ layout name: :string,
112
+ get: :pointer,
113
+ set: :pointer, # may be NULL for read-only members
114
+ doc: :string,
115
+ closure: :pointer
116
+ end
117
+
118
+ class PyMemberDef < FFI::Struct
119
+ layout name: :string,
120
+ type: :int,
121
+ offset: :ssize_t,
122
+ flags: :int,
123
+ doc: :string
124
+
125
+ [:name, :doc].each do |field|
126
+ define_method(:"#{field}=") do |str|
127
+ saved_str = FFI::MemoryPointer.from_string(str)
128
+ instance_variable_set(:"@saved_#{field}", saved_str)
129
+ self.pointer.put_pointer(offset_of(field), saved_str)
130
+ end
131
+ end
132
+ end
133
+
134
+ class PyTypeObjectStruct < PyObjectStruct
135
+ layout ob_refcnt: :ssize_t,
136
+ ob_type: PyTypeObjectStruct.by_ref,
137
+ ob_size: :ssize_t,
138
+
139
+ tp_name: :string, # For printing, in format "<module>.<name>"
140
+
141
+ # For allocation
142
+ tp_basicsize: :ssize_t,
143
+ tp_itemsize: :ssize_t,
144
+
145
+ # Methods to implement standard operations
146
+
147
+ tp_dealloc: :pointer,
148
+ tp_print: :pointer,
149
+ tp_getattr: :pointer,
150
+ tp_setattr: :pointer,
151
+ tp_as_async: :pointer, # formerly known as tp_compare (Python 2) or tp_reserved (Python 3)
152
+ tp_repr: :pointer,
153
+
154
+ # Method suites for standard classes
155
+
156
+ tp_as_number: :pointer,
157
+ tp_as_sequence: :pointer,
158
+ tp_as_mapping: :pointer,
159
+
160
+ # More standard operations (here for binary compatibility)
161
+
162
+ tp_hash: :pointer,
163
+ tp_call: :pointer,
164
+ tp_str: :pointer,
165
+ tp_getattro: :pointer,
166
+ tp_setattro: :pointer,
167
+
168
+ # Functions to access object as input/output buffer
169
+ tp_as_buffer: :pointer,
170
+
171
+ # Flags to define presence of optional/expanded features
172
+ tp_flags: :ulong,
173
+
174
+ tp_doc: :string, # Documentation string
175
+
176
+ # Assigned meaning in release 2.0
177
+ # call function for all accessible objects
178
+ tp_traverse: :pointer,
179
+
180
+ # delete references to contained objects
181
+ tp_clear: :pointer,
182
+
183
+ # Assigned meaning in release 2.1
184
+ # rich comparisons
185
+ tp_richcompare: :pointer,
186
+
187
+ # weak reference enabler
188
+ tp_weaklistoffset: :ssize_t,
189
+
190
+ # Iterators
191
+ tp_iter: :pointer,
192
+ tp_iternext: :pointer,
193
+
194
+ # Attribute descriptor and subclassing stuff
195
+ tp_methods: PyMethodDef.by_ref,
196
+ tp_members: PyMemberDef.by_ref,
197
+ tp_getset: PyGetSetDef.by_ref,
198
+ tp_base: :pointer,
199
+ tp_dict: PyObjectStruct.by_ref,
200
+ tp_descr_get: :pointer,
201
+ tp_descr_set: :pointer,
202
+ tp_dictoffset: :ssize_t,
203
+ tp_init: :pointer,
204
+ tp_alloc: :pointer,
205
+ tp_new: :pointer,
206
+ tp_free: :pointer, # Low-level free-memory routine
207
+ tp_is_gc: :pointer, # For PyObject_IS_GC
208
+ tp_bases: PyObjectStruct.by_ref,
209
+ tp_mro: PyObjectStruct.by_ref, # method resolution order
210
+ tp_cache: PyObjectStruct.by_ref,
211
+ tp_subclasses: PyObjectStruct.by_ref,
212
+ tp_weaklist: PyObjectStruct.by_ref,
213
+ tp_del: :pointer,
214
+
215
+ # Type attribute cache version tag. Added in version 2.6
216
+ tp_version_tag: :uint,
217
+
218
+ tp_finalize: :pointer,
219
+
220
+ # The following members are only used for COUNT_ALLOCS builds of Python
221
+ tp_allocs: :ssize_t,
222
+ tp_frees: :ssize_t,
223
+ tp_maxalloc: :ssize_t,
224
+ tp_prev: :pointer,
225
+ tp_next: :pointer
226
+
227
+ def self.new(*args)
228
+ case args.length
229
+ when 0, 1
230
+ super
231
+ else
232
+ name, basic_size = *args
233
+ new.tap do |t|
234
+ # NOTE: Disable autorelease for avoiding SEGV occurrance in Python's GC collect function
235
+ # at which the __new__ method object of this type object is freed.
236
+ t.pointer.autorelease = false
237
+
238
+ # PyVarObject_HEAD_INIT(&PyType_Type, 0)
239
+ t[:ob_refcnt] = 1
240
+ t[:ob_type] = LibPython.PyType_Type
241
+ t[:ob_size] = 0
242
+
243
+ t[:tp_basicsize] = basic_size
244
+ stackless_extension_flag = PyCall.has_stackless_extension ? Py_TPFLAGS_HAVE_STACKLESS_EXTENSION_ : 0
245
+ t[:tp_flags] = if PYTHON_VERSION >= '3'
246
+ stackless_extension_flag | Py_TPFLAGS_HAVE_VERSION_TAG
247
+ else
248
+ Py_TPFLAGS_HAVE_GETCHARBUFFER |
249
+ Py_TPFLAGS_HAVE_SEQUENCE_IN |
250
+ Py_TPFLAGS_HAVE_INPLACEOPS |
251
+ Py_TPFLAGS_HAVE_RICHCOMPARE |
252
+ Py_TPFLAGS_HAVE_WEAKREFS |
253
+ Py_TPFLAGS_HAVE_ITER |
254
+ Py_TPFLAGS_HAVE_CLASS |
255
+ stackless_extension_flag |
256
+ Py_TPFLAGS_HAVE_INDEX
257
+ end
258
+ t.tp_name = name
259
+ yield t if block_given?
260
+ t[:tp_new] = LibPython.find_symbol(:PyType_GenericNew) if t[:tp_new] == FFI::Pointer::NULL
261
+ raise PyError.fetch if LibPython.PyType_Ready(t) < 0
262
+ LibPython.Py_IncRef(t)
263
+ end
264
+ end
265
+ end
266
+
267
+ def tp_name=(str)
268
+ @saved_name = FFI::MemoryPointer.from_string(str)
269
+ self.pointer.put_pointer(offset_of(:tp_name), @saved_name)
270
+ end
271
+ end
272
+ end
273
+ end
@@ -0,0 +1,12 @@
1
+ module PyCall
2
+ module LibPython
3
+ require 'pycall/libpython/finder'
4
+
5
+ def self.handle
6
+ # NOTE: PyCall.init redefine this method.
7
+ # See pycall/init.rb for the detail.
8
+ PyCall.init
9
+ handle
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,45 @@
1
+ module PyCall
2
+ List = builtins.list
3
+ class List
4
+ register_python_type_mapping
5
+
6
+ include Enumerable
7
+
8
+ def include?(item)
9
+ LibPython::Helpers.sequence_contains(__pyptr__, item)
10
+ end
11
+
12
+ def length
13
+ PyCall.len(self)
14
+ end
15
+
16
+ def each
17
+ return enum_for unless block_given?
18
+ LibPython::Helpers.sequence_each(__pyptr__, &proc)
19
+ self
20
+ end
21
+
22
+ def <<(item)
23
+ append(item)
24
+ end
25
+
26
+ def push(*items)
27
+ items.each {|i| append(i) }
28
+ end
29
+
30
+ def sort
31
+ dup.sort!
32
+ end
33
+
34
+ def sort!
35
+ LibPython::Helpers.getattr(__pyptr__, :sort).__call__
36
+ self
37
+ end
38
+
39
+ def to_a
40
+ Array.new(length) {|i| self[i] }
41
+ end
42
+
43
+ alias to_ary to_a
44
+ end
45
+ end
@@ -0,0 +1,9 @@
1
+ require 'pycall'
2
+ require 'pp'
3
+
4
+ PyCall.init
5
+ module PyCall
6
+ class PyPtr < BasicObject
7
+ include ::PP::ObjectMixin
8
+ end
9
+ end
@@ -0,0 +1,30 @@
1
+ require 'pycall/error'
2
+
3
+ module PyCall
4
+ class PyError < Error
5
+ def initialize(type, value, traceback)
6
+ @type = type
7
+ @value = value
8
+ @traceback = traceback
9
+ super("Exception occurred in Python")
10
+ end
11
+
12
+ attr_reader :type, :value, :traceback
13
+
14
+ def to_s
15
+ "#{type}: #{value}".tap do |msg|
16
+ if (strs = format_traceback)
17
+ msg << "\n"
18
+ strs.each {|s| msg << s }
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def format_traceback
26
+ return nil if traceback.nil?
27
+ ::PyCall.import_module('traceback').format_tb(traceback)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,212 @@
1
+ require 'pycall/wrapper_object_cache'
2
+
3
+ module PyCall
4
+ module PyObjectWrapper
5
+ attr_reader :__pyptr__
6
+
7
+ def self.extend_object(obj)
8
+ pyptr = obj.instance_variable_get(:@__pyptr__)
9
+ unless pyptr.kind_of? PyPtr
10
+ raise TypeError, "@__pyptr__ should have PyCall::PyPtr object"
11
+ end
12
+ super
13
+ end
14
+
15
+ OPERATOR_METHOD_NAMES = {
16
+ :+ => :__add__,
17
+ :- => :__sub__,
18
+ :* => :__mul__,
19
+ :/ => :__truediv__,
20
+ :% => :__mod__,
21
+ :** => :__pow__,
22
+ :<< => :__lshift__,
23
+ :>> => :__rshift__,
24
+ :& => :__and__,
25
+ :^ => :__xor__,
26
+ :| => :__or__
27
+ }.freeze
28
+
29
+ def method_missing(name, *args)
30
+ name_str = name.to_s if name.kind_of?(Symbol)
31
+ name_str.chop! if name_str.end_with?('=')
32
+ case name
33
+ when *OPERATOR_METHOD_NAMES.keys
34
+ op_name = OPERATOR_METHOD_NAMES[name]
35
+ if LibPython::Helpers.hasattr?(__pyptr__, op_name)
36
+ LibPython::Helpers.define_wrapper_method(self, op_name)
37
+ singleton_class.__send__(:alias_method, name, op_name)
38
+ return self.__send__(name, *args)
39
+ end
40
+ else
41
+ if LibPython::Helpers.hasattr?(__pyptr__, name_str)
42
+ LibPython::Helpers.define_wrapper_method(self, name)
43
+ return self.__send__(name, *args)
44
+ end
45
+ end
46
+ super
47
+ end
48
+
49
+ def respond_to_missing?(name, include_private)
50
+ return true if LibPython::Helpers.hasattr?(__pyptr__, name)
51
+ super
52
+ end
53
+
54
+ def kind_of?(cls)
55
+ case cls
56
+ when PyTypeObjectWrapper
57
+ __pyptr__.kind_of?(cls.__pyptr__)
58
+ else
59
+ super
60
+ end
61
+ end
62
+
63
+ [:==, :!=, :<, :<=, :>, :>=].each do |op|
64
+ class_eval("#{<<-"begin;"}\n#{<<-"end;"}", __FILE__, __LINE__+1)
65
+ begin;
66
+ def #{op}(other)
67
+ case other
68
+ when PyObjectWrapper
69
+ LibPython::Helpers.compare(:#{op}, __pyptr__, other.__pyptr__)
70
+ else
71
+ other = Conversion.from_ruby(other)
72
+ LibPython::Helpers.compare(:#{op}, __pyptr__, other)
73
+ end
74
+ end
75
+ end;
76
+ end
77
+
78
+ def [](*key)
79
+ LibPython::Helpers.getitem(__pyptr__, key)
80
+ end
81
+
82
+ def []=(*key, value)
83
+ LibPython::Helpers.setitem(__pyptr__, key, value)
84
+ end
85
+
86
+ def call(*args)
87
+ LibPython::Helpers.call_object(__pyptr__, *args)
88
+ end
89
+
90
+ class SwappedOperationAdapter
91
+ def initialize(obj)
92
+ @obj = obj
93
+ end
94
+
95
+ attr_reader :obj
96
+
97
+ def +(other)
98
+ other.__radd__(self.obj)
99
+ end
100
+
101
+ def -(other)
102
+ other.__rsub__(self.obj)
103
+ end
104
+
105
+ def *(other)
106
+ other.__rmul__(self.obj)
107
+ end
108
+
109
+ def /(other)
110
+ other.__rtruediv__(self.obj)
111
+ end
112
+
113
+ def %(other)
114
+ other.__rmod__(self.obj)
115
+ end
116
+
117
+ def **(other)
118
+ other.__rpow__(self.obj)
119
+ end
120
+
121
+ def <<(other)
122
+ other.__rlshift__(self.obj)
123
+ end
124
+
125
+ def >>(other)
126
+ other.__rrshift__(self.obj)
127
+ end
128
+
129
+ def &(other)
130
+ other.__rand__(self.obj)
131
+ end
132
+
133
+ def ^(other)
134
+ other.__rxor__(self.obj)
135
+ end
136
+
137
+ def |(other)
138
+ other.__ror__(self.obj)
139
+ end
140
+ end
141
+
142
+ def coerce(other)
143
+ [SwappedOperationAdapter.new(other), self]
144
+ end
145
+
146
+ def dup
147
+ super.tap do |duped|
148
+ copied = PyCall.import_module('copy').copy(__pyptr__)
149
+ copied = copied.__pyptr__ if copied.kind_of? PyObjectWrapper
150
+ duped.instance_variable_set(:@__pyptr__, copied)
151
+ end
152
+ end
153
+
154
+ def inspect
155
+ PyCall.builtins.repr(__pyptr__)
156
+ end
157
+
158
+ def to_s
159
+ LibPython::Helpers.str(__pyptr__)
160
+ end
161
+
162
+ def to_i
163
+ LibPython::Helpers.call_object(PyCall::builtins.int.__pyptr__, __pyptr__)
164
+ end
165
+
166
+ def to_f
167
+ LibPython::Helpers.call_object(PyCall::builtins.float.__pyptr__, __pyptr__)
168
+ end
169
+ end
170
+
171
+ module_function
172
+
173
+ class WrapperModuleCache < WrapperObjectCache
174
+ def initialize
175
+ super(LibPython::API::PyModule_Type)
176
+ end
177
+
178
+ def check_wrapper_object(wrapper_object)
179
+ unless wrapper_object.kind_of?(Module) && wrapper_object.kind_of?(PyObjectWrapper)
180
+ raise TypeError, "unexpected type #{wrapper_object.class} (expected Module extended by PyObjectWrapper)"
181
+ end
182
+ end
183
+
184
+ def self.instance
185
+ @instance ||= self.new
186
+ end
187
+ end
188
+
189
+ private_constant :WrapperModuleCache
190
+
191
+ def wrap_module(pymodptr)
192
+ check_ismodule(pymodptr)
193
+ WrapperModuleCache.instance.lookup(pymodptr) do
194
+ Module.new do |mod|
195
+ mod.instance_variable_set(:@__pyptr__, pymodptr)
196
+ mod.extend PyObjectWrapper
197
+ end
198
+ end
199
+ end
200
+
201
+ def check_isclass(pyptr)
202
+ pyptr = pyptr.__pyptr__ if pyptr.kind_of? PyObjectWrapper
203
+ return if pyptr.kind_of? LibPython::API::PyType_Type
204
+ return defined?(LibPython::API::PyClass_Type) && pyptr.kind_of?(LibPython::API::PyClass_Type)
205
+ raise TypeError, "PyType object is required"
206
+ end
207
+
208
+ def check_ismodule(pyptr)
209
+ return if pyptr.kind_of? LibPython::API::PyModule_Type
210
+ raise TypeError, "PyModule object is required"
211
+ end
212
+ end
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,23 @@
1
+ import sys
2
+
3
+ PY3 = sys.version_info[0] == 3
4
+
5
+ if PY3:
6
+ import builtins
7
+ else:
8
+ import __builtin__ as builtins
9
+
10
+ if PY3:
11
+ exec_ = getattr(builtins, 'exec')
12
+ else:
13
+ def exec_(_code_, _globals_=None, _locals_=None):
14
+ """Execute code in a namespace."""
15
+ if _globals_ is None:
16
+ frame = sys._getframe(1)
17
+ _globals_ = frame.f_globals
18
+ if _locals_ is None:
19
+ _locals_ = frame.f_locals
20
+ del frame
21
+ elif _locals_ is None:
22
+ _locals_ = _globals_
23
+ exec("""exec _code_ in _globals_, _locals_""")
@@ -0,0 +1,7 @@
1
+ from distutils.sysconfig import get_config_var
2
+ import sys
3
+ for var in ('executable', 'exec_prefix', 'prefix'):
4
+ print(var + ': ' + str(getattr(sys, var)))
5
+ print('multiarch: ' + str(getattr(getattr(sys, 'implementation', sys), '_multiarch', None)))
6
+ for var in ('VERSION', 'INSTSONAME', 'LIBRARY', 'LDLIBRARY', 'LIBDIR', 'PYTHONFRAMEWORKPREFIX', 'MULTIARCH'):
7
+ print(var + ': ' + str(get_config_var(var)))
@@ -0,0 +1,90 @@
1
+ require 'pycall/pyobject_wrapper'
2
+
3
+ module PyCall
4
+ module PyTypeObjectWrapper
5
+ include PyObjectWrapper
6
+
7
+ def self.extend_object(cls)
8
+ unless cls.kind_of? Class
9
+ raise TypeError, "PyTypeObjectWrapper cannot extend non-class objects"
10
+ end
11
+ pyptr = cls.instance_variable_get(:@__pyptr__)
12
+ unless pyptr.kind_of? PyTypePtr
13
+ raise TypeError, "@__pyptr__ should have PyCall::PyTypePtr object"
14
+ end
15
+ super
16
+ cls.include PyObjectWrapper
17
+ end
18
+
19
+ def inherited(subclass)
20
+ subclass.instance_variable_set(:@__pyptr__, __pyptr__)
21
+ end
22
+
23
+ def new(*args)
24
+ wrap_pyptr(LibPython::Helpers.call_object(__pyptr__, *args))
25
+ end
26
+
27
+ def wrap_pyptr(pyptr)
28
+ return pyptr if pyptr.kind_of? self
29
+ pyptr = pyptr.__pyptr__ if pyptr.kind_of? PyObjectWrapper
30
+ unless pyptr.kind_of? PyPtr
31
+ raise TypeError, "unexpected argument type #{pyptr.class} (expected PyCall::PyPtr)"
32
+ end
33
+ unless pyptr.kind_of? __pyptr__
34
+ raise TypeError, "unexpected argument Python type #{pyptr.__ob_type__.__tp_name__} (expected #{__pyptr__.__tp_name__})"
35
+ end
36
+ allocate.tap do |obj|
37
+ obj.instance_variable_set(:@__pyptr__, pyptr)
38
+ end
39
+ end
40
+
41
+ def ===(other)
42
+ case other
43
+ when PyObjectWrapper
44
+ __pyptr__ === other.__pyptr__
45
+ when PyPtr
46
+ __pyptr__ === other
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def register_python_type_mapping
55
+ PyCall::Conversion.register_python_type_mapping(__pyptr__, self)
56
+ end
57
+ end
58
+
59
+ module_function
60
+
61
+ class WrapperClassCache < WrapperObjectCache
62
+ def initialize
63
+ types = [LibPython::API::PyType_Type]
64
+ types << LibPython::API::PyClass_Type if defined? LibPython::API::PyClass_Type
65
+ super(*types)
66
+ end
67
+
68
+ def check_wrapper_object(wrapper_object)
69
+ unless wrapper_object.kind_of?(Class) && wrapper_object.kind_of?(PyTypeObjectWrapper)
70
+ raise TypeError, "unexpected type #{wrapper_object.class} (expected Class extended by PyTypeObjectWrapper)"
71
+ end
72
+ end
73
+
74
+ def self.instance
75
+ @instance ||= self.new
76
+ end
77
+ end
78
+
79
+ private_constant :WrapperClassCache
80
+
81
+ def wrap_class(pytypeptr)
82
+ check_isclass(pytypeptr)
83
+ WrapperClassCache.instance.lookup(pytypeptr) do
84
+ Class.new do |cls|
85
+ cls.instance_variable_set(:@__pyptr__, pytypeptr)
86
+ cls.extend PyTypeObjectWrapper
87
+ end
88
+ end
89
+ end
90
+ end