pycall 1.2.0 → 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 +150 -0
- data/.github/workflows/windows.yml +127 -0
- data/.gitignore +2 -0
- data/CHANGES.md +39 -1
- 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/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 +11 -0
- data/lib/pycall/dict.rb +2 -2
- data/lib/pycall/init.rb +3 -8
- data/lib/pycall/iruby_helper.rb +1 -1
- 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 +51 -25
- data/pycall.gemspec +9 -2
- metadata +23 -7
- data/.travis.yml +0 -56
- data/appveyor.yml +0 -104
data/Rakefile
CHANGED
@@ -1,31 +1,93 @@
|
|
1
|
-
require "bundler"
|
2
|
-
|
1
|
+
require "bundler/gem_helper"
|
2
|
+
require "rake/clean"
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
base_dir = File.join(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
helper = Bundler::GemHelper.new(base_dir)
|
7
|
+
helper.install
|
8
|
+
spec = helper.gemspec
|
9
|
+
|
10
|
+
def run_extconf(build_dir, extension_dir, *arguments)
|
11
|
+
cd(build_dir) do
|
12
|
+
ruby(File.join(extension_dir, "extconf.rb"), *arguments)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def make_command
|
17
|
+
if RUBY_PLATFORM =~ /mswin/
|
18
|
+
"nmake"
|
19
|
+
else
|
20
|
+
ENV["MAKE"] || find_make
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_make
|
25
|
+
candidates = ["gmake", "make"]
|
26
|
+
paths = ENV.fetch("PATH", "").split(File::PATH_SEPARATOR)
|
27
|
+
exeext = RbConfig::CONFIG["EXEEXT"]
|
28
|
+
candidates.each do |candidate|
|
29
|
+
paths.each do |path|
|
30
|
+
cmd = File.join(path, "#{candidate}#{exeext}")
|
31
|
+
return cmd if File.executable?(cmd)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
7
35
|
|
8
36
|
Dir[File.expand_path('../tasks/**/*.rake', __FILE__)].each {|f| load f }
|
9
37
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
38
|
+
spec.extensions.each do |extension|
|
39
|
+
extension_dir = File.join(base_dir, File.dirname(extension))
|
40
|
+
build_dir = ENV["BUILD_DIR"]
|
41
|
+
if build_dir
|
42
|
+
build_dir = File.join(build_dir, "pycall")
|
43
|
+
directory build_dir
|
44
|
+
else
|
45
|
+
build_dir = extension_dir
|
46
|
+
end
|
47
|
+
|
48
|
+
makefile = File.join(build_dir, "Makefile")
|
49
|
+
file makefile => build_dir do
|
50
|
+
run_extconf(build_dir, extension_dir)
|
51
|
+
end
|
52
|
+
|
53
|
+
CLOBBER << makefile
|
54
|
+
CLOBBER << File.join(build_dir, "mkmf.log")
|
55
|
+
|
56
|
+
desc "Configure"
|
57
|
+
task configure: makefile
|
58
|
+
|
59
|
+
desc "Compile"
|
60
|
+
task compile: makefile do
|
61
|
+
cd(build_dir) do
|
62
|
+
sh(make_command)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
task :clean do
|
67
|
+
cd(build_dir) do
|
68
|
+
sh(make_command, "clean") if File.exist?("Makefile")
|
69
|
+
end
|
17
70
|
end
|
18
71
|
end
|
19
72
|
|
20
|
-
|
73
|
+
require "rake/extensiontask"
|
74
|
+
Rake::ExtensionTask.new("pycall/spec_helper")
|
21
75
|
|
22
|
-
desc "
|
23
|
-
task
|
24
|
-
|
25
|
-
|
76
|
+
desc "Run tests"
|
77
|
+
task :test do
|
78
|
+
cd(base_dir) do
|
79
|
+
ruby("test/run-test.rb")
|
80
|
+
end
|
26
81
|
end
|
27
82
|
|
28
|
-
|
83
|
+
task default: :test
|
84
|
+
|
85
|
+
require "rspec/core/rake_task"
|
86
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
87
|
+
ext_dir = File.join(base_dir, "ext/pycall")
|
88
|
+
t.ruby_opts = "-I#{ext_dir}"
|
89
|
+
t.verbose = true
|
90
|
+
end
|
29
91
|
|
30
|
-
task :
|
92
|
+
task default: :spec
|
31
93
|
task spec: :compile
|
data/ci/travis_install.sh
CHANGED
@@ -10,19 +10,35 @@ if test -z "$PYENV_VERSION"; then
|
|
10
10
|
exit 1
|
11
11
|
fi
|
12
12
|
|
13
|
+
pyenv_root=$(pyenv root)
|
14
|
+
|
13
15
|
if test -n "$LIBPYTHON"; then
|
14
|
-
|
16
|
+
if test ! -f $LIBPYTHON; then
|
17
|
+
if test -f ${pyenv_root}/$LIBPYTHON; then
|
18
|
+
export LIBPYTHON=${pyenv_root}/$LIBPYTHON
|
19
|
+
else
|
20
|
+
echo "Invalid value in LIBPYTHON: ${LIBPYTHON}" >&2
|
21
|
+
exit 1
|
22
|
+
fi
|
23
|
+
fi
|
15
24
|
fi
|
16
25
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
26
|
+
(
|
27
|
+
cd $(pyenv root)
|
28
|
+
if [ -d .git ]; then
|
29
|
+
git fetch origin
|
30
|
+
git checkout master
|
31
|
+
git reset --hard origin/master
|
21
32
|
fi
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
33
|
+
)
|
34
|
+
|
35
|
+
case $PYENV_VERSION in
|
36
|
+
system)
|
37
|
+
;;
|
38
|
+
*)
|
39
|
+
PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install -f $PYENV_VERSION
|
40
|
+
;;
|
41
|
+
esac
|
26
42
|
|
27
43
|
case "$PYENV_VERSION" in
|
28
44
|
*conda*)
|
@@ -40,6 +56,11 @@ case "$PYENV_VERSION" in
|
|
40
56
|
travis_retry conda create -q -n test-environment python=$python_version numpy
|
41
57
|
source $(pyenv prefix)/bin/activate test-environment
|
42
58
|
;;
|
59
|
+
system)
|
60
|
+
travis_retry pip install --user numpy
|
61
|
+
sudo sh -c "apt-get update && apt-get install --no-install-recommends -y python3-pip"
|
62
|
+
travis_retry python3.6 -m pip install --user numpy
|
63
|
+
;;
|
43
64
|
*)
|
44
65
|
travis_retry pip install --user numpy
|
45
66
|
;;
|
@@ -2,7 +2,7 @@ require 'pycall/import'
|
|
2
2
|
include PyCall::Import
|
3
3
|
|
4
4
|
pyimport 'numpy', as: :np
|
5
|
-
pyfrom 'sklearn.
|
5
|
+
pyfrom 'sklearn.model_selection', import: :train_test_split
|
6
6
|
pyfrom 'sklearn.preprocessing', import: :StandardScaler
|
7
7
|
pyfrom 'sklearn.datasets', import: %i(make_moons make_circles make_classification)
|
8
8
|
pyfrom 'sklearn.neighbors', import: :KNeighborsClassifier
|
data/examples/hist.rb
CHANGED
@@ -38,7 +38,7 @@
|
|
38
38
|
"include PyCall::Import\n",
|
39
39
|
"\n",
|
40
40
|
"pyimport 'numpy', as: :np\n",
|
41
|
-
"pyfrom 'sklearn.
|
41
|
+
"pyfrom 'sklearn.model_selection', import: :train_test_split\n",
|
42
42
|
"pyfrom 'sklearn.preprocessing', import: :StandardScaler\n",
|
43
43
|
"pyfrom 'sklearn.datasets', import: %i(make_moons make_circles make_classification)\n",
|
44
44
|
"pyfrom 'sklearn.neighbors', import: :KNeighborsClassifier\n",
|
@@ -0,0 +1,77 @@
|
|
1
|
+
{
|
2
|
+
"cells": [
|
3
|
+
{
|
4
|
+
"cell_type": "code",
|
5
|
+
"execution_count": 1,
|
6
|
+
"id": "burning-montreal",
|
7
|
+
"metadata": {},
|
8
|
+
"outputs": [
|
9
|
+
{
|
10
|
+
"data": {
|
11
|
+
"text/plain": [
|
12
|
+
"<module 'folium' from '/opt/brew/Cellar/python@3.9/3.9.2/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/folium/__init__.py'>"
|
13
|
+
]
|
14
|
+
},
|
15
|
+
"execution_count": 1,
|
16
|
+
"metadata": {},
|
17
|
+
"output_type": "execute_result"
|
18
|
+
}
|
19
|
+
],
|
20
|
+
"source": [
|
21
|
+
"require \"pycall\"\n",
|
22
|
+
"folium = PyCall.import_module(\"folium\")"
|
23
|
+
]
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"cell_type": "code",
|
27
|
+
"execution_count": 7,
|
28
|
+
"id": "resistant-agriculture",
|
29
|
+
"metadata": {
|
30
|
+
"scrolled": false
|
31
|
+
},
|
32
|
+
"outputs": [
|
33
|
+
{
|
34
|
+
"data": {
|
35
|
+
"text/html": [
|
36
|
+
"<div style=\"width:100%;\"><div style=\"position:relative;width:100%;height:0;padding-bottom:60%;\"><span style=\"color:#565656\">Make this Notebook Trusted to load map: File -> Trust Notebook</span><iframe src=\"about:blank\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" data-html=%3C%21DOCTYPE%20html%3E%0A%3Chead%3E%20%20%20%20%0A%20%20%20%20%3Cmeta%20http-equiv%3D%22content-type%22%20content%3D%22text/html%3B%20charset%3DUTF-8%22%20/%3E%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20%3Cscript%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20L_NO_TOUCH%20%3D%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20L_DISABLE_3D%20%3D%20false%3B%0A%20%20%20%20%20%20%20%20%3C/script%3E%0A%20%20%20%20%0A%20%20%20%20%3Cstyle%3Ehtml%2C%20body%20%7Bwidth%3A%20100%25%3Bheight%3A%20100%25%3Bmargin%3A%200%3Bpadding%3A%200%3B%7D%3C/style%3E%0A%20%20%20%20%3Cstyle%3E%23map%20%7Bposition%3Aabsolute%3Btop%3A0%3Bbottom%3A0%3Bright%3A0%3Bleft%3A0%3B%7D%3C/style%3E%0A%20%20%20%20%3Cscript%20src%3D%22https%3A//cdn.jsdelivr.net/npm/leaflet%401.6.0/dist/leaflet.js%22%3E%3C/script%3E%0A%20%20%20%20%3Cscript%20src%3D%22https%3A//code.jquery.com/jquery-1.12.4.min.js%22%3E%3C/script%3E%0A%20%20%20%20%3Cscript%20src%3D%22https%3A//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js%22%3E%3C/script%3E%0A%20%20%20%20%3Cscript%20src%3D%22https%3A//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js%22%3E%3C/script%3E%0A%20%20%20%20%3Clink%20rel%3D%22stylesheet%22%20href%3D%22https%3A//cdn.jsdelivr.net/npm/leaflet%401.6.0/dist/leaflet.css%22/%3E%0A%20%20%20%20%3Clink%20rel%3D%22stylesheet%22%20href%3D%22https%3A//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css%22/%3E%0A%20%20%20%20%3Clink%20rel%3D%22stylesheet%22%20href%3D%22https%3A//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css%22/%3E%0A%20%20%20%20%3Clink%20rel%3D%22stylesheet%22%20href%3D%22https%3A//maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css%22/%3E%0A%20%20%20%20%3Clink%20rel%3D%22stylesheet%22%20href%3D%22https%3A//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css%22/%3E%0A%20%20%20%20%3Clink%20rel%3D%22stylesheet%22%20href%3D%22https%3A//cdn.jsdelivr.net/gh/python-visualization/folium/folium/templates/leaflet.awesome.rotate.min.css%22/%3E%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cmeta%20name%3D%22viewport%22%20content%3D%22width%3Ddevice-width%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20initial-scale%3D1.0%2C%20maximum-scale%3D1.0%2C%20user-scalable%3Dno%22%20/%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cstyle%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23map_5fca0053c20247f19cc1284357d59a29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20position%3A%20relative%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20width%3A%20100.0%25%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20height%3A%20100.0%25%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20left%3A%200.0%25%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20top%3A%200.0%25%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C/style%3E%0A%20%20%20%20%20%20%20%20%0A%3C/head%3E%0A%3Cbody%3E%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22folium-map%22%20id%3D%22map_5fca0053c20247f19cc1284357d59a29%22%20%3E%3C/div%3E%0A%20%20%20%20%20%20%20%20%0A%3C/body%3E%0A%3Cscript%3E%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20map_5fca0053c20247f19cc1284357d59a29%20%3D%20L.map%28%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22map_5fca0053c20247f19cc1284357d59a29%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20center%3A%20%5B35.68053684909772%2C%20139.75749875116222%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20crs%3A%20L.CRS.EPSG3857%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20zoom%3A%2015%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20zoomControl%3A%20true%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20preferCanvas%3A%20false%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%29%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%0A%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20tile_layer_a0bac7f0648a4b10b642992e43f1cdab%20%3D%20L.tileLayer%28%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22https%3A//%7Bs%7D.tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%22attribution%22%3A%20%22Data%20by%20%5Cu0026copy%3B%20%5Cu003ca%20href%3D%5C%22http%3A//openstreetmap.org%5C%22%5Cu003eOpenStreetMap%5Cu003c/a%5Cu003e%2C%20under%20%5Cu003ca%20href%3D%5C%22http%3A//www.openstreetmap.org/copyright%5C%22%5Cu003eODbL%5Cu003c/a%5Cu003e.%22%2C%20%22detectRetina%22%3A%20false%2C%20%22maxNativeZoom%22%3A%2018%2C%20%22maxZoom%22%3A%2018%2C%20%22minZoom%22%3A%200%2C%20%22noWrap%22%3A%20false%2C%20%22opacity%22%3A%201%2C%20%22subdomains%22%3A%20%22abc%22%2C%20%22tms%22%3A%20false%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%29.addTo%28map_5fca0053c20247f19cc1284357d59a29%29%3B%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20marker_b70f6fe03da84c00b40a5540bf220d8d%20%3D%20L.marker%28%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B35.67400045350403%2C%20139.75593234124372%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%29.addTo%28map_5fca0053c20247f19cc1284357d59a29%29%3B%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20var%20popup_b529c15361c6471ca5b708097315db55%20%3D%20L.popup%28%7B%22maxWidth%22%3A%20%22100%25%22%7D%29%3B%0A%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20html_ceaac4d79b8942afbefdcd504a795de8%20%3D%20%24%28%60%3Cdiv%20id%3D%22html_ceaac4d79b8942afbefdcd504a795de8%22%20style%3D%22width%3A%20100.0%25%3B%20height%3A%20100.0%25%3B%22%3E%E6%97%A5%E6%AF%94%E8%B0%B7%E5%85%AC%E5%9C%92%3C/div%3E%60%29%5B0%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20popup_b529c15361c6471ca5b708097315db55.setContent%28html_ceaac4d79b8942afbefdcd504a795de8%29%3B%0A%20%20%20%20%20%20%20%20%0A%0A%20%20%20%20%20%20%20%20marker_b70f6fe03da84c00b40a5540bf220d8d.bindPopup%28popup_b529c15361c6471ca5b708097315db55%29%0A%20%20%20%20%20%20%20%20%3B%0A%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%0A%3C/script%3E onload=\"this.contentDocument.open();this.contentDocument.write( decodeURIComponent(this.getAttribute('data-html')));this.contentDocument.close();\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
|
37
|
+
],
|
38
|
+
"text/plain": [
|
39
|
+
"<folium.folium.Map object at 0x165c3bc10>"
|
40
|
+
]
|
41
|
+
},
|
42
|
+
"execution_count": 7,
|
43
|
+
"metadata": {},
|
44
|
+
"output_type": "execute_result"
|
45
|
+
}
|
46
|
+
],
|
47
|
+
"source": [
|
48
|
+
"map = folium.Map.new(location: [35.68053684909772, 139.75749875116222], zoom_start: 15)\n",
|
49
|
+
"folium.Marker.new([35.67400045350403, 139.75593234124372], popup: \"日比谷公園\").add_to(map)\n",
|
50
|
+
"map"
|
51
|
+
]
|
52
|
+
},
|
53
|
+
{
|
54
|
+
"cell_type": "code",
|
55
|
+
"execution_count": null,
|
56
|
+
"id": "angry-giant",
|
57
|
+
"metadata": {},
|
58
|
+
"outputs": [],
|
59
|
+
"source": []
|
60
|
+
}
|
61
|
+
],
|
62
|
+
"metadata": {
|
63
|
+
"kernelspec": {
|
64
|
+
"display_name": "Ruby 3.0.0",
|
65
|
+
"language": "ruby",
|
66
|
+
"name": "ruby"
|
67
|
+
},
|
68
|
+
"language_info": {
|
69
|
+
"file_extension": ".rb",
|
70
|
+
"mimetype": "application/x-ruby",
|
71
|
+
"name": "ruby",
|
72
|
+
"version": "3.0.0"
|
73
|
+
}
|
74
|
+
},
|
75
|
+
"nbformat": 4,
|
76
|
+
"nbformat_minor": 5
|
77
|
+
}
|
data/ext/pycall/libpython.c
CHANGED
@@ -30,7 +30,13 @@ lookup_libpython_api(VALUE libpython_handle, char const *name)
|
|
30
30
|
arg.libpython_handle = libpython_handle;
|
31
31
|
arg.name = name;
|
32
32
|
addr = rb_protect((VALUE (*)(VALUE))lookup_libpython_api_0, (VALUE)&arg, &state);
|
33
|
-
|
33
|
+
if (state) {
|
34
|
+
rb_set_errinfo(Qnil);
|
35
|
+
return NULL;
|
36
|
+
}
|
37
|
+
else {
|
38
|
+
return NIL_P(addr) ? NULL : NUM2PTR(addr);
|
39
|
+
}
|
34
40
|
}
|
35
41
|
|
36
42
|
#define LOOKUP_API_ENTRY(api_name) lookup_libpython_api(libpython_handle, #api_name)
|
data/ext/pycall/pycall.c
CHANGED
@@ -70,6 +70,52 @@ pycall_after_fork(VALUE mod)
|
|
70
70
|
return Qnil;
|
71
71
|
}
|
72
72
|
|
73
|
+
static volatile pycall_tls_key without_gvl_key;
|
74
|
+
|
75
|
+
int
|
76
|
+
pycall_without_gvl_p(void)
|
77
|
+
{
|
78
|
+
/*
|
79
|
+
* In pthread, the default value is NULL (== 0).
|
80
|
+
*
|
81
|
+
* In Win32 thread, the default value is 0 (initialized by TlsAlloc).
|
82
|
+
*/
|
83
|
+
return (int)pycall_tls_get(without_gvl_key);
|
84
|
+
}
|
85
|
+
|
86
|
+
static inline int
|
87
|
+
pycall_set_without_gvl(void)
|
88
|
+
{
|
89
|
+
return pycall_tls_set(without_gvl_key, (void *)1);
|
90
|
+
}
|
91
|
+
|
92
|
+
static inline int
|
93
|
+
pycall_set_with_gvl(void)
|
94
|
+
{
|
95
|
+
return pycall_tls_set(without_gvl_key, (void *)0);
|
96
|
+
}
|
97
|
+
|
98
|
+
VALUE
|
99
|
+
pycall_without_gvl(VALUE (* func)(VALUE), VALUE arg)
|
100
|
+
{
|
101
|
+
int state;
|
102
|
+
VALUE result;
|
103
|
+
|
104
|
+
pycall_set_without_gvl();
|
105
|
+
|
106
|
+
result = rb_protect(func, arg, &state);
|
107
|
+
|
108
|
+
pycall_set_with_gvl();
|
109
|
+
|
110
|
+
return result;
|
111
|
+
}
|
112
|
+
|
113
|
+
static VALUE
|
114
|
+
pycall_m_without_gvl(VALUE mod)
|
115
|
+
{
|
116
|
+
return pycall_without_gvl(rb_yield, Qnil);
|
117
|
+
}
|
118
|
+
|
73
119
|
/* ==== PyCall::PyPtr ==== */
|
74
120
|
|
75
121
|
const rb_data_type_t pycall_pyptr_data_type = {
|
@@ -890,7 +936,7 @@ struct call_pyobject_call_params {
|
|
890
936
|
PyObject *kwargs;
|
891
937
|
};
|
892
938
|
|
893
|
-
PyObject *
|
939
|
+
static inline PyObject *
|
894
940
|
call_pyobject_call(struct call_pyobject_call_params *params)
|
895
941
|
{
|
896
942
|
PyObject *res;
|
@@ -899,7 +945,7 @@ call_pyobject_call(struct call_pyobject_call_params *params)
|
|
899
945
|
}
|
900
946
|
|
901
947
|
PyObject *
|
902
|
-
|
948
|
+
pyobject_call(PyObject *pycallable, PyObject *args, PyObject *kwargs)
|
903
949
|
{
|
904
950
|
PyObject *res;
|
905
951
|
struct call_pyobject_call_params params;
|
@@ -907,9 +953,14 @@ pyobject_call_without_gvl(PyObject *pycallable, PyObject *args, PyObject *kwargs
|
|
907
953
|
params.args = args;
|
908
954
|
params.kwargs = kwargs;
|
909
955
|
|
910
|
-
|
911
|
-
|
912
|
-
|
956
|
+
if (pycall_without_gvl_p()) {
|
957
|
+
res = (PyObject *)rb_thread_call_without_gvl(
|
958
|
+
(void * (*)(void *))call_pyobject_call, (void *)¶ms,
|
959
|
+
(rb_unblock_function_t *)pycall_interrupt_python_thread, NULL);
|
960
|
+
}
|
961
|
+
else {
|
962
|
+
res = call_pyobject_call(¶ms);
|
963
|
+
}
|
913
964
|
|
914
965
|
return res;
|
915
966
|
}
|
@@ -961,7 +1012,7 @@ pycall_call_python_callable(PyObject *pycallable, int argc, VALUE *argv)
|
|
961
1012
|
}
|
962
1013
|
}
|
963
1014
|
|
964
|
-
res =
|
1015
|
+
res = pyobject_call(pycallable, args, kwargs); /* New reference */
|
965
1016
|
if (!res) {
|
966
1017
|
pycall_pyerror_fetch_and_raise("PyObject_Call in pycall_call_python_callable");
|
967
1018
|
}
|
@@ -2185,6 +2236,9 @@ Init_pycall(void)
|
|
2185
2236
|
|
2186
2237
|
rb_define_module_function(mPyCall, "after_fork", pycall_after_fork, 0);
|
2187
2238
|
|
2239
|
+
pycall_tls_create(&without_gvl_key);
|
2240
|
+
rb_define_module_function(mPyCall, "without_gvl", pycall_m_without_gvl, 0);
|
2241
|
+
|
2188
2242
|
/* PyCall::PyPtr */
|
2189
2243
|
|
2190
2244
|
cPyPtr = rb_define_class_under(mPyCall, "PyPtr", rb_cBasicObject);
|
@@ -11,10 +11,19 @@ extern "C" {
|
|
11
11
|
#include <ruby.h>
|
12
12
|
#include <ruby/encoding.h>
|
13
13
|
#include <ruby/thread.h>
|
14
|
+
|
14
15
|
#include <assert.h>
|
15
16
|
#include <inttypes.h>
|
16
17
|
#include <limits.h>
|
17
18
|
|
19
|
+
#if defined(_WIN32)
|
20
|
+
# define PYCALL_THREAD_WIN32
|
21
|
+
# include <ruby/win32.h>
|
22
|
+
#elif defined(HAVE_PTHREAD_H)
|
23
|
+
# define PYCALL_THREAD_PTHREAD
|
24
|
+
# include <pthread.h>
|
25
|
+
#endif
|
26
|
+
|
18
27
|
#if SIZEOF_LONG == SIZEOF_VOIDP
|
19
28
|
# define PTR2NUM(x) (LONG2NUM((long)(x)))
|
20
29
|
# define NUM2PTR(x) ((void*)(NUM2ULONG(x)))
|
@@ -492,6 +501,23 @@ extern PyTypeObject PyRuby_Type;
|
|
492
501
|
|
493
502
|
PyObject * PyRuby_New(VALUE ruby_object);
|
494
503
|
|
504
|
+
/* ==== thread support ==== */
|
505
|
+
|
506
|
+
#if defined(PYCALL_THREAD_WIN32)
|
507
|
+
typedef DWORD pycall_tls_key;
|
508
|
+
#elif defined(PYCALL_THREAD_PTHREAD)
|
509
|
+
typedef pthread_key_t pycall_tls_key;
|
510
|
+
#else
|
511
|
+
# error "unsupported thread type"
|
512
|
+
#endif
|
513
|
+
|
514
|
+
int pycall_tls_create(pycall_tls_key* tls_key);
|
515
|
+
void *pycall_tls_get(pycall_tls_key tls_key);
|
516
|
+
int pycall_tls_set(pycall_tls_key tls_key, void *ptr);
|
517
|
+
|
518
|
+
int pycall_without_gvl_p(void);
|
519
|
+
VALUE pycall_without_gvl(VALUE (* func)(VALUE), VALUE arg);
|
520
|
+
|
495
521
|
/* ==== pycall ==== */
|
496
522
|
|
497
523
|
typedef struct {
|
@@ -637,7 +663,7 @@ Py_ssize_t pycall_python_hexversion(void);
|
|
637
663
|
|
638
664
|
void pycall_Py_DecRef(PyObject *);
|
639
665
|
|
640
|
-
|
666
|
+
extern const rb_data_type_t pycall_pyptr_data_type;
|
641
667
|
size_t pycall_pyptr_memsize(void const *);
|
642
668
|
void pycall_pyptr_free(void *);
|
643
669
|
|