pycall 1.2.1 → 1.4.1
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 +4 -4
- data/.github/workflows/ci.yml +150 -0
- data/.github/workflows/windows.yml +127 -0
- data/.gitignore +2 -0
- data/CHANGES.md +39 -0
- data/README.md +153 -7
- data/Rakefile +81 -19
- data/ci/travis_install.sh +30 -9
- data/examples/classifier_comparison.rb +1 -1
- data/examples/hist.rb +1 -1
- data/examples/notebooks/classifier_comparison.ipynb +1 -1
- data/examples/notebooks/leaflet.ipynb +77 -0
- data/ext/pycall/gc.c +84 -5
- data/ext/pycall/libpython.c +7 -1
- data/ext/pycall/pycall.c +60 -6
- data/ext/pycall/pycall_internal.h +27 -1
- data/ext/pycall/ruby_wrapper.c +11 -2
- data/ext/pycall/thread.c +36 -0
- data/lib/pycall.rb +16 -0
- data/lib/pycall/dict.rb +2 -2
- data/lib/pycall/init.rb +3 -8
- data/lib/pycall/iterable_wrapper.rb +32 -0
- data/lib/pycall/libpython/finder.rb +131 -84
- data/lib/pycall/list.rb +2 -2
- data/lib/pycall/pyobject_wrapper.rb +1 -1
- data/lib/pycall/python/investigator.py +82 -9
- data/lib/pycall/pytypeobject_wrapper.rb +10 -0
- data/lib/pycall/version.rb +7 -1
- data/lib/pycall/wrapper_object_cache.rb +56 -25
- data/pycall.gemspec +9 -2
- metadata +24 -7
- data/.travis.yml +0 -56
- data/appveyor.yml +0 -104
data/lib/pycall/list.rb
CHANGED
@@ -178,7 +178,7 @@ module PyCall
|
|
178
178
|
def check_isclass(pyptr)
|
179
179
|
pyptr = pyptr.__pyptr__ if pyptr.kind_of? PyObjectWrapper
|
180
180
|
return if pyptr.kind_of? LibPython::API::PyType_Type
|
181
|
-
return defined?(LibPython::API::PyClass_Type) && pyptr.kind_of?(LibPython::API::PyClass_Type)
|
181
|
+
return if defined?(LibPython::API::PyClass_Type) && pyptr.kind_of?(LibPython::API::PyClass_Type)
|
182
182
|
raise TypeError, "PyType object is required"
|
183
183
|
end
|
184
184
|
end
|
@@ -1,12 +1,85 @@
|
|
1
|
-
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
import ctypes.util
|
4
|
+
from distutils.sysconfig import get_config_var, get_python_version
|
5
|
+
import os
|
2
6
|
import sys
|
3
7
|
|
4
|
-
|
5
|
-
|
8
|
+
is_windows = os.name == "nt"
|
9
|
+
|
10
|
+
def linked_libpython():
|
11
|
+
if is_windows:
|
12
|
+
return _linked_libpython_windows()
|
13
|
+
return _linked_libpython_unix()
|
14
|
+
|
15
|
+
class Dl_info(ctypes.Structure):
|
16
|
+
_fields_ = [
|
17
|
+
("dli_fname", ctypes.c_char_p),
|
18
|
+
("dli_fbase", ctypes.c_void_p),
|
19
|
+
("dli_sname", ctypes.c_char_p),
|
20
|
+
("dli_saddr", ctypes.c_void_p),
|
21
|
+
]
|
22
|
+
|
23
|
+
def _linked_libpython_unix():
|
24
|
+
libdl = ctypes.CDLL(ctypes.util.find_library("dl"))
|
25
|
+
libdl.dladdr.argtypes = [ctypes.c_void_p, ctypes.POINTER(Dl_info)]
|
26
|
+
libdl.dladdr.restype = ctypes.c_int
|
27
|
+
|
28
|
+
dlinfo = Dl_info()
|
29
|
+
retcode = libdl.dladdr(
|
30
|
+
ctypes.cast(ctypes.pythonapi.Py_GetVersion, ctypes.c_void_p),
|
31
|
+
ctypes.pointer(dlinfo))
|
32
|
+
if retcode == 0: # means error
|
33
|
+
return None
|
34
|
+
path = os.path.realpath(dlinfo.dli_fname.decode())
|
35
|
+
if path == os.path.realpath(sys.executable):
|
36
|
+
return None
|
37
|
+
return path
|
38
|
+
|
39
|
+
def _linked_libpython_windows():
|
40
|
+
# Based on: https://stackoverflow.com/a/16659821
|
41
|
+
from ctypes.wintypes import HANDLE, LPWSTR, DWORD
|
42
|
+
|
43
|
+
GetModuleFileName = ctypes.windll.kernel32.GetModuleFileNameW
|
44
|
+
GetModuleFileName.argtypes = [HANDLE, LPWSTR, DWORD]
|
45
|
+
GetModuleFileName.restype = DWORD
|
46
|
+
|
47
|
+
MAX_PATH = 260
|
48
|
+
try:
|
49
|
+
buf = ctypes.create_unicode_buffer(MAX_PATH)
|
50
|
+
GetModuleFileName(ctypes.pythonapi._handle, buf, MAX_PATH)
|
51
|
+
return buf.value
|
52
|
+
except (ValueError, OSError):
|
53
|
+
return None
|
54
|
+
|
55
|
+
print("linked_libpython: {val}".format(val=(linked_libpython() or "None")))
|
56
|
+
|
57
|
+
sys_keys = [ "executable", "exec_prefix", "prefix" ]
|
58
|
+
|
59
|
+
for var in sys_keys:
|
60
|
+
print("{var}: {val}".format(var=var, val=(getattr(sys, var) or "None")))
|
61
|
+
|
62
|
+
config_keys = [ "INSTSONAME", "LIBDIR", "LIBPL", "LIBRARY", "LDLIBRARY",
|
63
|
+
"MULTIARCH", "PYTHONFRAMEWORKPREFIX", "SHLIB_SUFFIX", "srcdir" ]
|
64
|
+
|
65
|
+
for var in config_keys:
|
66
|
+
print("{var}: {val}".format(var=var, val=(get_config_var(var) or "None")))
|
67
|
+
|
68
|
+
print("ABIFLAGS: {val}".format(val=get_config_var("ABIFLAGS") or get_config_var("abiflags") or "None"))
|
69
|
+
|
70
|
+
version = get_python_version() or \
|
71
|
+
"{v.major}.{v.minor}".format(v=sys.version_info) or \
|
72
|
+
get_config_var("VERSION")
|
73
|
+
print("VERSION: {val}".format(val=version))
|
6
74
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
75
|
+
if is_windows:
|
76
|
+
if hasattr(sys, "base_exec_prefix"):
|
77
|
+
PYTHONHOME = sys.base_exec_prefix
|
78
|
+
else:
|
79
|
+
PYTHONHOME = sys.exec_prefix
|
80
|
+
else:
|
81
|
+
if hasattr(sys, "base_exec_prefix"):
|
82
|
+
PYTHONHOME = ":".join([sys.base_prefix, sys.base_exec_prefix])
|
83
|
+
else:
|
84
|
+
PYTHONHOME = ":".join([sys.prefix, sys.exec_prefix])
|
85
|
+
print("PYTHONHOME: {val}".format(val=PYTHONHOME))
|
@@ -51,8 +51,18 @@ module PyCall
|
|
51
51
|
|
52
52
|
def <(other)
|
53
53
|
case other
|
54
|
+
when self
|
55
|
+
false
|
54
56
|
when PyTypeObjectWrapper
|
55
57
|
__pyptr__ < other.__pyptr__
|
58
|
+
when Class
|
59
|
+
false if other.ancestors.include?(self)
|
60
|
+
when Module
|
61
|
+
if ancestors.include?(other)
|
62
|
+
true
|
63
|
+
elsif other.ancestors.include?(self)
|
64
|
+
false
|
65
|
+
end
|
56
66
|
else
|
57
67
|
raise TypeError, "compared with non class/module"
|
58
68
|
end
|
data/lib/pycall/version.rb
CHANGED
@@ -1,5 +1,54 @@
|
|
1
1
|
module PyCall
|
2
2
|
class WrapperObjectCache
|
3
|
+
|
4
|
+
begin
|
5
|
+
ObjectSpace::WeakMap.new[42] = Object.new
|
6
|
+
rescue
|
7
|
+
WMAP_SUPPORT_INT_KEY = false
|
8
|
+
else
|
9
|
+
case RUBY_PLATFORM
|
10
|
+
when /cygwin/, /mingw/, /mswin/
|
11
|
+
WMAP_SUPPORT_INT_KEY = false
|
12
|
+
else
|
13
|
+
WMAP_SUPPORT_INT_KEY = true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if WMAP_SUPPORT_INT_KEY
|
18
|
+
def self.get_key(pyptr)
|
19
|
+
pyptr.__address__
|
20
|
+
end
|
21
|
+
else
|
22
|
+
class Key
|
23
|
+
@address_key_map = {}
|
24
|
+
|
25
|
+
def self.[](address)
|
26
|
+
# An instance of Key created here is parmanently cached in @address_key_map.
|
27
|
+
# This behavior is intentional.
|
28
|
+
@address_key_map[address] ||= new(address)
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(address)
|
32
|
+
@address = address
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :address
|
36
|
+
|
37
|
+
def ==(other)
|
38
|
+
case other
|
39
|
+
when Key
|
40
|
+
self.address == other.address
|
41
|
+
else
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.get_key(pyptr)
|
48
|
+
Key[pyptr.__address__]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
3
52
|
def initialize(*restricted_pytypes)
|
4
53
|
unless restricted_pytypes.empty?
|
5
54
|
restricted_pytypes.each do |pytype|
|
@@ -8,9 +57,7 @@ module PyCall
|
|
8
57
|
end
|
9
58
|
end
|
10
59
|
@restricted_pytypes = restricted_pytypes
|
11
|
-
@wrapper_object_table =
|
12
|
-
@wrapped_pyptr_table = {}
|
13
|
-
@weakref_table = {}
|
60
|
+
@wrapper_object_table = ObjectSpace::WeakMap.new
|
14
61
|
end
|
15
62
|
|
16
63
|
def lookup(pyptr)
|
@@ -25,16 +72,14 @@ module PyCall
|
|
25
72
|
end
|
26
73
|
end
|
27
74
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
75
|
+
key = self.class.get_key(pyptr)
|
76
|
+
wrapper_object = @wrapper_object_table[key]
|
77
|
+
unless wrapper_object
|
78
|
+
wrapper_object = yield(pyptr)
|
79
|
+
check_wrapper_object(wrapper_object)
|
80
|
+
@wrapper_object_table[key] = wrapper_object
|
32
81
|
end
|
33
82
|
|
34
|
-
wrapper_object = yield(pyptr)
|
35
|
-
check_wrapper_object(wrapper_object)
|
36
|
-
register_wrapper_object(pyptr, wrapper_object)
|
37
|
-
|
38
83
|
wrapper_object
|
39
84
|
end
|
40
85
|
|
@@ -43,19 +88,5 @@ module PyCall
|
|
43
88
|
raise TypeError, "unexpected wrapper object (expected an object extended by PyObjectWrapper)"
|
44
89
|
end
|
45
90
|
end
|
46
|
-
|
47
|
-
def register_wrapper_object(pyptr, wrapper_object)
|
48
|
-
@wrapper_object_table[pyptr.__address__] = wrapper_object.__id__
|
49
|
-
@wrapped_pyptr_table[wrapper_object.__id__] = pyptr.__address__
|
50
|
-
ObjectSpace.define_finalizer(wrapper_object, &method(:unregister_wrapper_object))
|
51
|
-
# TODO: weakref
|
52
|
-
self
|
53
|
-
end
|
54
|
-
|
55
|
-
def unregister_wrapper_object(wrapper_object_id)
|
56
|
-
pyptr_addr = @wrapped_pyptr_table.delete(wrapper_object_id)
|
57
|
-
@wrapper_object_table.delete(pyptr_addr) if pyptr_addr
|
58
|
-
self
|
59
|
-
end
|
60
91
|
end
|
61
92
|
end
|
data/pycall.gemspec
CHANGED
@@ -5,7 +5,13 @@ require 'pycall/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "pycall"
|
8
|
-
|
8
|
+
version_components = [
|
9
|
+
PyCall::Version::MAJOR.to_s,
|
10
|
+
PyCall::Version::MINOR.to_s,
|
11
|
+
PyCall::Version::MICRO.to_s,
|
12
|
+
PyCall::Version::TAG,
|
13
|
+
]
|
14
|
+
spec.version = version_components.compact.join(".")
|
9
15
|
spec.authors = ["Kenta Murata"]
|
10
16
|
spec.email = ["mrkn@mrkn.jp"]
|
11
17
|
|
@@ -30,7 +36,7 @@ Gem::Specification.new do |spec|
|
|
30
36
|
spec.require_paths = ["lib"]
|
31
37
|
spec.extensions = ["ext/pycall/extconf.rb"]
|
32
38
|
|
33
|
-
spec.add_development_dependency "bundler"
|
39
|
+
spec.add_development_dependency "bundler"
|
34
40
|
spec.add_development_dependency "rake"
|
35
41
|
spec.add_development_dependency "rake-compiler"
|
36
42
|
spec.add_development_dependency "rake-compiler-dock"
|
@@ -38,4 +44,5 @@ Gem::Specification.new do |spec|
|
|
38
44
|
spec.add_development_dependency "launchy"
|
39
45
|
spec.add_development_dependency "pry"
|
40
46
|
spec.add_development_dependency "pry-byebug"
|
47
|
+
spec.add_development_dependency "test-unit"
|
41
48
|
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: 1.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenta Murata
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: test-unit
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
125
139
|
description: pycall
|
126
140
|
email:
|
127
141
|
- mrkn@mrkn.jp
|
@@ -130,15 +144,15 @@ extensions:
|
|
130
144
|
- ext/pycall/extconf.rb
|
131
145
|
extra_rdoc_files: []
|
132
146
|
files:
|
147
|
+
- ".github/workflows/ci.yml"
|
148
|
+
- ".github/workflows/windows.yml"
|
133
149
|
- ".gitignore"
|
134
150
|
- ".rspec"
|
135
|
-
- ".travis.yml"
|
136
151
|
- CHANGES.md
|
137
152
|
- Gemfile
|
138
153
|
- LICENSE.txt
|
139
154
|
- README.md
|
140
155
|
- Rakefile
|
141
|
-
- appveyor.yml
|
142
156
|
- bin/console
|
143
157
|
- bin/guard
|
144
158
|
- bin/rspec
|
@@ -157,6 +171,7 @@ files:
|
|
157
171
|
- examples/notebooks/classifier_comparison.ipynb
|
158
172
|
- examples/notebooks/forest_importances.ipynb
|
159
173
|
- examples/notebooks/iruby_integration.ipynb
|
174
|
+
- examples/notebooks/leaflet.ipynb
|
160
175
|
- examples/notebooks/lorenz_attractor.ipynb
|
161
176
|
- examples/notebooks/polar_axes.ipynb
|
162
177
|
- examples/notebooks/sum_benchmarking.ipynb
|
@@ -171,6 +186,7 @@ files:
|
|
171
186
|
- ext/pycall/pycall_internal.h
|
172
187
|
- ext/pycall/range.c
|
173
188
|
- ext/pycall/ruby_wrapper.c
|
189
|
+
- ext/pycall/thread.c
|
174
190
|
- images/pycallrb_logo.png
|
175
191
|
- images/pycallrb_logo_200.png
|
176
192
|
- lib/pycall.rb
|
@@ -180,6 +196,7 @@ files:
|
|
180
196
|
- lib/pycall/import.rb
|
181
197
|
- lib/pycall/init.rb
|
182
198
|
- lib/pycall/iruby_helper.rb
|
199
|
+
- lib/pycall/iterable_wrapper.rb
|
183
200
|
- lib/pycall/libpython.rb
|
184
201
|
- lib/pycall/libpython/finder.rb
|
185
202
|
- lib/pycall/libpython/pyobject_struct.rb
|
@@ -219,7 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
236
|
- !ruby/object:Gem::Version
|
220
237
|
version: '0'
|
221
238
|
requirements: []
|
222
|
-
rubygems_version: 3.
|
239
|
+
rubygems_version: 3.2.21
|
223
240
|
signing_key:
|
224
241
|
specification_version: 4
|
225
242
|
summary: pycall
|
data/.travis.yml
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
|
3
|
-
os: linux
|
4
|
-
|
5
|
-
dist: trusty
|
6
|
-
sudo: required
|
7
|
-
|
8
|
-
rvm:
|
9
|
-
- ruby-head
|
10
|
-
- 2.5.0
|
11
|
-
- 2.4.3
|
12
|
-
- 2.3.5
|
13
|
-
|
14
|
-
env:
|
15
|
-
global:
|
16
|
-
- PYCALL_DEBUG_FIND_LIBPYTHON=1
|
17
|
-
matrix:
|
18
|
-
- PYENV_VERSION=2.7.13
|
19
|
-
- PYENV_VERSION=3.6.2
|
20
|
-
- PYENV_VERSION=system LIBPYTHON=versions/3.6.2/lib/libpython3.6m.so
|
21
|
-
- PYENV_VERSION=miniconda2-4.1.11
|
22
|
-
- PYENV_VERSION=miniconda3-4.3.11
|
23
|
-
|
24
|
-
matrix:
|
25
|
-
include:
|
26
|
-
- os: osx
|
27
|
-
osx_image: xcode9
|
28
|
-
compiler: clang
|
29
|
-
rvm: 2.4.1
|
30
|
-
env: PYENV_VERSION=3.6.2
|
31
|
-
- os: osx
|
32
|
-
osx_image: xcode9
|
33
|
-
compiler: clang
|
34
|
-
rvm: 2.4.1
|
35
|
-
env: PYENV_VERSION=system LIBPYTHON=versions/3.6.2/lib/libpython3.6m.so
|
36
|
-
- os: osx
|
37
|
-
osx_image: xcode9
|
38
|
-
compiler: clang
|
39
|
-
rvm: 2.4.1
|
40
|
-
env: PYENV_VERSION=miniconda3-4.3.11
|
41
|
-
allow_failures:
|
42
|
-
- os: osx
|
43
|
-
|
44
|
-
before_install:
|
45
|
-
- gem update --system
|
46
|
-
- gem update bundler
|
47
|
-
- export PATH="$(pyenv root)/bin:$PATH"
|
48
|
-
- eval "$(pyenv init -)"
|
49
|
-
|
50
|
-
install:
|
51
|
-
- ci/travis_install.sh
|
52
|
-
|
53
|
-
before_script:
|
54
|
-
- . ci/travis_before_script.sh
|
55
|
-
- bundle exec rake clobber compile
|
56
|
-
- python lib/pycall/python/investigator.py
|