memorytalk 0.8.2__tar.gz → 0.8.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.
- {memorytalk-0.8.2 → memorytalk-0.8.3}/PKG-INFO +1 -1
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/_format.py +19 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/server.py +92 -1
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/setup.py +51 -20
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk.egg-info/PKG-INFO +1 -1
- {memorytalk-0.8.2 → memorytalk-0.8.3}/pyproject.toml +1 -1
- {memorytalk-0.8.2 → memorytalk-0.8.3}/LICENSE +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/README.md +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/__init__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/__main__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/adapters/__init__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/adapters/base.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/adapters/claude_code.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/adapters/codex.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/adapters/openclaw.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/api/__init__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/api/cards.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/api/read.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/api/recall.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/api/reviews.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/api/search.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/api/sessions.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/api/status.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/api/sync.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/__init__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/_http.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/_render.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/card.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/read.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/recall.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/review.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/search.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/session.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/sync.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/cli/upgrade.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/config.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/provider/__init__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/provider/embedding.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/provider/lancedb.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/provider/storage.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/repository/__init__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/repository/cards.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/repository/recall.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/repository/reviews.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/repository/schema.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/repository/search_log.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/repository/sessions.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/repository/store.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/repository/sync_checkpoint.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/__init__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/card.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/cards.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/read.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/recall.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/review.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/reviews.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/search.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/session.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/status.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/schemas/sync.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/server.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/__init__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/backfill.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/cards.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/events.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/index_buffer.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/read.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/recall.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/reviews.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/search.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/sessions.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/service/sync.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/__init__.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/console.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/dsl.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/env_template.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/formula.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/highlight.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/ids.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/indexes.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/settings_io.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/tag_filter.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk/util/tags.py +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk.egg-info/SOURCES.txt +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk.egg-info/dependency_links.txt +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk.egg-info/entry_points.txt +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk.egg-info/requires.txt +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/memorytalk.egg-info/top_level.txt +0 -0
- {memorytalk-0.8.2 → memorytalk-0.8.3}/setup.cfg +0 -0
|
@@ -48,6 +48,25 @@ def fmt_server_stop(payload: dict) -> str:
|
|
|
48
48
|
return f"**{status}**\n"
|
|
49
49
|
|
|
50
50
|
|
|
51
|
+
def fmt_server_restart(payload: dict) -> str:
|
|
52
|
+
status = payload.get("status", "")
|
|
53
|
+
if status == "restarted":
|
|
54
|
+
return (
|
|
55
|
+
f"**restarted** · prev pid `{payload.get('previous_pid')}` "
|
|
56
|
+
f"→ pid `{payload['pid']}` · port `{payload['port']}`\n"
|
|
57
|
+
)
|
|
58
|
+
if status == "started":
|
|
59
|
+
# No previous daemon — restart degenerated into a fresh start.
|
|
60
|
+
return (
|
|
61
|
+
f"**started** · pid `{payload['pid']}` · port `{payload['port']}` "
|
|
62
|
+
"(was not running)\n"
|
|
63
|
+
)
|
|
64
|
+
if status == "failed":
|
|
65
|
+
# Reuse start's failure shape — same fields are populated.
|
|
66
|
+
return fmt_server_start(payload)
|
|
67
|
+
return f"**{status}**\n"
|
|
68
|
+
|
|
69
|
+
|
|
51
70
|
def fmt_status(payload: dict) -> str:
|
|
52
71
|
if payload.get("status") == "not_running":
|
|
53
72
|
return (
|
|
@@ -14,7 +14,9 @@ from pathlib import Path
|
|
|
14
14
|
|
|
15
15
|
import click
|
|
16
16
|
|
|
17
|
-
from memorytalk.cli._format import
|
|
17
|
+
from memorytalk.cli._format import (
|
|
18
|
+
fmt_server_restart, fmt_server_start, fmt_server_stop, fmt_status,
|
|
19
|
+
)
|
|
18
20
|
from memorytalk.cli._http import ApiError, api
|
|
19
21
|
from memorytalk.cli._render import emit_json, emit_md
|
|
20
22
|
from memorytalk.config import Config
|
|
@@ -115,6 +117,84 @@ def stop_server_proc(cfg: Config) -> dict:
|
|
|
115
117
|
return {"status": "stopped", "pid": pid}
|
|
116
118
|
|
|
117
119
|
|
|
120
|
+
# Graceful-exit budget after SIGTERM. The lifespan __aexit__ has to
|
|
121
|
+
# stop the sync watcher, drain the IndexWriteBuffer, close the LanceDB
|
|
122
|
+
# connection and shut SQLite down — on a busy install with a half-full
|
|
123
|
+
# buffer that's ~1–3 s typical, with headroom for outliers. After this
|
|
124
|
+
# window we escalate to SIGKILL so ``restart`` never hangs the CLI.
|
|
125
|
+
_RESTART_GRACE_SECONDS = 10.0
|
|
126
|
+
_RESTART_POLL_INTERVAL = 0.1
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def restart_server_proc(cfg: Config) -> dict:
|
|
130
|
+
"""Stop the running daemon (if any) + wait for graceful exit +
|
|
131
|
+
start fresh. Returns one of:
|
|
132
|
+
|
|
133
|
+
{"status": "restarted",
|
|
134
|
+
"previous_pid": int, "pid": int, "port": int}
|
|
135
|
+
— there was a daemon, it died cleanly, new one is up.
|
|
136
|
+
|
|
137
|
+
{"status": "started", "pid": int, "port": int}
|
|
138
|
+
— no daemon was running; same shape as a plain ``start``.
|
|
139
|
+
|
|
140
|
+
{"status": "failed",
|
|
141
|
+
"exit_code": int, "error": str, "previous_pid": int | None}
|
|
142
|
+
— the *new* daemon failed startup; the previous one is
|
|
143
|
+
already gone (we don't roll back — leaves logs intact for
|
|
144
|
+
debugging).
|
|
145
|
+
|
|
146
|
+
Waits up to ``_RESTART_GRACE_SECONDS`` for the old process to exit,
|
|
147
|
+
then SIGKILLs if it's still around. Without this wait, the new
|
|
148
|
+
daemon races the old one for the TCP port and gets EADDRINUSE.
|
|
149
|
+
"""
|
|
150
|
+
previous_pid: int | None = None
|
|
151
|
+
if cfg.pid_path.exists():
|
|
152
|
+
try:
|
|
153
|
+
previous_pid = int(cfg.pid_path.read_text().strip())
|
|
154
|
+
except ValueError:
|
|
155
|
+
previous_pid = None
|
|
156
|
+
|
|
157
|
+
if previous_pid is not None and pid_alive(previous_pid):
|
|
158
|
+
try:
|
|
159
|
+
os.kill(previous_pid, signal.SIGTERM)
|
|
160
|
+
except ProcessLookupError:
|
|
161
|
+
pass
|
|
162
|
+
deadline = time.monotonic() + _RESTART_GRACE_SECONDS
|
|
163
|
+
while time.monotonic() < deadline:
|
|
164
|
+
if not pid_alive(previous_pid):
|
|
165
|
+
break
|
|
166
|
+
time.sleep(_RESTART_POLL_INTERVAL)
|
|
167
|
+
else:
|
|
168
|
+
# 10 s and still alive — escalate. SIGKILL is uncatchable;
|
|
169
|
+
# the kernel reaps the process so ``pid_alive`` flips fast.
|
|
170
|
+
try:
|
|
171
|
+
os.kill(previous_pid, signal.SIGKILL)
|
|
172
|
+
except ProcessLookupError:
|
|
173
|
+
pass
|
|
174
|
+
# Tiny window for the kernel to actually reap.
|
|
175
|
+
time.sleep(0.3)
|
|
176
|
+
|
|
177
|
+
# Stale pid/port files would let start_server_proc misread "already
|
|
178
|
+
# running" — clear them regardless of how we got here.
|
|
179
|
+
cfg.pid_path.unlink(missing_ok=True)
|
|
180
|
+
cfg.port_path.unlink(missing_ok=True)
|
|
181
|
+
|
|
182
|
+
start_payload = start_server_proc(cfg)
|
|
183
|
+
status = start_payload.get("status")
|
|
184
|
+
if status == "failed":
|
|
185
|
+
return {**start_payload, "previous_pid": previous_pid}
|
|
186
|
+
if previous_pid is not None:
|
|
187
|
+
# Distinguish from a fresh start so the user sees "the old
|
|
188
|
+
# daemon was actually replaced", not just "a daemon started".
|
|
189
|
+
return {
|
|
190
|
+
"status": "restarted",
|
|
191
|
+
"previous_pid": previous_pid,
|
|
192
|
+
"pid": start_payload["pid"],
|
|
193
|
+
"port": start_payload["port"],
|
|
194
|
+
}
|
|
195
|
+
return start_payload # status="started" — no previous daemon
|
|
196
|
+
|
|
197
|
+
|
|
118
198
|
def _emit(payload: dict, json_out: bool, md_formatter) -> None:
|
|
119
199
|
if json_out:
|
|
120
200
|
emit_json(payload)
|
|
@@ -140,6 +220,17 @@ def server_stop(json_out: bool) -> None:
|
|
|
140
220
|
_emit(payload, json_out, fmt_server_stop)
|
|
141
221
|
|
|
142
222
|
|
|
223
|
+
@server.command("restart")
|
|
224
|
+
@click.option("--json", "json_out", is_flag=True, default=False, help="Emit JSON")
|
|
225
|
+
def server_restart(json_out: bool) -> None:
|
|
226
|
+
"""Stop the running daemon (if any) and start it again."""
|
|
227
|
+
cfg = Config()
|
|
228
|
+
payload = restart_server_proc(cfg)
|
|
229
|
+
_emit(payload, json_out, fmt_server_restart)
|
|
230
|
+
if payload.get("status") == "failed":
|
|
231
|
+
sys.exit(1)
|
|
232
|
+
|
|
233
|
+
|
|
143
234
|
@server.command("status")
|
|
144
235
|
@click.option("--json", "json_out", is_flag=True, default=False, help="Emit JSON")
|
|
145
236
|
def server_status(json_out: bool) -> None:
|
|
@@ -85,8 +85,11 @@ def _wizard(cfg: Config, old_raw: dict | None, is_first_install: bool) -> dict:
|
|
|
85
85
|
err_console.print(f"[bold]memory.talk setup[/bold] · {mode}")
|
|
86
86
|
err_console.print(f"data_root: [cyan]{cfg.data_root}[/cyan]\n")
|
|
87
87
|
|
|
88
|
-
base
|
|
89
|
-
|
|
88
|
+
# ``base`` is the raw existing settings.json — NOT a Settings model
|
|
89
|
+
# dump. Mixing model defaults in would re-introduce the old bug
|
|
90
|
+
# where wizard-untouched fields (search.ranking_formula etc.) got
|
|
91
|
+
# materialized to disk and stopped tracking schema-default changes.
|
|
92
|
+
base = dict(old_raw) if old_raw else {}
|
|
90
93
|
|
|
91
94
|
# ── embedding ───────────────────────────────────────────────────────
|
|
92
95
|
section("Embedding")
|
|
@@ -108,7 +111,6 @@ def _wizard(cfg: Config, old_raw: dict | None, is_first_install: bool) -> dict:
|
|
|
108
111
|
else:
|
|
109
112
|
emb_base = dict(base.get("embedding") or {})
|
|
110
113
|
emb = _step_embedding(emb_base)
|
|
111
|
-
new["embedding"] = emb
|
|
112
114
|
|
|
113
115
|
# Probe the embedding before writing — fail-fast.
|
|
114
116
|
err_console.print("[dim]probing embedding provider...[/dim]")
|
|
@@ -117,14 +119,14 @@ def _wizard(cfg: Config, old_raw: dict | None, is_first_install: bool) -> dict:
|
|
|
117
119
|
|
|
118
120
|
# ── storage ─────────────────────────────────────────────────────────
|
|
119
121
|
section("Storage")
|
|
120
|
-
|
|
122
|
+
vector_provider = _choice(
|
|
121
123
|
"vector provider", ["lancedb"],
|
|
122
124
|
(base.get("vector") or {}).get("provider", "lancedb"),
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
+
)
|
|
126
|
+
relation_provider = _choice(
|
|
125
127
|
"relation provider", ["sqlite"],
|
|
126
128
|
(base.get("relation") or {}).get("provider", "sqlite"),
|
|
127
|
-
)
|
|
129
|
+
)
|
|
128
130
|
|
|
129
131
|
# ── server ──────────────────────────────────────────────────────────
|
|
130
132
|
section("Server")
|
|
@@ -135,7 +137,6 @@ def _wizard(cfg: Config, old_raw: dict | None, is_first_install: bool) -> dict:
|
|
|
135
137
|
validate=lambda v: (v.strip().isdigit() and 1 <= int(v) <= 65535)
|
|
136
138
|
or "must be an integer in 1..65535",
|
|
137
139
|
)
|
|
138
|
-
new["server"] = {"port": int(port_str)}
|
|
139
140
|
|
|
140
141
|
# ── sync ────────────────────────────────────────────────────────────
|
|
141
142
|
section("Sync")
|
|
@@ -149,19 +150,23 @@ def _wizard(cfg: Config, old_raw: dict | None, is_first_install: bool) -> dict:
|
|
|
149
150
|
"Enable backend sync? (auto-ingest Claude Code / Codex sessions etc.)",
|
|
150
151
|
default=enabled_default,
|
|
151
152
|
)
|
|
152
|
-
new["sync"] = {
|
|
153
|
-
"enabled": sync_enabled,
|
|
154
|
-
"debounce_ms": old_sync.get("debounce_ms", 200),
|
|
155
|
-
}
|
|
156
153
|
|
|
157
|
-
#
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
# ── PATCH onto base ─────────────────────────────────────────────────
|
|
155
|
+
# Setup writes ONLY the fields it actually prompted for. Anything
|
|
156
|
+
# else the user had in settings.json — sync.debounce_ms, search.*,
|
|
157
|
+
# recall.*, explore.*, embedding.batch_size, future fields — is
|
|
158
|
+
# left untouched. This keeps "defaults that haven't been explicitly
|
|
159
|
+
# overridden" tracking the Settings schema, so future default
|
|
160
|
+
# changes (like the 0.8.2 ranking_formula -> "relevance") flow
|
|
161
|
+
# through on next load without manual intervention.
|
|
162
|
+
owned = {
|
|
163
|
+
"server": {"port": int(port_str)},
|
|
164
|
+
"vector": {"provider": vector_provider},
|
|
165
|
+
"relation": {"provider": relation_provider},
|
|
166
|
+
"embedding": emb,
|
|
167
|
+
"sync": {"enabled": sync_enabled},
|
|
168
|
+
}
|
|
169
|
+
new = _patch_owned(base, owned)
|
|
165
170
|
|
|
166
171
|
# ── diff + persist ──────────────────────────────────────────────────
|
|
167
172
|
diff = diff_settings(base, new)
|
|
@@ -228,6 +233,32 @@ def _step_embedding(base: dict) -> dict:
|
|
|
228
233
|
return out
|
|
229
234
|
|
|
230
235
|
|
|
236
|
+
def _patch_owned(base: dict, owned: dict[str, dict]) -> dict:
|
|
237
|
+
"""Apply ``owned`` updates onto ``base`` at field-level granularity.
|
|
238
|
+
|
|
239
|
+
For each section in ``owned``:
|
|
240
|
+
- Merge ``owned[section]`` keys into ``base[section]`` (creating
|
|
241
|
+
the section if missing).
|
|
242
|
+
- Keys that are in ``base[section]`` but NOT in ``owned[section]``
|
|
243
|
+
are preserved as-is.
|
|
244
|
+
|
|
245
|
+
Sections that aren't in ``owned`` at all (e.g. ``search``, ``recall``,
|
|
246
|
+
``explore``, ``index``) are returned untouched.
|
|
247
|
+
|
|
248
|
+
Provider switch (openai → local) note: stale provider-specific
|
|
249
|
+
keys like ``endpoint`` / ``auth_key`` survive in the file. They're
|
|
250
|
+
inert when ``provider != "openai"`` (Settings just ignores them on
|
|
251
|
+
load). Strict patch — wizard owns what wizard prompted for; it
|
|
252
|
+
doesn't synthesize cleanup of unrelated keys.
|
|
253
|
+
"""
|
|
254
|
+
new = dict(base)
|
|
255
|
+
for section, fields in owned.items():
|
|
256
|
+
section_data = dict(new.get(section, {}))
|
|
257
|
+
section_data.update(fields)
|
|
258
|
+
new[section] = section_data
|
|
259
|
+
return new
|
|
260
|
+
|
|
261
|
+
|
|
231
262
|
def _show_detected_endpoints() -> None:
|
|
232
263
|
"""List adapters whose ``DEFAULT_LOCATION`` exists on the user's
|
|
233
264
|
machine — those will be auto-attached on server start. Adapters
|
|
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
|
|
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
|
|
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
|