jupyterlite-simple-cors-proxy 0.1.10__py3-none-any.whl → 0.1.12__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 +1 -1
- jupyterlite_simple_cors_proxy/cacheproxy.py +61 -11
- jupyterlite_simple_cors_proxy/proxy.py +42 -8
- {jupyterlite_simple_cors_proxy-0.1.10.dist-info → jupyterlite_simple_cors_proxy-0.1.12.dist-info}/METADATA +2 -2
- jupyterlite_simple_cors_proxy-0.1.12.dist-info/RECORD +9 -0
- {jupyterlite_simple_cors_proxy-0.1.10.dist-info → jupyterlite_simple_cors_proxy-0.1.12.dist-info}/WHEEL +1 -1
- jupyterlite_simple_cors_proxy-0.1.10.dist-info/RECORD +0 -9
- {jupyterlite_simple_cors_proxy-0.1.10.dist-info → jupyterlite_simple_cors_proxy-0.1.12.dist-info}/LICENSE +0 -0
- {jupyterlite_simple_cors_proxy-0.1.10.dist-info → jupyterlite_simple_cors_proxy-0.1.12.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,22 @@
|
|
1
1
|
# File: simple_cors_proxy/proxy.py
|
2
2
|
from urllib.parse import urlencode, quote
|
3
3
|
import requests
|
4
|
-
|
4
|
+
|
5
5
|
import io
|
6
6
|
import platform
|
7
7
|
from typing import Optional, Union
|
8
8
|
|
9
9
|
PLATFORM = platform.system().lower()
|
10
|
+
CORS_PROXIES = {
|
11
|
+
"corsproxyio": {"url": "https://corsproxy.io/?url={}", "quote": False},
|
12
|
+
"allorigins": {"url": "https://api.allorigins.win/raw?url={}", "quote": True},
|
13
|
+
"none": {"url": "{}", "quote": False},
|
14
|
+
}
|
15
|
+
|
10
16
|
|
11
17
|
class CorsProxy:
|
12
18
|
"""CORS Proxy with optional caching support."""
|
13
|
-
|
19
|
+
|
14
20
|
def __init__(self, use_cache: bool = False, **cache_kwargs):
|
15
21
|
"""
|
16
22
|
Initialize the CORS proxy.
|
@@ -21,6 +27,7 @@ class CorsProxy:
|
|
21
27
|
(e.g., cache_name, backend, expire_after)
|
22
28
|
"""
|
23
29
|
if use_cache:
|
30
|
+
import requests_cache
|
24
31
|
# Set some sensible defaults if not provided
|
25
32
|
if 'cache_name' not in cache_kwargs:
|
26
33
|
cache_kwargs['cache_name'] = 'cors_proxy_cache'
|
@@ -29,21 +36,61 @@ class CorsProxy:
|
|
29
36
|
self.session = requests_cache.CachedSession(**cache_kwargs)
|
30
37
|
else:
|
31
38
|
self.session = requests
|
39
|
+
if "proxy" in cache_kwargs:
|
40
|
+
self.proxy = cache_kwargs["proxy"]
|
41
|
+
else:
|
42
|
+
self.proxy = "corsproxyio"
|
32
43
|
|
33
|
-
def
|
44
|
+
def apply_cors_proxy(self, url, proxy="corsproxyio"):
|
45
|
+
"""
|
46
|
+
Apply a CORS proxy to the given URL.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
url (str): The original URL to proxy
|
50
|
+
proxy (str): The proxy identifier to use from CORS_PROXIES
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
str: The proxied URL
|
54
|
+
"""
|
55
|
+
if proxy not in CORS_PROXIES:
|
56
|
+
raise ValueError(
|
57
|
+
f"Unknown proxy: {proxy}. Available proxies: {', '.join(CORS_PROXIES.keys())}"
|
58
|
+
)
|
59
|
+
|
60
|
+
proxy_config = CORS_PROXIES[proxy]
|
61
|
+
|
62
|
+
if proxy_config["quote"]:
|
63
|
+
url = proxy_config["url"].format(quote(url))
|
64
|
+
else:
|
65
|
+
url = proxy_config["url"].format(url)
|
66
|
+
|
67
|
+
return url
|
68
|
+
|
69
|
+
def xurl(
|
70
|
+
self,
|
71
|
+
url: str,
|
72
|
+
params: Optional[dict] = None,
|
73
|
+
force: bool = False,
|
74
|
+
proxy: str = "",
|
75
|
+
) -> str:
|
34
76
|
"""Generate a proxied URL."""
|
35
77
|
if PLATFORM == "emscripten" or force:
|
36
78
|
if params:
|
37
79
|
url = f"{url}?{urlencode(params)}"
|
38
|
-
url = f"https://corsproxy.io/{quote(url)}"
|
80
|
+
# url = f"https://corsproxy.io/{quote(url)}"
|
81
|
+
if not proxy:
|
82
|
+
proxy = self.proxy
|
83
|
+
url = self.apply_cors_proxy(url, proxy=proxy)
|
39
84
|
return url
|
40
85
|
|
41
|
-
def furl(self, url: str, params: Optional[dict] = None, force: bool = False) -> io.BytesIO:
|
86
|
+
def furl(self, url: str, params: Optional[dict] = None, force: bool = False, proxy: str = "") -> io.BytesIO:
|
42
87
|
"""Return file like object after calling the proxied URL."""
|
43
|
-
r = self.cors_proxy_get(url, params, force)
|
88
|
+
r = self.cors_proxy_get(url, params, force, proxy)
|
89
|
+
# TO DO - something to consider?
|
90
|
+
# https://simonwillison.net/2025/Jan/31/save-memory-with-bytesio/
|
44
91
|
return io.BytesIO(r.content)
|
45
92
|
|
46
|
-
def cors_proxy_get(self, url: str, params: Optional[dict] = None, force: bool = False) -> requests.Response:
|
93
|
+
def cors_proxy_get(self, url: str, params: Optional[dict] = None, force: bool = False, proxy: str = "corsproxyio") -> requests.Response:
|
47
94
|
"""
|
48
95
|
CORS proxy for GET resources with requests-like response.
|
49
96
|
|
@@ -55,19 +102,22 @@ class CorsProxy:
|
|
55
102
|
Returns:
|
56
103
|
A requests response object.
|
57
104
|
"""
|
58
|
-
proxy_url = self.xurl(url, params, force)
|
105
|
+
proxy_url = self.xurl(url, params, force), proxy
|
59
106
|
return self.session.get(proxy_url)
|
60
107
|
|
61
|
-
def robust_get_request(
|
108
|
+
def robust_get_request(
|
109
|
+
self, url: str, params: Optional[dict] = None, proxy: str = ""
|
110
|
+
) -> requests.Response:
|
62
111
|
"""
|
63
112
|
Try to make a simple request else fall back to a proxy.
|
64
113
|
"""
|
65
114
|
try:
|
66
115
|
r = self.session.get(url, params=params)
|
67
116
|
except:
|
68
|
-
r = self.cors_proxy_get(url, params=params)
|
117
|
+
r = self.cors_proxy_get(url, params=params, proxy=proxy)
|
69
118
|
return r
|
70
119
|
|
120
|
+
|
71
121
|
# Create default instance
|
72
122
|
_default_proxy = CorsProxy()
|
73
123
|
|
@@ -80,4 +130,4 @@ robust_get_request = _default_proxy.robust_get_request
|
|
80
130
|
# Convenience function to create a cached proxy
|
81
131
|
def create_cached_proxy(**cache_kwargs):
|
82
132
|
"""Create a new CorsProxy instance with caching enabled."""
|
83
|
-
return CorsProxy(use_cache=True, **cache_kwargs)
|
133
|
+
return CorsProxy(use_cache=True, **cache_kwargs)
|
@@ -6,27 +6,61 @@ import io
|
|
6
6
|
import platform
|
7
7
|
|
8
8
|
PLATFORM = platform.system().lower()
|
9
|
+
CORS_PROXIES = {
|
10
|
+
"corsproxyio": {"url": "https://corsproxy.io/?url={}", "quote": False},
|
11
|
+
"allorigins": {"url": "https://api.allorigins.win/raw?url={}", "quote": True},
|
12
|
+
"none": {"url": "{}", "quote": False},
|
13
|
+
}
|
9
14
|
|
10
15
|
|
11
|
-
def
|
16
|
+
def apply_cors_proxy(url, proxy="corsproxyio"):
|
17
|
+
"""
|
18
|
+
Apply a CORS proxy to the given URL.
|
19
|
+
|
20
|
+
Args:
|
21
|
+
url (str): The original URL to proxy
|
22
|
+
proxy (str): The proxy identifier to use from CORS_PROXIES
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
str: The proxied URL
|
26
|
+
"""
|
27
|
+
if proxy not in CORS_PROXIES:
|
28
|
+
raise ValueError(
|
29
|
+
f"Unknown proxy: {proxy}. Available proxies: {', '.join(CORS_PROXIES.keys())}"
|
30
|
+
)
|
31
|
+
|
32
|
+
proxy_config = CORS_PROXIES[proxy]
|
33
|
+
|
34
|
+
if proxy_config["quote"]:
|
35
|
+
url = proxy_config["url"].format(quote(url))
|
36
|
+
else:
|
37
|
+
url = proxy_config["url"].format(url)
|
38
|
+
|
39
|
+
return url
|
40
|
+
|
41
|
+
|
42
|
+
def xurl(url, params=None, force=False, proxy="corsproxyio"):
|
12
43
|
"""Generate a proxied URL."""
|
13
44
|
if PLATFORM == "emscripten" or force:
|
14
45
|
if params:
|
15
46
|
url = f"{url}?{urlencode(params)}"
|
16
|
-
url = f"https://corsproxy.io/{quote(url)}"
|
47
|
+
# url = f"https://corsproxy.io/{quote(url)}"
|
48
|
+
url = apply_cors_proxy(url, proxy=proxy)
|
17
49
|
|
18
50
|
return url
|
19
51
|
|
20
52
|
|
21
|
-
def furl(url, params=None, force=False):
|
53
|
+
def furl(url, params=None, force=False, proxy="corsproxyio"):
|
22
54
|
"""Return file like object after calling the proxied URL."""
|
23
|
-
r = cors_proxy_get(url, params, force)
|
55
|
+
r = cors_proxy_get(url, params, force, proxy=proxy)
|
24
56
|
|
25
57
|
# Return a file-like object from the JSON string
|
58
|
+
# TO DO - something to consider?
|
59
|
+
# https://simonwillison.net/2025/Jan/31/save-memory-with-bytesio/
|
26
60
|
return io.BytesIO(r.content)
|
27
61
|
|
28
62
|
|
29
|
-
def cors_proxy_get(url, params=None, force=False):
|
63
|
+
def cors_proxy_get(url, params=None, force=False, proxy="corsproxyio"):
|
30
64
|
"""
|
31
65
|
CORS proxy for GET resources with requests-like response.
|
32
66
|
|
@@ -37,19 +71,19 @@ def cors_proxy_get(url, params=None, force=False):
|
|
37
71
|
Returns:
|
38
72
|
A requests response object.
|
39
73
|
"""
|
40
|
-
proxy_url = xurl(url, params, force)
|
74
|
+
proxy_url = xurl(url, params, force, proxy=proxy)
|
41
75
|
|
42
76
|
# Do a simple requests get and
|
43
77
|
# just pass through the entire response object
|
44
78
|
return requests.get(proxy_url)
|
45
79
|
|
46
80
|
|
47
|
-
def robust_get_request(url, params=None):
|
81
|
+
def robust_get_request(url, params=None, proxy="corsproxyio"):
|
48
82
|
"""
|
49
83
|
Try to make a simple request else fall back to a proxy.
|
50
84
|
"""
|
51
85
|
try:
|
52
86
|
r = requests.get(url, params=params)
|
53
87
|
except:
|
54
|
-
r = cors_proxy_get(url, params=params)
|
88
|
+
r = cors_proxy_get(url, params=params, proxy=proxy)
|
55
89
|
return r
|
@@ -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.12
|
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
|
@@ -87,7 +87,7 @@ Via `claude.ai`, the package is now further enriched.
|
|
87
87
|
|
88
88
|
*Note that `pyodide` sqlite can't write to `/drive` so the cache path dir needs to be something like `/tmp` or a dir created on `/`.*
|
89
89
|
|
90
|
-
*I'm not convinced the following works in `pyodide` and `xeus-python` yet - `requests-cache` dependency issues etc
|
90
|
+
*I'm not convinced the following works in `pyodide` and `xeus-python` yet - `requests-cache` dependency issues etc. `requests-cache` has requirements `attrs`, `cattrs`,`platformdirs`, `url-normalize`.*
|
91
91
|
|
92
92
|
```python
|
93
93
|
from simple_cors_proxy.proxy import CorsProxy
|
@@ -0,0 +1,9 @@
|
|
1
|
+
jupyterlite_simple_cors_proxy/__init__.py,sha256=vE2WKSaR1d-lu1EoKN3obCHFUB-oowD7I1jwEl5qvok,280
|
2
|
+
jupyterlite_simple_cors_proxy/cacheproxy.py,sha256=H-PCbg5qQ9Tn-kQzALpIrfkJzQoIuv5ZKR4vK8fzUIk,4472
|
3
|
+
jupyterlite_simple_cors_proxy/fastf1_proxy.py,sha256=FglRogTIlSJvHOu6lFS3S-EHDb37M93aYjQpoKc1QYs,7614
|
4
|
+
jupyterlite_simple_cors_proxy/proxy.py,sha256=HkPMY1Tq8Cm4w7nNnzdw8uiRpVuCBj0PtW5Dhk5xQ2c,2478
|
5
|
+
jupyterlite_simple_cors_proxy-0.1.12.dist-info/LICENSE,sha256=Ogw7GUmeZIxmDNiKWsu_N07svNoGnPB7lWyiXHX_rMY,1074
|
6
|
+
jupyterlite_simple_cors_proxy-0.1.12.dist-info/METADATA,sha256=9BU-LuRYblp6muW1R_0GzYRd1OGbIpffkO0O8M5sVLE,3144
|
7
|
+
jupyterlite_simple_cors_proxy-0.1.12.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
|
8
|
+
jupyterlite_simple_cors_proxy-0.1.12.dist-info/top_level.txt,sha256=Oh0oQrSmRnBq5u675coiKMbkb2ASg8AGF8ZiZTzUS5Q,30
|
9
|
+
jupyterlite_simple_cors_proxy-0.1.12.dist-info/RECORD,,
|
@@ -1,9 +0,0 @@
|
|
1
|
-
jupyterlite_simple_cors_proxy/__init__.py,sha256=QNqJ64TlAKsoaOKeVcRqeaibDiO3SpOyEakvenkuiuU,280
|
2
|
-
jupyterlite_simple_cors_proxy/cacheproxy.py,sha256=SzKQrflMbIJdHoDZ2dtRenGCAGMZEBSl_fs7sjIkiHk,2989
|
3
|
-
jupyterlite_simple_cors_proxy/fastf1_proxy.py,sha256=FglRogTIlSJvHOu6lFS3S-EHDb37M93aYjQpoKc1QYs,7614
|
4
|
-
jupyterlite_simple_cors_proxy/proxy.py,sha256=uFpevhGlkbcNqVb1d43uBrqVdvAbOQ2m1PLqxsML6BE,1346
|
5
|
-
jupyterlite_simple_cors_proxy-0.1.10.dist-info/LICENSE,sha256=Ogw7GUmeZIxmDNiKWsu_N07svNoGnPB7lWyiXHX_rMY,1074
|
6
|
-
jupyterlite_simple_cors_proxy-0.1.10.dist-info/METADATA,sha256=g2KklCts9AuEwEUEQ7EpaMh9JBAE8Nmb050_yZNqZbs,3059
|
7
|
-
jupyterlite_simple_cors_proxy-0.1.10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
8
|
-
jupyterlite_simple_cors_proxy-0.1.10.dist-info/top_level.txt,sha256=Oh0oQrSmRnBq5u675coiKMbkb2ASg8AGF8ZiZTzUS5Q,30
|
9
|
-
jupyterlite_simple_cors_proxy-0.1.10.dist-info/RECORD,,
|
File without changes
|
File without changes
|