refactor(config_flow): restructure package to satisfy hassfest validation

Home Assistant's hassfest validation requires config flows to be defined
in a file named config_flow.py (not a package directory).

Changes:
- Renamed custom_components/tibber_prices/config_flow/ → config_flow_handlers/
- Created config_flow.py as bridge file re-exporting from config_flow_handlers/
- Updated all import paths across 5 files (user_flow, options_flow, subentry_flow, etc.)
- Added ./scripts/hassfest for local validation (JSON/Python syntax, required files)
- Added ./scripts/clean with three modes (--minimal, normal, --deep)
- Refactored develop/lint/lint-check to use centralized cleanup (DRY principle)
- Updated documentation in AGENTS.md and docs/development/

Technical details:
- Bridge file uses __all__ exports to maintain clean public API
- hassfest script uses ast.parse() for syntax validation (no disk artifacts)
- clean --minimal removes .egg-info only (silent, for automated scripts)
- Dual pip/uv pip compatibility for package uninstallation

Impact: Integration now passes hassfest validation. Local validation available
via ./scripts/hassfest before pushing to GitHub. Cleanup logic centralized and
DRY across all development scripts.
This commit is contained in:
Julian Pawlowski 2025-11-15 17:40:53 +00:00
parent decca432df
commit 503075c443
17 changed files with 367 additions and 50 deletions

View file

@ -435,6 +435,15 @@ If you notice commands failing or missing dependencies:
```bash ```bash
./scripts/develop # Starts HA in debug mode with config/ dir, sets PYTHONPATH ./scripts/develop # Starts HA in debug mode with config/ dir, sets PYTHONPATH
# Automatically runs minimal cleanup (.egg-info only)
```
**Clean up artifacts:**
```bash
./scripts/clean # Remove build artifacts, caches (pytest, ruff, coverage)
./scripts/clean --deep # Also remove __pycache__ (normally not needed)
./scripts/clean --minimal # Only critical issues (.egg-info) - used by develop
``` ```
**Linting (auto-fix):** **Linting (auto-fix):**
@ -449,6 +458,14 @@ If you notice commands failing or missing dependencies:
./scripts/lint-check # CI mode, no modifications ./scripts/lint-check # CI mode, no modifications
``` ```
**Local validation:**
```bash
./scripts/hassfest # Lightweight local integration validation
```
Note: The local `hassfest` script performs basic validation checks (JSON syntax, required files, Python syntax). Full hassfest validation runs in GitHub Actions.
**Testing:** **Testing:**
```bash ```bash
@ -1044,19 +1061,17 @@ cargo install git-cliff # or download binary from releases
- **Markdown**: Standard GitHub-flavored Markdown supported - **Markdown**: Standard GitHub-flavored Markdown supported
- **HTML**: Can include `<ha-alert>` tags for special notices (HA update entities only) - **HTML**: Can include `<ha-alert>` tags for special notices (HA update entities only)
**Validate JSON files:** **Validate integration:**
```bash ```bash
# After editing translation files, validate syntax (ruff doesn't check JSON) # Run local validation (checks JSON syntax, Python syntax, required files)
python -m json.tool custom_components/tibber_prices/translations/de.json > /dev/null ./scripts/hassfest
# Or validate all translation files at once: # Or validate JSON files manually if needed:
for f in custom_components/tibber_prices/translations/*.json; do python -m json.tool custom_components/tibber_prices/translations/de.json > /dev/null
python -m json.tool "$f" > /dev/null && echo "✓ $f" || echo "✗ INVALID: $f"
done
``` ```
**Why:** `ruff` only formats/lints Python code. JSON syntax errors (trailing commas, missing quotes) will cause HA to fail at runtime with cryptic error messages. Always validate JSON after manual edits. **Why:** The `./scripts/hassfest` script validates JSON syntax (translations, manifest), Python syntax, and required files. This catches common errors before pushing to GitHub Actions. For quick JSON-only checks, you can still use `python -m json.tool` directly.
## Linting Best Practices ## Linting Best Practices
@ -1071,28 +1086,43 @@ done
Calling `ruff` or `uv run ruff` directly can cause unintended side effects: Calling `ruff` or `uv run ruff` directly can cause unintended side effects:
- May install the integration as a Python package (creates `__pycache__`, `.egg-info`, etc.) - May install the integration as a Python package (creates `.egg-info`, etc.)
- HA will then load the **installed** version instead of the **development** version from `custom_components/` - HA will then load the **installed** version instead of the **development** version from `custom_components/`
- Causes confusing behavior where code changes don't take effect - Causes confusing behavior where code changes don't take effect
**About `__pycache__` directories:**
- **Normal and expected** when Home Assistant runs - this is Python's bytecode cache for faster loading
- **Not a problem** in development - speeds up HA startup
- **Already in `.gitignore`** - won't be committed
- **Only problematic** if the package gets installed in `.venv` (then HA loads installed version, not dev version)
- `./scripts/develop`, `./scripts/lint`, and `./scripts/lint-check` automatically clean up accidental installations
**Exception:** If you need to run `ruff` with custom flags not supported by our scripts: **Exception:** If you need to run `ruff` with custom flags not supported by our scripts:
1. Run your custom `ruff` command 1. Run your custom `ruff` command
2. **Immediately after**, clean up any installation artifacts: 2. **Immediately after**, clean up any installation artifacts:
```bash ```bash
# Remove any accidentally installed package # Use our cleanup script (uses both pip and uv pip for compatibility)
uv pip uninstall tibber_prices 2>/dev/null || true ./scripts/clean --minimal
# Clean up cache and build artifacts # Or manually:
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true pip uninstall -y tibber_prices 2>/dev/null || true
find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true uv pip uninstall tibber_prices 2>/dev/null || true
``` ```
3. Ask user to restart HA: `./scripts/develop` 3. Ask user to restart HA: `./scripts/develop`
**When in doubt:** Stick to `./scripts/lint` - it's tested and safe. **When in doubt:** Stick to `./scripts/lint` - it's tested and safe.
**Note on pip vs. uv pip:**
- `scripts/clean` uses **both** `pip` and `uv pip` for maximum compatibility
- Regular `pip uninstall` has cleaner output (no "Using Python X.Y..." messages)
- `uv pip uninstall` is used as fallback for robustness
- Both are needed because different commands may install via different methods
**Key commands:** **Key commands:**
- Dev container includes `hass` CLI for manual HA operations - Dev container includes `hass` CLI for manual HA operations

View file

@ -0,0 +1,52 @@
"""
Config flow for Tibber Prices integration.
This module serves as the entry point for Home Assistant's config flow discovery.
The actual implementation is in the config_flow_handlers package.
"""
from __future__ import annotations
from .config_flow_handlers.options_flow import (
TibberPricesOptionsFlowHandler as OptionsFlowHandler,
)
from .config_flow_handlers.schemas import (
get_best_price_schema,
get_options_init_schema,
get_peak_price_schema,
get_price_rating_schema,
get_price_trend_schema,
get_reauth_confirm_schema,
get_select_home_schema,
get_subentry_init_schema,
get_user_schema,
get_volatility_schema,
)
from .config_flow_handlers.subentry_flow import (
TibberPricesSubentryFlowHandler as SubentryFlowHandler,
)
from .config_flow_handlers.user_flow import TibberPricesFlowHandler as ConfigFlow
from .config_flow_handlers.validators import (
CannotConnectError,
InvalidAuthError,
validate_api_token,
)
__all__ = [
"CannotConnectError",
"ConfigFlow",
"InvalidAuthError",
"OptionsFlowHandler",
"SubentryFlowHandler",
"get_best_price_schema",
"get_options_init_schema",
"get_peak_price_schema",
"get_price_rating_schema",
"get_price_trend_schema",
"get_reauth_confirm_schema",
"get_select_home_schema",
"get_subentry_init_schema",
"get_user_schema",
"get_volatility_schema",
"validate_api_token",
]

View file

@ -3,10 +3,10 @@
from __future__ import annotations from __future__ import annotations
# Phase 3: Import flow handlers from their new modular structure # Phase 3: Import flow handlers from their new modular structure
from custom_components.tibber_prices.config_flow.options_flow import ( from custom_components.tibber_prices.config_flow_handlers.options_flow import (
TibberPricesOptionsFlowHandler, TibberPricesOptionsFlowHandler,
) )
from custom_components.tibber_prices.config_flow.schemas import ( from custom_components.tibber_prices.config_flow_handlers.schemas import (
get_best_price_schema, get_best_price_schema,
get_options_init_schema, get_options_init_schema,
get_peak_price_schema, get_peak_price_schema,
@ -18,13 +18,13 @@ from custom_components.tibber_prices.config_flow.schemas import (
get_user_schema, get_user_schema,
get_volatility_schema, get_volatility_schema,
) )
from custom_components.tibber_prices.config_flow.subentry_flow import ( from custom_components.tibber_prices.config_flow_handlers.subentry_flow import (
TibberPricesSubentryFlowHandler, TibberPricesSubentryFlowHandler,
) )
from custom_components.tibber_prices.config_flow.user_flow import ( from custom_components.tibber_prices.config_flow_handlers.user_flow import (
TibberPricesFlowHandler, TibberPricesFlowHandler,
) )
from custom_components.tibber_prices.config_flow.validators import ( from custom_components.tibber_prices.config_flow_handlers.validators import (
CannotConnectError, CannotConnectError,
InvalidAuthError, InvalidAuthError,
validate_api_token, validate_api_token,

View file

@ -4,7 +4,7 @@ from __future__ import annotations
from typing import Any, ClassVar from typing import Any, ClassVar
from custom_components.tibber_prices.config_flow.schemas import ( from custom_components.tibber_prices.config_flow_handlers.schemas import (
get_best_price_schema, get_best_price_schema,
get_options_init_schema, get_options_init_schema,
get_peak_price_schema, get_peak_price_schema,

View file

@ -4,7 +4,7 @@ from __future__ import annotations
from typing import Any from typing import Any
from custom_components.tibber_prices.config_flow.schemas import ( from custom_components.tibber_prices.config_flow_handlers.schemas import (
get_select_home_schema, get_select_home_schema,
get_subentry_init_schema, get_subentry_init_schema,
) )

View file

@ -4,18 +4,18 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from custom_components.tibber_prices.config_flow.options_flow import ( from custom_components.tibber_prices.config_flow_handlers.options_flow import (
TibberPricesOptionsFlowHandler, TibberPricesOptionsFlowHandler,
) )
from custom_components.tibber_prices.config_flow.schemas import ( from custom_components.tibber_prices.config_flow_handlers.schemas import (
get_reauth_confirm_schema, get_reauth_confirm_schema,
get_select_home_schema, get_select_home_schema,
get_user_schema, get_user_schema,
) )
from custom_components.tibber_prices.config_flow.subentry_flow import ( from custom_components.tibber_prices.config_flow_handlers.subentry_flow import (
TibberPricesSubentryFlowHandler, TibberPricesSubentryFlowHandler,
) )
from custom_components.tibber_prices.config_flow.validators import ( from custom_components.tibber_prices.config_flow_handlers.validators import (
CannotConnectError, CannotConnectError,
InvalidAuthError, InvalidAuthError,
validate_api_token, validate_api_token,

View file

@ -64,18 +64,21 @@ If you're working with AI tools on this project, the [`AGENTS.md`](../../AGENTS.
4. **Start development environment**: `./scripts/develop` 4. **Start development environment**: `./scripts/develop`
5. **Make your changes** following the [Coding Guidelines](coding-guidelines.md) 5. **Make your changes** following the [Coding Guidelines](coding-guidelines.md)
6. **Run linting**: `./scripts/lint` 6. **Run linting**: `./scripts/lint`
7. **Test your changes** in the running Home Assistant instance 7. **Validate integration**: `./scripts/hassfest`
8. **Commit using Conventional Commits** format 8. **Test your changes** in the running Home Assistant instance
9. **Open a Pull Request** with clear description 9. **Commit using Conventional Commits** format
10. **Open a Pull Request** with clear description
## 🛠️ Development Tools ## 🛠️ Development Tools
The project includes several helper scripts in `./scripts/`: The project includes several helper scripts in `./scripts/`:
- `bootstrap` - Initial setup of dependencies - `bootstrap` - Initial setup of dependencies
- `develop` - Start Home Assistant in debug mode - `develop` - Start Home Assistant in debug mode (auto-cleans .egg-info)
- `clean` - Remove build artifacts and caches
- `lint` - Auto-fix code issues with ruff - `lint` - Auto-fix code issues with ruff
- `lint-check` - Check code without modifications (CI mode) - `lint-check` - Check code without modifications (CI mode)
- `hassfest` - Validate integration structure (JSON, Python syntax, required files)
- `setup` - Install development tools (git-cliff, @github/copilot) - `setup` - Install development tools (git-cliff, @github/copilot)
- `prepare-release` - Prepare a new release (bump version, create tag) - `prepare-release` - Prepare a new release (bump version, create tag)
- `generate-release-notes` - Generate release notes from commits - `generate-release-notes` - Generate release notes from commits
@ -132,6 +135,9 @@ custom_components/tibber_prices/
## 🧪 Testing ## 🧪 Testing
```bash ```bash
# Validate integration structure
./scripts/hassfest
# Run all tests # Run all tests
pytest tests/ pytest tests/

View file

@ -4,14 +4,16 @@
## Code Style ## Code Style
- **Formatter/Linter**: Ruff (replaces Black, Flake8, isort) - **Formatter/Linter**: Ruff (replaces Black, Flake8, isort)
- **Max line length**: 120 characters - **Max line length**: 120 characters
- **Max complexity**: 25 (McCabe) - **Max complexity**: 25 (McCabe)
- **Target**: Python 3.13 - **Target**: Python 3.13
Run before committing: Run before committing:
```bash ```bash
./scripts/lint ./scripts/lint # Auto-fix issues
./scripts/hassfest # Validate integration structure
``` ```
## Import Order ## Import Order
@ -23,7 +25,9 @@ Run before committing:
## Critical Patterns ## Critical Patterns
### Time Handling ### Time Handling
Always use `dt_util` from `homeassistant.util`: Always use `dt_util` from `homeassistant.util`:
```python ```python
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
@ -33,6 +37,7 @@ now = dt_util.now()
``` ```
### Translation Loading ### Translation Loading
```python ```python
# In __init__.py async_setup_entry: # In __init__.py async_setup_entry:
await async_load_translations(hass, "en") await async_load_translations(hass, "en")
@ -40,7 +45,9 @@ await async_load_standard_translations(hass, "en")
``` ```
### Price Data Enrichment ### Price Data Enrichment
Always enrich raw API data: Always enrich raw API data:
```python ```python
from .price_utils import enrich_price_info_with_differences from .price_utils import enrich_price_info_with_differences

View file

@ -4,9 +4,9 @@
## Prerequisites ## Prerequisites
- VS Code with Dev Container support - VS Code with Dev Container support
- Docker installed and running - Docker installed and running
- GitHub account (for Tibber API token) - GitHub account (for Tibber API token)
## Quick Setup ## Quick Setup
@ -25,11 +25,12 @@ code .
## Development Environment ## Development Environment
The DevContainer includes: The DevContainer includes:
- Python 3.13 with `.venv` at `/home/vscode/.venv/`
- `uv` package manager (fast, modern Python tooling) - Python 3.13 with `.venv` at `/home/vscode/.venv/`
- Home Assistant development dependencies - `uv` package manager (fast, modern Python tooling)
- Ruff linter/formatter - Home Assistant development dependencies
- Git, GitHub CLI, Node.js, Rust toolchain - Ruff linter/formatter
- Git, GitHub CLI, Node.js, Rust toolchain
## Running the Integration ## Running the Integration
@ -48,6 +49,9 @@ Visit http://localhost:8123
# Check-only (CI mode) # Check-only (CI mode)
./scripts/lint-check ./scripts/lint-check
# Validate integration structure
./scripts/hassfest
``` ```
See [`AGENTS.md`](../../AGENTS.md) for detailed patterns and conventions. See [`AGENTS.md`](../../AGENTS.md) for detailed patterns and conventions.

View file

@ -2,6 +2,24 @@
> **Note:** This guide is under construction. > **Note:** This guide is under construction.
## Integration Validation
Before running tests or committing changes, validate the integration structure:
```bash
# Run local validation (JSON syntax, Python syntax, required files)
./scripts/hassfest
```
This lightweight script checks:
- ✓ `config_flow.py` exists
- ✓ `manifest.json` is valid JSON with required fields
- ✓ Translation files have valid JSON syntax
- ✓ All Python files compile without syntax errors
**Note:** Full hassfest validation runs in GitHub Actions on push.
## Running Tests ## Running Tests
```bash ```bash
@ -23,10 +41,11 @@ pytest --cov=custom_components.tibber_prices tests/
``` ```
Then test in Home Assistant UI: Then test in Home Assistant UI:
- Configuration flow
- Sensor states and attributes - Configuration flow
- Services - Sensor states and attributes
- Translation strings - Services
- Translation strings
## Test Guidelines ## Test Guidelines

89
scripts/clean Executable file
View file

@ -0,0 +1,89 @@
#!/usr/bin/env bash
# script/clean: Clean up development artifacts and caches
# Usage:
# ./scripts/clean # Standard cleanup (recommended)
# ./scripts/clean --deep # Also remove __pycache__
# ./scripts/clean --minimal # Only critical issues (.egg-info)
set -e
cd "$(dirname "$0")/.."
MINIMAL_MODE=false
DEEP_MODE=false
if [ "$1" = "--minimal" ]; then
MINIMAL_MODE=true
elif [ "$1" = "--deep" ]; then
DEEP_MODE=true
fi
if [ "$MINIMAL_MODE" = false ]; then
echo "==> Cleaning development artifacts..."
fi
# Clean up accidental package installation (always, even in minimal mode)
if [ -d "tibber_prices.egg-info" ]; then
if [ "$MINIMAL_MODE" = false ]; then
echo " → Removing tibber_prices.egg-info"
fi
rm -rf tibber_prices.egg-info
fi
# Uninstall if accidentally installed (always, even in minimal mode)
# Try both pip and uv pip for maximum compatibility
PACKAGE_INSTALLED=false
if pip show tibber_prices >/dev/null 2>&1 || uv pip show tibber_prices >/dev/null 2>&1; then
PACKAGE_INSTALLED=true
if [ "$MINIMAL_MODE" = false ]; then
echo " → Uninstalling accidentally installed package"
fi
# Use regular pip (cleaner output, always works in venv)
pip uninstall -y tibber_prices >/dev/null 2>&1 || true
# Also try uv pip as fallback
uv pip uninstall tibber_prices >/dev/null 2>&1 || true
fi
# Exit early if minimal mode
if [ "$MINIMAL_MODE" = true ]; then
exit 0
fi
# Clean pytest cache
if [ -d ".pytest_cache" ]; then
echo " → Removing .pytest_cache"
rm -rf .pytest_cache
fi
# Clean coverage files
if [ -f ".coverage" ]; then
echo " → Removing .coverage"
rm -f .coverage
fi
if [ -f "coverage.xml" ]; then
echo " → Removing coverage.xml"
rm -f coverage.xml
fi
# Clean ruff cache
if [ -d ".ruff_cache" ]; then
echo " → Removing .ruff_cache"
rm -rf .ruff_cache
fi
# Optional: Clean __pycache__ (normally not needed, but useful for troubleshooting)
if [ "$DEEP_MODE" = true ]; then
echo " → Deep clean: Removing all __pycache__ directories"
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
echo " → Deep clean: Removing all .pyc files"
find . -type f -name "*.pyc" -delete 2>/dev/null || true
fi
echo ""
echo "==> Cleanup complete!"
if [ "$DEEP_MODE" = false ]; then
echo ""
echo "Tip: Use './scripts/clean --deep' to also remove __pycache__ directories"
echo " (normally not needed - __pycache__ speeds up Home Assistant startup)"
fi

View file

@ -10,6 +10,10 @@ if [ -z "$VIRTUAL_ENV" ]; then
. "$HOME/.venv/bin/activate" . "$HOME/.venv/bin/activate"
fi fi
# Clean up critical issues (accidental package installations)
# Uses minimal mode to avoid deleting useful caches
"$(dirname "$0")/clean" --minimal
# Create config dir if not present # Create config dir if not present
if [ ! -d "${PWD}/config" ]; then if [ ! -d "${PWD}/config" ]; then
mkdir -p "${PWD}/config" mkdir -p "${PWD}/config"

106
scripts/hassfest Executable file
View file

@ -0,0 +1,106 @@
#!/usr/bin/env bash
# script/hassfest: Lightweight local validation for Home Assistant integration
# Note: This is a simplified version. Full hassfest runs in GitHub Actions.
set -e
cd "$(dirname "$0")/.."
INTEGRATION_PATH="custom_components/tibber_prices"
ERRORS=0
echo "==> Running local integration validation..."
echo ""
# Check 1: config_flow.py exists
echo "✓ Checking config_flow.py existence..."
if [ ! -f "$INTEGRATION_PATH/config_flow.py" ]; then
echo " ✗ ERROR: config_flow.py not found"
ERRORS=$((ERRORS + 1))
else
echo " ✓ config_flow.py exists"
fi
# Check 2: manifest.json syntax
echo "✓ Checking manifest.json syntax..."
if ! python -m json.tool "$INTEGRATION_PATH/manifest.json" > /dev/null 2>&1; then
echo " ✗ ERROR: manifest.json has invalid JSON syntax"
ERRORS=$((ERRORS + 1))
else
echo " ✓ manifest.json is valid JSON"
fi
# Check 3: Translation files syntax
echo "✓ Checking translation files syntax..."
for lang_file in "$INTEGRATION_PATH"/translations/*.json; do
if [ -f "$lang_file" ]; then
lang=$(basename "$lang_file")
if ! python -m json.tool "$lang_file" > /dev/null 2>&1; then
echo " ✗ ERROR: $lang has invalid JSON syntax"
ERRORS=$((ERRORS + 1))
else
echo " ✓ $lang is valid JSON"
fi
fi
done
# Check 4: Custom translation files syntax
if [ -d "$INTEGRATION_PATH/custom_translations" ]; then
echo "✓ Checking custom translation files syntax..."
for lang_file in "$INTEGRATION_PATH"/custom_translations/*.json; do
if [ -f "$lang_file" ]; then
lang=$(basename "$lang_file")
if ! python -m json.tool "$lang_file" > /dev/null 2>&1; then
echo " ✗ ERROR: custom_translations/$lang has invalid JSON syntax"
ERRORS=$((ERRORS + 1))
else
echo " ✓ custom_translations/$lang is valid JSON"
fi
fi
done
fi
# Check 5: Python syntax
# Note: We use ast.parse() instead of py_compile to avoid creating __pycache__ artifacts
# ast.parse() validates syntax without writing any files to disk
echo "✓ Checking Python syntax..."
PYTHON_ERRORS=0
while IFS= read -r py_file; do
if ! python -c "import ast; ast.parse(open('$py_file').read())" 2>/dev/null; then
echo " ✗ ERROR: $py_file has syntax errors"
PYTHON_ERRORS=$((PYTHON_ERRORS + 1))
ERRORS=$((ERRORS + 1))
fi
done < <(find "$INTEGRATION_PATH" -name "*.py" -type f)
if [ $PYTHON_ERRORS -eq 0 ]; then
echo " ✓ All Python files have valid syntax"
fi
# Check 6: Required manifest fields
echo "✓ Checking required manifest fields..."
REQUIRED_FIELDS=("domain" "name" "version" "documentation" "issue_tracker" "codeowners")
for field in "${REQUIRED_FIELDS[@]}"; do
if ! python -c "import json; data=json.load(open('$INTEGRATION_PATH/manifest.json')); exit(0 if '$field' in data else 1)" 2>/dev/null; then
echo " ✗ ERROR: manifest.json missing required field: $field"
ERRORS=$((ERRORS + 1))
fi
done
if [ $ERRORS -eq 0 ]; then
echo " ✓ All required manifest fields present"
fi
echo ""
if [ $ERRORS -eq 0 ]; then
echo "==> ✓ All local validation checks passed!"
echo ""
echo "Note: Full hassfest validation runs in GitHub Actions."
echo " Push your changes to run complete validation."
exit 0
else
echo "==> ✗ Found $ERRORS error(s)"
echo ""
echo "Note: This is a simplified local validation."
echo " Full hassfest validation runs in GitHub Actions."
exit 1
fi

View file

@ -18,7 +18,7 @@ uv run --active ruff format .
echo "==> Running Ruff check..." echo "==> Running Ruff check..."
uv run --active ruff check . --fix uv run --active ruff check . --fix
# Uninstall editable package to avoid conflicts with Home Assistant # Clean up any accidental package installation from uv run
pip uninstall -y tibber_prices >/dev/null 2>&1 || true "$(dirname "$0")/clean" --minimal
echo "==> Linting completed!" echo "==> Linting completed!"

View file

@ -16,7 +16,7 @@ uv run --active ruff format . --check
echo "==> Checking code with Ruff..." echo "==> Checking code with Ruff..."
uv run --active ruff check . uv run --active ruff check .
# Uninstall editable package to avoid conflicts with Home Assistant # Clean up any accidental package installation from uv run
pip uninstall -y tibber_prices >/dev/null 2>&1 || true "$(dirname "$0")/clean" --minimal
echo "==> Linting check completed!" echo "==> Linting check completed!"