jupyterlite-simple-cors-proxy 0.1.7__py3-none-any.whl → 0.1.9__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- __version__ = "0.1.7"
6
- __all__ = ["cors_proxy_get", "robust_get_request", "xurl", "furl", "fastf1_cors_proxy"]
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
- PLATFORM = platform.system().lower()
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
- return url
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
- # Return a file-like object from the JSON string
23
- return io.BytesIO(r.content)
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 cors_proxy_get(url, params=None, force=False):
27
- """
28
- CORS proxy for GET resources with requests-like response.
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
- Args:
31
- url (str): The URL to fetch
32
- params (dict, optional): Query parameters to include
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
- Returns:
35
- A requests response object.
36
- """
37
- proxy_url = xurl(url, params, force)
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
- # Do a simple requests get and
40
- # just pass through the entire response object
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
- def robust_get_request(url, params=None):
45
- """
46
- Try to make a simple request else fall back to a proxy.
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.7
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,,