pycall_thread 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/Gemfile +1 -5
- data/Gemfile.lock +1 -5
- data/examples/puma/Gemfile +4 -0
- data/examples/puma/Gemfile.lock +19 -0
- data/examples/puma/README.md +10 -0
- data/examples/puma/app.rb +2 -2
- data/lib/pycall_thread/version.rb +1 -1
- data/lib/pycall_thread.rb +36 -30
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb8af01c4091f60fbf0e3255b487817e6779b18d4f3dc1c449f303cea75094d4
|
4
|
+
data.tar.gz: a8099eecf60897ccc436d5662be887f4ed4641fa1fa655af374b0d322cb64406
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 453798c6771820f009dfefb8ffde48039ca4924df3de24af4a6fffb0a07906cb253c4272006a31072b4e310dae0513a8ca60fd04760d2f8e93ac96480d9d80c5
|
7
|
+
data.tar.gz: 708877b2fbdb55043ed13b84ecbd3ebe6b7c22b9b73b7f074a7435f3294e8762c626aef61695c912a79568672b016b1fa1e7679635db2233ee89b8bdebb45bb6
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
@@ -9,11 +9,7 @@ gem "rake", "~> 13.0"
|
|
9
9
|
gem "minitest", "~> 5.0"
|
10
10
|
gem "rubocop", "~> 1.21"
|
11
11
|
|
12
|
-
|
13
|
-
# Include Puma for testing examples:
|
14
|
-
gem 'puma', '~> 6.4.1'
|
15
|
-
|
16
|
-
# To use the local path, you must also run things with:
|
12
|
+
# To use the local pycall, you must also run things with e.g.:
|
17
13
|
# bundle exec ruby -I/Users/seth/src/pycall.rb/ext/pycall
|
18
14
|
#
|
19
15
|
# gem 'pycall', path: '/Users/seth/src/pycall.rb', require: false
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pycall_thread (0.1.
|
4
|
+
pycall_thread (0.1.1)
|
5
5
|
pycall
|
6
6
|
|
7
7
|
GEM
|
@@ -11,13 +11,10 @@ GEM
|
|
11
11
|
json (2.7.2)
|
12
12
|
language_server-protocol (3.17.0.3)
|
13
13
|
minitest (5.24.1)
|
14
|
-
nio4r (2.7.3)
|
15
14
|
parallel (1.26.0)
|
16
15
|
parser (3.3.4.2)
|
17
16
|
ast (~> 2.4.1)
|
18
17
|
racc
|
19
|
-
puma (6.4.2)
|
20
|
-
nio4r (~> 2.0)
|
21
18
|
pycall (1.5.2)
|
22
19
|
racc (1.8.1)
|
23
20
|
rainbow (3.1.1)
|
@@ -47,7 +44,6 @@ PLATFORMS
|
|
47
44
|
|
48
45
|
DEPENDENCIES
|
49
46
|
minitest (~> 5.0)
|
50
|
-
puma (~> 6.4.1)
|
51
47
|
pycall_thread!
|
52
48
|
rake (~> 13.0)
|
53
49
|
rubocop (~> 1.21)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
nio4r (2.7.3)
|
5
|
+
puma (6.4.2)
|
6
|
+
nio4r (~> 2.0)
|
7
|
+
pycall (1.5.2)
|
8
|
+
pycall_thread (0.1.0)
|
9
|
+
pycall
|
10
|
+
|
11
|
+
PLATFORMS
|
12
|
+
arm64-darwin-23
|
13
|
+
|
14
|
+
DEPENDENCIES
|
15
|
+
puma
|
16
|
+
pycall_thread
|
17
|
+
|
18
|
+
BUNDLED WITH
|
19
|
+
2.2.33
|
data/examples/puma/app.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require 'pycall_thread'
|
2
2
|
|
3
3
|
PyCallThread.init do
|
4
4
|
# Setup our local venv (using pdm, in .venv)
|
@@ -17,7 +17,7 @@ class App
|
|
17
17
|
winequality = PyCallThread.run do
|
18
18
|
pandas = PyCall.import_module('pandas')
|
19
19
|
data = pandas.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv', sep: ';')
|
20
|
-
data.
|
20
|
+
data.to_json()
|
21
21
|
end
|
22
22
|
|
23
23
|
[200, { 'Content-Type' => 'text/html' }, [winequality]]
|
data/lib/pycall_thread.rb
CHANGED
@@ -1,30 +1,40 @@
|
|
1
|
+
# Provides a way to run PyCall code from multiple threads, see
|
2
|
+
# PyCallThread.init and PyCallThread.run for more information.
|
1
3
|
module PyCallThread
|
2
4
|
@queue = Queue.new
|
3
5
|
|
4
|
-
VALID_UNSAFE_RETURN_VALUES = [
|
6
|
+
VALID_UNSAFE_RETURN_VALUES = %i[allow error warn].freeze
|
5
7
|
|
6
8
|
def self.init(unsafe_return: :error, &require_pycall_block)
|
7
|
-
|
8
|
-
raise "PyCall::LibPython already exists: PyCall can't have been initialized already" if defined?(PyCall::LibPython)
|
9
|
+
raise ArgumentError, "Invalid value for unsafe_return: #{unsafe_return}. Must be one of: #{VALID_UNSAFE_RETURN_VALUES.join(", ")}" unless VALID_UNSAFE_RETURN_VALUES.include?(unsafe_return)
|
9
10
|
|
10
|
-
@
|
11
|
+
@unsafe_return = unsafe_return
|
11
12
|
|
12
|
-
if VALID_UNSAFE_RETURN_VALUES.include?(unsafe_return)
|
13
|
-
@unsafe_return = unsafe_return
|
14
|
-
else
|
15
|
-
raise ArgumentError, "Invalid value for unsafe_return: #{unsafe_return}. Must be one of: #{VALID_UNSAFE_RETURN_VALUES.join(', ')}"
|
16
|
-
end
|
17
|
-
|
18
13
|
# Start the thread we will use to run code invoked with PyCallThread.run
|
14
|
+
@py_thread = Thread.new { pycall_thread_loop }
|
15
|
+
|
19
16
|
# If we've been passed a require_pycall_block, use that to require 'pycall'
|
20
17
|
# instead of doing it directly.
|
21
|
-
|
18
|
+
require_pycall(&require_pycall_block)
|
22
19
|
|
23
|
-
at_exit
|
24
|
-
stop_pycall_thread
|
25
|
-
end
|
20
|
+
at_exit { stop_pycall_thread }
|
26
21
|
|
27
|
-
|
22
|
+
@initialized = true
|
23
|
+
end
|
24
|
+
|
25
|
+
def require_pycall(&require_pycall_block)
|
26
|
+
# Only safe to use PyCallThread if PyCall hasn't already been loaded
|
27
|
+
raise "PyCall::LibPython already exists: PyCall can't have been initialized already" if defined?(PyCall::LibPython)
|
28
|
+
|
29
|
+
run do
|
30
|
+
# require 'pycall' or run a user-defined block that should do the same
|
31
|
+
if require_pycall_block
|
32
|
+
require_pycall_block.call
|
33
|
+
else
|
34
|
+
require "pycall"
|
35
|
+
end
|
36
|
+
nil
|
37
|
+
end
|
28
38
|
end
|
29
39
|
|
30
40
|
# Runs &block on the PyCall thread, and returns the result
|
@@ -32,16 +42,18 @@ module PyCallThread
|
|
32
42
|
init unless @initialized
|
33
43
|
|
34
44
|
result_queue = Queue.new
|
35
|
-
@queue <<
|
45
|
+
@queue << lambda {
|
36
46
|
begin
|
37
47
|
result_queue << { retval: block.call }
|
38
|
-
rescue => e
|
48
|
+
rescue StandardError => e
|
39
49
|
result_queue << { exception: e }
|
40
50
|
end
|
41
|
-
|
51
|
+
}
|
42
52
|
|
43
|
-
|
53
|
+
run_result(result_queue.pop)
|
54
|
+
end
|
44
55
|
|
56
|
+
def self.run_result
|
45
57
|
if result[:exception]
|
46
58
|
raise result[:exception]
|
47
59
|
elsif python_object?(result[:retval])
|
@@ -62,21 +74,15 @@ module PyCallThread
|
|
62
74
|
@py_thread.join
|
63
75
|
end
|
64
76
|
|
65
|
-
def self.pycall_thread_loop
|
77
|
+
def self.pycall_thread_loop
|
66
78
|
Thread.current.name = "pycall"
|
67
79
|
|
68
|
-
# require 'pycall' or run a user-defined block that should do the same
|
69
|
-
if require_pycall_block
|
70
|
-
require_pycall_block.call
|
71
|
-
else
|
72
|
-
require 'pycall'
|
73
|
-
end
|
74
|
-
|
75
80
|
loop do
|
76
81
|
block = @queue.pop
|
77
82
|
break if block == :stop
|
83
|
+
|
78
84
|
block.call
|
79
|
-
rescue => e
|
85
|
+
rescue StandardError => e
|
80
86
|
puts "pycall_thread_loop(): exception in pycall_thread_loop #{e}"
|
81
87
|
puts e.backtrace.join("\n")
|
82
88
|
end
|
@@ -93,7 +99,7 @@ module PyCallThread
|
|
93
99
|
PyCall::PyModuleWrapper,
|
94
100
|
PyCall::PyObjectWrapper,
|
95
101
|
PyCall::PyTypeObjectWrapper,
|
96
|
-
PyCall::PyPtr
|
102
|
+
PyCall::PyPtr
|
97
103
|
].any? { |kind| obj.is_a?(kind) }
|
98
104
|
end
|
99
|
-
end
|
105
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pycall_thread
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Seth Nickell
|
@@ -41,6 +41,9 @@ files:
|
|
41
41
|
- Rakefile
|
42
42
|
- bin/console
|
43
43
|
- bin/setup
|
44
|
+
- examples/puma/Gemfile
|
45
|
+
- examples/puma/Gemfile.lock
|
46
|
+
- examples/puma/README.md
|
44
47
|
- examples/puma/app.rb
|
45
48
|
- examples/puma/config.ru
|
46
49
|
- examples/puma/start_puma.sh
|