|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | 3 | import logging |
| 4 | +import os |
| 5 | +import urllib.response |
4 | 6 | from contextlib import suppress |
| 7 | +from urllib.error import URLError |
5 | 8 |
|
6 | 9 | try: |
7 | 10 | import boto3 |
@@ -60,17 +63,56 @@ def clear_cache() -> None: |
60 | 63 | shutil.rmtree(COSEM_CACHE, ignore_errors=True) |
61 | 64 |
|
62 | 65 |
|
| 66 | +def _urlopen(url: str) -> Any: |
| 67 | + # urlopen with a custom user agent |
| 68 | + from microsim import __version__ |
| 69 | + |
| 70 | + user_agent = f"microsim/{__version__}" |
| 71 | + request = urllib.request.Request(url, headers={"User-Agent": user_agent}) |
| 72 | + return urllib.request.urlopen(request) |
| 73 | + |
| 74 | + |
| 75 | +def _get_chunk_js() -> str | None: |
| 76 | + root = "https://openorganelle.janelia.org" |
| 77 | + with _urlopen(root) as response: |
| 78 | + if response.status != 200: |
| 79 | + raise URLError(f"Failed to fetch {root}.") |
| 80 | + text = response.read().decode("utf-8") |
| 81 | + if main := re.search(r"(/static/js/main\.[^/]+\.js)", text): |
| 82 | + return root + main.group(1) |
| 83 | + return None |
| 84 | + |
| 85 | + |
63 | 86 | @cache |
64 | | -def _supabase(url: str | None = None, key: str | None = None) -> supabase.Client: |
65 | | - if not (url and key): |
66 | | - with urllib.request.urlopen( |
67 | | - "https://openorganelle.janelia.org/static/js/4743.a9f85e14.chunk.js" |
68 | | - ) as response: |
| 87 | +def _guess_cosem_url_key() -> tuple[str, str]: |
| 88 | + if not (url := _get_chunk_js()): |
| 89 | + raise ValueError("Failed to fetch openorganelle JS file.") |
| 90 | + try: |
| 91 | + with _urlopen(url) as response: |
69 | 92 | if response.status != 200: |
70 | | - raise ValueError("Failed to fetch Supabase URL and key") |
71 | | - text = response.read().decode("utf-8") |
72 | | - key = text.split("SUPABASE_KEY:")[1].split(",")[0].strip("\"'") |
| 93 | + raise URLError(f"Failed to fetch {url}.") |
| 94 | + text: str = response.read().decode("utf-8") |
73 | 95 | url = text.split("SUPABASE_URL:")[1].split(",")[0].strip("\"'") |
| 96 | + key = text.split("SUPABASE_KEY:")[1].split(",")[0].strip("\"'") |
| 97 | + return url, key |
| 98 | + except Exception as e: |
| 99 | + raise ValueError(f"Failed to fetch Supabase URL and key: {e}") from e |
| 100 | + |
| 101 | + |
| 102 | +@cache |
| 103 | +def _supabase(url: str | None = None, key: str | None = None) -> supabase.Client: |
| 104 | + if url is None: |
| 105 | + url = os.getenv("COSEM_SUPABASE_URL") |
| 106 | + if key is None: |
| 107 | + key = os.getenv("COSEM_SUPABASE_KEY") |
| 108 | + if url is None or key is None: |
| 109 | + try: |
| 110 | + url, key = _guess_cosem_url_key() |
| 111 | + except ValueError as e: # pragma: no cover |
| 112 | + raise ValueError( |
| 113 | + "No Cosem API key. You may set your own COSEM_SUPABASE_URL " |
| 114 | + "and COSEM_SUPABASE_KEY environment variables." |
| 115 | + ) from e |
74 | 116 | return Client(url, key) |
75 | 117 |
|
76 | 118 |
|
|
0 commit comments