Skip to content
Merged
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
29 changes: 0 additions & 29 deletions .github/workflows/test.yml

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ htmlcov
.idea
.vscode
*.swp

logs
36 changes: 24 additions & 12 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ Run the CLI: `uv run brix --help`
uv run pre-commit run --all-files
```

This runs ruff linting, ruff formatting, type checking, and tests. The CI will fail if formatting is not applied.

## Code Style

- Python 3.10+, strict type hints required (ANN rules enforced)
Expand All @@ -38,19 +36,33 @@ This runs ruff linting, ruff formatting, type checking, and tests. The CI will f
- Ruff handles linting and formatting
- ty for type checking (src-layout aware via `tool.ty.environment.root`)

## Project Structure
## Architecture

- `src/brix/` - Main package (src-layout)
- `tests/unit/` - Unit tests (mocked, isolated)
- `tests/integration/` - Integration tests (require dbt, marked with `@pytest.mark.integration`)
- `tests/fixtures/` - Test fixtures (e.g., minimal dbt project for integration tests)
### Layer Separation

## Architecture
```
commands/ CLI layer (Typer) - argument parsing, output, errors
└── dbt/
└── profile.py
modules/ Business logic layer - reusable, CLI-independent
└── dbt/
└── profile/
├── service.py # Core operations, configuration
├── editor.py # CRUD operations
├── models.py # Pydantic models
└── prompts.py # Interactive questionary prompts
```

### Key Patterns

**dbt Passthrough**: Custom `DbtGroup` class in `commands/dbt/__init__.py` intercepts unknown commands and passes them to the dbt CLI. This allows `brix dbt run` to execute `dbt run` while `brix dbt profile` is handled by brix.

**Profile Models** (`modules/dbt/profile/models.py`): Pydantic models with discriminated unions for adapter types (DuckDB, Databricks). `DbtProfiles` provides YAML serialization via `from_yaml()`/`to_yaml()`.

**CLI Entry Point** (`main.py`): Typer-based CLI with global callback pattern. Global options (--version, --log-level, --log-path, --log-json) are processed before subcommands. Add new commands via `@app.command()` decorators.
**Template System** (`templates/`): Bundled files loaded via `importlib.resources`. Use `get_template(name)` to load content.

**Logging System** (`utils/logging.py`): Terraform-style logging with environment variables (`BRIX_LOG`, `BRIX_LOG_PATH`, `BRIX_LOG_JSON`) and CLI flag overrides. Uses thread-safe singleton pattern. Call `get_logger()` from any module to access the logger.
**Configuration**: Uses `pydantic-settings` with `BRIX_` prefix (e.g., `BRIX_DBT_PROFILE_PATH`). CLI arguments override environment variables.

**Configuration Pattern**: Uses `pydantic-settings` for env var parsing with `BRIX_` prefix. CLI arguments override environment variables.
**Logging** (`utils/logging.py`): Terraform-style with env vars (`BRIX_LOG`, `BRIX_LOG_PATH`, `BRIX_LOG_JSON`). Thread-safe singleton; use `get_logger()` from any module.

**Version Checking** (`version_check.py`): Non-blocking update checker using background threads. Caches results to `~/.cache/brix/` with 24-hour TTL.
**Version Checking** (`version_check.py`): Non-blocking background thread with 24-hour cache in `~/.cache/brix/`.
38 changes: 17 additions & 21 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ version = "1.0.1"
description = "Add your description here"
readme = "README.md"
license = "MIT"
authors = [
{ name = "Kraus, Pascal", email = "pascal.kraus@outlook.com" }
]
authors = [{ name = "Kraus, Pascal", email = "pascal.kraus@outlook.com" }]
requires-python = ">=3.10"
dependencies = [
"httpx>=0.28.1",
"pydantic>=2.12.5",
"pydantic-settings>=2.12.0",
"questionary>=2.1.1",
"typer>=0.20.0",
]

Expand All @@ -25,6 +24,7 @@ build-backend = "hatchling.build"
[dependency-groups]
dev = [
"dbt-core>=1.9.0",
"dbt-databricks>=1.11.0",
"dbt-duckdb>=1.9.0",
"poethepoet>=0.38.0",
"pre-commit>=4.5.0",
Expand All @@ -38,37 +38,32 @@ dev = [

[tool.ruff]
target-version = "py310"
exclude = [
".git",
"dist",
]
exclude = [".git", "dist"]

line-length = 120
indent-width = 4

[tool.ruff.lint]
select = [
"E", # PEP8 code-style
"N", # naming conventions
"F", # pyflakes
"I", # isort
"B", # bugbear
"S", # security issues
"UP", # pyupgrade
"E", # PEP8 code-style
"N", # naming conventions
"F", # pyflakes
"I", # isort
"B", # bugbear
"S", # security issues
"UP", # pyupgrade
"C90", # function complexity check
"PTH", # pythlib nagger
"SIM", # simplifications
"D", # pydocstyle
"PT", # pytest pyflakes
"D", # pydocstyle
"PT", # pytest pyflakes
"ANN", # enforce type hints
"RUF", # ruff rules
"T20", # flag prints
"C4", # comprehensions
"W", # pycodestyle warnings
]
ignore = [
"E501"
"C4", # comprehensions
"W", # pycodestyle warnings
]
ignore = ["E501"]

fixable = ["ALL"]
unfixable = ["B"]
Expand Down Expand Up @@ -122,6 +117,7 @@ test = "pytest"
test-unit = "pytest tests/unit"
test-integration = "pytest tests/integration -m integration"
check = ["lint", "typecheck"]
pre-commit = "pre-commit run --all-files"

[tool.semantic_release]
version_toml = ["pyproject.toml:project.version"]
Expand Down
2 changes: 2 additions & 0 deletions src/brix/commands/dbt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import typer
from typer.core import TyperGroup

from brix.commands.dbt.profile import app as profile_app
from brix.modules.dbt import run_dbt


Expand Down Expand Up @@ -40,6 +41,7 @@ def invoke(self, ctx: click.Context) -> None:
invoke_without_command=True,
context_settings={"allow_extra_args": True, "ignore_unknown_options": True, "help_option_names": ["-h", "--help"]},
)
app.add_typer(profile_app, name="profile")


@app.callback()
Expand Down
Loading