rubyx-py 0.1.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 +7 -0
- data/Cargo.toml +19 -0
- data/README.md +469 -0
- data/ext/rubyx/Cargo.toml +19 -0
- data/ext/rubyx/extconf.rb +22 -0
- data/ext/rubyx/src/async_gen.rs +1298 -0
- data/ext/rubyx/src/context.rs +812 -0
- data/ext/rubyx/src/convert.rs +1498 -0
- data/ext/rubyx/src/eval.rs +377 -0
- data/ext/rubyx/src/exception.rs +184 -0
- data/ext/rubyx/src/future.rs +126 -0
- data/ext/rubyx/src/import.rs +34 -0
- data/ext/rubyx/src/lib.rs +4212 -0
- data/ext/rubyx/src/nonblocking_stream.rs +1422 -0
- data/ext/rubyx/src/pipe_notify.rs +232 -0
- data/ext/rubyx/src/python/sync_adapter.py +31 -0
- data/ext/rubyx/src/python_api.rs +6029 -0
- data/ext/rubyx/src/python_ffi.rs +18 -0
- data/ext/rubyx/src/python_finder.rs +119 -0
- data/ext/rubyx/src/python_guard.rs +25 -0
- data/ext/rubyx/src/ruby_helpers.rs +74 -0
- data/ext/rubyx/src/rubyx_object.rs +1931 -0
- data/ext/rubyx/src/rubyx_stream.rs +950 -0
- data/ext/rubyx/src/stream.rs +713 -0
- data/ext/rubyx/src/test_helpers.rs +351 -0
- data/lib/generators/rubyx/install_generator.rb +24 -0
- data/lib/generators/rubyx/templates/rubyx_initializer.rb +17 -0
- data/lib/rubyx/context.rb +27 -0
- data/lib/rubyx/error.rb +30 -0
- data/lib/rubyx/rails.rb +105 -0
- data/lib/rubyx/railtie.rb +20 -0
- data/lib/rubyx/uv.rb +261 -0
- data/lib/rubyx/version.rb +4 -0
- data/lib/rubyx-py.rb +1 -0
- data/lib/rubyx.rb +136 -0
- metadata +123 -0
data/lib/rubyx/uv.rb
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
require 'digest'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'open-uri'
|
|
4
|
+
require 'stringio'
|
|
5
|
+
require 'rubygems/package'
|
|
6
|
+
require 'zlib'
|
|
7
|
+
|
|
8
|
+
module Rubyx
|
|
9
|
+
module Uv
|
|
10
|
+
DEFAULT_UV_VERSION = '0.10.2'.freeze
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
# Download uv (if needed), write pyproject.toml, and run `uv sync`.
|
|
14
|
+
#
|
|
15
|
+
# @param pyproject_toml [String] Content of pyproject.toml
|
|
16
|
+
# @param force [Boolean] Force re-setup even if .venv exists
|
|
17
|
+
# @param uv_version [String] Version of uv to download
|
|
18
|
+
# @param project_dir [String, Symbol, nil] Where to create the project
|
|
19
|
+
# - nil: use Dir.pwd
|
|
20
|
+
# - :cache: use a hash-based cache directory
|
|
21
|
+
# - String: use the specified path
|
|
22
|
+
# @param uv_args [Array<String>] Extra arguments to pass to `uv sync`
|
|
23
|
+
# @param uv_path [String, nil] Path to an existing uv binary. When set,
|
|
24
|
+
# auto-download is skipped entirely.
|
|
25
|
+
# @return [String] The resolved project directory path
|
|
26
|
+
def setup(pyproject_toml, force: false, uv_version: DEFAULT_UV_VERSION,
|
|
27
|
+
project_dir: nil, uv_args: [], uv_path: nil)
|
|
28
|
+
proj_dir = resolve_project_dir(pyproject_toml, uv_version, project_dir)
|
|
29
|
+
|
|
30
|
+
venv_dir = File.join(proj_dir, '.venv')
|
|
31
|
+
pyproject_path = File.join(proj_dir, 'pyproject.toml')
|
|
32
|
+
|
|
33
|
+
needs_setup = force || !Dir.exist?(venv_dir)
|
|
34
|
+
|
|
35
|
+
if !needs_setup && File.exist?(pyproject_path)
|
|
36
|
+
needs_setup = File.read(pyproject_path).strip != pyproject_toml.strip
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if needs_setup
|
|
40
|
+
FileUtils.rm_rf(venv_dir) if force
|
|
41
|
+
FileUtils.mkdir_p(proj_dir)
|
|
42
|
+
File.write(pyproject_path, pyproject_toml)
|
|
43
|
+
|
|
44
|
+
success = run_uv!(
|
|
45
|
+
['sync', '--managed-python', '--no-config', '--project', proj_dir, *uv_args],
|
|
46
|
+
chdir: proj_dir,
|
|
47
|
+
env: { 'UV_PYTHON_INSTALL_DIR' => python_install_dir(uv_version) },
|
|
48
|
+
uv_version: uv_version,
|
|
49
|
+
uv_path: uv_path
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
unless success
|
|
53
|
+
FileUtils.rm_rf(venv_dir)
|
|
54
|
+
raise SetupError, 'uv sync failed to setup Python environment'
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
proj_dir
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Parse pyvenv.cfg, resolve platform paths, and call Rubyx.init.
|
|
62
|
+
#
|
|
63
|
+
# @param pyproject_toml [String] Content of pyproject.toml (used to resolve project_dir)
|
|
64
|
+
# @param uv_version [String] Version of uv (used to resolve project_dir)
|
|
65
|
+
# @param project_dir [String, Symbol, nil] Same as setup
|
|
66
|
+
# @return [Hash] Resolved paths (:root_dir, :project_dir, :python_dl, etc.)
|
|
67
|
+
def init(pyproject_toml, uv_version: DEFAULT_UV_VERSION, project_dir: nil)
|
|
68
|
+
proj_dir = resolve_project_dir(pyproject_toml, uv_version, project_dir)
|
|
69
|
+
|
|
70
|
+
venv_dir = File.join(proj_dir, '.venv')
|
|
71
|
+
raise InitError, "Not set up. Call Rubyx::Uv.setup first." unless Dir.exist?(venv_dir)
|
|
72
|
+
|
|
73
|
+
cfg_path = File.join(venv_dir, 'pyvenv.cfg')
|
|
74
|
+
raise InitError, "pyvenv.cfg not found at #{cfg_path}" unless File.exist?(cfg_path)
|
|
75
|
+
|
|
76
|
+
pyvenv_cfg = File.read(cfg_path)
|
|
77
|
+
home_line = pyvenv_cfg.lines.find { |l| l.start_with?('home = ') }
|
|
78
|
+
raise InitError, "Could not find 'home' in pyvenv.cfg" unless home_line
|
|
79
|
+
|
|
80
|
+
home_path = home_line.sub('home = ', '').strip
|
|
81
|
+
root_dir = File.dirname(home_path) # Parent of bin/
|
|
82
|
+
|
|
83
|
+
paths = platform_paths(root_dir, proj_dir)
|
|
84
|
+
validate_paths!(paths)
|
|
85
|
+
|
|
86
|
+
sys_paths = []
|
|
87
|
+
sys_paths << paths[:venv_packages] if paths[:venv_packages]
|
|
88
|
+
sys_paths << proj_dir if project_dir && project_dir != :cache
|
|
89
|
+
|
|
90
|
+
# Call the Rust init
|
|
91
|
+
Rubyx.init(
|
|
92
|
+
paths[:python_dl],
|
|
93
|
+
paths[:python_home],
|
|
94
|
+
paths[:python_exe],
|
|
95
|
+
sys_paths
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
{ root_dir: root_dir, project_dir: proj_dir, **paths }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
# Download the uv binary from GitHub releases.
|
|
104
|
+
def download_uv!(uv_version)
|
|
105
|
+
archive_type, archive_name = archive_name_for_platform
|
|
106
|
+
url = "https://github.com/astral-sh/uv/releases/download/#{uv_version}/#{archive_name}"
|
|
107
|
+
|
|
108
|
+
warn "Downloading uv #{uv_version}..."
|
|
109
|
+
|
|
110
|
+
archive_data = URI.open(url, 'rb', &:read)
|
|
111
|
+
uv_binary = extract_uv(archive_type, archive_data)
|
|
112
|
+
|
|
113
|
+
path = default_uv_path(uv_version)
|
|
114
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
115
|
+
File.binwrite(path, uv_binary)
|
|
116
|
+
File.chmod(0o755, path)
|
|
117
|
+
|
|
118
|
+
path
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def archive_name_for_platform
|
|
122
|
+
case RUBY_PLATFORM
|
|
123
|
+
when /arm64.*darwin/, /aarch64.*darwin/
|
|
124
|
+
[:tar_gz, 'uv-aarch64-apple-darwin.tar.gz']
|
|
125
|
+
when /x86_64.*darwin/, /darwin/
|
|
126
|
+
[:tar_gz, 'uv-x86_64-apple-darwin.tar.gz']
|
|
127
|
+
when /aarch64.*linux/
|
|
128
|
+
[:tar_gz, 'uv-aarch64-unknown-linux-gnu.tar.gz']
|
|
129
|
+
when /x86_64.*linux/, /linux/
|
|
130
|
+
[:tar_gz, 'uv-x86_64-unknown-linux-gnu.tar.gz']
|
|
131
|
+
when /mingw/, /mswin/, /cygwin/
|
|
132
|
+
[:zip, 'uv-x86_64-pc-windows-msvc.zip']
|
|
133
|
+
else
|
|
134
|
+
raise SetupError, "Unsupported platform: #{RUBY_PLATFORM}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def extract_uv(type, data)
|
|
139
|
+
case type
|
|
140
|
+
when :tar_gz
|
|
141
|
+
io = StringIO.new(data)
|
|
142
|
+
gzip = Zlib::GzipReader.new(io)
|
|
143
|
+
Gem::Package::TarReader.new(gzip) do |tar|
|
|
144
|
+
tar.each do |entry|
|
|
145
|
+
return entry.read if File.basename(entry.full_name) == 'uv'
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
raise SetupError, 'uv binary not found in archive'
|
|
149
|
+
when :zip
|
|
150
|
+
require 'zip'
|
|
151
|
+
Zip::File.open_buffer(data) do |zip|
|
|
152
|
+
zip.each do |entry|
|
|
153
|
+
return entry.get_input_stream.read if File.basename(entry.name, '.*') == 'uv'
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
raise SetupError, 'uv binary not found in archive'
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Run a uv command.
|
|
161
|
+
#
|
|
162
|
+
# @param uv_path [String, nil] Custom uv binary path. When nil, uses
|
|
163
|
+
# the auto-downloaded binary (downloading if needed).
|
|
164
|
+
def run_uv!(args, chdir:, env:, uv_version:, uv_path: nil)
|
|
165
|
+
path = if uv_path
|
|
166
|
+
raise SetupError, "uv not found at #{uv_path}" unless File.exist?(uv_path)
|
|
167
|
+
uv_path
|
|
168
|
+
else
|
|
169
|
+
default = default_uv_path(uv_version)
|
|
170
|
+
download_uv!(uv_version) unless File.exist?(default)
|
|
171
|
+
default
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
require 'open3'
|
|
175
|
+
full_env = env.transform_keys(&:to_s)
|
|
176
|
+
success = nil
|
|
177
|
+
Dir.chdir(chdir) do
|
|
178
|
+
Open3.popen2e(full_env, path, *args) do |stdin, stdout_err, wait_thr|
|
|
179
|
+
stdin.close
|
|
180
|
+
stdout_err.each_line { |line| $stderr.print line }
|
|
181
|
+
success = wait_thr.value.success?
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
success
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Resolve platform-specific paths for libpython, home, exe, and site-packages.
|
|
189
|
+
def platform_paths(root_dir, project_dir)
|
|
190
|
+
case RUBY_PLATFORM
|
|
191
|
+
when /darwin/
|
|
192
|
+
{
|
|
193
|
+
python_dl: find_lib(root_dir, 'lib/libpython3.*.dylib'),
|
|
194
|
+
python_home: root_dir,
|
|
195
|
+
python_exe: File.join(project_dir, '.venv/bin/python'),
|
|
196
|
+
venv_packages: find_lib(project_dir, '.venv/lib/python3.*/site-packages'),
|
|
197
|
+
}
|
|
198
|
+
when /linux/
|
|
199
|
+
{
|
|
200
|
+
python_dl: find_lib(root_dir, 'lib/libpython3.*.so'),
|
|
201
|
+
python_home: root_dir,
|
|
202
|
+
python_exe: File.join(project_dir, '.venv/bin/python'),
|
|
203
|
+
venv_packages: find_lib(project_dir, '.venv/lib/python3.*/site-packages'),
|
|
204
|
+
}
|
|
205
|
+
when /mingw/, /mswin/, /cygwin/
|
|
206
|
+
{
|
|
207
|
+
python_dl: find_lib(root_dir, 'python3*.dll'),
|
|
208
|
+
python_home: root_dir,
|
|
209
|
+
python_exe: File.join(project_dir, '.venv/Scripts/python.exe'),
|
|
210
|
+
venv_packages: File.join(project_dir, '.venv/Lib/site-packages'),
|
|
211
|
+
}
|
|
212
|
+
else
|
|
213
|
+
raise InitError, "Unsupported platform: #{RUBY_PLATFORM}"
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def find_lib(base_dir, pattern)
|
|
218
|
+
matches = Dir.glob(File.join(base_dir, pattern))
|
|
219
|
+
matches.min_by(&:length)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def validate_paths!(paths)
|
|
223
|
+
paths.each do |key, path|
|
|
224
|
+
next if path.nil? && key == :venv_packages
|
|
225
|
+
raise InitError, "Path not found: #{key} (#{path})" unless path && File.exist?(path)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Determine where the project directory should be.
|
|
230
|
+
def resolve_project_dir(pyproject_toml, uv_version, project_dir)
|
|
231
|
+
case project_dir
|
|
232
|
+
when nil
|
|
233
|
+
Dir.pwd
|
|
234
|
+
when :cache
|
|
235
|
+
cache_id = Digest::MD5.hexdigest(pyproject_toml)
|
|
236
|
+
File.join(cache_dir(uv_version), 'projects', cache_id)
|
|
237
|
+
else
|
|
238
|
+
File.expand_path(project_dir)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Path to the auto-downloaded uv binary.
|
|
243
|
+
def default_uv_path(uv_version)
|
|
244
|
+
File.join(cache_dir(uv_version), 'bin', 'uv')
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Root cache directory for this rubyx + uv version combination.
|
|
248
|
+
def cache_dir(uv_version)
|
|
249
|
+
File.join(
|
|
250
|
+
ENV.fetch('XDG_CACHE_HOME', File.join(Dir.home, '.cache')),
|
|
251
|
+
'rubyx', Rubyx::VERSION, 'uv', uv_version
|
|
252
|
+
)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Directory where uv installs managed Python distributions.
|
|
256
|
+
def python_install_dir(uv_version)
|
|
257
|
+
File.join(cache_dir(uv_version), 'python')
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
data/lib/rubyx-py.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_relative 'rubyx'
|
data/lib/rubyx.rb
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
require 'rbconfig'
|
|
2
|
+
require_relative 'rubyx/version'
|
|
3
|
+
require_relative 'rubyx/error'
|
|
4
|
+
|
|
5
|
+
# Load the native extension
|
|
6
|
+
begin
|
|
7
|
+
ruby_version = RUBY_VERSION.match(/\d+\.\d+/)[0]
|
|
8
|
+
require "rubyx/#{ruby_version}/rubyx"
|
|
9
|
+
rescue LoadError
|
|
10
|
+
begin
|
|
11
|
+
require 'rubyx/rubyx'
|
|
12
|
+
rescue LoadError
|
|
13
|
+
# dev
|
|
14
|
+
dev_root = File.expand_path('..', __dir__)
|
|
15
|
+
unless File.exist?(File.join(dev_root, 'Cargo.toml'))
|
|
16
|
+
raise LoadError,
|
|
17
|
+
"Could not load rubyx native extension. Install the rubyx-py gem."
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
lib_ext = case RbConfig::CONFIG['host_os']
|
|
21
|
+
when /darwin/ then 'dylib'
|
|
22
|
+
when /linux/ then 'so'
|
|
23
|
+
when /mingw|mswin/ then 'dll'
|
|
24
|
+
else 'so'
|
|
25
|
+
end
|
|
26
|
+
bundle_ext = RbConfig::CONFIG['host_os'] =~ /darwin/ ? 'bundle' : lib_ext
|
|
27
|
+
|
|
28
|
+
lib_path = File.join(dev_root, "target/release/librubyx.#{lib_ext}")
|
|
29
|
+
bundle_path = File.join(dev_root, "target/release/rubyx.#{bundle_ext}")
|
|
30
|
+
|
|
31
|
+
unless File.exist?(lib_path)
|
|
32
|
+
raise LoadError,
|
|
33
|
+
"Native extension not built. Run: cargo build --release"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if !File.exist?(bundle_path) || File.mtime(lib_path) > File.mtime(bundle_path)
|
|
37
|
+
require 'fileutils'
|
|
38
|
+
FileUtils.cp(lib_path, bundle_path)
|
|
39
|
+
end
|
|
40
|
+
require bundle_path
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
require_relative 'rubyx/context'
|
|
45
|
+
require_relative 'rubyx/uv'
|
|
46
|
+
require_relative 'rubyx/railtie' if defined?(::Rails::Railtie)
|
|
47
|
+
|
|
48
|
+
module Rubyx
|
|
49
|
+
# Import a Python module by name.
|
|
50
|
+
#
|
|
51
|
+
# @param module_name [String] Python module name (e.g., "os", "numpy", "my_module.sub")
|
|
52
|
+
# @return [RubyxObject] Wrapped Python module
|
|
53
|
+
# @raise [InvalidModuleNameError] if the name contains invalid characters
|
|
54
|
+
def self.import(module_name)
|
|
55
|
+
name = module_name.to_s
|
|
56
|
+
unless name.match?(VALID_MODULE_NAME_PATTERN)
|
|
57
|
+
raise InvalidModuleNameError,
|
|
58
|
+
"Invalid Python module name: '#{name}'. " \
|
|
59
|
+
"Module names must contain only alphanumeric characters, underscores, and dots."
|
|
60
|
+
end
|
|
61
|
+
_import(name)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Evaluate Python code and return the result.
|
|
65
|
+
#
|
|
66
|
+
# @param code [String] Python code to evaluate
|
|
67
|
+
# @param globals [Hash] Ruby values to inject as Python globals
|
|
68
|
+
# @return [RubyxObject] The result as a wrapped Python object
|
|
69
|
+
# @example
|
|
70
|
+
# Rubyx.eval("x + y", x: 10, y: 20)
|
|
71
|
+
class << self
|
|
72
|
+
public define_method(:eval) { |code, **globals|
|
|
73
|
+
if globals.empty?
|
|
74
|
+
Rubyx._eval(code.to_s)
|
|
75
|
+
else
|
|
76
|
+
Rubyx._eval_with_globals(code.to_s, globals)
|
|
77
|
+
end
|
|
78
|
+
}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Run a Python coroutine with asyncio.run() (blocking).
|
|
82
|
+
# Accepts either a RubyxObject (coroutine) or a code string with globals.
|
|
83
|
+
#
|
|
84
|
+
# @param code_or_coroutine [String, RubyxObject] Python code or coroutine object
|
|
85
|
+
# @param globals [Hash] Ruby values to inject as Python globals (only with code string)
|
|
86
|
+
# @return [RubyxObject] The awaited result
|
|
87
|
+
# @example
|
|
88
|
+
# Rubyx.await("fetch(url)", url: "https://example.com")
|
|
89
|
+
def self.await(code_or_coroutine, **globals)
|
|
90
|
+
if code_or_coroutine.is_a?(String)
|
|
91
|
+
if globals.empty?
|
|
92
|
+
_await_with_globals(code_or_coroutine, {})
|
|
93
|
+
else
|
|
94
|
+
_await_with_globals(code_or_coroutine, globals)
|
|
95
|
+
end
|
|
96
|
+
else
|
|
97
|
+
raise ArgumentError, "cannot pass globals with a coroutine object" unless globals.empty?
|
|
98
|
+
_await(code_or_coroutine)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Run a Python coroutine on a background thread (non-blocking).
|
|
103
|
+
# Accepts either a RubyxObject (coroutine) or a code string with globals.
|
|
104
|
+
#
|
|
105
|
+
# @param code_or_coroutine [String, RubyxObject] Python code or coroutine object
|
|
106
|
+
# @param globals [Hash] Ruby values to inject as Python globals (only with code string)
|
|
107
|
+
# @return [Rubyx::Future] A future that resolves to the result
|
|
108
|
+
# @example
|
|
109
|
+
# future = Rubyx.async_await("fetch(url)", url: "https://example.com")
|
|
110
|
+
# future.value
|
|
111
|
+
def self.async_await(code_or_coroutine, **globals)
|
|
112
|
+
if code_or_coroutine.is_a?(String)
|
|
113
|
+
if globals.empty?
|
|
114
|
+
_async_await_with_globals(code_or_coroutine, {})
|
|
115
|
+
else
|
|
116
|
+
_async_await_with_globals(code_or_coroutine, globals)
|
|
117
|
+
end
|
|
118
|
+
else
|
|
119
|
+
raise ArgumentError, "cannot pass globals with a coroutine object" unless globals.empty?
|
|
120
|
+
_async_await(code_or_coroutine)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Convenience method: setup Python environment via uv and initialize.
|
|
125
|
+
#
|
|
126
|
+
# @param pyproject_toml [String] Content of pyproject.toml
|
|
127
|
+
# @param options [Hash] Options passed to Uv.setup and Uv.init
|
|
128
|
+
# @return [Hash] Resolved paths from Uv.init
|
|
129
|
+
def self.uv_init(pyproject_toml, **options)
|
|
130
|
+
setup_keys = %i[force uv_version project_dir uv_args uv_path]
|
|
131
|
+
init_keys = %i[uv_version project_dir]
|
|
132
|
+
|
|
133
|
+
Uv.setup(pyproject_toml, **options.slice(*setup_keys))
|
|
134
|
+
Uv.init(pyproject_toml, **options.slice(*init_keys))
|
|
135
|
+
end
|
|
136
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rubyx-py
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Naiker
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rb_sys
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.9'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.9'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rake-compiler
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.2'
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.2'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rspec
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.0'
|
|
54
|
+
description: Call Python libraries directly from Ruby and Rails. No microservices,
|
|
55
|
+
no REST APIs — just seamless interop. Powered by Rust for safety and performance.
|
|
56
|
+
email:
|
|
57
|
+
- yinho999@gmail.com
|
|
58
|
+
executables: []
|
|
59
|
+
extensions:
|
|
60
|
+
- ext/rubyx/extconf.rb
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- Cargo.toml
|
|
64
|
+
- README.md
|
|
65
|
+
- ext/rubyx/Cargo.toml
|
|
66
|
+
- ext/rubyx/extconf.rb
|
|
67
|
+
- ext/rubyx/src/async_gen.rs
|
|
68
|
+
- ext/rubyx/src/context.rs
|
|
69
|
+
- ext/rubyx/src/convert.rs
|
|
70
|
+
- ext/rubyx/src/eval.rs
|
|
71
|
+
- ext/rubyx/src/exception.rs
|
|
72
|
+
- ext/rubyx/src/future.rs
|
|
73
|
+
- ext/rubyx/src/import.rs
|
|
74
|
+
- ext/rubyx/src/lib.rs
|
|
75
|
+
- ext/rubyx/src/nonblocking_stream.rs
|
|
76
|
+
- ext/rubyx/src/pipe_notify.rs
|
|
77
|
+
- ext/rubyx/src/python/sync_adapter.py
|
|
78
|
+
- ext/rubyx/src/python_api.rs
|
|
79
|
+
- ext/rubyx/src/python_ffi.rs
|
|
80
|
+
- ext/rubyx/src/python_finder.rs
|
|
81
|
+
- ext/rubyx/src/python_guard.rs
|
|
82
|
+
- ext/rubyx/src/ruby_helpers.rs
|
|
83
|
+
- ext/rubyx/src/rubyx_object.rs
|
|
84
|
+
- ext/rubyx/src/rubyx_stream.rs
|
|
85
|
+
- ext/rubyx/src/stream.rs
|
|
86
|
+
- ext/rubyx/src/test_helpers.rs
|
|
87
|
+
- lib/generators/rubyx/install_generator.rb
|
|
88
|
+
- lib/generators/rubyx/templates/rubyx_initializer.rb
|
|
89
|
+
- lib/rubyx-py.rb
|
|
90
|
+
- lib/rubyx.rb
|
|
91
|
+
- lib/rubyx/context.rb
|
|
92
|
+
- lib/rubyx/error.rb
|
|
93
|
+
- lib/rubyx/rails.rb
|
|
94
|
+
- lib/rubyx/railtie.rb
|
|
95
|
+
- lib/rubyx/uv.rb
|
|
96
|
+
- lib/rubyx/version.rb
|
|
97
|
+
homepage: https://github.com/yinho999/rubyx
|
|
98
|
+
licenses:
|
|
99
|
+
- MIT
|
|
100
|
+
metadata:
|
|
101
|
+
homepage_uri: https://github.com/yinho999/rubyx
|
|
102
|
+
source_code_uri: https://github.com/yinho999/rubyx
|
|
103
|
+
changelog_uri: https://github.com/yinho999/rubyx/blob/main/CHANGELOG.md
|
|
104
|
+
bug_tracker_uri: https://github.com/yinho999/rubyx/issues
|
|
105
|
+
rubygems_mfa_required: 'true'
|
|
106
|
+
rdoc_options: []
|
|
107
|
+
require_paths:
|
|
108
|
+
- lib
|
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - ">="
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: 3.0.0
|
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: '0'
|
|
119
|
+
requirements: []
|
|
120
|
+
rubygems_version: 3.6.9
|
|
121
|
+
specification_version: 4
|
|
122
|
+
summary: Ruby-Python bridge powered by Rust
|
|
123
|
+
test_files: []
|