Profile + lightweight open_client¶
The Profile Pydantic model + open_client(profile) for PAT and Basic auth live in dhis2w-client — no dhis2w-core install needed for library users embedding the client in their own Python tooling. OAuth2 still requires dhis2w-core because OAuth2 token refresh needs the concurrent-writer-safe token store; calling dhis2w_client.open_client(oauth2_profile) raises NotImplementedError pointing at dhis2w_core.open_client.
When to reach for this surface¶
- Embedding
dhis2w-clientin a third-party app (FastAPI service, script, notebook) with PAT or Basic auth — you don't want the full CLI/MCP runtime weight (Typer, FastMCP, SQLAlchemy, bcrypt, questionary). - OAuth2 auth? Use
dhis2w_core.open_client(profile)instead — sameProfilemodel, full token-store-backed refresh. - Multi-profile TOML resolution? That lives in
dhis2w-core. Usedhis2w_core.profile_from_env()for the full precedence chain (TOML + env), or this module'sprofile_from_env_raw()for the env-only fallback that returnsNoneinstead of consulting TOML.
Worked example — pure dhis2w-client use¶
import asyncio
from dhis2w_client import NoProfileError, Profile, open_client, profile_from_env_raw
async def main() -> None:
"""Build a Profile (in-memory or from env) and open a connected client."""
profile = profile_from_env_raw()
if profile is None:
# No DHIS2_URL+credentials env — construct one explicitly:
profile = Profile(
base_url="https://play.im.dhis2.org/dev-2-43",
auth="pat",
token="d2pat_yourtoken",
)
try:
async with open_client(profile) as client:
me = await client.system.me()
info = await client.system.info()
print(f"Connected to DHIS2 {info.version} as {me.username}")
except NoProfileError as exc:
print(f"misconfigured: {exc}")
asyncio.run(main())
See examples/v{41,42,43}/client/profile_pat_pure_client.py for the runnable, version-pinned form.
Profile model¶
Profile
¶
Bases: BaseModel
Resolved DHIS2 connection settings for a single session.
version is a plugin-tree hint, NOT a wire-client pin. When set, CLI
and MCP bootstraps load the matching dhis2w_core.v{N}.plugins.* tree
(so v43 plugin overrides for BUGS #33/#34/#35 are picked up against a
v43 stack). The wire Dhis2Client always auto-detects the server's
version on connect and rebinds accessors via _dispatch.py —
profile.version doesn't override that. When unset, plugin discovery
falls back to DHIS2_VERSION env var (41/42/43), then to v42.
Source code in packages/dhis2w-client/src/dhis2w_client/profile.py
Exceptions¶
NoProfileError
¶
UnknownProfileError
¶
InvalidProfileNameError
¶
Constructors + helpers¶
profile_from_env_raw()
¶
Build a Profile from DHIS2_URL + credentials env vars.
Returns None when DHIS2_URL is unset or no credential pair is present.
Recognises DHIS2_PAT (PAT auth, wins over Basic) and the
DHIS2_USERNAME + DHIS2_PASSWORD pair (Basic auth). Reads
DHIS2_VERSION ("41" / "42" / "43" or "v41" / "v42" / "v43")
into Profile.version when set.
Library callers that want full TOML + env precedence resolution (the
chain the d2w CLI uses) should install dhis2w-core and call
dhis2w_core.profile_from_env() instead.
Source code in packages/dhis2w-client/src/dhis2w_client/profile.py
validate_profile_name(name)
¶
Validate and return a profile name.
Rules
- must not be empty
- first character must be an ASCII letter (A-Z, a-z)
- remaining characters must be letters, digits, or underscore
- max length 64 characters
Typical valid names: local, prod, prod_eu, test42, laohis42.
Raises InvalidProfileNameError on violation. The constraint keeps names
safe as env var suffixes, TOML keys, and unquoted shell arguments.
Source code in packages/dhis2w-client/src/dhis2w_client/profile.py
Open a client from a profile¶
build_auth_for_basic(profile) returns a PatAuth or BasicAuth AuthProvider. open_client(profile) is the async context manager that wires that auth provider into a connected Dhis2Client. Both live at the top of dhis2w_client (re-exported from dhis2w_client.v42.client_context) and on each per-version surface (dhis2w_client.v41, dhis2w_client.v42, dhis2w_client.v43).
build_auth_for_basic(profile)
¶
Return a PatAuth or BasicAuth provider for the profile.
Raises NotImplementedError on profile.auth == "oauth2" pointing at
dhis2w_core — OAuth2 needs the token-store machinery that lives there.
Raises ValueError when the matching credential fields are missing.
Source code in packages/dhis2w-client/src/dhis2w_client/v42/client_context.py
open_client(profile, *, allow_version_fallback=True, retry_policy=None, http_limits=None, system_cache_ttl=300.0)
async
¶
Open a connected Dhis2Client for profile — PAT or Basic auth only.
Yields a connected client inside async with. Raises NotImplementedError
on OAuth2 profiles — use dhis2w_core.open_client(profile, scope=..., profile_name=...)
for those.
retry_policy, http_limits, and system_cache_ttl mirror the
underlying Dhis2Client constructor — see its docstring for tuning.