diff --git a/.cursor/rules/makefile-commands.md b/.cursor/rules/makefile-commands.md index dbb21c3..f2ed7f6 100644 --- a/.cursor/rules/makefile-commands.md +++ b/.cursor/rules/makefile-commands.md @@ -5,5 +5,5 @@ Some helpful commands have been defined in the `Makefile` already. If the user is confused, point them towards these resources. - `make all` - runs `main.py` -- `make lint` - runs `black` linter, an opinionated linter +- `make fmt` - runs `ruff format` + JSON formatting - `make test` - runs all tests defined by `TEST_TARGETS = tests/folder1 tests/folder2` diff --git a/CLAUDE.md b/CLAUDE.md index b68b1e6..06e8759 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,7 +21,7 @@ make test_slow # Run slow tests only make test_nondeterministic # Run nondeterministic tests only # Code Quality (run after major changes) -make fmt # Run black formatter + JSON formatting +make fmt # Run ruff formatter + JSON formatting make ruff # Run ruff linter make vulture # Find dead code make ty # Run typer type checker diff --git a/Makefile b/Makefile index be82d2b..8720de0 100644 --- a/Makefile +++ b/Makefile @@ -171,24 +171,24 @@ test_flaky: check_uv ## Repeat fast tests to detect flaky tests ######################################################## # Linter will ignore these directories -IGNORE_LINT_DIRS = .venv|venv +IGNORE_LINT_DIRS = .venv venv LINE_LENGTH = 88 +FIND_PRUNE = $(foreach dir,$(IGNORE_LINT_DIRS),-path "./$(dir)" -o) -false ### Code Quality install_tools: check_uv ## Install linting/formatting tools @echo "$(YELLOW)🔧Installing tools...$(RESET)" - @uv tool install black --force @uv tool install ruff --force @uv tool install ty --force @uv tool install vulture --force @echo "$(GREEN)✅Tools installed.$(RESET)" -fmt: install_tools check_jq ## Format code with black and jq - @echo "$(YELLOW)✨Formatting project with Black...$(RESET)" - @uv tool run black --exclude '/($(IGNORE_LINT_DIRS))/' . --line-length $(LINE_LENGTH) +fmt: install_tools check_jq ## Format code with ruff and jq + @echo "$(YELLOW)✨Formatting project with Ruff...$(RESET)" + @uv tool run ruff format @echo "$(YELLOW)✨Formatting JSONs with jq...$(RESET)" @count=0; \ - find . \( $(IGNORE_LINT_DIRS:%=-path './%' -prune -o) \) -type f -name '*.json' -print0 | \ + find . \( $(FIND_PRUNE) \) -prune -o -type f -name '*.json' -print0 | \ while IFS= read -r -d '' file; do \ if jq . "$$file" > "$$file.tmp" 2>/dev/null && mv "$$file.tmp" "$$file"; then \ count=$$((count + 1)); \ diff --git a/README.md b/README.md index ac95f97..6af8942 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Opinionated Python stack for fast development. The `saas` branch extends `main` | Feature | `main` | `saas` | |---------|:------:|:------:| | UV + Pydantic config | ✅ | ✅ | -| CI/Linters (Ruff, Black, Vulture) | ✅ | ✅ | +| CI/Linters (Ruff, Vulture) | ✅ | ✅ | | Pre-commit hooks (prek) | ✅ | ✅ | | LLM (DSPY + LangFuse Observability) | ✅ | ✅ | | FastAPI + Uvicorn | ❌ | ✅ | @@ -55,7 +55,7 @@ Opinionated Python stack for fast development. The `saas` branch extends `main` ## Quick Start - `make all` - runs `main.py` -- `make fmt` - runs `black` linter, an opinionated linter +- `make fmt` - runs `ruff format` + JSON formatting - `make banner` - create a new banner that makes the README nice 😊 - `make test` - runs all tests defined by `TEST_TARGETS = tests/folder1 tests/folder2` @@ -91,4 +91,3 @@ This software uses the following tools: Made with [contrib.rocks](https://contrib.rocks). - diff --git a/docs/package.json b/docs/package.json index 94a2a81..c56f0c9 100644 --- a/docs/package.json +++ b/docs/package.json @@ -34,4 +34,4 @@ "tailwindcss": "^4.1.18", "typescript": "^5.9.3" } -} \ No newline at end of file +} diff --git a/docs/tsconfig.json b/docs/tsconfig.json index 3838223..797119b 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -2,7 +2,11 @@ "compilerOptions": { "baseUrl": ".", "target": "ESNext", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -16,8 +20,12 @@ "jsx": "react-jsx", "incremental": true, "paths": { - "@/*": ["./*"], - "fumadocs-mdx:collections/*": [".source/*"] + "@/*": [ + "./*" + ], + "fumadocs-mdx:collections/*": [ + ".source/*" + ] }, "plugins": [ { @@ -32,5 +40,7 @@ ".next/types/**/*.ts", ".next/dev/types/**/*.ts" ], - "exclude": ["node_modules"] + "exclude": [ + "node_modules" + ] } diff --git a/manual_docs/branch_comparison.md b/manual_docs/branch_comparison.md index 5020950..57280cf 100644 --- a/manual_docs/branch_comparison.md +++ b/manual_docs/branch_comparison.md @@ -25,7 +25,7 @@ This document provides a detailed comparison of features available in the `main` | Feature | `main` | `saas` | Notes | |---------|:------:|:------:|-------| | Ruff linter | ✅ | ✅ | Fast Python linter | -| Black formatter | ✅ | ✅ | Opinionated code formatting | +| Ruff formatter | ✅ | ✅ | Opinionated code formatting | | Vulture dead code detection | ✅ | ✅ | Find unused code | | ty type checker | ✅ | ✅ | Type checking | | GitHub Actions CI | ✅ | ✅ | Automated testing & linting | diff --git a/pyproject.toml b/pyproject.toml index ff2cae7..2b117e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,6 @@ authors = [ { name = "Miyamura80", email = "eitomiyamura@gmail.com" } ] dependencies = [ - "black>=24.8.0", "pyyaml>=6.0.2", "python-dotenv>=1.0.1", "human-id>=0.2.0", diff --git a/tests/healthcheck/test_env_var_loading.py b/tests/healthcheck/test_env_var_loading.py index 628c924..c1b92da 100644 --- a/tests/healthcheck/test_env_var_loading.py +++ b/tests/healthcheck/test_env_var_loading.py @@ -31,7 +31,7 @@ def test_env_var_loading_precedence(monkeypatch): monkeypatch.setenv("OPENAI_API_KEY", "system_openai_key") # 2. Create a temporary .env file - dot_env_content = "DEV_ENV=dotenv\n" "OPENAI_API_KEY=dotenv_openai_key\n" + dot_env_content = "DEV_ENV=dotenv\nOPENAI_API_KEY=dotenv_openai_key\n" with open(dot_env_path, "w") as f: f.write(dot_env_content) @@ -41,12 +41,12 @@ def test_env_var_loading_precedence(monkeypatch): # 4. Assert that the variables are loaded with the correct precedence assert reloaded_config.DEV_ENV == "dotenv", "Should load from .env first" - assert ( - reloaded_config.ANTHROPIC_API_KEY == "system_anthropic_key" - ), "Should fall back to system env" - assert ( - reloaded_config.OPENAI_API_KEY == "dotenv_openai_key" - ), "Should load from .env" + assert reloaded_config.ANTHROPIC_API_KEY == "system_anthropic_key", ( + "Should fall back to system env" + ) + assert reloaded_config.OPENAI_API_KEY == "dotenv_openai_key", ( + "Should load from .env" + ) finally: # Clean up and restore the original .env file if it existed diff --git a/tests/healthcheck/test_pydantic_type_coercion.py b/tests/healthcheck/test_pydantic_type_coercion.py index 0cde858..2c49e3a 100644 --- a/tests/healthcheck/test_pydantic_type_coercion.py +++ b/tests/healthcheck/test_pydantic_type_coercion.py @@ -39,51 +39,51 @@ def test_pydantic_type_coercion(monkeypatch): config = common_module.global_config # type: ignore[attr-defined] # Verify integer coercion - assert isinstance( - config.default_llm.default_max_tokens, int - ), "default_max_tokens should be int" - assert ( - config.default_llm.default_max_tokens == 50000 - ), "default_max_tokens should be 50000" - - assert isinstance( - config.llm_config.retry.max_attempts, int - ), "max_attempts should be int" + assert isinstance(config.default_llm.default_max_tokens, int), ( + "default_max_tokens should be int" + ) + assert config.default_llm.default_max_tokens == 50000, ( + "default_max_tokens should be 50000" + ) + + assert isinstance(config.llm_config.retry.max_attempts, int), ( + "max_attempts should be int" + ) assert config.llm_config.retry.max_attempts == 5, "max_attempts should be 5" - assert isinstance( - config.llm_config.retry.min_wait_seconds, int - ), "min_wait_seconds should be int" + assert isinstance(config.llm_config.retry.min_wait_seconds, int), ( + "min_wait_seconds should be int" + ) assert config.llm_config.retry.min_wait_seconds == 2, "min_wait_seconds should be 2" - assert isinstance( - config.llm_config.retry.max_wait_seconds, int - ), "max_wait_seconds should be int" - assert ( - config.llm_config.retry.max_wait_seconds == 10 - ), "max_wait_seconds should be 10" + assert isinstance(config.llm_config.retry.max_wait_seconds, int), ( + "max_wait_seconds should be int" + ) + assert config.llm_config.retry.max_wait_seconds == 10, ( + "max_wait_seconds should be 10" + ) # Verify float coercion - assert isinstance( - config.default_llm.default_temperature, float - ), "default_temperature should be float" - assert ( - config.default_llm.default_temperature == 0.7 - ), "default_temperature should be 0.7" + assert isinstance(config.default_llm.default_temperature, float), ( + "default_temperature should be float" + ) + assert config.default_llm.default_temperature == 0.7, ( + "default_temperature should be 0.7" + ) # Verify boolean coercion - assert isinstance( - config.llm_config.cache_enabled, bool - ), "cache_enabled should be bool" + assert isinstance(config.llm_config.cache_enabled, bool), ( + "cache_enabled should be bool" + ) assert config.llm_config.cache_enabled is True, "cache_enabled should be True" assert isinstance(config.logging.verbose, bool), "verbose should be bool" assert config.logging.verbose is False, "verbose should be False" assert isinstance(config.logging.format.show_time, bool), "show_time should be bool" - assert ( - config.logging.format.show_time is True - ), "show_time should be True (from '1')" + assert config.logging.format.show_time is True, ( + "show_time should be True (from '1')" + ) assert isinstance(config.logging.levels.debug, bool), "debug should be bool" assert config.logging.levels.debug is True, "debug should be True" diff --git a/tests/test_logging_thread_safety.py b/tests/test_logging_thread_safety.py index 47efc7c..9aef2eb 100644 --- a/tests/test_logging_thread_safety.py +++ b/tests/test_logging_thread_safety.py @@ -43,7 +43,7 @@ def call_setup(): logger_any.remove = original_remove assert not errors, f"Errors during concurrent setup: {errors}" - assert ( - call_count == 1 - ), f"logger.remove() called {call_count} times, expected exactly 1" + assert call_count == 1, ( + f"logger.remove() called {call_count} times, expected exactly 1" + ) assert logging_module._logging_initialized is True diff --git a/uv.lock b/uv.lock index ce06327..4671cfe 100644 --- a/uv.lock +++ b/uv.lock @@ -1688,7 +1688,6 @@ name = "python-template" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "black" }, { name = "dspy" }, { name = "google-genai" }, { name = "human-id" }, @@ -1712,7 +1711,6 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "black", specifier = ">=24.8.0" }, { name = "dspy", specifier = ">=2.6.24" }, { name = "google-genai", specifier = ">=1.15.0" }, { name = "human-id", specifier = ">=0.2.0" },