mainsequence 2.0.2__py3-none-any.whl → 2.0.3__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.
- mainsequence/cli/api.py +29 -0
- mainsequence/cli/cli.py +27 -0
- mainsequence/cli/config.py +4 -0
- {mainsequence-2.0.2.dist-info → mainsequence-2.0.3.dist-info}/METADATA +1 -1
- {mainsequence-2.0.2.dist-info → mainsequence-2.0.3.dist-info}/RECORD +9 -9
- {mainsequence-2.0.2.dist-info → mainsequence-2.0.3.dist-info}/WHEEL +0 -0
- {mainsequence-2.0.2.dist-info → mainsequence-2.0.3.dist-info}/entry_points.txt +0 -0
- {mainsequence-2.0.2.dist-info → mainsequence-2.0.3.dist-info}/licenses/LICENSE +0 -0
- {mainsequence-2.0.2.dist-info → mainsequence-2.0.3.dist-info}/top_level.txt +0 -0
mainsequence/cli/api.py
CHANGED
@@ -155,3 +155,32 @@ def add_deploy_key(project_id: int | str, key_title: str, public_key: str) -> No
|
|
155
155
|
{"key_title": key_title, "public_key": public_key})
|
156
156
|
except Exception:
|
157
157
|
pass
|
158
|
+
|
159
|
+
def get_project_token(project_id: int | str) -> str:
|
160
|
+
"""
|
161
|
+
Fetch the project's token using the current access token.
|
162
|
+
If the access token is expired or missing, authed() will refresh once.
|
163
|
+
If refresh also fails, NotLoggedIn is raised so the caller can prompt re-login.
|
164
|
+
"""
|
165
|
+
r = authed("GET", f"/orm/api/pods/projects/{project_id}/get_project_token/")
|
166
|
+
if not r.ok:
|
167
|
+
# authed() already tried refresh on 401;
|
168
|
+
# at this point treat as API error with server message.
|
169
|
+
msg = r.text
|
170
|
+
try:
|
171
|
+
if r.headers.get("content-type","").startswith("application/json"):
|
172
|
+
data = r.json()
|
173
|
+
msg = data.get("detail") or data.get("message") or msg
|
174
|
+
except Exception:
|
175
|
+
pass
|
176
|
+
raise ApiError(f"Project token fetch failed ({r.status_code}). {msg}")
|
177
|
+
|
178
|
+
token = None
|
179
|
+
if r.headers.get("content-type","").startswith("application/json"):
|
180
|
+
data = r.json()
|
181
|
+
token=data["development"]
|
182
|
+
if not token:
|
183
|
+
token = (r.text or "").strip()
|
184
|
+
if not token:
|
185
|
+
raise ApiError("Project token response did not include a token.")
|
186
|
+
return token[0]
|
mainsequence/cli/cli.py
CHANGED
@@ -26,6 +26,7 @@ from .api import (
|
|
26
26
|
login as api_login,
|
27
27
|
repo_name_from_git_url,
|
28
28
|
safe_slug,
|
29
|
+
get_project_token
|
29
30
|
)
|
30
31
|
from .ssh_utils import (
|
31
32
|
ensure_key_for_repo,
|
@@ -287,6 +288,7 @@ def project_set_up_locally(
|
|
287
288
|
cfg_obj = cfg.get_config()
|
288
289
|
base = base_dir or cfg_obj["mainsequence_path"]
|
289
290
|
|
291
|
+
|
290
292
|
org_slug = _org_slug_from_profile()
|
291
293
|
|
292
294
|
items = get_projects()
|
@@ -346,8 +348,33 @@ def project_set_up_locally(
|
|
346
348
|
else:
|
347
349
|
if env_text and not env_text.endswith("\n"): env_text += "\n"
|
348
350
|
env_text += f"VFB_PROJECT_PATH={str(target_dir)}\n"
|
351
|
+
|
352
|
+
try:
|
353
|
+
project_token = get_project_token(project_id)
|
354
|
+
except NotLoggedIn:
|
355
|
+
typer.secho("Session expired or refresh failed. Run: mainsequence login <email>", fg=typer.colors.RED)
|
356
|
+
raise typer.Exit(1)
|
357
|
+
except ApiError as e:
|
358
|
+
typer.secho(f"Could not fetch project token: {e}", fg=typer.colors.RED)
|
359
|
+
raise typer.Exit(1)
|
360
|
+
|
361
|
+
lines = env_text.splitlines()
|
362
|
+
if any(line.startswith("MAINSEQUENCE_TOKEN=") for line in lines):
|
363
|
+
lines = [
|
364
|
+
(f"MAINSEQUENCE_TOKEN={project_token}" if line.startswith("MAINSEQUENCE_TOKEN=") else line)
|
365
|
+
for line in lines
|
366
|
+
]
|
367
|
+
env_text = "\n".join(lines)
|
368
|
+
else:
|
369
|
+
if env_text and not env_text.endswith("\n"): env_text += "\n"
|
370
|
+
env_text += f"MAINSEQUENCE_TOKEN={project_token}\n"
|
371
|
+
|
372
|
+
# write final .env with both vars present
|
349
373
|
(target_dir / ".env").write_text(env_text, encoding="utf-8")
|
350
374
|
|
375
|
+
|
376
|
+
|
377
|
+
|
351
378
|
cfg.set_link(project_id, str(target_dir))
|
352
379
|
|
353
380
|
typer.secho(f"Local folder: {target_dir}", fg=typer.colors.GREEN)
|
mainsequence/cli/config.py
CHANGED
@@ -75,4 +75,8 @@ def set_env_access(access: str) -> None:
|
|
75
75
|
def backend_url() -> str:
|
76
76
|
cfg = get_config()
|
77
77
|
url = (cfg.get("backend_url") or DEFAULTS["backend_url"]).rstrip("/")
|
78
|
+
|
79
|
+
if os.environ.get("MAIN_SEQUENCE_BACKEND_URL") is not None:
|
80
|
+
url=os.environ.get("MAIN_SEQUENCE_BACKEND_URL")
|
81
|
+
|
78
82
|
return url
|
@@ -2,9 +2,9 @@ mainsequence/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
mainsequence/__main__.py,sha256=1_gCQd-MlXQxAubgVdTDgmP2117UQmj5DvTI_PASZis,162
|
3
3
|
mainsequence/logconf.py,sha256=OLkhALon2uIDZSeGOwX3DneapkVqlwDjqJm96TRAhgA,10057
|
4
4
|
mainsequence/cli/__init__.py,sha256=TNxXsTPgb52OhakIda9wTRh91cqoBqgQRx5TxjzQQFU,21
|
5
|
-
mainsequence/cli/api.py,sha256=
|
6
|
-
mainsequence/cli/cli.py,sha256=
|
7
|
-
mainsequence/cli/config.py,sha256=
|
5
|
+
mainsequence/cli/api.py,sha256=PocYESdJvywSo7WyZnnJZmPR_Q8TKe-5jaNazyMhX9I,7313
|
6
|
+
mainsequence/cli/cli.py,sha256=CPG-Q_8b2KFGWGgGbfZzSx8qjauVrgBzg5UMUyQrM00,17308
|
7
|
+
mainsequence/cli/config.py,sha256=UAi0kfxro2oJhzaRdd2D3F72eGpqkYaWjSsCzBrb2LY,2705
|
8
8
|
mainsequence/cli/ssh_utils.py,sha256=95CmZk2nIoJhNTCmifMEsE9QXJrXY3zvfxLQp3QpdiM,5088
|
9
9
|
mainsequence/client/__init__.py,sha256=CDlJtsh0L9Z29OVMBnZsQajKBa193Yy5TkqLoilkbZM,869
|
10
10
|
mainsequence/client/base.py,sha256=j6_iXmt6vPCS7INSOItTpM6ZbAmITAuPpMFNB9ZQTeE,15000
|
@@ -103,9 +103,9 @@ mainsequence/virtualfundbuilder/resource_factory/app_factory.py,sha256=XSZo9ImdT
|
|
103
103
|
mainsequence/virtualfundbuilder/resource_factory/base_factory.py,sha256=jPXdK2WCaNw3r6kP3sZGIL7M4ygfIMs8ek3Yq4QYQZg,9434
|
104
104
|
mainsequence/virtualfundbuilder/resource_factory/rebalance_factory.py,sha256=ysEeJrlbxrMPA7wFw7KDtuCTzXYkdfYZuxUFpPPY7vE,3732
|
105
105
|
mainsequence/virtualfundbuilder/resource_factory/signal_factory.py,sha256=ywa7vxxLlQopuRwwRKyj866ftgaj8uKVoiPQ9YJ2IIo,7198
|
106
|
-
mainsequence-2.0.
|
107
|
-
mainsequence-2.0.
|
108
|
-
mainsequence-2.0.
|
109
|
-
mainsequence-2.0.
|
110
|
-
mainsequence-2.0.
|
111
|
-
mainsequence-2.0.
|
106
|
+
mainsequence-2.0.3.dist-info/licenses/LICENSE,sha256=fXoCKgEuZXmP84_QDXpvO18QHze_6AAhd-zvZBUjJxQ,4524
|
107
|
+
mainsequence-2.0.3.dist-info/METADATA,sha256=NKlRdCIFUq6JmHdtsEktvayTEKAWrhNVnWdQ4A_-JAk,8028
|
108
|
+
mainsequence-2.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
109
|
+
mainsequence-2.0.3.dist-info/entry_points.txt,sha256=2J8TprrUndh7AttNTlXAaxgGtkXFUAHgXs-M7DCj5MU,58
|
110
|
+
mainsequence-2.0.3.dist-info/top_level.txt,sha256=uSLD9rXMDMN0cc1x0p808bwyQMoRmYY2pdQZEWLajX8,13
|
111
|
+
mainsequence-2.0.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|