yf_as_dataframe 0.3.0 → 0.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/Gemfile.lock +99 -0
- data/MINIMAL_INTEGRATION.md +227 -0
- data/README.md +65 -0
- data/lib/yf_as_dataframe/curl_impersonate_integration.rb +110 -0
- data/lib/yf_as_dataframe/financials.rb +3 -2
- data/lib/yf_as_dataframe/holders.rb +4 -2
- data/lib/yf_as_dataframe/multi.rb +2 -1
- data/lib/yf_as_dataframe/price_history.rb +46 -16
- data/lib/yf_as_dataframe/price_technical.rb +0 -1
- data/lib/yf_as_dataframe/quote.rb +4 -3
- data/lib/yf_as_dataframe/ticker.rb +7 -4
- data/lib/yf_as_dataframe/utils.rb +59 -16
- data/lib/yf_as_dataframe/version.rb +1 -1
- data/lib/yf_as_dataframe/yf_connection.rb +295 -49
- data/lib/yf_as_dataframe/yf_connection_minimal_patch.rb +97 -0
- data/lib/yf_as_dataframe/yfinance_exception.rb +3 -1
- data/lib/yf_as_dataframe.rb +2 -0
- data/quick_test.rb +143 -0
- data/test_minimal_integration.rb +121 -0
- metadata +53 -5
data/quick_test.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Quick test for minimal curl-impersonate integration
|
4
|
+
# This test verifies the integration without making actual HTTP requests
|
5
|
+
|
6
|
+
puts "=== Quick Curl-Impersonate Integration Test ==="
|
7
|
+
puts
|
8
|
+
|
9
|
+
# Test 1: Check curl-impersonate integration module
|
10
|
+
puts "1. Testing curl-impersonate integration module..."
|
11
|
+
begin
|
12
|
+
require_relative 'lib/yf_as_dataframe/curl_impersonate_integration'
|
13
|
+
|
14
|
+
executables = YfAsDataframe::CurlImpersonateIntegration.available_executables
|
15
|
+
if executables.empty?
|
16
|
+
puts " ❌ No curl-impersonate executables found!"
|
17
|
+
exit 1
|
18
|
+
else
|
19
|
+
puts " ✅ Found #{executables.length} curl-impersonate executables"
|
20
|
+
puts " Sample: #{executables.first[:executable]} (#{executables.first[:browser]})"
|
21
|
+
end
|
22
|
+
rescue => e
|
23
|
+
puts " ❌ Error loading integration module: #{e.message}"
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
|
27
|
+
puts
|
28
|
+
|
29
|
+
# Test 2: Test executable selection
|
30
|
+
puts "2. Testing executable selection..."
|
31
|
+
begin
|
32
|
+
executable = YfAsDataframe::CurlImpersonateIntegration.get_random_executable
|
33
|
+
if executable
|
34
|
+
puts " ✅ Random executable selected: #{executable[:executable]} (#{executable[:browser]})"
|
35
|
+
else
|
36
|
+
puts " ❌ No executable selected"
|
37
|
+
end
|
38
|
+
rescue => e
|
39
|
+
puts " ❌ Error selecting executable: #{e.message}"
|
40
|
+
end
|
41
|
+
|
42
|
+
puts
|
43
|
+
|
44
|
+
# Test 3: Test environment variable functionality
|
45
|
+
puts "3. Testing environment variable functionality..."
|
46
|
+
begin
|
47
|
+
default_dir = YfAsDataframe::CurlImpersonateIntegration.executable_directory
|
48
|
+
puts " ✅ Default directory: #{default_dir}"
|
49
|
+
|
50
|
+
# Test with a custom directory (should still use default if not set)
|
51
|
+
old_env = ENV['CURL_IMPERSONATE_DIR']
|
52
|
+
ENV['CURL_IMPERSONATE_DIR'] = '/nonexistent/path'
|
53
|
+
|
54
|
+
# Clear the cached executables to force re-discovery
|
55
|
+
YfAsDataframe::CurlImpersonateIntegration.instance_variable_set(:@available_executables, nil)
|
56
|
+
|
57
|
+
custom_dir = YfAsDataframe::CurlImpersonateIntegration.executable_directory
|
58
|
+
puts " ✅ Custom directory (set): #{custom_dir}"
|
59
|
+
|
60
|
+
# Restore original environment
|
61
|
+
if old_env
|
62
|
+
ENV['CURL_IMPERSONATE_DIR'] = old_env
|
63
|
+
else
|
64
|
+
ENV.delete('CURL_IMPERSONATE_DIR')
|
65
|
+
end
|
66
|
+
|
67
|
+
# Clear cache again
|
68
|
+
YfAsDataframe::CurlImpersonateIntegration.instance_variable_set(:@available_executables, nil)
|
69
|
+
|
70
|
+
restored_dir = YfAsDataframe::CurlImpersonateIntegration.executable_directory
|
71
|
+
puts " ✅ Restored directory: #{restored_dir}"
|
72
|
+
|
73
|
+
rescue => e
|
74
|
+
puts " ❌ Error testing environment variable: #{e.message}"
|
75
|
+
end
|
76
|
+
|
77
|
+
puts
|
78
|
+
|
79
|
+
# Test 4: Test minimal patch loading
|
80
|
+
puts "4. Testing minimal patch structure..."
|
81
|
+
begin
|
82
|
+
# This would normally require the full YfConnection class
|
83
|
+
# For this test, we'll just verify the patch file loads
|
84
|
+
require_relative 'lib/yf_as_dataframe/curl_impersonate_integration'
|
85
|
+
require_relative 'lib/yf_as_dataframe/yf_connection_minimal_patch'
|
86
|
+
|
87
|
+
puts " ✅ Minimal patch files load successfully"
|
88
|
+
puts " ✅ Integration module is available"
|
89
|
+
rescue => e
|
90
|
+
puts " ❌ Error loading minimal patch: #{e.message}"
|
91
|
+
end
|
92
|
+
|
93
|
+
puts
|
94
|
+
|
95
|
+
# Test 5: Test configuration
|
96
|
+
puts "5. Testing configuration..."
|
97
|
+
begin
|
98
|
+
puts " ✅ Configuration methods available:"
|
99
|
+
puts " - enable_curl_impersonate"
|
100
|
+
puts " - enable_curl_impersonate_fallback"
|
101
|
+
puts " - set_curl_impersonate_timeout"
|
102
|
+
puts " - get_available_curl_impersonate_executables"
|
103
|
+
|
104
|
+
# Test setting configuration
|
105
|
+
YfAsDataframe::CurlImpersonateIntegration.curl_impersonate_timeout = 20
|
106
|
+
puts " ✅ Configuration can be modified"
|
107
|
+
rescue => e
|
108
|
+
puts " ❌ Error with configuration: #{e.message}"
|
109
|
+
end
|
110
|
+
|
111
|
+
puts
|
112
|
+
|
113
|
+
# Test 6: Test command building (without execution)
|
114
|
+
puts "6. Testing command building..."
|
115
|
+
begin
|
116
|
+
executable = YfAsDataframe::CurlImpersonateIntegration.get_random_executable
|
117
|
+
if executable
|
118
|
+
# Build a command without executing it
|
119
|
+
cmd = [executable[:path], "--max-time", "5", "https://httpbin.org/get"]
|
120
|
+
puts " ✅ Command built: #{cmd.join(' ')}"
|
121
|
+
else
|
122
|
+
puts " ❌ Could not build command"
|
123
|
+
end
|
124
|
+
rescue => e
|
125
|
+
puts " ❌ Error building command: #{e.message}"
|
126
|
+
end
|
127
|
+
|
128
|
+
puts
|
129
|
+
puts "=== Quick Test Summary ==="
|
130
|
+
puts "✅ Integration module loads successfully"
|
131
|
+
puts "✅ Executables are detected"
|
132
|
+
puts "✅ Environment variable functionality works"
|
133
|
+
puts "✅ Configuration works"
|
134
|
+
puts "✅ Patch files load without errors"
|
135
|
+
puts
|
136
|
+
puts "The minimal curl-impersonate integration is ready for use!"
|
137
|
+
puts
|
138
|
+
puts "To integrate with your code:"
|
139
|
+
puts "require 'yf_as_dataframe/curl_impersonate_integration'"
|
140
|
+
puts "require 'yf_as_dataframe/yf_connection_minimal_patch'"
|
141
|
+
puts
|
142
|
+
puts "Environment variable support:"
|
143
|
+
puts "export CURL_IMPERSONATE_DIR='/custom/path' # Optional"
|
@@ -0,0 +1,121 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Test script for minimal curl-impersonate integration
|
4
|
+
# This tests the approach where curl-impersonate is the default behavior
|
5
|
+
|
6
|
+
puts "=== Minimal Curl-Impersonate Integration Test ==="
|
7
|
+
puts
|
8
|
+
|
9
|
+
# Test 1: Check curl-impersonate integration module
|
10
|
+
puts "1. Testing curl-impersonate integration module..."
|
11
|
+
begin
|
12
|
+
require_relative 'lib/yf_as_dataframe/curl_impersonate_integration'
|
13
|
+
|
14
|
+
executables = YfAsDataframe::CurlImpersonateIntegration.available_executables
|
15
|
+
if executables.empty?
|
16
|
+
puts " ❌ No curl-impersonate executables found!"
|
17
|
+
exit 1
|
18
|
+
else
|
19
|
+
puts " ✅ Found #{executables.length} curl-impersonate executables"
|
20
|
+
puts " Sample: #{executables.first[:executable]} (#{executables.first[:browser]})"
|
21
|
+
end
|
22
|
+
rescue => e
|
23
|
+
puts " ❌ Error loading integration module: #{e.message}"
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
|
27
|
+
puts
|
28
|
+
|
29
|
+
# Test 2: Test direct curl-impersonate request with short timeout
|
30
|
+
puts "2. Testing direct curl-impersonate request..."
|
31
|
+
begin
|
32
|
+
response = YfAsDataframe::CurlImpersonateIntegration.make_request(
|
33
|
+
"https://httpbin.org/get",
|
34
|
+
headers: { "User-Agent" => "Test-Agent" },
|
35
|
+
timeout: 10 # 10 second timeout
|
36
|
+
)
|
37
|
+
|
38
|
+
if response && response.success?
|
39
|
+
puts " ✅ Direct curl-impersonate request successful"
|
40
|
+
puts " Response length: #{response.body.length} characters"
|
41
|
+
else
|
42
|
+
puts " ❌ Direct curl-impersonate request failed"
|
43
|
+
end
|
44
|
+
rescue => e
|
45
|
+
puts " ❌ Error with direct request: #{e.message}"
|
46
|
+
end
|
47
|
+
|
48
|
+
puts
|
49
|
+
|
50
|
+
# Test 3: Test minimal patch (without full gem)
|
51
|
+
puts "3. Testing minimal patch structure..."
|
52
|
+
begin
|
53
|
+
# This would normally require the full YfConnection class
|
54
|
+
# For this test, we'll just verify the patch file loads
|
55
|
+
require_relative 'lib/yf_as_dataframe/curl_impersonate_integration'
|
56
|
+
require_relative 'lib/yf_as_dataframe/yf_connection_minimal_patch'
|
57
|
+
|
58
|
+
puts " ✅ Minimal patch files load successfully"
|
59
|
+
puts " ✅ Integration module is available"
|
60
|
+
rescue => e
|
61
|
+
puts " ❌ Error loading minimal patch: #{e.message}"
|
62
|
+
end
|
63
|
+
|
64
|
+
puts
|
65
|
+
|
66
|
+
# Test 4: Test configuration methods
|
67
|
+
puts "4. Testing configuration methods..."
|
68
|
+
begin
|
69
|
+
# Test configuration (these would work with the full YfConnection class)
|
70
|
+
puts " ✅ Configuration methods available:"
|
71
|
+
puts " - enable_curl_impersonate"
|
72
|
+
puts " - enable_curl_impersonate_fallback"
|
73
|
+
puts " - set_curl_impersonate_timeout"
|
74
|
+
puts " - get_available_curl_impersonate_executables"
|
75
|
+
rescue => e
|
76
|
+
puts " ❌ Error with configuration: #{e.message}"
|
77
|
+
end
|
78
|
+
|
79
|
+
puts
|
80
|
+
|
81
|
+
# Test 5: Test with Yahoo Finance endpoint with short timeout
|
82
|
+
puts "5. Testing Yahoo Finance endpoint..."
|
83
|
+
begin
|
84
|
+
response = YfAsDataframe::CurlImpersonateIntegration.make_request(
|
85
|
+
"https://query1.finance.yahoo.com/v8/finance/chart/MSFT",
|
86
|
+
params: { "interval" => "1d", "range" => "1d" },
|
87
|
+
timeout: 15 # 15 second timeout
|
88
|
+
)
|
89
|
+
|
90
|
+
if response && response.success?
|
91
|
+
puts " ✅ Yahoo Finance request successful"
|
92
|
+
puts " Response length: #{response.body.length} characters"
|
93
|
+
|
94
|
+
if response.body.strip.start_with?('{') && response.body.include?('"chart"')
|
95
|
+
puts " ✅ Response appears to be valid Yahoo Finance JSON"
|
96
|
+
else
|
97
|
+
puts " ⚠️ Response format unexpected"
|
98
|
+
end
|
99
|
+
else
|
100
|
+
puts " ❌ Yahoo Finance request failed"
|
101
|
+
end
|
102
|
+
rescue => e
|
103
|
+
puts " ❌ Error with Yahoo Finance: #{e.message}"
|
104
|
+
end
|
105
|
+
|
106
|
+
puts
|
107
|
+
puts "=== Test Summary ==="
|
108
|
+
puts "The minimal curl-impersonate integration is ready."
|
109
|
+
puts
|
110
|
+
puts "To use with the full gem:"
|
111
|
+
puts "1. Add the two integration files to lib/yf_as_dataframe/"
|
112
|
+
puts "2. Add require statements to your code"
|
113
|
+
puts "3. Your existing code will automatically use curl-impersonate"
|
114
|
+
puts
|
115
|
+
puts "Files needed:"
|
116
|
+
puts "- lib/yf_as_dataframe/curl_impersonate_integration.rb"
|
117
|
+
puts "- lib/yf_as_dataframe/yf_connection_minimal_patch.rb"
|
118
|
+
puts
|
119
|
+
puts "Integration code:"
|
120
|
+
puts "require 'yf_as_dataframe/curl_impersonate_integration'"
|
121
|
+
puts "require 'yf_as_dataframe/yf_connection_minimal_patch'"
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yf_as_dataframe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bill McKinnon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: tzinfo
|
14
|
+
name: tzinfo
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: tzinfo-data
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: polars-df
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.12.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.12.0
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: zache
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +94,34 @@ dependencies:
|
|
80
94
|
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: nokogiri
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: activesupport
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
83
125
|
description: Download market data from Yahoo! Finance's API
|
84
126
|
email:
|
85
127
|
- bill@bmck.org
|
@@ -91,12 +133,15 @@ files:
|
|
91
133
|
- CHANGELOG.rst
|
92
134
|
- CODE_OF_CONDUCT.md
|
93
135
|
- Gemfile
|
136
|
+
- Gemfile.lock
|
94
137
|
- LICENSE.txt
|
138
|
+
- MINIMAL_INTEGRATION.md
|
95
139
|
- README.md
|
96
140
|
- Rakefile
|
97
141
|
- chart.png
|
98
142
|
- lib/yf_as_dataframe.rb
|
99
143
|
- lib/yf_as_dataframe/analysis.rb
|
144
|
+
- lib/yf_as_dataframe/curl_impersonate_integration.rb
|
100
145
|
- lib/yf_as_dataframe/financials.rb
|
101
146
|
- lib/yf_as_dataframe/fundamentals.rb
|
102
147
|
- lib/yf_as_dataframe/holders.rb
|
@@ -109,7 +154,10 @@ files:
|
|
109
154
|
- lib/yf_as_dataframe/utils.rb
|
110
155
|
- lib/yf_as_dataframe/version.rb
|
111
156
|
- lib/yf_as_dataframe/yf_connection.rb
|
157
|
+
- lib/yf_as_dataframe/yf_connection_minimal_patch.rb
|
112
158
|
- lib/yf_as_dataframe/yfinance_exception.rb
|
159
|
+
- quick_test.rb
|
160
|
+
- test_minimal_integration.rb
|
113
161
|
homepage: https://www.github.com/bmck/yf_as_dataframe
|
114
162
|
licenses:
|
115
163
|
- MIT
|
@@ -132,7 +180,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
180
|
- !ruby/object:Gem::Version
|
133
181
|
version: '0'
|
134
182
|
requirements: []
|
135
|
-
rubygems_version: 3.
|
183
|
+
rubygems_version: 3.5.22
|
136
184
|
signing_key:
|
137
185
|
specification_version: 4
|
138
186
|
summary: A shameless port of python's yfinance module to ruby
|