"""Shared paths and helpers for the `silurian` study.""" import os, ssl, time, json, urllib.request, urllib.parse STUDY = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) CODE = os.path.join(STUDY, "code") DATA = os.path.join(STUDY, "data") FIGS = os.path.join(STUDY, "figures") RAW = os.environ.get("SILURIAN_RAW", "fermi_raw/silurian") for d in (DATA, FIGS, RAW): os.makedirs(d, exist_ok=True) SEED = 20261012 UA = "fermi-silurian-study/1.0 (research; python-urllib)" # Physical / geographic constants used throughout A_EARTH = 510.1e6 # km2 A_LAND = 148.9e6 # km2 present land area (incl. Antarctica, Greenland) A_OCEAN = A_EARTH - A_LAND def fetch(url, dest, timeout=600, retries=4, min_bytes=1): """Download url to dest unless it is already cached. Returns dest.""" if os.path.exists(dest) and os.path.getsize(dest) >= min_bytes: return dest os.makedirs(os.path.dirname(dest), exist_ok=True) last = None for k in range(retries): try: req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=timeout) as r, open(dest + ".part", "wb") as f: while True: b = r.read(1 << 16) if not b: break f.write(b) if os.path.getsize(dest + ".part") < min_bytes: raise IOError("short download") os.replace(dest + ".part", dest) return dest except Exception as e: # noqa last = e time.sleep(3 + 5 * k) raise IOError(f"download failed: {url}: {last}") def save_json(obj, name): p = os.path.join(DATA, name) with open(p, "w") as f: json.dump(obj, f, indent=1, sort_keys=True, default=float) return p def load_json(name): with open(os.path.join(DATA, name)) as f: return json.load(f)