pycall 1.3.1 → 1.4.0
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 +133 -50
- data/.github/workflows/windows.yml +127 -0
- data/.gitignore +2 -0
- data/CHANGES.md +8 -0
- data/README.md +112 -6
- data/Rakefile +81 -19
- data/examples/notebooks/leaflet.ipynb +77 -0
- data/ext/pycall/pycall_internal.h +1 -1
- data/ext/pycall/ruby_wrapper.c +11 -2
- data/lib/pycall.rb +11 -0
- data/lib/pycall/init.rb +3 -8
- data/lib/pycall/libpython/finder.rb +126 -78
- data/lib/pycall/python/investigator.py +83 -6
- data/lib/pycall/version.rb +1 -1
- data/lib/pycall/wrapper_object_cache.rb +51 -25
- data/pycall.gemspec +1 -0
- metadata +19 -5
- data/.travis.yml +0 -82
- data/appveyor.yml +0 -92
@@ -1,8 +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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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))
|
74
|
+
|
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))
|
data/lib/pycall/version.rb
CHANGED
@@ -1,5 +1,49 @@
|
|
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
|
+
WMAP_SUPPORT_INT_KEY = true
|
10
|
+
end
|
11
|
+
|
12
|
+
if WMAP_SUPPORT_INT_KEY
|
13
|
+
def self.get_key(pyptr)
|
14
|
+
pyptr.__address__
|
15
|
+
end
|
16
|
+
else
|
17
|
+
class Key
|
18
|
+
@address_key_map = {}
|
19
|
+
|
20
|
+
def self.[](address)
|
21
|
+
# An instance of Key created here is parmanently cached in @address_key_map.
|
22
|
+
# This behavior is intentional.
|
23
|
+
@address_key_map[address] ||= new(address)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(address)
|
27
|
+
@address = address
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :address
|
31
|
+
|
32
|
+
def ==(other)
|
33
|
+
case other
|
34
|
+
when Key
|
35
|
+
self.address == other.address
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.get_key(pyptr)
|
43
|
+
Key[pyptr.__address__]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
3
47
|
def initialize(*restricted_pytypes)
|
4
48
|
unless restricted_pytypes.empty?
|
5
49
|
restricted_pytypes.each do |pytype|
|
@@ -8,9 +52,7 @@ module PyCall
|
|
8
52
|
end
|
9
53
|
end
|
10
54
|
@restricted_pytypes = restricted_pytypes
|
11
|
-
@wrapper_object_table =
|
12
|
-
@wrapped_pyptr_table = {}
|
13
|
-
@weakref_table = {}
|
55
|
+
@wrapper_object_table = ObjectSpace::WeakMap.new
|
14
56
|
end
|
15
57
|
|
16
58
|
def lookup(pyptr)
|
@@ -25,16 +67,14 @@ module PyCall
|
|
25
67
|
end
|
26
68
|
end
|
27
69
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
70
|
+
key = self.class.get_key(pyptr)
|
71
|
+
wrapper_object = @wrapper_object_table[key]
|
72
|
+
unless wrapper_object
|
73
|
+
wrapper_object = yield(pyptr)
|
74
|
+
check_wrapper_object(wrapper_object)
|
75
|
+
@wrapper_object_table[key] = wrapper_object
|
32
76
|
end
|
33
77
|
|
34
|
-
wrapper_object = yield(pyptr)
|
35
|
-
check_wrapper_object(wrapper_object)
|
36
|
-
register_wrapper_object(pyptr, wrapper_object)
|
37
|
-
|
38
78
|
wrapper_object
|
39
79
|
end
|
40
80
|
|
@@ -43,19 +83,5 @@ module PyCall
|
|
43
83
|
raise TypeError, "unexpected wrapper object (expected an object extended by PyObjectWrapper)"
|
44
84
|
end
|
45
85
|
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
86
|
end
|
61
87
|
end
|
data/pycall.gemspec
CHANGED
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.0
|
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-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -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
|
@@ -131,15 +145,14 @@ extensions:
|
|
131
145
|
extra_rdoc_files: []
|
132
146
|
files:
|
133
147
|
- ".github/workflows/ci.yml"
|
148
|
+
- ".github/workflows/windows.yml"
|
134
149
|
- ".gitignore"
|
135
150
|
- ".rspec"
|
136
|
-
- ".travis.yml"
|
137
151
|
- CHANGES.md
|
138
152
|
- Gemfile
|
139
153
|
- LICENSE.txt
|
140
154
|
- README.md
|
141
155
|
- Rakefile
|
142
|
-
- appveyor.yml
|
143
156
|
- bin/console
|
144
157
|
- bin/guard
|
145
158
|
- bin/rspec
|
@@ -158,6 +171,7 @@ files:
|
|
158
171
|
- examples/notebooks/classifier_comparison.ipynb
|
159
172
|
- examples/notebooks/forest_importances.ipynb
|
160
173
|
- examples/notebooks/iruby_integration.ipynb
|
174
|
+
- examples/notebooks/leaflet.ipynb
|
161
175
|
- examples/notebooks/lorenz_attractor.ipynb
|
162
176
|
- examples/notebooks/polar_axes.ipynb
|
163
177
|
- examples/notebooks/sum_benchmarking.ipynb
|
@@ -221,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
221
235
|
- !ruby/object:Gem::Version
|
222
236
|
version: '0'
|
223
237
|
requirements: []
|
224
|
-
rubygems_version: 3.
|
238
|
+
rubygems_version: 3.2.3
|
225
239
|
signing_key:
|
226
240
|
specification_version: 4
|
227
241
|
summary: pycall
|
data/.travis.yml
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
|
3
|
-
os: linux
|
4
|
-
|
5
|
-
dist: bionic
|
6
|
-
sudo: required
|
7
|
-
|
8
|
-
rvm:
|
9
|
-
- ruby-head
|
10
|
-
- 2.7
|
11
|
-
- 2.6
|
12
|
-
- 2.5
|
13
|
-
- 2.4
|
14
|
-
|
15
|
-
env:
|
16
|
-
global:
|
17
|
-
- PYCALL_DEBUG_FIND_LIBPYTHON=1
|
18
|
-
matrix:
|
19
|
-
- PYENV_VERSION=3.8.0
|
20
|
-
- PYENV_VERSION=3.7.5
|
21
|
-
- PYENV_VERSION=2.7.17
|
22
|
-
- PYENV_VERSION=system LIBPYTHON=/usr/lib/x86_64-linux-gnu/libpython3.6m.so
|
23
|
-
- PYENV_VERSION=system LIBPYTHON=/usr/lib/x86_64-linux-gnu/libpython2.7.so
|
24
|
-
- PYENV_VERSION=miniconda2-4.3.30
|
25
|
-
- PYENV_VERSION=miniconda3-4.3.30
|
26
|
-
|
27
|
-
matrix:
|
28
|
-
include:
|
29
|
-
- os: osx
|
30
|
-
osx_image: xcode11.2
|
31
|
-
compiler: clang
|
32
|
-
rvm: 2.7
|
33
|
-
env: PYENV_VERSION=3.8.0
|
34
|
-
- os: osx
|
35
|
-
osx_image: xcode11.2
|
36
|
-
compiler: clang
|
37
|
-
rvm: 2.6
|
38
|
-
env: PYENV_VERSION=3.8.0
|
39
|
-
- os: osx
|
40
|
-
osx_image: xcode11.2
|
41
|
-
compiler: clang
|
42
|
-
rvm: 2.5
|
43
|
-
env: PYENV_VERSION=3.8.0
|
44
|
-
- os: osx
|
45
|
-
osx_image: xcode11.2
|
46
|
-
compiler: clang
|
47
|
-
rvm: 2.4
|
48
|
-
env: PYENV_VERSION=3.8.0
|
49
|
-
- os: osx
|
50
|
-
osx_image: xcode11.2
|
51
|
-
compiler: clang
|
52
|
-
rvm: 2.7
|
53
|
-
env: PYENV_VERSION=miniconda3-4.3.11
|
54
|
-
- os: osx
|
55
|
-
osx_image: xcode11.2
|
56
|
-
compiler: clang
|
57
|
-
rvm: 2.6
|
58
|
-
env: PYENV_VERSION=miniconda3-4.3.11
|
59
|
-
- os: osx
|
60
|
-
osx_image: xcode11.2
|
61
|
-
compiler: clang
|
62
|
-
rvm: 2.5
|
63
|
-
env: PYENV_VERSION=miniconda3-4.3.11
|
64
|
-
- os: osx
|
65
|
-
osx_image: xcode11.2
|
66
|
-
compiler: clang
|
67
|
-
rvm: 2.4
|
68
|
-
env: PYENV_VERSION=miniconda3-4.3.11
|
69
|
-
allow_failures:
|
70
|
-
- os: osx
|
71
|
-
|
72
|
-
before_install:
|
73
|
-
- export PATH="$(pyenv root)/bin:$PATH"
|
74
|
-
- eval "$(pyenv init -)"
|
75
|
-
|
76
|
-
install:
|
77
|
-
- ci/travis_install.sh
|
78
|
-
|
79
|
-
before_script:
|
80
|
-
- . ci/travis_before_script.sh
|
81
|
-
- bundle exec rake clobber compile
|
82
|
-
- python lib/pycall/python/investigator.py
|
data/appveyor.yml
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
---
|
2
|
-
environment:
|
3
|
-
matrix:
|
4
|
-
# Ruby 2.4 (32bit)
|
5
|
-
- ruby_version: "24"
|
6
|
-
PYTHONDIR: "C:\\Python27"
|
7
|
-
PYTHON: "C:\\Python27\\python.exe"
|
8
|
-
|
9
|
-
- ruby_version: "24"
|
10
|
-
PYTHONDIR: "C:\\Python35"
|
11
|
-
PYTHON: "C:\\Python35\\python.exe"
|
12
|
-
|
13
|
-
- ruby_version: "24"
|
14
|
-
PYTHONDIR: "C:\\Python36"
|
15
|
-
PYTHON: "C:\\Python36\\python.exe"
|
16
|
-
|
17
|
-
# Ruby 2.4 (64bit)
|
18
|
-
- ruby_version: "24-x64"
|
19
|
-
PYTHONDIR: "C:\\Python27-x64"
|
20
|
-
PYTHON: "C:\\Python27-x64\\python.exe"
|
21
|
-
|
22
|
-
- ruby_version: "24-x64"
|
23
|
-
PYTHONDIR: "C:\\Python35-x64"
|
24
|
-
PYTHON: "C:\\Python35-x64\\python.exe"
|
25
|
-
|
26
|
-
- ruby_version: "24-x64"
|
27
|
-
PYTHONDIR: "C:\\Python36-x64"
|
28
|
-
PYTHON: "C:\\Python36-x64\\python.exe"
|
29
|
-
|
30
|
-
# Ruby 2.3 (32bit)
|
31
|
-
- ruby_version: "23"
|
32
|
-
PYTHONDIR: "C:\\Python27"
|
33
|
-
PYTHON: "C:\\Python27\\python.exe"
|
34
|
-
|
35
|
-
- ruby_version: "23"
|
36
|
-
PYTHONDIR: "C:\\Python34"
|
37
|
-
PYTHON: "C:\\Python34\\python.exe"
|
38
|
-
|
39
|
-
- ruby_version: "23"
|
40
|
-
PYTHONDIR: "C:\\Python35"
|
41
|
-
PYTHON: "C:\\Python35\\python.exe"
|
42
|
-
|
43
|
-
- ruby_version: "23"
|
44
|
-
PYTHONDIR: "C:\\Python36"
|
45
|
-
PYTHON: "C:\\Python36\\python.exe"
|
46
|
-
|
47
|
-
# Ruby 2.3 (64bit)
|
48
|
-
- ruby_version: "23-x64"
|
49
|
-
PYTHONDIR: "C:\\Python27-x64"
|
50
|
-
PYTHON: "C:\\Python27-x64\\python.exe"
|
51
|
-
|
52
|
-
- ruby_version: "23-x64"
|
53
|
-
PYTHONDIR: "C:\\Python35-x64"
|
54
|
-
PYTHON: "C:\\Python35-x64\\python.exe"
|
55
|
-
|
56
|
-
- ruby_version: "23-x64"
|
57
|
-
PYTHONDIR: "C:\\Python36-x64"
|
58
|
-
PYTHON: "C:\\Python36-x64\\python.exe"
|
59
|
-
|
60
|
-
branches:
|
61
|
-
only:
|
62
|
-
- master
|
63
|
-
- /release-.*/
|
64
|
-
|
65
|
-
notifications:
|
66
|
-
- provider: Email
|
67
|
-
on_build_success: false
|
68
|
-
on_build_failure: false
|
69
|
-
on_build_status_changed: false
|
70
|
-
|
71
|
-
deploy: off
|
72
|
-
build: off
|
73
|
-
|
74
|
-
install:
|
75
|
-
- "SET PATH=%PYTHONDIR%;%PYTHONDIR%\\Scripts;%PATH%"
|
76
|
-
- "SET PATH=C:\\Ruby%ruby_version%\\bin;%PATH%"
|
77
|
-
- "bundle install"
|
78
|
-
- "pip install numpy"
|
79
|
-
|
80
|
-
before_test:
|
81
|
-
- "bundle exec rake -rdevkit clobber compile"
|
82
|
-
- ECHO "=== python investigator.py ==="
|
83
|
-
- "python lib\\pycall\\python\\investigator.py"
|
84
|
-
|
85
|
-
test_script:
|
86
|
-
- "SET PYCALL_DEBUG_FIND_LIBPYTHON=1"
|
87
|
-
- rake
|
88
|
-
|
89
|
-
matrix:
|
90
|
-
allow_failures:
|
91
|
-
- PYTHONDIR: "C:\\Python27"
|
92
|
-
- PYTHONDIR: "C:\\Python27-x64"
|