From 88cfe91c569702bf0bdde072c616a6af9372cd89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roog=20=28=E9=A1=BE=E6=96=B0=E5=9F=B9=29?= Date: Tue, 3 Feb 2026 11:29:37 +0800 Subject: [PATCH] =?UTF-8?q?main:=E7=A7=BB=E9=99=A4=20src=20=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E7=BB=93=E6=9E=84=EF=BC=8C=E6=9B=B4=E6=96=B0=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=BC=95=E7=94=A8=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 变更内容: - 删除 `src` 子目录,将模块引用路径从 `src.functional_scaffold` 更新为 `functional_scaffold`。 - 修改相关代码、文档、测试用例及配置文件中的路径引用,包括 `README.md`、`Dockerfile`、`uvicorn` 启动命令等。 - 优化项目目录结构,提升代码维护性和可读性。 --- AGENTS.md | 2 +- CLAUDE.md | 8 ++++---- README.md | 2 +- deployment/Dockerfile | 6 +++++- deployment/serverless/aliyun-fc.yaml | 2 +- docs/algorithm-development.md | 2 +- docs/getting-started.md | 2 +- docs/grafana-dashboard-usage.md | 2 +- main.py | 16 ---------------- pyproject.toml | 1 + scripts/run_dev.sh | 2 +- tests/conftest.py | 2 +- tests/test_algorithms.py | 2 +- tests/test_job_manager.py | 18 +++++++++--------- tests/test_metrics_unified.py | 20 ++++++++++---------- tests/test_middleware.py | 28 ++++++++++++++-------------- 16 files changed, 52 insertions(+), 63 deletions(-) delete mode 100644 main.py diff --git a/AGENTS.md b/AGENTS.md index 85582f7..9e6b3cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 ``` 测试与质量: diff --git a/CLAUDE.md b/CLAUDE.md index abd1984..f8b434d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 ``` 访问地址: diff --git a/README.md b/README.md index 97b05e3..7744145 100644 --- a/README.md +++ b/README.md @@ -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 文档 diff --git a/deployment/Dockerfile b/deployment/Dockerfile index c954b95..244aa5b 100644 --- a/deployment/Dockerfile +++ b/deployment/Dockerfile @@ -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"] \ No newline at end of file +CMD ["uvicorn", "functional_scaffold.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/deployment/serverless/aliyun-fc.yaml b/deployment/serverless/aliyun-fc.yaml index fb9f793..5ad0028 100644 --- a/deployment/serverless/aliyun-fc.yaml +++ b/deployment/serverless/aliyun-fc.yaml @@ -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 diff --git a/docs/algorithm-development.md b/docs/algorithm-development.md index ee4ca76..43dd7b4 100644 --- a/docs/algorithm-development.md +++ b/docs/algorithm-development.md @@ -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: """文本处理算法测试""" diff --git a/docs/getting-started.md b/docs/getting-started.md index 7e05231..238857a 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -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 ``` diff --git a/docs/grafana-dashboard-usage.md b/docs/grafana-dashboard-usage.md index de88258..308ae1f 100644 --- a/docs/grafana-dashboard-usage.md +++ b/docs/grafana-dashboard-usage.md @@ -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" ``` ### 故障排查 diff --git a/main.py b/main.py deleted file mode 100644 index b56c695..0000000 --- a/main.py +++ /dev/null @@ -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 帮助 diff --git a/pyproject.toml b/pyproject.toml index a70f1da..6d96702 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,3 +48,4 @@ python_files = ["test_*.py"] python_classes = ["Test*"] python_functions = ["test_*"] addopts = "-v --strict-markers" +pythonpath = ["src"] diff --git a/scripts/run_dev.sh b/scripts/run_dev.sh index 58347ac..6df0072 100755 --- a/scripts/run_dev.sh +++ b/scripts/run_dev.sh @@ -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 diff --git a/tests/conftest.py b/tests/conftest.py index d7334dc..bedf377 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -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 diff --git a/tests/test_algorithms.py b/tests/test_algorithms.py index 13f026f..b0d5b12 100644 --- a/tests/test_algorithms.py +++ b/tests/test_algorithms.py @@ -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: diff --git a/tests/test_job_manager.py b/tests/test_job_manager.py index 2fadd7c..6b2bbff 100644 --- a/tests/test_job_manager.py +++ b/tests/test_job_manager.py @@ -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 diff --git a/tests/test_metrics_unified.py b/tests/test_metrics_unified.py index 337d8a1..80fa5c3 100644 --- a/tests/test_metrics_unified.py +++ b/tests/test_metrics_unified.py @@ -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, ) diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 53e1f70..0e884ad 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -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