Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .github/scripts/gen_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ def main() -> int:
m = COMMIT_RE.match(subj)
if not m:
continue
typ, scope, bang, desc = (m.group("type"), m.group("scope"), m.group("bang"), m.group("desc"))
typ, scope, bang, desc = (
m.group("type"),
m.group("scope"),
m.group("bang"),
m.group("desc"),
)
# Release/CI plumbing is never user-facing: drop it even when a commit is
# mis-typed as feat/fix (e.g. `fix(ci): ...`) instead of `ci: ...`.
if scope in ("ci", "release"):
Expand All @@ -72,9 +77,7 @@ def main() -> int:
buckets[typ].append(bullet)

if prev_tag:
header = (
f"## [{new_version}]({repo_url}/compare/{prev_tag}...v{new_version}) ({date})\n"
)
header = f"## [{new_version}]({repo_url}/compare/{prev_tag}...v{new_version}) ({date})\n"
else:
header = f"## {new_version} ({date})\n"

Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ jobs:
- name: Install dependencies
run: poetry install --no-interaction

- name: Type check
run: poetry run type-check

- name: Check formatting (black)
run: poetry run black --check --line-length=100 .

- name: Lint (ruff)
run: poetry run ruff check .

- name: Run unit tests
run: poetry run test-unit

Expand Down
8 changes: 5 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,23 @@ repos:
- id: mixed-line-ending
args: ['--fix=lf']

# black / ruff / mypy revs are pinned to the SAME versions as pyproject.toml's dev
# dependencies (see the comment there) — bump them together.
- repo: https://github.com/psf/black
rev: 24.10.0
rev: 25.12.0
hooks:
- id: black
language_version: python3
args: ['--line-length=100']

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
rev: v0.16.3
hooks:
- id: ruff
args: [--fix, --unsafe-fixes, --exit-non-zero-on-fix]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.15.0
rev: v1.19.1
hooks:
- id: mypy
args: [--show-error-codes, --pretty, --explicit-package-bases]
Expand Down
11 changes: 5 additions & 6 deletions parrant/artifacts/adapter_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"""

import logging
from typing import Dict, Optional, Set

logger = logging.getLogger(__name__)

Expand All @@ -27,7 +26,7 @@
# bigquery, redshift, databricks, postgres, duckdb, spark, trino, presto,
# athena, clickhouse, ...) an explicit identity entry is optional -- the
# fallthrough in normalize_adapter returns the lowercased name unchanged.
ADAPTER_TO_DIALECT: Dict[str, str] = {
ADAPTER_TO_DIALECT: dict[str, str] = {
# --- adapters whose dbt name differs from the sqlglot dialect name ---
# The T-SQL family: dbt reports sqlserver/synapse/fabric, sqlglot uses "tsql".
"sqlserver": "tsql",
Expand All @@ -47,7 +46,7 @@
}


def _known_sqlglot_dialects() -> Set[str]:
def _known_sqlglot_dialects() -> set[str]:
"""Return the set of dialect names sqlglot actually supports.

Derived from sqlglot at runtime so the check stays correct as sqlglot is
Expand All @@ -62,14 +61,14 @@ def _known_sqlglot_dialects() -> Set[str]:
return set()


_KNOWN_DIALECTS: Set[str] = _known_sqlglot_dialects()
_KNOWN_DIALECTS: set[str] = _known_sqlglot_dialects()

# Track adapters we have already warned about so the warning fires once per
# unresolved adapter instead of on every column parsed.
_warned_adapters: Set[str] = set()
_warned_adapters: set[str] = set()


def normalize_adapter(adapter_name: Optional[str]) -> Optional[str]:
def normalize_adapter(adapter_name: str | None) -> str | None:
"""Normalize a dbt adapter name to a sqlglot dialect name.

If adapter_name is None or empty, returns it unchanged.
Expand Down
9 changes: 5 additions & 4 deletions parrant/artifacts/catalog.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
from pathlib import Path
from typing import Dict, Any
import json
from pathlib import Path
from typing import Any

from parrant.models.schema import Model


class CatalogReader:
def __init__(self, catalog_path: str):
self.catalog_path = Path(catalog_path)
self.catalog: Dict[str, Any] = {}
self.catalog: dict[str, Any] = {}

def load(self) -> None:
if not self.catalog_path.exists():
raise FileNotFoundError(f"Catalog file not found: {self.catalog_path}")
with open(self.catalog_path, "r") as f:
self.catalog = json.load(f)

def get_models_nodes(self) -> Dict[str, Model]:
def get_models_nodes(self) -> dict[str, Model]:
models = {}
nodes = self.catalog.get("nodes", {})
sources = self.catalog.get("sources", {})
Expand Down
7 changes: 3 additions & 4 deletions parrant/artifacts/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
class RegistryError(Exception):
"""Base exception for all registry-related errors."""
pass


class ModelNotFoundError(RegistryError):
"""Raised when a requested model is not found."""
pass


class RegistryNotLoadedError(RegistryError):
"""Raised when trying to access registry before loading data."""
pass


class RegistryLoadError(Exception):
"""Base exception for registry loading errors."""
pass
Loading
Loading