main:移除 src 目录结构,更新模块引用路径
变更内容: - 删除 `src` 子目录,将模块引用路径从 `src.functional_scaffold` 更新为 `functional_scaffold`。 - 修改相关代码、文档、测试用例及配置文件中的路径引用,包括 `README.md`、`Dockerfile`、`uvicorn` 启动命令等。 - 优化项目目录结构,提升代码维护性和可读性。
This commit is contained in:
@@ -70,7 +70,7 @@ pip install -e ".[dev]"
|
||||
|
||||
```bash
|
||||
./scripts/run_dev.sh
|
||||
uvicorn src.functional_scaffold.main:app --reload --port 8000
|
||||
uvicorn functional_scaffold.main:app --reload --port 8000
|
||||
```
|
||||
|
||||
测试与质量:
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
本文件为 Claude Code (claude.ai/code) 在此代码仓库中工作时提供指导。
|
||||
|
||||
为了方便团队交流,项目的自然语言使用中文,包括代码注释和文档等
|
||||
|
||||
## 项目概述
|
||||
|
||||
**FunctionalScaffold(函数式脚手架)** 是一个算法工程化 Serverless 解决方案的脚手架生成器。
|
||||
|
||||
- 为了方便团队交流,项目的自然语言使用中文,包括代码注释和文档等
|
||||
|
||||
### 核心目标
|
||||
|
||||
解决三大痛点:
|
||||
@@ -88,10 +88,10 @@ pip install -e ".[dev]"
|
||||
./scripts/run_dev.sh
|
||||
|
||||
# 方式2:直接运行(开发模式,自动重载)
|
||||
uvicorn src.functional_scaffold.main:app --reload --port 8000
|
||||
uvicorn functional_scaffold.main:app --reload --port 8000
|
||||
|
||||
# 方式3:生产模式
|
||||
uvicorn src.functional_scaffold.main:app --host 0.0.0.0 --port 8000 --workers 4
|
||||
uvicorn functional_scaffold.main:app --host 0.0.0.0 --port 8000 --workers 4
|
||||
```
|
||||
|
||||
访问地址:
|
||||
|
||||
@@ -58,7 +58,7 @@ pip install -e ".[dev]"
|
||||
./scripts/run_dev.sh
|
||||
|
||||
# 方式2:直接运行
|
||||
uvicorn src.functional_scaffold.main:app --reload --port 8000
|
||||
uvicorn functional_scaffold.main:app --reload --port 8000
|
||||
```
|
||||
|
||||
4. 访问 API 文档
|
||||
|
||||
@@ -18,6 +18,10 @@ RUN pip install --no-cache-dir -r requirements-dev.txt
|
||||
# 复制应用代码和配置
|
||||
COPY src/ ./src/
|
||||
COPY config/ ./config/
|
||||
COPY pyproject.toml .
|
||||
|
||||
# 安装包(使用 editable 模式)
|
||||
RUN pip install --no-cache-dir -e .
|
||||
|
||||
# 创建非 root 用户
|
||||
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
|
||||
@@ -31,4 +35,4 @@ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/healthz')"
|
||||
|
||||
# 启动命令
|
||||
CMD ["uvicorn", "src.functional_scaffold.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
CMD ["uvicorn", "functional_scaffold.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
@@ -25,7 +25,7 @@ Resources:
|
||||
CAPort: 8000
|
||||
CustomContainerConfig:
|
||||
Image: 'registry.cn-hangzhou.aliyuncs.com/your-namespace/functional-scaffold:latest'
|
||||
Command: '["uvicorn", "src.functional_scaffold.main:app", "--host", "0.0.0.0", "--port", "8000"]'
|
||||
Command: '["uvicorn", "functional_scaffold.main:app", "--host", "0.0.0.0", "--port", "8000"]'
|
||||
EnvironmentVariables:
|
||||
APP_ENV: production
|
||||
LOG_LEVEL: INFO
|
||||
|
||||
@@ -412,7 +412,7 @@ class MLPredictor(BaseAlgorithm):
|
||||
```python
|
||||
# tests/test_text_processor.py
|
||||
import pytest
|
||||
from src.functional_scaffold.algorithms.text_processor import TextProcessor
|
||||
from functional_scaffold.algorithms.text_processor import TextProcessor
|
||||
|
||||
class TestTextProcessor:
|
||||
"""文本处理算法测试"""
|
||||
|
||||
@@ -34,7 +34,7 @@ pip install -e ".[dev]"
|
||||
|
||||
```bash
|
||||
# 开发模式(自动重载)
|
||||
uvicorn src.functional_scaffold.main:app --reload --port 8000
|
||||
uvicorn functional_scaffold.main:app --reload --port 8000
|
||||
# docker 开发者模式
|
||||
cd deployment && docker compose up -d
|
||||
```
|
||||
|
||||
@@ -94,7 +94,7 @@ curl -X POST http://localhost:8111/invoke \
|
||||
{job="functional-scaffold-app", level="ERROR"} |= "59017bdd-5963-40b1-a325-5088593382c0"
|
||||
|
||||
# 特定 request_id 的特定 logger
|
||||
{job="functional-scaffold-app", logger="src.functional_scaffold.algorithms.base"} |= "59017bdd-5963-40b1-a325-5088593382c0"
|
||||
{job="functional-scaffold-app", logger="functional_scaffold.algorithms.base"} |= "59017bdd-5963-40b1-a325-5088593382c0"
|
||||
```
|
||||
|
||||
### 故障排查
|
||||
|
||||
16
main.py
16
main.py
@@ -1,16 +0,0 @@
|
||||
# 这是一个示例 Python 脚本。
|
||||
|
||||
# 按 ⌃R 执行或将其替换为您的代码。
|
||||
# 按 双击 ⇧ 在所有地方搜索类、文件、工具窗口、操作和设置。
|
||||
|
||||
|
||||
def print_hi(name):
|
||||
# 在下面的代码行中使用断点来调试脚本。
|
||||
print(f'Hi, {name}') # 按 ⌘F8 切换断点。
|
||||
|
||||
|
||||
# 按装订区域中的绿色按钮以运行脚本。
|
||||
if __name__ == '__main__':
|
||||
print_hi('PyCharm')
|
||||
|
||||
# 访问 https://www.jetbrains.com/help/pycharm/ 获取 PyCharm 帮助
|
||||
@@ -48,3 +48,4 @@ python_files = ["test_*.py"]
|
||||
python_classes = ["Test*"]
|
||||
python_functions = ["test_*"]
|
||||
addopts = "-v --strict-markers"
|
||||
pythonpath = ["src"]
|
||||
|
||||
@@ -21,4 +21,4 @@ pip install -e ".[dev]"
|
||||
# 启动服务
|
||||
echo "Starting server on http://localhost:8000"
|
||||
echo "API docs available at http://localhost:8000/docs"
|
||||
uvicorn src.functional_scaffold.main:app --reload --host 0.0.0.0 --port 8000
|
||||
uvicorn functional_scaffold.main:app --reload --host 0.0.0.0 --port 8000
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from src.functional_scaffold.main import app
|
||||
from functional_scaffold.main import app
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""算法单元测试"""
|
||||
|
||||
import pytest
|
||||
from src.functional_scaffold.algorithms.prime_checker import PrimeChecker
|
||||
from functional_scaffold.algorithms.prime_checker import PrimeChecker
|
||||
|
||||
|
||||
class TestPrimeChecker:
|
||||
|
||||
@@ -6,12 +6,12 @@ import pytest
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
from fastapi import status
|
||||
|
||||
from src.functional_scaffold.core.job_manager import (
|
||||
from functional_scaffold.core.job_manager import (
|
||||
JobManager,
|
||||
get_job_manager,
|
||||
shutdown_job_manager,
|
||||
)
|
||||
from src.functional_scaffold.api.models import JobStatus
|
||||
from functional_scaffold.api.models import JobStatus
|
||||
|
||||
|
||||
class TestJobManager:
|
||||
@@ -203,7 +203,7 @@ class TestJobsAPI:
|
||||
def test_create_job_success(self, client):
|
||||
"""测试成功创建任务"""
|
||||
with patch(
|
||||
"src.functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
"functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
) as mock_get_manager:
|
||||
mock_manager = MagicMock()
|
||||
mock_manager.is_available.return_value = True
|
||||
@@ -237,7 +237,7 @@ class TestJobsAPI:
|
||||
def test_create_job_algorithm_not_found(self, client):
|
||||
"""测试创建任务时算法不存在"""
|
||||
with patch(
|
||||
"src.functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
"functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
) as mock_get_manager:
|
||||
mock_manager = MagicMock()
|
||||
mock_manager.is_available.return_value = True
|
||||
@@ -259,7 +259,7 @@ class TestJobsAPI:
|
||||
def test_create_job_service_unavailable(self, client):
|
||||
"""测试服务不可用时创建任务"""
|
||||
with patch(
|
||||
"src.functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
"functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
) as mock_get_manager:
|
||||
mock_manager = MagicMock()
|
||||
mock_manager.is_available.return_value = False
|
||||
@@ -278,7 +278,7 @@ class TestJobsAPI:
|
||||
def test_get_job_status_success(self, client):
|
||||
"""测试成功查询任务状态"""
|
||||
with patch(
|
||||
"src.functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
"functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
) as mock_get_manager:
|
||||
mock_manager = MagicMock()
|
||||
mock_manager.is_available.return_value = True
|
||||
@@ -308,7 +308,7 @@ class TestJobsAPI:
|
||||
def test_get_job_status_not_found(self, client):
|
||||
"""测试查询不存在的任务"""
|
||||
with patch(
|
||||
"src.functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
"functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
) as mock_get_manager:
|
||||
mock_manager = MagicMock()
|
||||
mock_manager.is_available.return_value = True
|
||||
@@ -324,7 +324,7 @@ class TestJobsAPI:
|
||||
def test_get_job_status_service_unavailable(self, client):
|
||||
"""测试服务不可用时查询任务"""
|
||||
with patch(
|
||||
"src.functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
"functional_scaffold.api.routes.get_job_manager", new_callable=AsyncMock
|
||||
) as mock_get_manager:
|
||||
mock_manager = MagicMock()
|
||||
mock_manager.is_available.return_value = False
|
||||
@@ -395,7 +395,7 @@ class TestWebhook:
|
||||
manager._http_client = mock_http
|
||||
|
||||
# 使用较短的重试间隔进行测试
|
||||
with patch("src.functional_scaffold.core.job_manager.settings") as mock_settings:
|
||||
with patch("functional_scaffold.core.job_manager.settings") as mock_settings:
|
||||
mock_settings.webhook_max_retries = 2
|
||||
mock_settings.webhook_timeout = 1
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class TestMetricsManager:
|
||||
@pytest.fixture
|
||||
def manager(self, mock_redis):
|
||||
"""创建测试用的 MetricsManager"""
|
||||
from src.functional_scaffold.core.metrics_unified import (
|
||||
from functional_scaffold.core.metrics_unified import (
|
||||
MetricsManager,
|
||||
reset_metrics_manager,
|
||||
)
|
||||
@@ -108,7 +108,7 @@ class TestConvenienceFunctions:
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self):
|
||||
"""每个测试前重置管理器"""
|
||||
from src.functional_scaffold.core.metrics_unified import reset_metrics_manager
|
||||
from functional_scaffold.core.metrics_unified import reset_metrics_manager
|
||||
|
||||
reset_metrics_manager()
|
||||
|
||||
@@ -119,7 +119,7 @@ class TestConvenienceFunctions:
|
||||
mock_instance.ping.return_value = True
|
||||
mock_redis_class.return_value = mock_instance
|
||||
|
||||
from src.functional_scaffold.core.metrics_unified import incr, reset_metrics_manager
|
||||
from functional_scaffold.core.metrics_unified import incr, reset_metrics_manager
|
||||
|
||||
reset_metrics_manager()
|
||||
incr("http_requests_total", {"method": "GET", "endpoint": "/", "status": "success"})
|
||||
@@ -133,7 +133,7 @@ class TestConvenienceFunctions:
|
||||
mock_instance.ping.return_value = True
|
||||
mock_redis_class.return_value = mock_instance
|
||||
|
||||
from src.functional_scaffold.core.metrics_unified import reset_metrics_manager, set
|
||||
from functional_scaffold.core.metrics_unified import reset_metrics_manager, set
|
||||
|
||||
reset_metrics_manager()
|
||||
set("http_requests_in_progress", {}, 10)
|
||||
@@ -149,7 +149,7 @@ class TestConvenienceFunctions:
|
||||
mock_instance.pipeline.return_value = mock_pipeline
|
||||
mock_redis_class.return_value = mock_instance
|
||||
|
||||
from src.functional_scaffold.core.metrics_unified import observe, reset_metrics_manager
|
||||
from functional_scaffold.core.metrics_unified import observe, reset_metrics_manager
|
||||
|
||||
reset_metrics_manager()
|
||||
observe("http_request_duration_seconds", {"method": "GET", "endpoint": "/"}, 0.1)
|
||||
@@ -168,7 +168,7 @@ class TestExport:
|
||||
mock_instance.hgetall.return_value = {"method=GET,endpoint=/,status=success": "10"}
|
||||
mock_redis_class.return_value = mock_instance
|
||||
|
||||
from src.functional_scaffold.core.metrics_unified import export, reset_metrics_manager
|
||||
from functional_scaffold.core.metrics_unified import export, reset_metrics_manager
|
||||
|
||||
reset_metrics_manager()
|
||||
output = export()
|
||||
@@ -192,7 +192,7 @@ class TestExport:
|
||||
mock_instance.hget.return_value = "3"
|
||||
mock_redis_class.return_value = mock_instance
|
||||
|
||||
from src.functional_scaffold.core.metrics_unified import export, reset_metrics_manager
|
||||
from functional_scaffold.core.metrics_unified import export, reset_metrics_manager
|
||||
|
||||
reset_metrics_manager()
|
||||
output = export()
|
||||
@@ -206,7 +206,7 @@ class TestEnvVarSubstitution:
|
||||
def test_substitute_env_vars(self):
|
||||
"""测试环境变量替换"""
|
||||
import os
|
||||
from src.functional_scaffold.core.metrics_unified import MetricsManager
|
||||
from functional_scaffold.core.metrics_unified import MetricsManager
|
||||
|
||||
# 设置测试环境变量
|
||||
os.environ["TEST_VAR"] = "test_value"
|
||||
@@ -235,7 +235,7 @@ class TestTrackAlgorithmExecution:
|
||||
mock_instance.pipeline.return_value = mock_pipeline
|
||||
mock_redis_class.return_value = mock_instance
|
||||
|
||||
from src.functional_scaffold.core.metrics_unified import (
|
||||
from functional_scaffold.core.metrics_unified import (
|
||||
reset_metrics_manager,
|
||||
track_algorithm_execution,
|
||||
)
|
||||
@@ -258,7 +258,7 @@ class TestTrackAlgorithmExecution:
|
||||
mock_instance.pipeline.return_value = mock_pipeline
|
||||
mock_redis_class.return_value = mock_instance
|
||||
|
||||
from src.functional_scaffold.core.metrics_unified import (
|
||||
from functional_scaffold.core.metrics_unified import (
|
||||
reset_metrics_manager,
|
||||
track_algorithm_execution,
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ import pytest
|
||||
from unittest.mock import patch, MagicMock
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from src.functional_scaffold.main import app, normalize_path
|
||||
from functional_scaffold.main import app, normalize_path
|
||||
|
||||
|
||||
class TestNormalizePath:
|
||||
@@ -32,10 +32,10 @@ class TestNormalizePath:
|
||||
class TestMetricsMiddleware:
|
||||
"""测试指标中间件"""
|
||||
|
||||
@patch("src.functional_scaffold.main.incr")
|
||||
@patch("src.functional_scaffold.main.observe")
|
||||
@patch("src.functional_scaffold.main.gauge_incr")
|
||||
@patch("src.functional_scaffold.main.gauge_decr")
|
||||
@patch("functional_scaffold.main.incr")
|
||||
@patch("functional_scaffold.main.observe")
|
||||
@patch("functional_scaffold.main.gauge_incr")
|
||||
@patch("functional_scaffold.main.gauge_decr")
|
||||
def test_skip_health_endpoints(self, mock_gauge_decr, mock_gauge_incr, mock_observe, mock_incr):
|
||||
"""测试跳过健康检查端点"""
|
||||
client = TestClient(app)
|
||||
@@ -51,10 +51,10 @@ class TestMetricsMiddleware:
|
||||
mock_gauge_incr.assert_not_called()
|
||||
mock_gauge_decr.assert_not_called()
|
||||
|
||||
@patch("src.functional_scaffold.main.incr")
|
||||
@patch("src.functional_scaffold.main.observe")
|
||||
@patch("src.functional_scaffold.main.gauge_incr")
|
||||
@patch("src.functional_scaffold.main.gauge_decr")
|
||||
@patch("functional_scaffold.main.incr")
|
||||
@patch("functional_scaffold.main.observe")
|
||||
@patch("functional_scaffold.main.gauge_incr")
|
||||
@patch("functional_scaffold.main.gauge_decr")
|
||||
def test_record_normal_endpoints(self, mock_gauge_decr, mock_gauge_incr, mock_observe, mock_incr):
|
||||
"""测试记录普通端点"""
|
||||
client = TestClient(app)
|
||||
@@ -72,11 +72,11 @@ class TestMetricsMiddleware:
|
||||
incr_call_args = mock_incr.call_args
|
||||
assert incr_call_args[0][1]["endpoint"] == "/invoke"
|
||||
|
||||
@patch("src.functional_scaffold.main.incr")
|
||||
@patch("src.functional_scaffold.main.observe")
|
||||
@patch("src.functional_scaffold.main.gauge_incr")
|
||||
@patch("src.functional_scaffold.main.gauge_decr")
|
||||
@patch("src.functional_scaffold.core.job_manager.get_job_manager")
|
||||
@patch("functional_scaffold.main.incr")
|
||||
@patch("functional_scaffold.main.observe")
|
||||
@patch("functional_scaffold.main.gauge_incr")
|
||||
@patch("functional_scaffold.main.gauge_decr")
|
||||
@patch("functional_scaffold.core.job_manager.get_job_manager")
|
||||
def test_normalize_job_path(self, mock_get_manager, mock_gauge_decr, mock_gauge_incr, mock_observe, mock_incr):
|
||||
"""测试规范化任务路径"""
|
||||
# Mock job manager
|
||||
|
||||
Reference in New Issue
Block a user