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/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/gc.c
CHANGED
@@ -1,5 +1,74 @@
|
|
1
1
|
#include "pycall_internal.h"
|
2
2
|
|
3
|
+
struct gcguard {
|
4
|
+
st_table *guarded_objects;
|
5
|
+
};
|
6
|
+
|
7
|
+
static int
|
8
|
+
gcguard_mark_i(st_data_t key, st_data_t val, st_data_t arg)
|
9
|
+
{
|
10
|
+
VALUE obj = (VALUE)val;
|
11
|
+
rb_gc_mark(obj);
|
12
|
+
return ST_CONTINUE;
|
13
|
+
}
|
14
|
+
|
15
|
+
static void
|
16
|
+
gcguard_mark(void* ptr)
|
17
|
+
{
|
18
|
+
struct gcguard *gg = (struct gcguard *)ptr;
|
19
|
+
st_foreach(gg->guarded_objects, gcguard_mark_i, 0);
|
20
|
+
}
|
21
|
+
|
22
|
+
static void
|
23
|
+
gcguard_free(void* ptr)
|
24
|
+
{
|
25
|
+
struct gcguard *gg = (struct gcguard *)ptr;
|
26
|
+
st_free_table(gg->guarded_objects);
|
27
|
+
}
|
28
|
+
|
29
|
+
static size_t
|
30
|
+
gcguard_memsize(const void* ptr)
|
31
|
+
{
|
32
|
+
const struct gcguard *gg = (const struct gcguard *)ptr;
|
33
|
+
return st_memsize(gg->guarded_objects);
|
34
|
+
}
|
35
|
+
|
36
|
+
static rb_data_type_t gcguard_data_type = {
|
37
|
+
"PyCall::gcguard",
|
38
|
+
{
|
39
|
+
gcguard_mark,
|
40
|
+
gcguard_free,
|
41
|
+
gcguard_memsize,
|
42
|
+
},
|
43
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
44
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
45
|
+
#endif
|
46
|
+
};
|
47
|
+
|
48
|
+
static void
|
49
|
+
gcguard_aset(VALUE gcguard, PyObject *pyptr, VALUE rbobj)
|
50
|
+
{
|
51
|
+
struct gcguard *gg;
|
52
|
+
TypedData_Get_Struct(gcguard, struct gcguard, &gcguard_data_type, gg);
|
53
|
+
|
54
|
+
st_insert(gg->guarded_objects, (st_data_t)pyptr, (st_data_t)rbobj);
|
55
|
+
}
|
56
|
+
|
57
|
+
static void
|
58
|
+
gcguard_delete(VALUE gcguard, PyObject *pyptr)
|
59
|
+
{
|
60
|
+
if (rb_typeddata_is_kind_of(gcguard, &gcguard_data_type)) {
|
61
|
+
/* This check is necessary to avoid error on the process finalization phase */
|
62
|
+
struct gcguard *gg;
|
63
|
+
st_data_t key, val;
|
64
|
+
|
65
|
+
TypedData_Get_Struct(gcguard, struct gcguard, &gcguard_data_type, gg);
|
66
|
+
|
67
|
+
key = (st_data_t)pyptr;
|
68
|
+
st_delete(gg->guarded_objects, &key, &val);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
3
72
|
static ID id_gcguard_table;
|
4
73
|
static PyObject *weakref_callback_pyobj;
|
5
74
|
static PyObject *gcguard_weakref_destroyed(PyObject *self, PyObject *weakref);
|
@@ -21,15 +90,15 @@ gcguard_weakref_destroyed(PyObject *self, PyObject *weakref)
|
|
21
90
|
void
|
22
91
|
pycall_gcguard_aset(PyObject *pyobj, VALUE rbobj)
|
23
92
|
{
|
24
|
-
VALUE
|
25
|
-
|
93
|
+
VALUE gcguard = rb_ivar_get(mPyCall, id_gcguard_table);
|
94
|
+
gcguard_aset(gcguard, pyobj, rbobj);
|
26
95
|
}
|
27
96
|
|
28
97
|
void
|
29
98
|
pycall_gcguard_delete(PyObject *pyobj)
|
30
99
|
{
|
31
|
-
VALUE
|
32
|
-
|
100
|
+
VALUE gcguard = rb_ivar_get(mPyCall, id_gcguard_table);
|
101
|
+
gcguard_delete(gcguard, pyobj);
|
33
102
|
}
|
34
103
|
|
35
104
|
void
|
@@ -64,11 +133,21 @@ pycall_gcguard_register(PyObject *pyobj, VALUE obj)
|
|
64
133
|
pycall_gcguard_aset(wref, obj);
|
65
134
|
}
|
66
135
|
|
136
|
+
static VALUE
|
137
|
+
gcguard_new(void)
|
138
|
+
{
|
139
|
+
struct gcguard *gg;
|
140
|
+
VALUE obj = TypedData_Make_Struct(0, struct gcguard, &gcguard_data_type, gg);
|
141
|
+
gg->guarded_objects = st_init_numtable();
|
142
|
+
|
143
|
+
return obj;
|
144
|
+
}
|
145
|
+
|
67
146
|
void
|
68
147
|
pycall_init_gcguard(void)
|
69
148
|
{
|
70
149
|
id_gcguard_table = rb_intern("gcguard_table");
|
71
|
-
rb_ivar_set(mPyCall, id_gcguard_table,
|
150
|
+
rb_ivar_set(mPyCall, id_gcguard_table, gcguard_new());
|
72
151
|
|
73
152
|
weakref_callback_pyobj = Py_API(PyCFunction_NewEx)(&gcguard_weakref_callback_def, NULL, NULL);
|
74
153
|
}
|
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);
|