synology_apm_repo.sdk.profiles.model module

Data model for saved S3/Azure/SMB connection profiles.

One canonical, UI-facing field-naming scheme (bucket/endpoint/ region/verify_tls/… rather than aws_access_key_id/ region_name/…) is used everywhere a profile’s fields are named — CLI flags, the TUI’s saved/loaded field dicts, and the dataclasses here. Translation to the third-party client’s own kwarg names is isolated to each config dataclass’s client_kwargs property, never duplicated at each call site.

Secret fields (S3’s access/secret key, Azure’s credential, SMB’s password) never appear on these dataclasses — they live in the OS keyring (see secrets.py) and are merged back in only by profiles.build_store.

class synology_apm_repo.sdk.profiles.model.BackendKind(value)

Bases: Enum

Which backend a profile targets.

S3 = 's3'
AZURE = 'azure'
SMB = 'smb'
class synology_apm_repo.sdk.profiles.model.S3ProfileConfig(bucket, endpoint=None, region=None, verify_tls=True)

Bases: object

Non-secret S3Store constructor inputs. access_key/ secret_key are not fields here — see secrets.py.

bucket: str
endpoint: str | None = None
region: str | None = None
verify_tls: bool = True
property client_kwargs: dict[str, Any]

Everything but bucket and the secret fields, already in S3Store/aioboto3’s own kwarg names. Callers merge the resolved secrets in on top of this dict.

property display_fields: dict[str, str | None]

Ordered field-name -> value pairs for CLI/TUI display (a saved profile’s JSON and human-readable show output alike) — the one place this backend’s own display field list is spelled out, so both renderers read it from here instead of each re-declaring it.

class synology_apm_repo.sdk.profiles.model.AzureProfileConfig(container, account_url=None, verify_tls=True)

Bases: object

Non-secret AzureStore constructor inputs. credential is not a field here — see secrets.py.

container: str
account_url: str | None = None
verify_tls: bool = True
property client_kwargs: dict[str, Any]

Everything but container and the secret field, already in AzureStore/azure-storage-blob’s own kwarg names — note connection_verify, not verify (azure.core.Configuration’s own name for this, deliberately different from boto3’s).

property display_fields: dict[str, str | None]

Same role as S3ProfileConfig.display_fields.

class synology_apm_repo.sdk.profiles.model.SmbProfileConfig(server, share, port=445, username=None)

Bases: object

Non-secret SmbStore constructor inputs. password is not a field here — see secrets.py.

username takes the Windows-native DOMAIN\username (or user@domain UPN) form directly — smbprotocol’s own NTLM/SPNEGO layer splits the domain back out of that single string, so there is no separate domain field to keep in sync with it. No path/sub-root field either, matching S3ProfileConfig/AzureProfileConfig: a share, like a bucket/container, is the whole scope one profile names.

server: str
share: str
port: int = 445
username: str | None = None
property client_kwargs: dict[str, Any]

Everything but share and the secret field, already in SmbStore’s own kwarg names. Callers merge the resolved secret in on top of this dict.

property display_fields: dict[str, str | int | None]

Same role as S3ProfileConfig.display_fields.

class synology_apm_repo.sdk.profiles.model.Profile(name, kind, config)

Bases: object

One saved profile, keyed by its user-chosen name (unique across every backend kind). Never carries secret values.

name: str
kind: BackendKind
config: S3ProfileConfig | AzureProfileConfig | SmbProfileConfig
class synology_apm_repo.sdk.profiles.model.ProfileSummary(name, kind)

Bases: object

Cheap listing entry — derived from profiles.json alone, no keyring access needed to produce it.

name: str
kind: BackendKind
synology_apm_repo.sdk.profiles.model.S3_SECRET_FIELDS: tuple[str, ...] = ('access_key', 'secret_key')

Keyring “username” per secret field, and the fields dict key profiles.load_profile/save_profile use for it — see secrets.py for how these map onto the underlying client’s own kwarg names.

synology_apm_repo.sdk.profiles.model.secret_fields_for(kind)

Which fields dict keys are secret (keyring-backed) for kind — the rest are plain config, persisted to profiles.json.

class synology_apm_repo.sdk.profiles.model.ProfileFieldSpec(name, strip=True, is_checkbox=False)

Bases: object

One profile field’s widget-binding shape, in canonical collection/ display order, for one backend — the single place a connection form (the TUI’s connect/saved-profile tabs today) reads a backend’s full field list from, instead of privately re-enumerating it. strip is False for a value whose leading/trailing whitespace might be significant (secret_key/credential/password) — not simply every secret field, since access_key (also keyring-backed, per secret_fields_for) has no such concern and is stripped like an ordinary field.

name: str
strip: bool = True
is_checkbox: bool = False
synology_apm_repo.sdk.profiles.model.S3_FORM_FIELDS: tuple[ProfileFieldSpec, ...] = (ProfileFieldSpec(name='bucket', strip=True, is_checkbox=False), ProfileFieldSpec(name='endpoint', strip=True, is_checkbox=False), ProfileFieldSpec(name='region', strip=True, is_checkbox=False), ProfileFieldSpec(name='verify_tls', strip=True, is_checkbox=True), ProfileFieldSpec(name='access_key', strip=True, is_checkbox=False), ProfileFieldSpec(name='secret_key', strip=False, is_checkbox=False))

Each backend’s own field table — the CLI’s per-backend prompt collectors (cli/commands/profile.py) keep their own field lists (each prompt has a distinct human label typer options don’t carry, so looping over this table there wouldn’t save anything); this is for a consumer that needs the field set/order and nothing else, one entry per real widget a connection form binds.

synology_apm_repo.sdk.profiles.model.AZURE_FORM_FIELDS: tuple[ProfileFieldSpec, ...] = (ProfileFieldSpec(name='container', strip=True, is_checkbox=False), ProfileFieldSpec(name='account_url', strip=True, is_checkbox=False), ProfileFieldSpec(name='credential', strip=False, is_checkbox=False))

No verify_tls entry — unlike S3, no Azure connection form in this project has a verify_tls widget (AzureProfileConfig.verify_tls only ever takes its dataclass default here), so this table stays an explicit list rather than one derived from AzureProfileConfig’s own dataclass fields.

synology_apm_repo.sdk.profiles.model.form_fields_for(kind)

kind’s full field list, in canonical order — every field a connection form binds, secrets included, unlike display_fields (non-secret only, read from an already-built config instance rather than named ahead of one existing).

synology_apm_repo.sdk.profiles.model.client_kwargs_with_secrets(config, secrets)

config.client_kwargs, overlaid with whichever of secret_fields_for(kind)’s fields secrets actually carries a truthy value for — the shared shape behind every “resolve one profile’s config plus its secrets into constructor kwargs” call site (profiles.build_store, cli/commands/profile.py::_store_from_fields, browser/screens/connect_dialog.py’s s3_client_kwargs/ azure_client_kwargs — SMB has no bucket-less/container-less “Browse” counterpart calling this directly, only smb_config_and_secrets feeding store_from_config straight from _build_smb_store). secrets may be a superset of what applies here (a not-yet-saved connection form carries every backend’s fields at once) — only the keys secret_fields_for names for config’s own kind are ever read from it; a present-but-falsy value (an empty string from an untouched form field) is treated the same as absent, matching every prior hand-rolled version of this check.