Add detailed step-by-step implementation plan for migrating from .env to YAML configuration using pydantic-yaml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
10 KiB
YAML Configuration Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Migrate FastAPI configuration from .env to YAML using pydantic-yaml
Architecture: Create new config/ module with YAML-based settings using pydantic-yaml, preserving type validation and improving readability through nested configuration structure.
Tech Stack: pydantic-yaml, pyyaml, pytest
Task 1: Add pydantic-yaml Dependency
Files:
- Modify:
requirements.txt
Step 1: Add pydantic-yaml to requirements.txt
Add this line to requirements.txt:
pydantic-yaml>=0.12.0
Step 2: Install the dependency
Run: .venv/Scripts/pip install pydantic-yaml
Expected: Successfully installs pydantic-yaml and its dependencies
Step 3: Verify installation
Run: .venv/Scripts/python -c "import pydantic_yaml; print(pydantic_yaml.__version__)"
Expected: Prints version number without errors
Step 4: Commit
git add requirements.txt
git commit -m "deps: add pydantic-yaml for YAML configuration support"
Task 2: Create config Directory Structure
Files:
- Create:
config/__init__.py - Create:
config/settings.py - Create:
config/settings.yaml
Step 1: Create config directory
Run: mkdir config
Step 2: Create config/init.py
from config.settings import settings, Settings, load_settings
__all__ = ["settings", "Settings", "load_settings"]
Step 3: Create config/settings.py with configuration classes
from pathlib import Path
from sqlalchemy.engine import URL
from pydantic import BaseModel
from pydantic_yaml import YamlModel
class SqlServerConfig(BaseModel):
"""SQL Server 连接配置"""
host: str
port: int = 1433
database: str
username: str
password: str
driver: str = "{ODBC Driver 18 for SQL Server}"
trust_server_certificate: str = "yes"
class Settings(YamlModel):
"""应用配置"""
database: SqlServerConfig
@property
def database_url(self) -> URL:
"""构建数据库连接 URL"""
conf = self.database.sql_server
return URL.create(
"mssql+pyodbc",
username=conf.username,
password=conf.password,
host=conf.host,
port=conf.port,
database=conf.database,
query={
"driver": conf.driver.strip("{}"),
"TrustServerCertificate": conf.trust_server_certificate,
},
)
def load_settings(config_path: str = "config/settings.yaml") -> Settings:
"""加载 YAML 配置文件"""
path = Path(config_path)
if not path.exists():
raise FileNotFoundError(
f"配置文件不存在: {config_path}\n"
f"请确保文件存在于项目根目录或指定正确路径"
)
return Settings.parse_yaml_file(path)
# 全局配置单例
settings = load_settings()
Step 4: Create config/settings.yaml with current configuration
# 数据库配置
database:
sql_server:
host: 192.168.110.114
port: 1433
database: CompanyDB
username: peng
password: Cqbld123456.
driver: "{ODBC Driver 18 for SQL Server}"
trust_server_certificate: yes
Step 5: Commit
git add config/
git commit -m "feat: add YAML configuration module with pydantic-yaml"
Task 3: Write Configuration Loading Tests
Files:
- Create:
tests/test_config.py - Create:
tests/fixtures/test_config.yaml
Step 1: Create tests/fixtures directory
Run: mkdir tests/fixtures
Step 2: Create tests/fixtures/test_config.yaml
# 测试配置
database:
sql_server:
host: localhost
port: 1433
database: TestDB
username: test_user
password: test_pass
driver: "{ODBC Driver 18 for SQL Server}"
trust_server_certificate: yes
Step 3: Write the failing test for settings loading
Create tests/test_config.py:
import pytest
from config.settings import load_settings
def test_load_settings_success():
"""测试成功加载配置文件"""
settings = load_settings("tests/fixtures/test_config.yaml")
assert settings.database.sql_server.port == 1433
assert settings.database.sql_server.host == "localhost"
assert settings.database.sql_server.database == "TestDB"
def test_load_settings_file_not_found():
"""测试配置文件不存在时抛出异常"""
with pytest.raises(FileNotFoundError):
load_settings("nonexistent.yaml")
def test_database_url_property():
"""测试 database_url 属性生成"""
settings = load_settings("tests/fixtures/test_config.yaml")
url = settings.database_url
assert "mssql+pyodbc" in str(url)
assert "test_user" in str(url)
assert "TestDB" in str(url)
Step 4: Run tests to verify they pass
Run: .venv/Scripts/pytest tests/test_config.py -v
Expected: All tests PASS
Step 5: Commit
git add tests/test_config.py tests/fixtures/test_config.yaml
git commit -m "test: add configuration loading tests"
Task 4: Update database.py to Use New Config
Files:
- Modify:
app/core/database.py
Step 1: Read current database.py to understand usage
Check the current import and usage of settings
Step 2: Update import statement
Change:
from app.core.config import settings
To:
from config.settings import settings
Step 3: Verify the rest of the code works unchanged
The database_url property should work exactly as before
Step 4: Run existing tests to ensure no breakage
Run: .venv/Scripts/pytest tests/ -v
Expected: All existing tests still PASS
Step 5: Commit
git add app/core/database.py
git commit -m "refactor: update database.py to use new config module"
Task 5: Update API Module Imports
Files:
- Modify:
app/api/v1/box.py - Modify:
app/api/v1/location.py - Modify:
app/services/box_service.py - Modify:
app/services/location_service.py
Step 1: Check all files that import from app.core.config
Run: grep -r "from app.core.config import" app/
Step 2: Update each file's import
Change:
from app.core.config import settings
To:
from config.settings import settings
Step 3: Run tests after each file change
Run: .venv/Scripts/pytest tests/ -v
Expected: All tests PASS
Step 4: Commit all import changes
git add app/api/v1/box.py app/api/v1/location.py app/services/
git commit -m "refactor: update all imports to use new config module"
Task 6: Update Test Fixtures
Files:
- Modify:
tests/conftest.py
Step 1: Read current conftest.py
Check for any references to app.core.config
Step 2: Update imports in conftest.py
Change any:
from app.core.config import settings
To:
from config.settings import settings
Step 3: Run tests
Run: .venv/Scripts/pytest tests/ -v
Expected: All tests PASS
Step 4: Commit
git add tests/conftest.py
git commit -m "test: update conftest imports"
Task 7: Update Main Application Entry Point
Files:
- Modify:
app/main.py
Step 1: Read current main.py
Check for any config-related initialization
Step 2: Add error handling for configuration loading
Add at the top of main.py or update existing initialization:
import sys
from config.settings import load_settings
try:
settings = load_settings()
except FileNotFoundError as e:
print(f"配置文件错误: {e}")
sys.exit(1)
except Exception as e:
print(f"加载配置失败: {e}")
sys.exit(1)
Step 3: Test application startup
Run: .venv/Scripts/python -m app.main
Expected: Application starts without errors
Step 4: Commit
git add app/main.py
git commit -m "feat: add config error handling on startup"
Task 8: Remove Old Configuration Files
Files:
- Delete:
app/core/config.py - Delete:
.env
Step 1: Verify no remaining imports of old config
Run: grep -r "from app.core.config import" .
Expected: No results (or only in .git directory)
Step 2: Remove old config.py file
Run: rm app/core/config.py
Step 3: Remove .env file
Run: rm .env
Step 4: Add .env to .gitignore if not already present
Ensure .env is in .gitignore
Step 5: Run final test suite
Run: .venv/Scripts/pytest tests/ -v
Expected: All tests PASS
Step 6: Run application to verify
Run: .venv/Scripts/python -m app.main
Expected: Application starts successfully
Step 7: Commit cleanup
git add app/core/config.py .env .gitignore
git commit -m "refactor: remove old .env and config.py files"
Task 9: Update .gitignore for YAML Config
Files:
- Modify:
.gitignore(if it exists, otherwise create)
Step 1: Check if .gitignore exists
Run: ls -la .gitignore
Step 2: Add or verify config/settings.local.yaml is ignored
Add to .gitignore:
# Local configuration overrides
config/settings.local.yaml
This allows developers to have local overrides without committing them
Step 3: Commit
git add .gitignore
git commit -m "chore: ignore local YAML config overrides"
Task 10: Final Verification and Documentation
Files:
- Update:
README.md(if exists)
Step 1: Run complete test suite
Run: .venv/Scripts/pytest tests/ -v --cov=app --cov-report=term-missing
Expected: All tests pass, coverage maintained
Step 2: Start application and verify database connection
Run: .venv/Scripts/python -m app.main
Expected: Application connects to database successfully
Step 3: Update README.md with configuration instructions
Add to README.md:
## Configuration
Configuration is managed via YAML files in the `config/` directory.
### Configuration File
Edit `config/settings.yaml` to configure your environment:
```yaml
database:
sql_server:
host: your-host
port: 1433
database: your-database
username: your-username
password: your-password
Local Overrides
For local development, create config/settings.local.yaml to override specific values without committing them.
**Step 4: Final commit**
```bash
git add README.md
git commit -m "docs: update README with YAML configuration instructions"
Verification Checklist
After completing all tasks:
- All tests pass:
pytest tests/ -v - Application starts successfully
- Database connection works
- No references to
app.core.configremain .envfile removed- YAML config file exists and is valid
- README updated with configuration instructions