tdfs4ds.app_launcher¶
tdfs4ds.app_launcher
¶
Start the tdfs4ds admin app from a notebook and get a link to open it.
launch_app() starts python -m tdfs4ds.serve in a separate process (the
notebook's own connection is untouched, closing the notebook does not stop
it), waits until it answers, and shows a link. In a Jupyter notebook
(SageMaker notebook instance, JupyterHub, Teradata AI Studio) the app is
reached through Jupyter's own proxy, <jupyter base>/proxy/absolute/<port>/,
so nothing has to be exposed and access is protected by the Jupyter login;
the app's path prefix (TDFS4DS_SERVE_ROOT_PATH) is set to match. Outside
Jupyter the link is http://localhost:<port>/.
app_status() and stop_app() read the state file the launch writes
(~/.tdfs4ds/app_<port>.json), so they work from another notebook or after
a kernel restart. sagemaker_lifecycle_script() returns the "Start
notebook" script that starts the app with the instance.
The proxy is the jupyter-server-proxy extension of the Jupyter SERVER
(on SageMaker it lives in the server's own environment, not the kernel's), so
it is checked by asking the Jupyter server through it, not by importing it.
__all__
module-attribute
¶
__all__ = ['launch_app', 'stop_app', 'app_status', 'sagemaker_lifecycle_script', 'connection_settings', 'dotenv_candidates']
_CONN_ATTRS
module-attribute
¶
_CONN_ATTRS = ('TD_HOST', 'TD_USERNAME', 'TD_PASSWORD', 'TD_ENCRYPT', 'TD_LOGMECH', 'TD_LOGDATA', 'TD_DATABASE')
_CONN_LABELS
module-attribute
¶
_CONN_LABELS = {'TD_HOST': 'host', 'TD_USERNAME': 'username', 'TD_PASSWORD': 'password', 'TD_ENCRYPT': 'encrypt', 'TD_LOGMECH': 'logon mechanism', 'TD_LOGDATA': 'token (logdata)', 'TD_DATABASE': 'default database'}
_in_notebook
¶
True inside a Jupyter kernel (a terminal IPython is not a notebook).
_ancestor_pids
¶
Process ids of this process's ancestors (Linux /proc; the parent elsewhere).
jupyter_server
¶
The running Jupyter server this kernel belongs to: {base_url, url, token}, or None.
Read from Jupyter's runtime files (jpserver-*.json / nbserver-*.json),
which is what list_running_servers reads, so it works even when the
kernel's environment has no jupyter_server package (SageMaker).
Other services write files there too (seen on SageMaker Studio: a
jpserver file for http://localhost:3001/mcp), so the newest file is
only the last resort. The choice is, in order: the server that is an
ancestor of this kernel, then a server whose URL path equals its base path
(a Jupyter server's always does), then the newest.
_studio_base
¶
/jupyterlab/default/ in a SageMaker Studio JupyterLab space, else None.
proxy_path
¶
<base>proxy/absolute/<port> (no trailing slash): the app's path prefix behind Jupyter.
_sagemaker_host
¶
https://<name>.notebook.<region>.sagemaker.aws on a SageMaker notebook instance, else None.
None on SageMaker Studio: its address (https://<id>.studio.<region>...)
cannot be worked out from inside the space.
_health
¶
The app's /health answer on this machine, or None.
_is_app_404
¶
A 404 written by the app itself (FastAPI's {"detail": ...}), not by Jupyter.
_proxy_reaches_app
¶
Does the Jupyter server's proxy reach the app?
True, False (Jupyter answered: no proxy), "prefix" (the proxy reached
the app but the app was started with another path prefix), or None when it
cannot be asked.
A JupyterHub single-user server (AI Studio) refuses the token of its own runtime file, and jupyter-server-proxy answers an unauthenticated request with a 404: that 404 says nothing about the proxy, so the answer is None when the server's API refuses the token too.
_show
¶
A clickable link in the notebook, the URL and notes printed otherwise.
dotenv_candidates
¶
The .env files the app or load_dotenv() could read, existing ones only
except env_file: env_file, ./.env, ~/.tdfs4ds/.env, and the one
python-dotenv's find_dotenv(usecwd=True) finds (searching up from here).
_app_dotenv
¶
The .env the app process will read, or None.
_resolve_connection
¶
{"values", "sources", "file", "missing", "invalid"} as the app will see them (raw values).
_gaps
¶
{"missing", "invalid", "token"} of a set of connection values (the one rule).
connection_settings
¶
The database connection settings the app would use, never a secret value.
{"file": the .env the app reads (or None), "variables": {TDFS4DS_TD_X:
{"value" (secrets hidden), "source"}}, "missing": [...], "invalid": {...},
"complete": bool, "candidates": [.env files found]}. TDFS4DS_TD_ENCRYPT
is reported missing when unset, though the app then runs unencrypted.
_probe
¶
(True | False | None, detail) - a logon with the raw driver; this session is untouched.
_menu
¶
A numbered choice; returns the 1-based index (the default when unanswered).
_ask_values
¶
Ask for wanted (plus the logon mechanism when unset); returns the answers.
_private
¶
A file under ~/.tdfs4ds (a per-user directory, never a project's).
_save_values
¶
Offer to write entered into a .env for the next launches; returns the file written, or None.
_connection_dialogue
¶
_connection_dialogue(env_file: Optional[str], ask: Optional[bool], check_logon: bool, preset: Optional[dict] = None) -> dict
Make sure the app can connect; ask what is missing. Returns {"env_file", "entered",
"saved_to", "logon", "notes"} (entered holds raw values for the app's environment).
_resolve_schema
¶
(database or None, source) of the feature store the app will open.
_raw_rows
¶
run(sql) -> rows over one raw teradatasql connection (this session is untouched), or None.
_discover_stores
¶
[{"database", "complete", "missing"}] visible with values, or None when not readable.
_query_band_notes
¶
Whether this user can tag runs and read DBQL (the Execution log's data); notes only, nothing asked: the app works without it, the figures are what is missing.
_store_dialogue
¶
Make sure the app opens a feature store; ask when none is set. Updates conn.
_child_env
¶
(environment, env_file for --env) of the app process.
Values typed in the dialogue reach the app through its environment. --env
loads its file OVER the environment, so when that file still holds a value
the user replaced without saving it there, the file is merged here instead
(file over environment, typed values over the file) and --env is dropped.
_token_settings
¶
Everything a session token replaces for the app: logon, Vector Store, MCP gateway.
_env_file_credentials
¶
TDFS4DS_TD_* for the MCP server, with the app's precedence: the env file over the session.
(python -m tdfs4ds.serve --env loads its file with override=True.)
launch_app
¶
launch_app(env_file: Optional[str] = None, port: int = DEFAULT_PORT, *, through_jupyter: Optional[bool] = None, timeout: float = 300, show: bool = True, log_file: Optional[str] = None, root_path: Optional[str] = None, mcp: bool = False, mcp_port: int = 8001, mcp_profile: Optional[str] = 'eda', ask: Optional[bool] = None, check_logon: bool = True, token: Optional[str] = None) -> dict
Start the tdfs4ds admin app in the background and show a link to open it.
Parameters¶
env_file : str, optional
A .env with the connection and models (TDFS4DS_TD_*, ...); it
wins over the environment. Without it the app reads the first of
./.env and ~/.tdfs4ds/.env (the environment winning).
port : int
The app's port on this machine (8000).
through_jupyter : bool, optional
Reach the app through Jupyter's proxy (<base>/proxy/absolute/<port>/).
Default: True inside a Jupyter notebook, False elsewhere
(http://localhost:<port>/).
timeout : float
Seconds to wait for the app to answer (the first start connects to the
database; the vector index is then built in the background, shown in the
app's status bar).
show : bool
Display the link (a button in a notebook, the URL in a terminal).
log_file : str, optional
Where the app writes its log (~/.tdfs4ds/app_<port>.log).
root_path : str, optional
The app's path prefix, when the one worked out from Jupyter is wrong
(e.g. '/jupyterlab/default/proxy/absolute/8000').
mcp : bool
Also start a local Teradata MCP server with the TDFS4DS_TD_*
credentials (:func:tdfs4ds.start_mcp_server) and give its address to
the app, which then offers the MCP skills. Needs
teradata-mcp-server installed; a failure is reported in the notes
and the app starts without it.
mcp_port, mcp_profile : int, str
The MCP server's port (8001) and tool profile ('eda').
ask : bool, optional
Before starting, check that the app has a database host, username,
password (or a JWT token) and TDFS4DS_TD_ENCRYPT, resolved the way
the app reads them (:func:connection_settings). When one is missing,
or the database refuses them, ask what to do: type them (the password
hidden; the logon is tested with the raw driver, this session is not
touched), use another .env found, or start without them (Connect
page). Typed values can then be saved in a .env found
(:func:dotenv_candidates) or a new one; the password is asked for
separately. None (default) = ask when someone can answer (a
terminal or a notebook); False = never ask (missing settings are
listed in the notes). Not asked when an app already runs on port.
check_logon : bool
Test the logon before starting (one connection with the raw driver).
token : str, optional
A session token. The app logs on with it and gives it to the Vector
Store and the MCP gateway, over what the .env holds; nothing is
written to the file. Not needed on AI Studio: when the .env logs on
with a token, the app takes the current one from the platform (as
%gen_token does) and renews it itself. Elsewhere it expires with
the session: launch again with a fresh one.
Returns¶
dict
url (the link), local_url, pid, log, reused (an app
was already running on that port), ready, proxy_ok (the Jupyter
proxy reaches the app: True / False / "prefix" = it reaches an app
started with another prefix / None = could not be checked), mcp
(the MCP server's start report, when asked).
app_status
¶
Is an app running on port? Its URL, pid, log and connection (from /health).
stop_app
¶
Stop the app started by :func:launch_app on port. True when it is stopped.
sagemaker_lifecycle_script
¶
sagemaker_lifecycle_script(env_file: str = '/home/ec2-user/SageMaker/tdfs4ds.env', port: int = DEFAULT_PORT, version: Optional[str] = None, conda_env: str = 'python3', start_app: bool = True, mcp: bool = False, mcp_port: int = 8001, share_env: bool = True) -> str
The "Start notebook" lifecycle script of a SageMaker notebook instance.
It installs tdfs4ds (the latest, or version) in the conda environment
behind the conda_python3 kernel, so notebooks get it too, and (with
start_app) starts the app behind Jupyter's proxy with env_file when it
exists. With mcp it also installs teradata-mcp-server and starts it
on 127.0.0.1:<mcp_port> with the env file's TDFS4DS_TD_*
credentials (:func:tdfs4ds.start_mcp_server), for the app's MCP skills.
Everything runs in the background as ec2-user: a lifecycle script must
finish within 5 minutes.
share_env (0.3.3.15): the env file's settings also reach the notebooks and the terminals, not only the app.
- Notebooks:
~/.tdfs4ds/.envis linked to env_file, andimport tdfs4dsreads that file when the working directory has no.envof its own. A kernel does not read shell profiles, so exporting variables (in/etc/profile.dor~/.bashrc) would not reach it. - Terminals:
~/.tdfs4ds/env.shholds theTDFS4DS_*variables as quotedexportlines, written by tdfs4ds's own.envparser (so a value with spaces, quotes or JSON is read the same way), and~/.bashrcsources it.
The env file holds credentials: it and env.sh are made readable by
ec2-user only (/etc/profile.d would make them readable by every account).
Both are rebuilt at each start (the home directory outside SageMaker/ is
reset when the instance stops), so an edited env file is taken into account
at the next start; a running terminal sees it after source ~/.bashrc.