diff --git a/docs/superpowers/plans/2026-05-13-profile-spec-migration.md b/docs/superpowers/plans/2026-05-13-profile-spec-migration.md new file mode 100644 index 0000000..dcb24b4 --- /dev/null +++ b/docs/superpowers/plans/2026-05-13-profile-spec-migration.md @@ -0,0 +1,236 @@ +# mountainash-data: profile-spec migration plan + +**Goal:** Migrate `mountainash-data` to the new `ProfileSpec` / `Profile` vocabulary introduced in `mountainash-settings 26.5.0`. Follow the [migration guide](../../../../mountainash-settings/docs/superpowers/specs/2026-05-13-profile-spec-rename-design.md#migration-guide-for-downstream-consumers) verbatim. + +**Architecture:** Mechanical search-and-replace across 21 backend files plus updates to `descriptor.py`, `registry.py`, `profile.py`, and test files. Add a PEP 562 `__getattr__` shim in `mountainash-data`'s own `descriptor.py` so any downstream consumer of `mountainash-data` gets the same one-release deprecation window. + +**Tech Stack:** Python 3.10+, pydantic 2.x, mountainash-settings ≥26.5.0 (via path-based dep), pytest, hatch. + +**Upstream spec:** `../../../../mountainash-settings/docs/superpowers/specs/2026-05-13-profile-spec-rename-design.md` + +**Out of scope:** +- Renaming `*AuthSettings` concrete class names (e.g. `PostgreSQLAuthSettings`) — explicitly deferred in the upstream spec. +- Adding a `mountainash-settings` version pin — `mountainash-data` uses a path-based dependency (`{root:uri}/../mountainash-settings`), so version coordination is implicit. + +--- + +## File survey (from `grep -ln`) + +**Source files using old names (21):** + +``` +src/mountainash_data/core/settings/registry.py +src/mountainash_data/core/settings/profile.py +src/mountainash_data/core/settings/descriptor.py +src/mountainash_data/core/settings/sqlite.py +src/mountainash_data/core/settings/duckdb.py (likely) +src/mountainash_data/core/settings/postgresql.py +src/mountainash_data/core/settings/mysql.py +src/mountainash_data/core/settings/mssql.py +src/mountainash_data/core/settings/snowflake.py +src/mountainash_data/core/settings/redshift.py +src/mountainash_data/core/settings/bigquery.py (likely) +src/mountainash_data/core/settings/databricks.py (likely) +src/mountainash_data/core/settings/motherduck.py +src/mountainash_data/core/settings/clickhouse.py (likely) +src/mountainash_data/core/settings/trino.py +src/mountainash_data/core/settings/singlestoredb.py +src/mountainash_data/core/settings/exasol.py +src/mountainash_data/core/settings/impala.py +src/mountainash_data/core/settings/materialize.py +src/mountainash_data/core/settings/risingwave.py +src/mountainash_data/core/settings/druid.py (likely) +src/mountainash_data/core/settings/pyspark.py +src/mountainash_data/core/settings/pyiceberg_rest.py +``` + +**Test files using old names (3):** + +``` +tests/test_unit/core/settings/test_descriptor.py +tests/test_unit/core/settings/test_profile.py +tests/test_unit/core/settings/test_descriptors_invariants.py +``` + +--- + +## Rename table + +Apply to every file touched: + +| Old | New | +|---|---| +| `from mountainash_settings.profiles import ProfileDescriptor` | `from mountainash_settings.profiles import ProfileSpec` | +| `from mountainash_settings.profiles.descriptor import _Missing` | `from mountainash_settings.profiles import Missing` | +| `class BackendDescriptor(ProfileDescriptor)` | `class BackendSpec(ProfileSpec)` | +| Any `BackendDescriptor` reference | `BackendSpec` | +| `*_DESCRIPTOR = BackendDescriptor(...)` | `*_SPEC = BackendSpec(...)` | +| Every reference to `POSTGRESQL_DESCRIPTOR` etc. | `POSTGRESQL_SPEC` etc. | +| `@register(POSTGRESQL_DESCRIPTOR)` | `@register` (argument-free) | +| `__descriptor__ = POSTGRESQL_DESCRIPTOR` | `__spec__ = POSTGRESQL_SPEC` | +| `Registry("databases")` | `Registry("databases", spec_type=BackendSpec, profile_type=ConnectionProfile)` | +| Local MRO walk in `to_driver_kwargs` | `lookup_class_var` import from `mountainash_settings` | +| `descriptor_invariants_for` | `spec_invariants_for` | +| `TestDescriptorInvariants_*` | `TestSpecInvariants_*` (in expected pytest output assertions) | + +--- + +## Tasks + +### Task A: `descriptor.py` rename + shim + +**Files:** +- Modify: `src/mountainash_data/core/settings/descriptor.py` +- Modify: `src/mountainash_data/core/settings/__init__.py` (if `BackendDescriptor` is re-exported there) + +**Required changes:** + +1. Rename `class BackendDescriptor` → `class BackendSpec`. +2. Replace `from mountainash_settings.profiles.descriptor import _Missing` with `from mountainash_settings.profiles import Missing`. +3. Replace `from mountainash_settings.profiles import ProfileDescriptor` with `from mountainash_settings.profiles import ProfileSpec`. Update `class BackendSpec(ProfileSpec)`. +4. Update `__all__` to use `BackendSpec` and `Missing`. +5. Add PEP 562 `__getattr__` shim at the bottom of `descriptor.py`: + +```python +import warnings + + +_DEPRECATED = { + "BackendDescriptor": ("BackendSpec", BackendSpec), + "_Missing": ("Missing", Missing), +} + + +def __getattr__(name): + if name in _DEPRECATED: + new_name, obj = _DEPRECATED[name] + warnings.warn( + f"{name!r} is renamed to {new_name!r} in mountainash-data. " + f"Update imports to use the new name.", + DeprecationWarning, stacklevel=2, + ) + return obj + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") +``` + +6. Update `__init__.py` re-exports if `BackendDescriptor` was previously exported — change to `BackendSpec` and add a top-level shim if downstream consumers may import directly from the package root. + +### Task B: `registry.py` constraints + `profile.py` lookup helper + +**Files:** +- Modify: `src/mountainash_data/core/settings/registry.py` +- Modify: `src/mountainash_data/core/settings/profile.py` + +**registry.py changes:** + +1. Update the `DATABASES_REGISTRY` construction: + +```python +# Before +DATABASES_REGISTRY = Registry("databases") + +# After +DATABASES_REGISTRY = Registry( + "databases", + spec_type=BackendSpec, + profile_type=ConnectionProfile, +) +``` + +2. Update any `descriptor_invariants_for` references to `spec_invariants_for`. + +**profile.py changes:** + +3. Replace local MRO walk in `to_driver_kwargs()`: + +```python +# Before — local MRO walk +adapter = type(self).__dict__.get("__adapter__") +if adapter is None: + for base in type(self).__mro__[1:]: + candidate = base.__dict__.get("__adapter__") + if candidate is not None: + adapter = candidate + break + +# After — public helper +from mountainash_settings import lookup_class_var +adapter = lookup_class_var(type(self), "__adapter__") +``` + +The import can go at the top of the file rather than inline. + +### Task C: 21 backend file sweep + +For each file in `src/mountainash_data/core/settings/` matching `^(?!__init__|descriptor|profile|registry).*\.py$`: + +**Replace:** +- `BackendDescriptor` → `BackendSpec` (imports and constructor calls) +- `_DESCRIPTOR = BackendDescriptor(` → `_SPEC = BackendSpec(` +- Every reference to `_DESCRIPTOR` → `_SPEC` +- `@register(_DESCRIPTOR)` → `@register` (drop the argument) +- `__descriptor__ = _DESCRIPTOR` (or whatever spec it points at) → `__spec__ = _SPEC` + +Each file is independent. Apply the same mechanical pattern. Verify after each that imports resolve. + +### Task D: Tests + +**Files:** +- Modify: `tests/test_unit/core/settings/test_profile.py` +- Modify: `tests/test_unit/core/settings/test_descriptor.py` (or rename to `test_spec.py` if desired — optional) +- Modify: `tests/test_unit/core/settings/test_descriptors_invariants.py` (consider renaming to `test_spec_invariants.py`) + +Apply the same rename table. Update any references to the old API names. + +### Task E: Version bump + verification + +**Files:** +- Modify: `src/mountainash_data/__version__.py` + +**Steps:** + +1. Bump version. Current is `2026.04.2`. Following `mountainash-data`'s CalVer pattern (`YYYY.MM.MICRO`), the next release is `2026.05.0` (since we're in May). + +2. Run full test suite: + ```bash + hatch run test:test + ``` + +3. Run with deprecation warnings escalated to errors: + ```bash + hatch run test:test -W "error::DeprecationWarning" -W "default::DeprecationWarning:mountainash_data.core.settings.descriptor" + ``` + The `-W default` filter explicitly allows warnings from `mountainash-data`'s own descriptor shim (which exists by design). Any warning from elsewhere fails the run — that's the migration completion check. + +4. Run lint: + ```bash + hatch run ruff:check + ``` + +5. Build: + ```bash + hatch build + ``` + +### Task F: Push and PR + +1. Push the feature branch. +2. Open PR targeting `develop` with the same level of detail as the upstream PR (description, test plan, removal commitment). + +### Restore stashed working tree + +After the PR is open: + +```bash +git stash pop # restore hatch.toml reorder + .claude/worktrees/settings-registry +``` + +(Or leave for the user to handle.) + +--- + +## Execution strategy + +The work is mechanical. Single-subagent dispatch can handle Tasks A-D as one batch since they're all in the same package and the transformations are templated. Task E and F can be done manually. + +This plan does not list individual TDD steps because the upstream contract guarantees behaviour: the new names resolve to the same objects as the old names (via deprecation aliases). Running the existing test suite is the verification. New tests are not added in this PR — the upstream PR added all the deprecation tests; this PR is purely a consumer migration. diff --git a/src/mountainash_data/__version__.py b/src/mountainash_data/__version__.py index aa02796..a4ad378 100644 --- a/src/mountainash_data/__version__.py +++ b/src/mountainash_data/__version__.py @@ -1 +1 @@ -__version__="2026.04.2" +__version__="2026.05.0" diff --git a/src/mountainash_data/backends/ibis/backend.py b/src/mountainash_data/backends/ibis/backend.py index 79267b1..e39a7bd 100644 --- a/src/mountainash_data/backends/ibis/backend.py +++ b/src/mountainash_data/backends/ibis/backend.py @@ -227,16 +227,16 @@ def _init_from_settings( obj_settings = settings_params.settings_class.get_settings( settings_parameters=settings_params ) - descriptor = getattr(obj_settings, "__descriptor__", None) + descriptor = getattr(obj_settings, "__spec__", None) if descriptor is None or getattr(descriptor, "ibis_dialect", None) is None: raise ValueError( f"Settings class {type(obj_settings).__name__} has no " - f"ibis_dialect on its descriptor" + f"ibis_dialect on its spec" ) resolved_dialect = descriptor.ibis_dialect if resolved_dialect not in DIALECTS: raise KeyError( - f"Unknown ibis dialect {resolved_dialect!r} from descriptor. " + f"Unknown ibis dialect {resolved_dialect!r} from spec. " f"Available: {sorted(DIALECTS)}" ) driver_kwargs = obj_settings.to_driver_kwargs() diff --git a/src/mountainash_data/core/settings/__init__.py b/src/mountainash_data/core/settings/__init__.py index 5b53466..ca43405 100644 --- a/src/mountainash_data/core/settings/__init__.py +++ b/src/mountainash_data/core/settings/__init__.py @@ -1,13 +1,13 @@ -"""Backend settings — declarative descriptor + registry. +"""Backend settings — declarative spec + registry. The *AuthSettings classes below are stable import anchors; internally each -class body is a two-line shell (``__descriptor__`` + ``__adapter__``). +class body is a two-line shell (``__spec__`` + ``__adapter__``). """ from __future__ import annotations # Core primitives -from .descriptor import MISSING, BackendDescriptor, ParameterSpec +from .descriptor import MISSING, Missing, BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import ( DATABASES_REGISTRY, @@ -55,9 +55,30 @@ class body is a two-line shell (``__descriptor__`` + ``__adapter__``). from .druid import DruidAuthSettings from .pyiceberg_rest import PyIcebergRestAuthSettings +import warnings as _warnings + + +_DEPRECATED_PKG = { + "BackendDescriptor": ("BackendSpec", BackendSpec), + "_Missing": ("Missing", Missing), +} + + +def __getattr__(name: str): + if name in _DEPRECATED_PKG: + new_name, obj = _DEPRECATED_PKG[name] + _warnings.warn( + f"{name!r} is renamed to {new_name!r} in mountainash-data. " + f"Update imports to use the new name.", + DeprecationWarning, stacklevel=2, + ) + return obj + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + __all__ = [ # primitives - "MISSING", "BackendDescriptor", "ParameterSpec", "ConnectionProfile", + "MISSING", "Missing", "BackendSpec", "ParameterSpec", "ConnectionProfile", "DATABASES_REGISTRY", "REGISTRY", "get_descriptor", "get_settings_class", "register", # auth diff --git a/src/mountainash_data/core/settings/bigquery.py b/src/mountainash_data/core/settings/bigquery.py index 86225e4..e2582c3 100644 --- a/src/mountainash_data/core/settings/bigquery.py +++ b/src/mountainash_data/core/settings/bigquery.py @@ -14,11 +14,11 @@ from ..constants import CONST_DB_PROVIDER_TYPE from .adapters import bigquery as _adapter from mountainash_settings.auth import NoAuth, ServiceAccountAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -__all__ = ["BigQueryAuthSettings", "BIGQUERY_DESCRIPTOR"] +__all__ = ["BigQueryAuthSettings", "BIGQUERY_SPEC"] _PROJECT_ID_RE = re.compile(r"^[a-z][a-z0-9-]{4,28}[a-z0-9]$") @@ -32,7 +32,7 @@ def _validate_project_id(value: str) -> str: return value -BIGQUERY_DESCRIPTOR = BackendDescriptor( +BIGQUERY_SPEC = BackendSpec( name="bigquery", provider_type=CONST_DB_PROVIDER_TYPE.BIGQUERY, connection_string_scheme="bigquery://", @@ -60,9 +60,9 @@ def _validate_project_id(value: str) -> str: ) -@register(BIGQUERY_DESCRIPTOR) +@register class BigQueryAuthSettings(ConnectionProfile): - __descriptor__ = BIGQUERY_DESCRIPTOR + __spec__ = BIGQUERY_SPEC __adapter__ = staticmethod(_adapter.build_driver_kwargs) @field_validator("PROJECT_ID", check_fields=False) diff --git a/src/mountainash_data/core/settings/clickhouse.py b/src/mountainash_data/core/settings/clickhouse.py index 0200797..cf4d29b 100644 --- a/src/mountainash_data/core/settings/clickhouse.py +++ b/src/mountainash_data/core/settings/clickhouse.py @@ -11,12 +11,12 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import NoAuth, PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -CLICKHOUSE_DESCRIPTOR = BackendDescriptor( +CLICKHOUSE_SPEC = BackendSpec( name="clickhouse", provider_type=CONST_DB_PROVIDER_TYPE.CLICKHOUSE, default_port=9000, @@ -44,6 +44,6 @@ ) -@register(CLICKHOUSE_DESCRIPTOR) +@register class ClickHouseAuthSettings(ConnectionProfile): - __descriptor__ = CLICKHOUSE_DESCRIPTOR + __spec__ = CLICKHOUSE_SPEC diff --git a/src/mountainash_data/core/settings/databricks.py b/src/mountainash_data/core/settings/databricks.py index 3a6579b..697b25a 100644 --- a/src/mountainash_data/core/settings/databricks.py +++ b/src/mountainash_data/core/settings/databricks.py @@ -12,12 +12,12 @@ from ..constants import CONST_DB_PROVIDER_TYPE from .adapters import databricks as _adapter from mountainash_settings.auth import NoAuth, PasswordAuth, TokenAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -DATABRICKS_DESCRIPTOR = BackendDescriptor( +DATABRICKS_SPEC = BackendSpec( name="databricks", provider_type=CONST_DB_PROVIDER_TYPE.DATABRICKS, ibis_dialect="databricks", @@ -37,7 +37,7 @@ ) -@register(DATABRICKS_DESCRIPTOR) +@register class DatabricksAuthSettings(ConnectionProfile): - __descriptor__ = DATABRICKS_DESCRIPTOR + __spec__ = DATABRICKS_SPEC __adapter__ = staticmethod(_adapter.build_driver_kwargs) diff --git a/src/mountainash_data/core/settings/descriptor.py b/src/mountainash_data/core/settings/descriptor.py index d418ce7..0459d70 100644 --- a/src/mountainash_data/core/settings/descriptor.py +++ b/src/mountainash_data/core/settings/descriptor.py @@ -1,4 +1,4 @@ -"""Database-flavored ProfileDescriptor with typed metadata fields. +"""Database-flavored ProfileSpec with typed metadata fields. Retained in mountainash-data (rather than lifted to mountainash-settings) because these fields are domain-specific: ``connection_string_scheme`` and @@ -7,21 +7,22 @@ from __future__ import annotations +import warnings from dataclasses import dataclass from mountainash_settings.profiles import ( MISSING, + Missing, ParameterSpec, - ProfileDescriptor, + ProfileSpec, ) -from mountainash_settings.profiles.descriptor import _Missing -__all__ = ["MISSING", "_Missing", "BackendDescriptor", "ParameterSpec"] +__all__ = ["MISSING", "Missing", "ParameterSpec", "BackendSpec"] @dataclass(frozen=True, kw_only=True) -class BackendDescriptor(ProfileDescriptor): - """ProfileDescriptor with database-specific typed metadata. +class BackendSpec(ProfileSpec): + """ProfileSpec with database-specific typed metadata. Extra fields: default_port: Default TCP port if the backend listens on one. @@ -36,3 +37,21 @@ class BackendDescriptor(ProfileDescriptor): connection_string_scheme: str | None = None ibis_dialect: str | None = None rides_on: str | None = None + + +_DEPRECATED = { + "BackendDescriptor": ("BackendSpec", BackendSpec), + "_Missing": ("Missing", Missing), +} + + +def __getattr__(name: str): + if name in _DEPRECATED: + new_name, obj = _DEPRECATED[name] + warnings.warn( + f"{name!r} is renamed to {new_name!r} in mountainash-data. " + f"Update imports to use the new name.", + DeprecationWarning, stacklevel=2, + ) + return obj + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/src/mountainash_data/core/settings/druid.py b/src/mountainash_data/core/settings/druid.py index 4ac1273..51c03dd 100644 --- a/src/mountainash_data/core/settings/druid.py +++ b/src/mountainash_data/core/settings/druid.py @@ -11,12 +11,12 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import NoAuth, PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -DRUID_DESCRIPTOR = BackendDescriptor( +DRUID_SPEC = BackendSpec( name="druid", provider_type=CONST_DB_PROVIDER_TYPE.DRUID, default_port=8082, @@ -35,6 +35,6 @@ ) -@register(DRUID_DESCRIPTOR) +@register class DruidAuthSettings(ConnectionProfile): - __descriptor__ = DRUID_DESCRIPTOR + __spec__ = DRUID_SPEC diff --git a/src/mountainash_data/core/settings/duckdb.py b/src/mountainash_data/core/settings/duckdb.py index 2ddb94f..eb74a45 100644 --- a/src/mountainash_data/core/settings/duckdb.py +++ b/src/mountainash_data/core/settings/duckdb.py @@ -15,11 +15,11 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import NoAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -__all__ = ["DuckDBAuthSettings", "DUCKDB_DESCRIPTOR"] +__all__ = ["DuckDBAuthSettings", "DUCKDB_SPEC"] _MEMORY_LIMIT_RE = re.compile(r"^(?:\d+(?:\.\d+)?\s*[KMG]i?B|\d+%)$", re.IGNORECASE) @@ -34,7 +34,7 @@ def _validate_memory_limit(value: t.Any) -> t.Any: return value -DUCKDB_DESCRIPTOR = BackendDescriptor( +DUCKDB_SPEC = BackendSpec( name="duckdb", provider_type=CONST_DB_PROVIDER_TYPE.DUCKDB, connection_string_scheme="duckdb://", @@ -84,9 +84,9 @@ def _validate_memory_limit(value: t.Any) -> t.Any: ) -@register(DUCKDB_DESCRIPTOR) +@register class DuckDBAuthSettings(ConnectionProfile): - __descriptor__ = DUCKDB_DESCRIPTOR + __spec__ = DUCKDB_SPEC @field_validator("MEMORY_LIMIT", check_fields=False) @classmethod diff --git a/src/mountainash_data/core/settings/exasol.py b/src/mountainash_data/core/settings/exasol.py index 5f29415..f5d4cd9 100644 --- a/src/mountainash_data/core/settings/exasol.py +++ b/src/mountainash_data/core/settings/exasol.py @@ -9,12 +9,12 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -EXASOL_DESCRIPTOR = BackendDescriptor( +EXASOL_SPEC = BackendSpec( name="exasol", provider_type=CONST_DB_PROVIDER_TYPE.EXASOL, default_port=8563, @@ -31,6 +31,6 @@ ) -@register(EXASOL_DESCRIPTOR) +@register class ExasolAuthSettings(ConnectionProfile): - __descriptor__ = EXASOL_DESCRIPTOR + __spec__ = EXASOL_SPEC diff --git a/src/mountainash_data/core/settings/impala.py b/src/mountainash_data/core/settings/impala.py index b7b0b29..c6b0691 100644 --- a/src/mountainash_data/core/settings/impala.py +++ b/src/mountainash_data/core/settings/impala.py @@ -13,7 +13,7 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import NoAuth, PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register @@ -25,7 +25,7 @@ class ImpalaAuthMechanism(StrEnum): LDAP = "LDAP" -IMPALA_DESCRIPTOR = BackendDescriptor( +IMPALA_SPEC = BackendSpec( name="impala", provider_type=CONST_DB_PROVIDER_TYPE.IMPALA, default_port=21050, @@ -54,6 +54,6 @@ class ImpalaAuthMechanism(StrEnum): ) -@register(IMPALA_DESCRIPTOR) +@register class ImpalaAuthSettings(ConnectionProfile): - __descriptor__ = IMPALA_DESCRIPTOR + __spec__ = IMPALA_SPEC diff --git a/src/mountainash_data/core/settings/materialize.py b/src/mountainash_data/core/settings/materialize.py index 50dd900..657f8ca 100644 --- a/src/mountainash_data/core/settings/materialize.py +++ b/src/mountainash_data/core/settings/materialize.py @@ -11,12 +11,12 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import NoAuth, PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -MATERIALIZE_DESCRIPTOR = BackendDescriptor( +MATERIALIZE_SPEC = BackendSpec( name="materialize", provider_type=CONST_DB_PROVIDER_TYPE.MATERIALIZE, default_port=6875, @@ -39,6 +39,6 @@ ) -@register(MATERIALIZE_DESCRIPTOR) +@register class MaterializeAuthSettings(ConnectionProfile): - __descriptor__ = MATERIALIZE_DESCRIPTOR + __spec__ = MATERIALIZE_SPEC diff --git a/src/mountainash_data/core/settings/motherduck.py b/src/mountainash_data/core/settings/motherduck.py index 607f401..1f96659 100644 --- a/src/mountainash_data/core/settings/motherduck.py +++ b/src/mountainash_data/core/settings/motherduck.py @@ -12,14 +12,14 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import TokenAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -__all__ = ["MotherDuckAuthSettings", "MOTHERDUCK_DESCRIPTOR"] +__all__ = ["MotherDuckAuthSettings", "MOTHERDUCK_SPEC"] -MOTHERDUCK_DESCRIPTOR = BackendDescriptor( +MOTHERDUCK_SPEC = BackendSpec( name="motherduck", provider_type=CONST_DB_PROVIDER_TYPE.MOTHERDUCK, connection_string_scheme="duckdb://md:", # md:?motherduck_token=... @@ -35,6 +35,6 @@ ) -@register(MOTHERDUCK_DESCRIPTOR) +@register class MotherDuckAuthSettings(ConnectionProfile): - __descriptor__ = MOTHERDUCK_DESCRIPTOR + __spec__ = MOTHERDUCK_SPEC diff --git a/src/mountainash_data/core/settings/mssql.py b/src/mountainash_data/core/settings/mssql.py index 9f3bb48..fa944ae 100644 --- a/src/mountainash_data/core/settings/mssql.py +++ b/src/mountainash_data/core/settings/mssql.py @@ -12,7 +12,7 @@ from ..constants import CONST_DB_PROVIDER_TYPE from .adapters import mssql as _adapter from mountainash_settings.auth import AzureADAuth, PasswordAuth, WindowsAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register @@ -29,7 +29,7 @@ class MSSQLEncryption(StrEnum): STRICT = "strict" -MSSQL_DESCRIPTOR = BackendDescriptor( +MSSQL_SPEC = BackendSpec( name="mssql", provider_type=CONST_DB_PROVIDER_TYPE.MSSQL, default_port=1433, @@ -106,7 +106,7 @@ class MSSQLEncryption(StrEnum): ) -@register(MSSQL_DESCRIPTOR) +@register class MSSQLAuthSettings(ConnectionProfile): - __descriptor__ = MSSQL_DESCRIPTOR + __spec__ = MSSQL_SPEC __adapter__ = staticmethod(_adapter.build_driver_kwargs) diff --git a/src/mountainash_data/core/settings/mysql.py b/src/mountainash_data/core/settings/mysql.py index b58807f..4e33ac8 100644 --- a/src/mountainash_data/core/settings/mysql.py +++ b/src/mountainash_data/core/settings/mysql.py @@ -15,7 +15,7 @@ from ..constants import CONST_DB_PROVIDER_TYPE from .adapters import mysql as _adapter from mountainash_settings.auth import PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register @@ -28,7 +28,7 @@ class MySQLSSLMode(StrEnum): VERIFY_IDENTITY = "VERIFY_IDENTITY" -MYSQL_DESCRIPTOR = BackendDescriptor( +MYSQL_SPEC = BackendSpec( name="mysql", provider_type=CONST_DB_PROVIDER_TYPE.MYSQL, default_port=3306, @@ -82,7 +82,7 @@ class MySQLSSLMode(StrEnum): ) -@register(MYSQL_DESCRIPTOR) +@register class MySQLAuthSettings(ConnectionProfile): - __descriptor__ = MYSQL_DESCRIPTOR + __spec__ = MYSQL_SPEC __adapter__ = staticmethod(_adapter.build_driver_kwargs) diff --git a/src/mountainash_data/core/settings/postgresql.py b/src/mountainash_data/core/settings/postgresql.py index 36e5433..afef815 100644 --- a/src/mountainash_data/core/settings/postgresql.py +++ b/src/mountainash_data/core/settings/postgresql.py @@ -16,7 +16,7 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import NoAuth, PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register @@ -63,7 +63,7 @@ def _join_require_auth(v: list[PostgresRequireAuthMethods]) -> str: return ",".join(m.value for m in v) -POSTGRESQL_DESCRIPTOR = BackendDescriptor( +POSTGRESQL_SPEC = BackendSpec( name="postgresql", provider_type=CONST_DB_PROVIDER_TYPE.POSTGRESQL, default_port=5432, @@ -156,6 +156,6 @@ def _join_require_auth(v: list[PostgresRequireAuthMethods]) -> str: ) -@register(POSTGRESQL_DESCRIPTOR) +@register class PostgreSQLAuthSettings(ConnectionProfile): - __descriptor__ = POSTGRESQL_DESCRIPTOR + __spec__ = POSTGRESQL_SPEC diff --git a/src/mountainash_data/core/settings/profile.py b/src/mountainash_data/core/settings/profile.py index 9613831..b0d2855 100644 --- a/src/mountainash_data/core/settings/profile.py +++ b/src/mountainash_data/core/settings/profile.py @@ -1,8 +1,8 @@ -"""ConnectionProfile — database-flavored subclass of DescriptorProfile. +"""ConnectionProfile — database-flavored subclass of Profile. Adds ``to_driver_kwargs()`` and ``to_connection_string()`` on top of the generic mechanism provided by -:class:`mountainash_settings.profiles.DescriptorProfile`. +:class:`mountainash_settings.profiles.Profile`. """ from __future__ import annotations @@ -10,12 +10,13 @@ import typing as t from urllib.parse import quote -from mountainash_settings.profiles import DescriptorProfile +from mountainash_settings import lookup_class_var +from mountainash_settings.profiles import Profile __all__ = ["ConnectionProfile"] -class ConnectionProfile(DescriptorProfile): +class ConnectionProfile(Profile): """Database connection settings. Public API: @@ -23,9 +24,9 @@ class ConnectionProfile(DescriptorProfile): - :meth:`to_connection_string` — URL form, or ``NotImplementedError`` if the descriptor has no ``connection_string_scheme`` metadata. - Subclasses set ``__descriptor__`` (a :class:`ProfileDescriptor`) and + Subclasses set ``__spec__`` (a :class:`BackendSpec`) and optionally ``__adapter__``. Field installation, auth union, and template - wiring are inherited from :class:`DescriptorProfile`. + wiring are inherited from :class:`Profile`. """ def to_driver_kwargs(self) -> dict[str, t.Any]: @@ -36,13 +37,7 @@ def to_driver_kwargs(self) -> dict[str, t.Any]: composite mappings on top. Otherwise defaults to descriptor ``driver_key`` mappings + default auth dispatch. """ - adapter = type(self).__dict__.get("__adapter__") - if adapter is None: - for base in type(self).__mro__[1:]: - candidate = base.__dict__.get("__adapter__") - if candidate is not None: - adapter = candidate - break + adapter = lookup_class_var(type(self), "__adapter__") if adapter is not None: return adapter(self) kwargs = self._default_kwargs() @@ -56,7 +51,7 @@ def to_connection_string(self) -> str: (or a typed ``connection_string_scheme`` attribute if the descriptor subclass provides one). Raises :class:`NotImplementedError` if absent. """ - desc = self.__descriptor__ + desc = lookup_class_var(type(self), "__spec__") scheme = getattr(desc, "connection_string_scheme", None) if scheme is None: scheme = desc.metadata.get("connection_string_scheme") diff --git a/src/mountainash_data/core/settings/pyiceberg_rest.py b/src/mountainash_data/core/settings/pyiceberg_rest.py index 6239bab..169d2f8 100644 --- a/src/mountainash_data/core/settings/pyiceberg_rest.py +++ b/src/mountainash_data/core/settings/pyiceberg_rest.py @@ -13,12 +13,12 @@ from ..constants import CONST_DB_PROVIDER_TYPE from .adapters import pyiceberg_rest as _adapter from mountainash_settings.auth import OAuth2Auth, TokenAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -PYICEBERG_REST_DESCRIPTOR = BackendDescriptor( +PYICEBERG_REST_SPEC = BackendSpec( name="pyiceberg_rest", provider_type=CONST_DB_PROVIDER_TYPE.PYICEBERG_REST, connection_string_scheme=None, # uri= kwarg, not URL form @@ -57,7 +57,7 @@ ) -@register(PYICEBERG_REST_DESCRIPTOR) +@register class PyIcebergRestAuthSettings(ConnectionProfile): - __descriptor__ = PYICEBERG_REST_DESCRIPTOR + __spec__ = PYICEBERG_REST_SPEC __adapter__ = staticmethod(_adapter.build_driver_kwargs) diff --git a/src/mountainash_data/core/settings/pyspark.py b/src/mountainash_data/core/settings/pyspark.py index f5faa88..4afdc64 100644 --- a/src/mountainash_data/core/settings/pyspark.py +++ b/src/mountainash_data/core/settings/pyspark.py @@ -16,11 +16,11 @@ from ..constants import CONST_DB_PROVIDER_TYPE from .adapters import pyspark as _adapter from mountainash_settings.auth import NoAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -__all__ = ["PySparkAuthSettings", "PySparkMode", "PYSPARK_DESCRIPTOR"] +__all__ = ["PySparkAuthSettings", "PySparkMode", "PYSPARK_SPEC"] class PySparkMode(StrEnum): @@ -28,7 +28,7 @@ class PySparkMode(StrEnum): STREAMING = "streaming" -PYSPARK_DESCRIPTOR = BackendDescriptor( +PYSPARK_SPEC = BackendSpec( name="pyspark", provider_type=CONST_DB_PROVIDER_TYPE.PYSPARK, connection_string_scheme=None, # SparkSession, not URL @@ -51,7 +51,7 @@ class PySparkMode(StrEnum): ) -@register(PYSPARK_DESCRIPTOR) +@register class PySparkAuthSettings(ConnectionProfile): - __descriptor__ = PYSPARK_DESCRIPTOR + __spec__ = PYSPARK_SPEC __adapter__ = staticmethod(_adapter.build_driver_kwargs) diff --git a/src/mountainash_data/core/settings/redshift.py b/src/mountainash_data/core/settings/redshift.py index 34ad712..fd4363e 100644 --- a/src/mountainash_data/core/settings/redshift.py +++ b/src/mountainash_data/core/settings/redshift.py @@ -16,7 +16,7 @@ from ..constants import CONST_DB_PROVIDER_TYPE from .adapters import redshift as _adapter from mountainash_settings.auth import IAMAuth, PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register @@ -34,7 +34,7 @@ class RedshiftSSLMode(StrEnum): _ROLE_ARN_RE = re.compile(r"^arn:aws(?:-us-gov|-cn)?:iam::\d{12}:role/.+$") -REDSHIFT_DESCRIPTOR = BackendDescriptor( +REDSHIFT_SPEC = BackendSpec( name="redshift", provider_type=CONST_DB_PROVIDER_TYPE.REDSHIFT, default_port=5439, @@ -67,9 +67,9 @@ class RedshiftSSLMode(StrEnum): ) -@register(REDSHIFT_DESCRIPTOR) +@register class RedshiftAuthSettings(ConnectionProfile): - __descriptor__ = REDSHIFT_DESCRIPTOR + __spec__ = REDSHIFT_SPEC __adapter__ = staticmethod(_adapter.build_driver_kwargs) @field_validator("REGION", check_fields=False) diff --git a/src/mountainash_data/core/settings/registry.py b/src/mountainash_data/core/settings/registry.py index 54e6f4f..98eb415 100644 --- a/src/mountainash_data/core/settings/registry.py +++ b/src/mountainash_data/core/settings/registry.py @@ -12,9 +12,8 @@ from mountainash_settings.profiles import Registry -if t.TYPE_CHECKING: - from mountainash_settings.profiles import ProfileDescriptor - from .profile import ConnectionProfile +from .descriptor import BackendSpec +from .profile import ConnectionProfile __all__ = [ "DATABASES_REGISTRY", @@ -26,12 +25,16 @@ "register", ] -DATABASES_REGISTRY = Registry("databases") +DATABASES_REGISTRY = Registry( + "databases", + spec_type=BackendSpec, + profile_type=ConnectionProfile, +) register = DATABASES_REGISTRY.decorator() -def get_descriptor(name: str) -> "ProfileDescriptor": +def get_descriptor(name: str) -> BackendSpec: return DATABASES_REGISTRY.get_descriptor(name) @@ -47,7 +50,7 @@ class _RegistryDictView(Mapping): def __contains__(self, name: object) -> bool: return isinstance(name, str) and name in DATABASES_REGISTRY - def __getitem__(self, name: str) -> "ProfileDescriptor": + def __getitem__(self, name: str) -> BackendSpec: return DATABASES_REGISTRY.get_descriptor(name) def __iter__(self) -> t.Iterator[str]: @@ -56,13 +59,13 @@ def __iter__(self) -> t.Iterator[str]: def __len__(self) -> int: return len(DATABASES_REGISTRY) - def items(self) -> t.ItemsView[str, "ProfileDescriptor"]: + def items(self) -> t.ItemsView[str, BackendSpec]: return DATABASES_REGISTRY.descriptors.items() def keys(self) -> t.KeysView[str]: return DATABASES_REGISTRY.descriptors.keys() - def values(self) -> t.ValuesView["ProfileDescriptor"]: + def values(self) -> t.ValuesView[BackendSpec]: return DATABASES_REGISTRY.descriptors.values() diff --git a/src/mountainash_data/core/settings/risingwave.py b/src/mountainash_data/core/settings/risingwave.py index 00e0866..c3f30b0 100644 --- a/src/mountainash_data/core/settings/risingwave.py +++ b/src/mountainash_data/core/settings/risingwave.py @@ -11,12 +11,12 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import NoAuth, PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -RISINGWAVE_DESCRIPTOR = BackendDescriptor( +RISINGWAVE_SPEC = BackendSpec( name="risingwave", provider_type=CONST_DB_PROVIDER_TYPE.RISINGWAVE, default_port=5432, @@ -35,6 +35,6 @@ ) -@register(RISINGWAVE_DESCRIPTOR) +@register class RisingWaveAuthSettings(ConnectionProfile): - __descriptor__ = RISINGWAVE_DESCRIPTOR + __spec__ = RISINGWAVE_SPEC diff --git a/src/mountainash_data/core/settings/singlestoredb.py b/src/mountainash_data/core/settings/singlestoredb.py index e85d754..3bafde0 100644 --- a/src/mountainash_data/core/settings/singlestoredb.py +++ b/src/mountainash_data/core/settings/singlestoredb.py @@ -12,7 +12,7 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import NoAuth, PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register @@ -23,7 +23,7 @@ class SingleStoreDriver(StrEnum): HTTPS = "https" -SINGLESTOREDB_DESCRIPTOR = BackendDescriptor( +SINGLESTOREDB_SPEC = BackendSpec( name="singlestoredb", provider_type=CONST_DB_PROVIDER_TYPE.SINGLESTOREDB, default_port=3306, @@ -46,6 +46,6 @@ class SingleStoreDriver(StrEnum): ) -@register(SINGLESTOREDB_DESCRIPTOR) +@register class SingleStoreDBAuthSettings(ConnectionProfile): - __descriptor__ = SINGLESTOREDB_DESCRIPTOR + __spec__ = SINGLESTOREDB_SPEC diff --git a/src/mountainash_data/core/settings/snowflake.py b/src/mountainash_data/core/settings/snowflake.py index 929d4c8..32bebb4 100644 --- a/src/mountainash_data/core/settings/snowflake.py +++ b/src/mountainash_data/core/settings/snowflake.py @@ -12,7 +12,7 @@ from ..constants import CONST_DB_PROVIDER_TYPE from .adapters import snowflake as _adapter from mountainash_settings.auth import CertificateAuth, OAuth2Auth, PasswordAuth, TokenAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register @@ -25,7 +25,7 @@ class SnowflakeAuthenticator(StrEnum): PASSWORD_MFA = "username_password_mfa" -SNOWFLAKE_DESCRIPTOR = BackendDescriptor( +SNOWFLAKE_SPEC = BackendSpec( name="snowflake", provider_type=CONST_DB_PROVIDER_TYPE.SNOWFLAKE, connection_string_scheme="snowflake://", @@ -67,7 +67,7 @@ class SnowflakeAuthenticator(StrEnum): ) -@register(SNOWFLAKE_DESCRIPTOR) +@register class SnowflakeAuthSettings(ConnectionProfile): - __descriptor__ = SNOWFLAKE_DESCRIPTOR + __spec__ = SNOWFLAKE_SPEC __adapter__ = staticmethod(_adapter.build_driver_kwargs) diff --git a/src/mountainash_data/core/settings/sqlite.py b/src/mountainash_data/core/settings/sqlite.py index 5bf872c..dec4f0a 100644 --- a/src/mountainash_data/core/settings/sqlite.py +++ b/src/mountainash_data/core/settings/sqlite.py @@ -11,14 +11,14 @@ from ..constants import CONST_DB_PROVIDER_TYPE from mountainash_settings.auth import NoAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -__all__ = ["SQLiteAuthSettings", "SQLITE_DESCRIPTOR"] +__all__ = ["SQLiteAuthSettings", "SQLITE_SPEC"] -SQLITE_DESCRIPTOR = BackendDescriptor( +SQLITE_SPEC = BackendSpec( name="sqlite", provider_type=CONST_DB_PROVIDER_TYPE.SQLITE, connection_string_scheme="sqlite://", @@ -45,6 +45,6 @@ ) -@register(SQLITE_DESCRIPTOR) +@register class SQLiteAuthSettings(ConnectionProfile): - __descriptor__ = SQLITE_DESCRIPTOR + __spec__ = SQLITE_SPEC diff --git a/src/mountainash_data/core/settings/trino.py b/src/mountainash_data/core/settings/trino.py index 72e656a..f663d59 100644 --- a/src/mountainash_data/core/settings/trino.py +++ b/src/mountainash_data/core/settings/trino.py @@ -13,12 +13,12 @@ from ..constants import CONST_DB_PROVIDER_TYPE from .adapters import trino as _adapter from mountainash_settings.auth import JWTAuth, KerberosAuth, NoAuth, PasswordAuth -from .descriptor import BackendDescriptor, ParameterSpec +from .descriptor import BackendSpec, ParameterSpec from .profile import ConnectionProfile from .registry import register -TRINO_DESCRIPTOR = BackendDescriptor( +TRINO_SPEC = BackendSpec( name="trino", provider_type=CONST_DB_PROVIDER_TYPE.TRINO, default_port=8080, @@ -75,7 +75,7 @@ ) -@register(TRINO_DESCRIPTOR) +@register class TrinoAuthSettings(ConnectionProfile): - __descriptor__ = TRINO_DESCRIPTOR + __spec__ = TRINO_SPEC __adapter__ = staticmethod(_adapter.build_driver_kwargs) diff --git a/tests/test_unit/core/settings/test_descriptor.py b/tests/test_unit/core/settings/test_descriptor.py index ded8375..3469d7a 100644 --- a/tests/test_unit/core/settings/test_descriptor.py +++ b/tests/test_unit/core/settings/test_descriptor.py @@ -1,18 +1,18 @@ -"""Tests for the database-flavored BackendDescriptor subclass.""" +"""Tests for the database-flavored BackendSpec subclass.""" import pytest from mountainash_data.core.settings.auth import NoAuth from mountainash_data.core.settings.descriptor import ( - BackendDescriptor, + BackendSpec, ParameterSpec, ) @pytest.mark.unit -class TestBackendDescriptor: +class TestBackendSpec: def test_default_port_field(self): - d = BackendDescriptor( + d = BackendSpec( name="x", provider_type="x", parameters=[], auth_modes=[NoAuth], default_port=5432, @@ -20,7 +20,7 @@ def test_default_port_field(self): assert d.default_port == 5432 def test_connection_string_scheme_field(self): - d = BackendDescriptor( + d = BackendSpec( name="x", provider_type="x", parameters=[], auth_modes=[NoAuth], connection_string_scheme="postgresql://", @@ -28,7 +28,7 @@ def test_connection_string_scheme_field(self): assert d.connection_string_scheme == "postgresql://" def test_rides_on_field(self): - d = BackendDescriptor( + d = BackendSpec( name="motherduck", provider_type="motherduck", parameters=[], auth_modes=[NoAuth], rides_on="duckdb", @@ -36,7 +36,7 @@ def test_rides_on_field(self): assert d.rides_on == "duckdb" def test_frozen(self): - d = BackendDescriptor( + d = BackendSpec( name="x", provider_type="x", parameters=[], auth_modes=[NoAuth], ) diff --git a/tests/test_unit/core/settings/test_descriptors_invariants.py b/tests/test_unit/core/settings/test_descriptors_invariants.py index 8868b48..d8d07ad 100644 --- a/tests/test_unit/core/settings/test_descriptors_invariants.py +++ b/tests/test_unit/core/settings/test_descriptors_invariants.py @@ -1,7 +1,7 @@ -"""Parametric descriptor invariants for all registered database backends. +"""Parametric spec invariants for all registered database backends. -Generated from the shared ``descriptor_invariants_for`` helper in -``mountainash-settings``. Every descriptor in ``DATABASES_REGISTRY`` gets +Generated from the shared ``spec_invariants_for`` helper in +``mountainash-settings``. Every spec in ``DATABASES_REGISTRY`` gets checked against the invariants for free — no per-backend test additions required. """ @@ -13,6 +13,6 @@ import mountainash_data.core.settings # noqa: F401 from mountainash_data.core.settings.registry import DATABASES_REGISTRY -from mountainash_settings.profiles import descriptor_invariants_for +from mountainash_settings.profiles import spec_invariants_for -TestDatabaseInvariants = descriptor_invariants_for(DATABASES_REGISTRY) +TestDatabaseInvariants = spec_invariants_for(DATABASES_REGISTRY) diff --git a/tests/test_unit/core/settings/test_profile.py b/tests/test_unit/core/settings/test_profile.py index f5d9f0b..3a7aa24 100644 --- a/tests/test_unit/core/settings/test_profile.py +++ b/tests/test_unit/core/settings/test_profile.py @@ -1,6 +1,6 @@ -"""Tests for ConnectionProfile — database-flavored DescriptorProfile. +"""Tests for ConnectionProfile — database-flavored Profile. -DescriptorProfile mechanism tests live in mountainash-settings. Here we only +Profile mechanism tests live in mountainash-settings. Here we only exercise the database-specific methods: to_driver_kwargs() and to_connection_string(). """ @@ -12,13 +12,13 @@ from mountainash_data.core.settings.auth import NoAuth, PasswordAuth from mountainash_data.core.settings.descriptor import ( - BackendDescriptor, + BackendSpec, ParameterSpec, ) from mountainash_data.core.settings.profile import ConnectionProfile -DUMMY_DESCRIPTOR = BackendDescriptor( +DUMMY_SPEC = BackendSpec( name="dummy", provider_type="dummy", default_port=9999, @@ -34,7 +34,7 @@ class DummyProfile(ConnectionProfile): - __descriptor__ = DUMMY_DESCRIPTOR + __spec__ = DUMMY_SPEC @pytest.mark.unit @@ -60,7 +60,7 @@ def _adapter(profile): return {"only": "thing"} class Adapted(ConnectionProfile): - __descriptor__ = DUMMY_DESCRIPTOR + __spec__ = DUMMY_SPEC __adapter__ = staticmethod(_adapter) p = Adapted(HOST="h", auth=NoAuth()) @@ -84,13 +84,13 @@ def test_to_connection_string_url_encodes_secrets(self): assert "p%40ss%3Aw%2Ford" in url def test_to_connection_string_no_scheme_raises(self): - desc = BackendDescriptor( + spec = BackendSpec( name="x", provider_type="x", parameters=[], auth_modes=[NoAuth], connection_string_scheme=None, ) class P(ConnectionProfile): - __descriptor__ = desc + __spec__ = spec p = P(auth=NoAuth()) with pytest.raises(NotImplementedError):