jupyterlite-simple-cors-proxy 0.1.7__py3-none-any.whl → 0.1.9__py3-none-any.whl
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.
- jupyterlite_simple_cors_proxy/__init__.py +4 -3
- jupyterlite_simple_cors_proxy/fastf1_proxy.py +29 -20
- jupyterlite_simple_cors_proxy/proxy.py +69 -38
- {jupyterlite_simple_cors_proxy-0.1.7.dist-info → jupyterlite_simple_cors_proxy-0.1.9.dist-info}/METADATA +17 -2
- jupyterlite_simple_cors_proxy-0.1.9.dist-info/RECORD +8 -0
- jupyterlite_simple_cors_proxy-0.1.7.dist-info/RECORD +0 -8
- {jupyterlite_simple_cors_proxy-0.1.7.dist-info → jupyterlite_simple_cors_proxy-0.1.9.dist-info}/LICENSE +0 -0
- {jupyterlite_simple_cors_proxy-0.1.7.dist-info → jupyterlite_simple_cors_proxy-0.1.9.dist-info}/WHEEL +0 -0
- {jupyterlite_simple_cors_proxy-0.1.7.dist-info → jupyterlite_simple_cors_proxy-0.1.9.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
|
|
1
1
|
# File: jupyterlite_simple_cors_proxy/__init__.py
|
2
2
|
from .proxy import cors_proxy_get, robust_get_request, xurl, furl
|
3
|
-
from .fastf1_proxy import enable_cors_proxy as fastf1_cors_proxy
|
4
3
|
|
5
|
-
|
6
|
-
|
4
|
+
# from .fastf1_proxy import enable_cors_proxy as fastf1_cors_proxy
|
5
|
+
|
6
|
+
__version__ = "0.1.9"
|
7
|
+
__all__ = ["cors_proxy_get", "robust_get_request", "xurl", "furl"]
|
@@ -1,8 +1,8 @@
|
|
1
|
-
#import functools
|
1
|
+
# import functools
|
2
2
|
from urllib.parse import urlparse, quote
|
3
3
|
import requests
|
4
|
-
#import requests_cache
|
5
|
-
#from requests_cache.session import CachedSession
|
4
|
+
# import requests_cache
|
5
|
+
# from requests_cache.session import CachedSession
|
6
6
|
import fastf1
|
7
7
|
import logging
|
8
8
|
from typing import List, Optional, Dict, Any
|
@@ -19,7 +19,7 @@ class ProxyConfig:
|
|
19
19
|
|
20
20
|
class CORSProxyPatcher:
|
21
21
|
"""Patches FastF1 to handle CORS requests through a proxy service."""
|
22
|
-
|
22
|
+
|
23
23
|
def __init__(self, config: ProxyConfig = None):
|
24
24
|
"""
|
25
25
|
Initialize the CORS proxy patcher for FastF1.
|
@@ -28,11 +28,14 @@ class CORSProxyPatcher:
|
|
28
28
|
config (ProxyConfig): Configuration object for the proxy
|
29
29
|
"""
|
30
30
|
self.config = config or ProxyConfig()
|
31
|
-
self.domains = self.config.domains or [
|
32
|
-
|
31
|
+
self.domains = self.config.domains or [
|
32
|
+
"api.formula1.com",
|
33
|
+
"livetiming.formula1.com",
|
34
|
+
]
|
35
|
+
|
33
36
|
self._setup_logging()
|
34
37
|
self._setup_session()
|
35
|
-
|
38
|
+
|
36
39
|
def _setup_logging(self) -> None:
|
37
40
|
"""Configure logging based on debug setting."""
|
38
41
|
self.logger = logging.getLogger('CORSProxyPatcher')
|
@@ -41,7 +44,7 @@ class CORSProxyPatcher:
|
|
41
44
|
level=logging.DEBUG,
|
42
45
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
43
46
|
)
|
44
|
-
|
47
|
+
|
45
48
|
def _setup_session(self) -> None:
|
46
49
|
"""Set up the requests session with retry functionality."""
|
47
50
|
self.session = requests.Session()
|
@@ -53,7 +56,7 @@ class CORSProxyPatcher:
|
|
53
56
|
adapter = requests.adapters.HTTPAdapter(max_retries=retry_strategy)
|
54
57
|
self.session.mount("http://", adapter)
|
55
58
|
self.session.mount("https://", adapter)
|
56
|
-
|
59
|
+
|
57
60
|
def should_proxy(self, url: str) -> bool:
|
58
61
|
"""
|
59
62
|
Check if the URL should be routed through proxy based on domain.
|
@@ -69,7 +72,7 @@ class CORSProxyPatcher:
|
|
69
72
|
if self.config.debug:
|
70
73
|
self.logger.debug(f"URL: {url} - Should proxy: {should_proxy}")
|
71
74
|
return should_proxy
|
72
|
-
|
75
|
+
|
73
76
|
def get_proxied_url(self, url: str) -> str:
|
74
77
|
"""
|
75
78
|
Get the proxied version of the URL if needed.
|
@@ -90,7 +93,7 @@ class CORSProxyPatcher:
|
|
90
93
|
self.logger.debug(f"Proxied URL: {proxied}")
|
91
94
|
return proxied
|
92
95
|
return url
|
93
|
-
|
96
|
+
|
94
97
|
def modify_headers(self, headers: Optional[Dict[str, str]] = None) -> Dict[str, str]:
|
95
98
|
"""
|
96
99
|
Modify request headers to handle CORS.
|
@@ -149,19 +152,19 @@ class CORSProxyPatcher:
|
|
149
152
|
modified_headers = self.modify_headers(headers)
|
150
153
|
kwargs['headers'] = modified_headers
|
151
154
|
kwargs['timeout'] = kwargs.get('timeout', self.config.timeout)
|
152
|
-
|
155
|
+
|
153
156
|
try:
|
154
157
|
if fastf1.Cache._requests_session_cached and not fastf1.Cache._tmp_disabled:
|
155
158
|
session = fastf1.Cache._requests_session_cached
|
156
159
|
else:
|
157
160
|
session = self.session
|
158
|
-
|
161
|
+
|
159
162
|
response = getattr(session, method)(proxied_url, **kwargs)
|
160
163
|
response.raise_for_status()
|
161
|
-
|
164
|
+
|
162
165
|
self.log_response(response, url)
|
163
166
|
return response
|
164
|
-
|
167
|
+
|
165
168
|
except requests.exceptions.RequestException as e:
|
166
169
|
if self.config.debug:
|
167
170
|
self.logger.error(f"Request failed: {str(e)}")
|
@@ -171,10 +174,10 @@ class CORSProxyPatcher:
|
|
171
174
|
"""Patch FastF1's request methods to use CORS proxy."""
|
172
175
|
def wrapped_get(cls, url: str, headers: Optional[Dict[str, str]] = None, **kwargs: Any) -> requests.Response:
|
173
176
|
return self.make_request('get', url, headers, **kwargs)
|
174
|
-
|
177
|
+
|
175
178
|
def wrapped_post(cls, url: str, headers: Optional[Dict[str, str]] = None, **kwargs: Any) -> requests.Response:
|
176
179
|
return self.make_request('post', url, headers, **kwargs)
|
177
|
-
|
180
|
+
|
178
181
|
fastf1.Cache.requests_get = classmethod(wrapped_get)
|
179
182
|
fastf1.Cache.requests_post = classmethod(wrapped_post)
|
180
183
|
|
@@ -205,8 +208,14 @@ def enable_cors_proxy(
|
|
205
208
|
retry_count=retry_count,
|
206
209
|
timeout=timeout
|
207
210
|
)
|
208
|
-
|
211
|
+
|
209
212
|
patcher = CORSProxyPatcher(config)
|
210
213
|
patcher.patch_fastf1()
|
211
|
-
|
212
|
-
return patcher
|
214
|
+
|
215
|
+
return patcher
|
216
|
+
|
217
|
+
# enable_cors_proxy(
|
218
|
+
# domains=["api.formula1.com", "livetiming.formula1.com"],
|
219
|
+
# debug=True,
|
220
|
+
# proxy_url="https://corsproxy.io/",
|
221
|
+
# )
|
@@ -1,52 +1,83 @@
|
|
1
1
|
# File: simple_cors_proxy/proxy.py
|
2
2
|
from urllib.parse import urlencode, quote
|
3
3
|
import requests
|
4
|
+
import requests_cache
|
4
5
|
import io
|
5
|
-
|
6
6
|
import platform
|
7
|
-
|
8
|
-
|
9
|
-
def xurl(url, params=None, force=False):
|
10
|
-
"""Generate a proxied URL."""
|
11
|
-
if PLATFORM=="emscripten" or force:
|
12
|
-
if params:
|
13
|
-
url = f"{url}?{urlencode(params)}"
|
14
|
-
url = f"https://corsproxy.io/{quote(url)}"
|
7
|
+
from typing import Optional, Union
|
15
8
|
|
16
|
-
|
17
|
-
|
18
|
-
def furl(url, params=None, force=False):
|
19
|
-
"""Return file like object after calling the proxied URL."""
|
20
|
-
r = cors_proxy_get(url, params, force)
|
9
|
+
PLATFORM = platform.system().lower()
|
21
10
|
|
22
|
-
|
23
|
-
|
11
|
+
class CorsProxy:
|
12
|
+
"""CORS Proxy with optional caching support."""
|
13
|
+
|
14
|
+
def __init__(self, use_cache: bool = False, **cache_kwargs):
|
15
|
+
"""
|
16
|
+
Initialize the CORS proxy.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
use_cache: Whether to enable request caching
|
20
|
+
**cache_kwargs: Arguments passed to requests_cache.CachedSession
|
21
|
+
(e.g., cache_name, backend, expire_after)
|
22
|
+
"""
|
23
|
+
if use_cache:
|
24
|
+
# Set some sensible defaults if not provided
|
25
|
+
if 'cache_name' not in cache_kwargs:
|
26
|
+
cache_kwargs['cache_name'] = 'cors_proxy_cache'
|
27
|
+
if 'expire_after' not in cache_kwargs:
|
28
|
+
cache_kwargs['expire_after'] = 3600 # 1 hour default
|
29
|
+
self.session = requests_cache.CachedSession(**cache_kwargs)
|
30
|
+
else:
|
31
|
+
self.session = requests
|
24
32
|
|
33
|
+
def xurl(self, url: str, params: Optional[dict] = None, force: bool = False) -> str:
|
34
|
+
"""Generate a proxied URL."""
|
35
|
+
if PLATFORM == "emscripten" or force:
|
36
|
+
if params:
|
37
|
+
url = f"{url}?{urlencode(params)}"
|
38
|
+
url = f"https://corsproxy.io/{quote(url)}"
|
39
|
+
return url
|
25
40
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
41
|
+
def furl(self, url: str, params: Optional[dict] = None, force: bool = False) -> io.BytesIO:
|
42
|
+
"""Return file like object after calling the proxied URL."""
|
43
|
+
r = self.cors_proxy_get(url, params, force)
|
44
|
+
return io.BytesIO(r.content)
|
29
45
|
|
30
|
-
|
31
|
-
|
32
|
-
|
46
|
+
def cors_proxy_get(self, url: str, params: Optional[dict] = None, force: bool = False) -> requests.Response:
|
47
|
+
"""
|
48
|
+
CORS proxy for GET resources with requests-like response.
|
49
|
+
|
50
|
+
Args:
|
51
|
+
url: The URL to fetch
|
52
|
+
params: Query parameters to include
|
53
|
+
force: Force using the proxy even on non-emscripten platforms
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
A requests response object.
|
57
|
+
"""
|
58
|
+
proxy_url = self.xurl(url, params, force)
|
59
|
+
return self.session.get(proxy_url)
|
33
60
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
61
|
+
def robust_get_request(self, url: str, params: Optional[dict] = None) -> requests.Response:
|
62
|
+
"""
|
63
|
+
Try to make a simple request else fall back to a proxy.
|
64
|
+
"""
|
65
|
+
try:
|
66
|
+
r = self.session.get(url, params=params)
|
67
|
+
except:
|
68
|
+
r = self.cors_proxy_get(url, params=params)
|
69
|
+
return r
|
38
70
|
|
39
|
-
|
40
|
-
|
41
|
-
return requests.get(proxy_url)
|
71
|
+
# Create default instance
|
72
|
+
_default_proxy = CorsProxy()
|
42
73
|
|
74
|
+
# Legacy function-based interface
|
75
|
+
xurl = _default_proxy.xurl
|
76
|
+
furl = _default_proxy.furl
|
77
|
+
cors_proxy_get = _default_proxy.cors_proxy_get
|
78
|
+
robust_get_request = _default_proxy.robust_get_request
|
43
79
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
try:
|
49
|
-
r = requests.get(url, params=params)
|
50
|
-
except:
|
51
|
-
r = cors_proxy_get(url, params=params)
|
52
|
-
return r
|
80
|
+
# Convenience function to create a cached proxy
|
81
|
+
def create_cached_proxy(**cache_kwargs):
|
82
|
+
"""Create a new CorsProxy instance with caching enabled."""
|
83
|
+
return CorsProxy(use_cache=True, **cache_kwargs)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: jupyterlite-simple-cors-proxy
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.9
|
4
4
|
Summary: A simple CORS proxy utility with requests-like response
|
5
5
|
Home-page: https://github.com/innovationOUtside/jupyterlite-simple-cors-proxy
|
6
6
|
Author: Tony Hirst
|
@@ -23,7 +23,7 @@ Dynamic: requires-python
|
|
23
23
|
Dynamic: summary
|
24
24
|
|
25
25
|
# jupyterlite-simple-cors-proxy
|
26
|
-
Simple CORS proxy for making http requests from JupyterLite
|
26
|
+
Simple CORS proxy wrapper for making http requests from JupyterLite. Uses https://corsproxy.io/
|
27
27
|
|
28
28
|
## Installation
|
29
29
|
|
@@ -65,3 +65,18 @@ The `robust_get_request()` will first try a simple request, then a proxied reque
|
|
65
65
|
- Simple CORS proxy wrapper
|
66
66
|
- Requests response object
|
67
67
|
- Support for URL parameters
|
68
|
+
|
69
|
+
## `fastf1` cors proxy
|
70
|
+
|
71
|
+
A monkey patch for `fastf1` is provided as:
|
72
|
+
|
73
|
+
```python
|
74
|
+
import fast f1
|
75
|
+
from jupyterlite_simple_cors_proxy.fastf1_proxy import enable_cors_proxy
|
76
|
+
|
77
|
+
enable_cors_proxy(
|
78
|
+
# domains=["api.formula1.com", "livetiming.formula1.com"],
|
79
|
+
# debug=True,
|
80
|
+
# proxy_url="https://corsproxy.io/",
|
81
|
+
)
|
82
|
+
```
|
@@ -0,0 +1,8 @@
|
|
1
|
+
jupyterlite_simple_cors_proxy/__init__.py,sha256=yMbwL10DDWnXt2GVs_yOQLmlQtU2dtcHfTit62Nc04g,274
|
2
|
+
jupyterlite_simple_cors_proxy/fastf1_proxy.py,sha256=FglRogTIlSJvHOu6lFS3S-EHDb37M93aYjQpoKc1QYs,7614
|
3
|
+
jupyterlite_simple_cors_proxy/proxy.py,sha256=SzKQrflMbIJdHoDZ2dtRenGCAGMZEBSl_fs7sjIkiHk,2989
|
4
|
+
jupyterlite_simple_cors_proxy-0.1.9.dist-info/LICENSE,sha256=Ogw7GUmeZIxmDNiKWsu_N07svNoGnPB7lWyiXHX_rMY,1074
|
5
|
+
jupyterlite_simple_cors_proxy-0.1.9.dist-info/METADATA,sha256=HrfzXYCuKpPWh7zCDpbmbTZGRgCtGjpvH1Q0snUAQfU,2031
|
6
|
+
jupyterlite_simple_cors_proxy-0.1.9.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
7
|
+
jupyterlite_simple_cors_proxy-0.1.9.dist-info/top_level.txt,sha256=Oh0oQrSmRnBq5u675coiKMbkb2ASg8AGF8ZiZTzUS5Q,30
|
8
|
+
jupyterlite_simple_cors_proxy-0.1.9.dist-info/RECORD,,
|
@@ -1,8 +0,0 @@
|
|
1
|
-
jupyterlite_simple_cors_proxy/__init__.py,sha256=4IEZXGJ78nCMkOujvGFjwgNf3Rmv77u_lkZWufob5wU,292
|
2
|
-
jupyterlite_simple_cors_proxy/fastf1_proxy.py,sha256=zsLspQjuj9gw4qbsFRydZvmfLelXUmb3gUOXjrGzQgs,7505
|
3
|
-
jupyterlite_simple_cors_proxy/proxy.py,sha256=hF7SeLx7whBkE8m8bDUaelx2tKfLrSHA_Lp_auFtqeY,1341
|
4
|
-
jupyterlite_simple_cors_proxy-0.1.7.dist-info/LICENSE,sha256=Ogw7GUmeZIxmDNiKWsu_N07svNoGnPB7lWyiXHX_rMY,1074
|
5
|
-
jupyterlite_simple_cors_proxy-0.1.7.dist-info/METADATA,sha256=oXlGf3Dux_i1RHxUOF5IUOUqNECoZ-4EkLUkTn1UsWc,1682
|
6
|
-
jupyterlite_simple_cors_proxy-0.1.7.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
7
|
-
jupyterlite_simple_cors_proxy-0.1.7.dist-info/top_level.txt,sha256=Oh0oQrSmRnBq5u675coiKMbkb2ASg8AGF8ZiZTzUS5Q,30
|
8
|
-
jupyterlite_simple_cors_proxy-0.1.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|