diff --git a/.gitignore b/.gitignore index 58b56a7..b93bbf7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,23 @@ -__pycache__ -.idea -database -logs + +# Poetry +poetry.lock +.venv/ +dist/ +*.egg-info/ + +# Python +__pycache__/ +*.py[cod] +*$py.class +.pytest_cache/ +.coverage +htmlcov/ + +# IDE +.vscode/ +.idea/ + +# Project specific +logs/ +database/ .pylint_rate diff --git a/README.md b/README.md index 80e0482..4d871a5 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@

License Version - Python + Python

diff --git a/config.py b/config.py index 6eb6941..511d797 100644 --- a/config.py +++ b/config.py @@ -96,9 +96,7 @@ # 数据库配置 DATABASE_CONFIG = { - "path": os.path.join( - ROOT_DIR, "database", "fund_analysis.v4.db" - ) # SQLite数据库文件路径 + "path": os.path.join(ROOT_DIR, "database", "fund_analysis.v4.db") # SQLite数据库文件路径 } # API配置 diff --git a/data_source/data_source_factory.py b/data_source/data_source_factory.py index 3dbde39..3a95897 100644 --- a/data_source/data_source_factory.py +++ b/data_source/data_source_factory.py @@ -14,9 +14,7 @@ class DataSourceFactory: @classmethod def register(cls, source_class: Type[IDataSource]) -> None: """注册新的数据源类型""" - logger.info( - "注册数据源: %s %s", source_class.get_name(), source_class.get_version() - ) + logger.info("注册数据源: %s %s", source_class.get_name(), source_class.get_version()) cls._sources[source_class.get_name()] = source_class @classmethod diff --git a/models/fund.py b/models/fund.py index 8ca612e..e659d44 100644 --- a/models/fund.py +++ b/models/fund.py @@ -21,9 +21,7 @@ class Fund(BaseModel): type = CharField(max_length=20) # 基金类型 issue_date = DateField() # 发行日期 establishment_date = DateField() # 成立日期 - establishment_size = DecimalField( - max_digits=20, decimal_places=4 - ) # 成立规模(单位:亿份) + establishment_size = DecimalField(max_digits=20, decimal_places=4) # 成立规模(单位:亿份) company = CharField(max_length=100) # 基金管理公司 custodian = CharField(max_length=100) # 基金托管人 fund_manager = CharField(max_length=100) # 基金经理人 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c33623d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,43 @@ +[tool.poetry] +name = "fund-analysis" +version = "0.1.0" +description = "基金分析系统" +authors = ["Fan Yefei "] + +[tool.poetry.dependencies] +python = "~3.10" +# Web框架 +dash = {version = "^2.18.1", extras = ["compress"]} +"dash-bootstrap-components" = "^1.5.0" +plotly = "^5.18.0" + +"feffery-antd-components" = "^0.3.8" +"feffery-dash-utils" = "^0.1.4" +"feffery-markdown-components" = "^0.3.0rc3" +"feffery-utils-components" = "^0.2.0rc20" + +# 服务端 +Flask = "^3.0.3" +"flask-restx" = "^1.3.0" + +# 网络 +requests = "^2.32.3" + +# 数据处理 +pandas = "^2.2.3" +numpy = "^1.26.2" +"beautifulsoup4" = "^4.12.3" +"flask-apscheduler" = "^1.13.1" + +# 数据库 +peewee = "^3.17.0" + +[tool.poetry.group.dev.dependencies] +# 开发工具 +black = "^23.11.0" # 代码格式化检查 +pylint = "^3.1.0" # 代码质量检查 +colorama = "^0.4.6" # 测试用 + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 515d72d..0000000 --- a/requirements.txt +++ /dev/null @@ -1,18 +0,0 @@ -dash[compress]==2.18.1 -feffery_antd_components>=0.3.8 -feffery_dash_utils>=0.1.4 -feffery_markdown_components>=0.3.0rc3 -feffery_utils_components>=0.2.0rc20 -Flask==3.0.3 -pandas>=2.0.0 -numpy>=1.24.0 -plotly>=5.18.0 -dash-bootstrap-components>=1.5.0 -requests~=2.32.3 -flask-restx>=1.3.0 -peewee>=3.17.0 -Flask-APScheduler==1.13.1 -beautifulsoup4==4.12.3 -colorama==0.4.6 # 测试用 -black>=24.2.0 # 代码格式化检查 -pylint>=3.1.0 # 代码质量检查 diff --git a/scheduler/tasks/fund_detail.py b/scheduler/tasks/fund_detail.py index 0107e74..b8c973c 100644 --- a/scheduler/tasks/fund_detail.py +++ b/scheduler/tasks/fund_detail.py @@ -105,7 +105,5 @@ def execute(self, **kwargs) -> Dict[str, Any]: return fund_data except Exception as e: - logger.error( - "更新基金信息失败: %s", str(e), exc_info=True - ) # 添加完整的错误堆栈 + logger.error("更新基金信息失败: %s", str(e), exc_info=True) # 添加完整的错误堆栈 raise diff --git a/scheduler/tasks/fund_info.py b/scheduler/tasks/fund_info.py index 3412dcc..aef10e5 100644 --- a/scheduler/tasks/fund_info.py +++ b/scheduler/tasks/fund_info.py @@ -112,7 +112,5 @@ def execute(self, **kwargs) -> Dict[str, Any]: } except Exception as e: - logger.error( - f"更新基金信息失败: {str(e)}", exc_info=True - ) # 添加完整的错误堆栈 + logger.error(f"更新基金信息失败: {str(e)}", exc_info=True) # 添加完整的错误堆栈 raise diff --git a/start.sh b/start.sh index ef626b0..f34150d 100755 --- a/start.sh +++ b/start.sh @@ -57,39 +57,53 @@ activate_conda_env() { if ! conda activate fund; then echo -e "${RED}激活conda环境失败${NC}" read -p "按回车键继续..." - return 1 + exit 1 fi echo -e "${GREEN}conda环境激活成功${NC}" return 0 } - -# 安装依赖 -install_dependencies() { - echo -e "${YELLOW}检查并安装依赖${NC}" - if [ -f "requirements.txt" ]; then - if ! pip install -r requirements.txt; then - echo -e "${RED}安装依赖失败${NC}" - read -p "按回车键继续..." - return 1 - fi - - # 安装代码检查工具 - echo -e "${YELLOW}安装代码检查工具...${NC}" - if ! pip install black pylint; then - echo -e "${RED}安装代码检查工具失败${NC}" - read -p "按回车键继续..." - return 1 +# 检查poetry是否已安装 +check_poetry() { + if ! command -v poetry &> /dev/null; then + echo -e "${RED}错误: 未找到poetry,正在安装...${NC}" + # 获取当前conda环境信息 + conda_env=$(conda info --envs | grep "*" | awk '{print $1}') + echo -e "${YELLOW}当前conda环境: ${conda_env}${NC}" + if ! conda install -y poetry; then + echo -e "${RED}安装poetry失败${NC}" + exit 1 fi + fi + return 0 +} - echo -e "${GREEN}依赖安装成功${NC}" - else - echo -e "${RED}错误: 未找到requirements.txt文件${NC}" - read -p "按回车键继续..." +# 创建并配置环境 +setup_env() { + echo -e "${YELLOW}配置开发环境...${NC}" + # 获取poetry版本 + poetry_version=$(poetry --version | cut -d' ' -f3) + echo -e "${GREEN}当前poetry版本: $poetry_version${NC}" + + # 配置poetry不使用虚拟环境 + echo -e "${YELLOW}配置poetry...${NC}" + poetry config virtualenvs.create false + + # 安装项目依赖 + echo -e "${YELLOW}安装项目依赖...${NC}" + if ! poetry install; then + echo -e "${RED}安装依赖失败${NC}" + echo -e "按回车键返回主菜单..." + read return 1 fi + + echo -e "${GREEN}环境配置成功${NC}" + read -p "按回车键继续..." return 0 } + + # 初始化数据库 init_database() { echo -e "${YELLOW}迁移数据库...${NC}" @@ -271,7 +285,7 @@ run_code_check() { echo -e "${RED}无法解析评分信息${NC}" fi - # 保存当前评分 + # 保存当前��分 echo "$curr_rate" > .pylint_rate has_error=1 @@ -338,7 +352,8 @@ do_full_install() { check_conda || return 1 setup_conda_env || return 1 activate_conda_env || return 1 - install_dependencies || return 1 + check_poetry || return 1 + setup_env || return 1 init_database || return 1 run_code_check || return 1 start_app || return 1 @@ -354,34 +369,35 @@ while true; do case $choice in 1) echo -e "${YELLOW}开始初始化环境...${NC}" - ensure_directories - check_conda - setup_conda_env - activate_conda_env - install_dependencies + ensure_directories || continue + check_conda || continue + setup_conda_env || continue + activate_conda_env || continue + check_poetry || continue + setup_env || continue if [ $? -eq 0 ]; then echo -e "${GREEN}环境初始化完成!${NC}" fi ;; 2) echo -e "${YELLOW}开始迁移数据库...${NC}" - init_database + init_database || continue ;; 3) echo -e "${YELLOW}开始运行代码检查...${NC}" - run_code_check + run_code_check || continue ;; 4) echo -e "${YELLOW}开始启动应用...${NC}" - ensure_directories - activate_conda_env - start_app + ensure_directories || continue + activate_conda_env || continue + start_app || continue ;; 5) - do_full_install + do_full_install || continue ;; 9) - start_test + start_test || continue ;; 0) echo -e "${GREEN}再见!${NC}" @@ -389,13 +405,13 @@ while true; do ;; *) echo -e "${RED}无效的选择,请重试${NC}" - read -p "按回车键继续..." + echo -e "按回车键返回主菜单..." ;; esac # 如果不是启动应用,则等待用户按回车继续 if [ "$choice" != "4" ] && [ "$choice" != "5" ]; then echo - read -p "按回车键继续..." + echo -e "按回车键返回主菜单..." fi -done \ No newline at end of file +done diff --git a/tests/test_data_source.py b/tests/test_data_source.py index f87653f..8b43a26 100644 --- a/tests/test_data_source.py +++ b/tests/test_data_source.py @@ -71,9 +71,7 @@ def assertIsValidPercentage(self, value, field_name: str): self.assertIsInstance(float_value, float, "\n".join(error_msg)) except (ValueError, TypeError) as e: - self.fail( - f"\n百分比转换失败: {field_name}\n" f"值: {value!r}\n" f"错误: {str(e)}" - ) + self.fail(f"\n百分比转换失败: {field_name}\n" f"值: {value!r}\n" f"错误: {str(e)}") def test_get_fund_detail(self): """测试获取基金详情功能""" diff --git a/tests/test_tasks.py b/tests/test_tasks.py index b58ca6d..fdb15d5 100644 --- a/tests/test_tasks.py +++ b/tests/test_tasks.py @@ -88,15 +88,9 @@ def test_task_execution(self): self.assertIsNotNone(results["company"], "基金公司不能为空") # 验证数值字段 - self.assertIsInstance( - results["establishment_size"], (int, float), "成立规模应为数值类型" - ) - self.assertIsInstance( - results["management_fee"], (int, float), "管理费率应为数值类型" - ) - self.assertIsInstance( - results["custodian_fee"], (int, float), "托管费率应为数值类型" - ) + self.assertIsInstance(results["establishment_size"], (int, float), "成立规模应为数值类型") + self.assertIsInstance(results["management_fee"], (int, float), "管理费率应为数值类型") + self.assertIsInstance(results["custodian_fee"], (int, float), "托管费率应为数值类型") self.assertIsInstance( results["sales_service_fee"], (int, float), "销售服务费率应为数值类型" )