alphaengine 0.1.1__tar.gz → 0.1.2__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.
- {alphaengine-0.1.1 → alphaengine-0.1.2}/CHANGELOG.md +19 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/PKG-INFO +1 -1
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/__init__.py +3 -1
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/_version.py +1 -1
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/study/__init__.py +4 -4
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/study/report.py +11 -10
- {alphaengine-0.1.1 → alphaengine-0.1.2}/.github/workflows/ci.yml +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/.github/workflows/publish.yml +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/.gitignore +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/LICENSE +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/README.md +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/SECURITY.md +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/pyproject.toml +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/agent/__init__.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/agent/driver.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/client/__init__.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/client/executor.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/client/session.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/core/__init__.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/core/backtest.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/core/factors.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/core/pairs.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/core/performance.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/core/risk.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/core/technical.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/core/validation.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/py.typed +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/study/schema.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/sweep/__init__.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/src/alphaengine/sweep/runner.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/tests/test_client.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/tests/test_goldens.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/tests/test_smoke.py +0 -0
- {alphaengine-0.1.1 → alphaengine-0.1.2}/tests/test_sweep.py +0 -0
|
@@ -7,6 +7,25 @@ minor bump.
|
|
|
7
7
|
|
|
8
8
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
9
9
|
|
|
10
|
+
## [0.1.2] - 2026-07-31
|
|
11
|
+
|
|
12
|
+
**No computed value changed.** Identical figures to 0.1.0 and 0.1.1.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- `report()` used `try`/`except`/`pass` to read an error body, which ruff's
|
|
17
|
+
SIM105 correctly objects to. It is `contextlib.suppress` now. The intent was
|
|
18
|
+
always total suppression: a server answering with HTML, an empty body or
|
|
19
|
+
nothing at all still has to produce a usable error rather than a second
|
|
20
|
+
exception raised on top of the first.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- `DEFAULT_BASE_URL` points at the live platform. 0.1.1 shipped with a
|
|
25
|
+
placeholder host, so every `report()` call that did not pass `base_url` or set
|
|
26
|
+
`QUANTOS_API_URL` resolved to a domain that does not answer. Reporting was
|
|
27
|
+
effectively unusable at its default in that release.
|
|
28
|
+
|
|
10
29
|
## [0.1.1] - 2026-07-31
|
|
11
30
|
|
|
12
31
|
**No computed value changed.** Every figure this version produces is identical
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alphaengine
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Validated research tooling for investment strategies: deflation, overfitting detection, and honest trial counts.
|
|
5
5
|
Project-URL: Homepage, https://github.com/quantOSC/alphaengine
|
|
6
6
|
Project-URL: Documentation, https://github.com/quantOSC/alphaengine#readme
|
|
@@ -27,6 +27,8 @@ OFFLINE BY CONSTRUCTION
|
|
|
27
27
|
and your data never leaves the machine.
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
+
from typing import Any
|
|
31
|
+
|
|
30
32
|
from ._version import __version__
|
|
31
33
|
from .study import SCHEMA_VERSION, Study, load, save
|
|
32
34
|
from .sweep import SweepResult, sweep
|
|
@@ -49,7 +51,7 @@ __all__ = [
|
|
|
49
51
|
]
|
|
50
52
|
|
|
51
53
|
|
|
52
|
-
def __getattr__(name: str): # PEP 562
|
|
54
|
+
def __getattr__(name: str) -> Any: # PEP 562
|
|
53
55
|
"""`report` and `ReportError` load on first use.
|
|
54
56
|
|
|
55
57
|
Everything else in this package is offline by construction and imports
|
|
@@ -27,14 +27,14 @@ WHAT IS NOT IN IT
|
|
|
27
27
|
whoever owns them.
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
+
from typing import Any
|
|
31
|
+
|
|
30
32
|
from .schema import SCHEMA_VERSION, Study, load, save
|
|
31
33
|
|
|
32
|
-
__all__ = [
|
|
33
|
-
"report",
|
|
34
|
-
"ReportError","Study", "save", "load", "SCHEMA_VERSION"]
|
|
34
|
+
__all__ = ["report", "ReportError", "Study", "save", "load", "SCHEMA_VERSION"]
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def __getattr__(name: str): # PEP 562
|
|
37
|
+
def __getattr__(name: str) -> Any: # PEP 562
|
|
38
38
|
"""`report` and `ReportError` load on first use.
|
|
39
39
|
|
|
40
40
|
Eager import would pull urllib into `import alphaengine`, which the offline
|
|
@@ -29,6 +29,7 @@ user of the offline half, who did not ask for this.
|
|
|
29
29
|
|
|
30
30
|
from __future__ import annotations
|
|
31
31
|
|
|
32
|
+
import contextlib
|
|
32
33
|
import json
|
|
33
34
|
import os
|
|
34
35
|
from typing import TYPE_CHECKING, Any
|
|
@@ -38,7 +39,7 @@ if TYPE_CHECKING: # pragma: no cover - typing only
|
|
|
38
39
|
|
|
39
40
|
__all__ = ["report", "ReportError"]
|
|
40
41
|
|
|
41
|
-
DEFAULT_BASE_URL = "https://
|
|
42
|
+
DEFAULT_BASE_URL = "https://alpha-backend-production-51df.up.railway.app"
|
|
42
43
|
_ENV_KEY = "QUANTOS_API_KEY"
|
|
43
44
|
_ENV_URL = "QUANTOS_API_URL"
|
|
44
45
|
_PATH = "/api/me/runs/ingest"
|
|
@@ -140,8 +141,7 @@ def report(
|
|
|
140
141
|
key = api_key or os.environ.get(_ENV_KEY, "")
|
|
141
142
|
if not key.strip():
|
|
142
143
|
raise ReportError(
|
|
143
|
-
f"No API key. Pass api_key=..., or set {_ENV_KEY}. "
|
|
144
|
-
"Create one in the portal under Settings."
|
|
144
|
+
f"No API key. Pass api_key=..., or set {_ENV_KEY}. Create one in the portal under Settings."
|
|
145
145
|
)
|
|
146
146
|
|
|
147
147
|
root = (base_url or os.environ.get(_ENV_URL) or DEFAULT_BASE_URL).rstrip("/")
|
|
@@ -160,13 +160,16 @@ def report(
|
|
|
160
160
|
|
|
161
161
|
try:
|
|
162
162
|
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
|
163
|
-
|
|
163
|
+
recorded: dict[str, Any] = json.loads(resp.read().decode("utf-8"))
|
|
164
|
+
return recorded
|
|
164
165
|
except urllib.error.HTTPError as e:
|
|
166
|
+
# The body is best-effort context for the message. A server that
|
|
167
|
+
# answers with HTML, an empty body, or nothing at all still has to
|
|
168
|
+
# produce a usable error rather than a second exception on top of the
|
|
169
|
+
# first, which is why the failure to read it is suppressed entirely.
|
|
165
170
|
detail = ""
|
|
166
|
-
|
|
171
|
+
with contextlib.suppress(Exception):
|
|
167
172
|
detail = json.loads(e.read().decode("utf-8")).get("detail", "")
|
|
168
|
-
except Exception: # noqa: BLE001 - the body is best-effort context
|
|
169
|
-
pass
|
|
170
173
|
if e.code in (401, 403):
|
|
171
174
|
raise ReportError(
|
|
172
175
|
f"The key was rejected ({e.code}). It may be revoked, or from a different "
|
|
@@ -174,6 +177,4 @@ def report(
|
|
|
174
177
|
) from e
|
|
175
178
|
raise ReportError(f"The server refused the study ({e.code}). {detail}".strip()) from e
|
|
176
179
|
except urllib.error.URLError as e:
|
|
177
|
-
raise ReportError(
|
|
178
|
-
f"Could not reach {root}: {e.reason}. Your study is still on your disk."
|
|
179
|
-
) from e
|
|
180
|
+
raise ReportError(f"Could not reach {root}: {e.reason}. Your study is still on your disk.") from e
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|