physistool 0.1.2__tar.gz → 0.1.3__tar.gz
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.
- {physistool-0.1.2 → physistool-0.1.3}/PKG-INFO +1 -1
- {physistool-0.1.2 → physistool-0.1.3}/physis/__init__.py +1 -1
- {physistool-0.1.2 → physistool-0.1.3}/physis/metering.py +40 -8
- {physistool-0.1.2 → physistool-0.1.3}/physis/physis_client.py +4 -0
- {physistool-0.1.2 → physistool-0.1.3}/physistool.egg-info/PKG-INFO +1 -1
- {physistool-0.1.2 → physistool-0.1.3}/pyproject.toml +1 -1
- {physistool-0.1.2 → physistool-0.1.3}/LICENSE +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/README.md +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/physis/attestation.py +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/physis/dispatcher.py +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/physis/envelope.py +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/physis/licensing.py +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/physistool.egg-info/SOURCES.txt +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/physistool.egg-info/dependency_links.txt +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/physistool.egg-info/entry_points.txt +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/physistool.egg-info/requires.txt +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/physistool.egg-info/top_level.txt +0 -0
- {physistool-0.1.2 → physistool-0.1.3}/setup.cfg +0 -0
|
@@ -36,7 +36,7 @@ _TIMEOUT = 15 # seconds
|
|
|
36
36
|
# in sync with ``build/package.py`` VERSION — this is the version of the shipped
|
|
37
37
|
# wheel. It is *spoofable* by design: the gate is a forced-upgrade lever, not an
|
|
38
38
|
# anti-tamper check — the real enforcement lives server-side.
|
|
39
|
-
CLIENT_VERSION = "0.1.
|
|
39
|
+
CLIENT_VERSION = "0.1.3"
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
class MeteringError(Exception):
|
|
@@ -52,6 +52,25 @@ class MeteringError(Exception):
|
|
|
52
52
|
self.detail = detail or message
|
|
53
53
|
|
|
54
54
|
|
|
55
|
+
class UpgradeRequiredError(MeteringError):
|
|
56
|
+
"""The server's MIN_CLIENT_VERSION gate refused this build (HTTP 403).
|
|
57
|
+
|
|
58
|
+
Enforced server-side on the charge path (reserve) BEFORE any credit moves, so
|
|
59
|
+
an old or cracked client cannot fold. Carries the required + current versions
|
|
60
|
+
and a ready-to-print ``pip install -U`` message. Subclasses MeteringError so
|
|
61
|
+
existing ``except MeteringError`` sites still catch it, but callers may catch
|
|
62
|
+
this specifically to show a clean forced-upgrade prompt.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def __init__(self, min_client_version: str, your_version: str):
|
|
66
|
+
self.min_client_version = min_client_version
|
|
67
|
+
self.your_version = your_version
|
|
68
|
+
msg = (f"this physistool client ({your_version}) is below the minimum "
|
|
69
|
+
f"supported version ({min_client_version}). "
|
|
70
|
+
f"Upgrade with: pip install -U physistool")
|
|
71
|
+
super().__init__(msg, status=403, detail=msg)
|
|
72
|
+
|
|
73
|
+
|
|
55
74
|
def _post(base_url: str, path: str, payload: dict) -> dict:
|
|
56
75
|
url = f"{base_url}{path}"
|
|
57
76
|
# client_version rides along on every call (see CLIENT_VERSION); an explicit
|
|
@@ -66,7 +85,16 @@ def _post(base_url: str, path: str, payload: dict) -> dict:
|
|
|
66
85
|
body = resp.read().decode("utf-8")
|
|
67
86
|
return json.loads(body) if body else {}
|
|
68
87
|
except urllib.error.HTTPError as e:
|
|
69
|
-
|
|
88
|
+
raw, obj = _read_error_body(e)
|
|
89
|
+
# Forced-upgrade gate: a 403 carrying min_client_version means this build
|
|
90
|
+
# is below the server's floor. Surface it as a dedicated, actionable error
|
|
91
|
+
# (the client prints "pip install -U") instead of a generic reserve failure.
|
|
92
|
+
if e.code == 403 and isinstance(obj, dict) and obj.get("min_client_version"):
|
|
93
|
+
raise UpgradeRequiredError(
|
|
94
|
+
str(obj["min_client_version"]),
|
|
95
|
+
str(obj.get("your_version") or CLIENT_VERSION)) from e
|
|
96
|
+
detail = (obj.get("error") or obj.get("detail") or raw) if isinstance(obj, dict) \
|
|
97
|
+
else (raw or e.reason or "unknown error")
|
|
70
98
|
raise MeteringError(f"backend returned HTTP {e.code}: {detail}",
|
|
71
99
|
status=e.code, detail=detail) from e
|
|
72
100
|
except urllib.error.URLError as e:
|
|
@@ -79,13 +107,17 @@ def _post(base_url: str, path: str, payload: dict) -> dict:
|
|
|
79
107
|
status=0, detail=str(e)) from e
|
|
80
108
|
|
|
81
109
|
|
|
82
|
-
def
|
|
110
|
+
def _read_error_body(e: "urllib.error.HTTPError") -> "tuple[str, object]":
|
|
111
|
+
"""Read an HTTPError body once, returning (raw_text, parsed_json_or_None)."""
|
|
112
|
+
raw = ""
|
|
113
|
+
try:
|
|
114
|
+
raw = e.read().decode("utf-8", "replace")
|
|
115
|
+
except OSError:
|
|
116
|
+
return "", None
|
|
83
117
|
try:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return
|
|
87
|
-
except (ValueError, OSError):
|
|
88
|
-
return e.reason or "unknown error"
|
|
118
|
+
return raw, json.loads(raw)
|
|
119
|
+
except ValueError:
|
|
120
|
+
return raw, None
|
|
89
121
|
|
|
90
122
|
|
|
91
123
|
# ── lifecycle calls ─────────────────────────────────────────────────────────
|
|
@@ -668,6 +668,10 @@ def fold(
|
|
|
668
668
|
backend, api_key, credits=credits,
|
|
669
669
|
idempotency_key=str(uuid.uuid4()), input_hash=input_hash,
|
|
670
670
|
)
|
|
671
|
+
except metering_mod.UpgradeRequiredError as exc:
|
|
672
|
+
# Forced-upgrade gate (server MIN_CLIENT_VERSION). Not a reserve/credit
|
|
673
|
+
# problem — the build is too old to fold. Surface the pip command as-is.
|
|
674
|
+
raise FoldError(exc.detail, status=exc.status, error="please_upgrade") from exc
|
|
671
675
|
except metering_mod.MeteringError as exc:
|
|
672
676
|
raise FoldError(
|
|
673
677
|
f"could not reserve {credits} credit(s): {exc.detail}",
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "physistool"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.3"
|
|
8
8
|
description = "Open-source PhysisFold client — CLI + SDK for constraint-guided all-atom protein folding via a remote (Nitro Enclave) endpoint."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|