From 726c21feac978fa721ef1441a003983081f9007b Mon Sep 17 00:00:00 2001 From: Dang Zerong Date: Fri, 13 Mar 2026 16:04:20 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=8F=AF=E6=BC=94=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 34 +++++++ config.yaml | 9 +- docker-compose.yml | 9 ++ pyproject.toml | 24 +++++ requirements.txt | 6 ++ test.py | 218 --------------------------------------------- web/index.html | 142 ----------------------------- 7 files changed, 77 insertions(+), 365 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 pyproject.toml delete mode 100644 test.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..64d7923 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +# 使用中科大镜像源的 Python 基础镜像 +FROM python:3.11.15-slim + +# 设置工作目录 +WORKDIR /app + +# 设置环境变量 +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV FLASK_RUN_HOST=0.0.0.0 + +# 安装系统依赖(用于 git 等工具) +RUN apt-get update && apt-get install -y --no-install-recommends \ + git \ + && rm -rf /var/lib/apt/lists/* + +# 复制依赖文件 +COPY requirements.txt . + +# 安装 Python 依赖(显式安装,避免缓存导致遗漏) +RUN pip install --no-cache-dir -r requirements.txt \ + && pip install --no-cache-dir "GitPython>=3.1.0" "gitdb>=4.0.1" "smmap>=3.0.1" + +# 复制应用代码 +COPY . . + +# 创建报告目录 +RUN mkdir -p reports + +# 暴露端口 +EXPOSE 5000 + +# 启动应用 +CMD ["python", "app.py"] diff --git a/config.yaml b/config.yaml index 8b8e755..49dd481 100644 --- a/config.yaml +++ b/config.yaml @@ -49,13 +49,12 @@ ai: # AI 审查器配置 # 支持: "ollama" (本地) 或 "api" (在线API) provider: "api" - # 模型名称(硅基流动可用模型)- Qwen 最强语言模型 - model: "deepseek-ai/DeepSeek-V3.2" + # 模型名称(阿里云通义千问) + model: "qwen3.5-plus" # API 地址 - # 硅基流动: https://api.siliconflow.cn/v1 - api_url: "https://api.siliconflow.cn/v1" + api_url: "https://dashscope.aliyuncs.com/compatible-mode/v1" # API 密钥 - api_key: "sk-cqxhnsxdxaalxlykfkjksyinjftdyejnblmgkfxmhwmmvdyu" + api_key: "sk-616332b2afa94699b4572d0fe6ac370a" # 是否启用 AI 审查 enabled: true # 每次审查的最大代码行数 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2a46add --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: "3.8" + +services: + code-scan: + image: dcr-by1jwyxk44.71826370.xyz/whlaoding/code-scan:latest + container_name: code-scan + ports: + - "5000:5000" + restart: unless-stopped diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c187f72 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["setuptools>=45", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "code-scan" +version = "1.0.0" +description = "代码扫描工具" +readme = "README.md" +requires-python = ">=3.8" +dependencies = [ + "flask>=2.0.0", + "pyyaml>=5.0", + "requests>=2.25.0", + "python-dotenv>=0.19.0", + "GitPython>=3.1.0", +] + +[project.scripts] +code-scan = "app:main" + +[tool.setuptools.packages.find] +where = ["."] +include = ["scanner*"] diff --git a/requirements.txt b/requirements.txt index 369f634..d2be847 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,9 @@ flask>=2.0.0 pyyaml>=5.0 requests>=2.25.0 python-dotenv>=0.19.0 +GitPython>=3.1.0 +gitdb>=4.0.1 +smmap>=3.0.1 +pylint>=2.17.0 +flake8>=6.0.0 +bandit>=1.7.0 diff --git a/test.py b/test.py deleted file mode 100644 index 14b50b7..0000000 --- a/test.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import os -import logging - - -os.environ.setdefault('FLASK_RUN_HOST', '0.0.0.0') - -from flask import Flask, request, jsonify -import yaml -from webhook.handler import GiteaWebhookHandler -from scanner.python_scanner import PythonScanner -from scanner.js_scanner import JavaScriptScanner -from scanner.security_scanner import SecurityScanner -from report.generator import ReportGenerator -from notify.feishu import FeishuNotifier - -# 配置日志 -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' -) -logger = logging.getLogger(__name__) - -# 加载配置 -def load_config(): - """加载配置文件""" - config_path = os.path.join(os.path.dirname(__file__), 'config.yaml') - with open(config_path, 'r', encoding='utf-8') as f: - return yaml.safe_load(f) - -# 全局配置 -config = load_config() - -# 初始化应用 -app = Flask(__name__) -app.config['SECRET_KEY'] = config.get('server', {}).get('secret_key', 'dev-secret-key') - -# 初始化组件 -webhook_handler = GiteaWebhookHandler(config['gitea']) -python_scanner = PythonScanner(config.get('scanner', {})) -js_scanner = JavaScriptScanner(config.get('scanner', {})) -security_scanner = SecurityScanner(config.get('scanner', {})) -report_generator = ReportGenerator(config.get('report', {})) -feishu_notifier = FeishuNotifier(config['feishu']) - - -@app.route('/') -def index(): - """健康检查接口""" - return jsonify({ - 'status': 'ok', - 'service': 'AI Code Quality Scanner', - 'version': '1.0.0' - }) - - -@app.route('/webhook/gitea', methods=['POST']) -def handle_gitea_webhook(): - """处理 Gitea Webhook 请求""" - try: - # 验证签名 - signature = request.headers.get('X-Gitea-Signature') - if signature: - if not webhook_handler.verify_signature( - request.data, - signature, - config['gitea']['webhook_secret'] - ): - logger.warning('Webhook 签名验证失败') - return jsonify({'error': 'Invalid signature'}), 401 - - # 解析 Webhook payload - payload = request.json - if not payload: - return jsonify({'error': 'No payload'}), 400 - - event_type = request.headers.get('X-Gitea-Event', 'push') - logger.info(f'收到 Gitea Webhook 事件: {event_type}') - - # 只处理 push 事件 - if event_type != 'push': - return jsonify({'message': 'Event ignored'}), 200 - - # 提取提交信息 - commits = payload.get('commits', []) - if not commits: - return jsonify({'message': 'No commits'}), 200 - - repo = payload.get('repository', {}) - repo_name = repo.get('full_name', 'unknown') - branch = payload.get('ref', '').replace('refs/heads/', '') - pusher = payload.get('pusher', {}).get('name', 'unknown') - - logger.info(f'处理仓库 {repo_name} 的 {len(commits)} 个提交') - - # 处理每个提交 - for commit in commits: - commit_id = commit.get('id', '')[:8] - commit_message = commit.get('message', '') - author = commit.get('author', {}).get('name', 'unknown') - - logger.info(f'扫描提交 {commit_id}: {commit_message}') - - try: - # 获取仓库 URL - clone_url = repo.get('clone_url') - if not clone_url: - # 尝试从 web_url 构建 - web_url = repo.get('web_url', '') - if web_url: - clone_url = web_url.replace('http://', 'http://').replace('https://', 'https://') - clone_url = clone_url.rstrip('/') + '.git' - - # 执行代码扫描 - scan_results = {} - - # Python 扫描 - if 'python' in config.get('scanner', {}).get('languages', []): - scan_results['python'] = python_scanner.scan( - clone_url, commit_id, branch - ) - - # JavaScript/TypeScript 扫描 - if any(lang in config.get('scanner', {}).get('languages', []) - for lang in ['javascript', 'typescript']): - scan_results['javascript'] = js_scanner.scan( - clone_url, commit_id, branch - ) - - # 安全扫描 - scan_results['security'] = security_scanner.scan( - clone_url, commit_id, branch - ) - - # 生成报告 - report = report_generator.generate( - repo_name=repo_name, - branch=branch, - commit_id=commit_id, - commit_message=commit_message, - author=author, - scan_results=scan_results - ) - - # 发送飞书通知 - feishu_notifier.send_report(report) - - logger.info(f'提交 {commit_id} 扫描完成') - - except Exception as e: - logger.error(f'扫描提交 {commit_id} 失败: {str(e)}') - # 继续处理其他提交 - continue - - return jsonify({'status': 'ok', 'message': 'Scan completed'}), 200 - - except Exception as e: - logger.error(f'处理 Webhook 失败: {str(e)}', exc_info=True) - return jsonify({'error': str(e)}), 500 - - -@app.route('/scan/manual', methods=['POST']) -def manual_scan(): - """手动触发扫描接口""" - try: - data = request.json - repo_url = data.get('repo_url') - branch = data.get('branch', 'main') - commit_id = data.get('commit_id') - - if not repo_url: - return jsonify({'error': 'repo_url is required'}), 400 - - # 执行扫描 - scan_results = {} - - if 'python' in config.get('scanner', {}).get('languages', []): - scan_results['python'] = python_scanner.scan(repo_url, commit_id, branch) - - if any(lang in config.get('scanner', {}).get('languages', []) - for lang in ['javascript', 'typescript']): - scan_results['javascript'] = js_scanner.scan(repo_url, commit_id, branch) - - scan_results['security'] = security_scanner.scan(repo_url, commit_id, branch) - - # 生成报告 - report = report_generator.generate( - repo_name=repo_url.split('/')[-1].replace('.git', ''), - branch=branch, - commit_id=commit_id or 'manual', - commit_message='Manual scan', - author='manual', - scan_results=scan_results - ) - - # 发送飞书通知 - feishu_notifier.send_report(report) - - return jsonify({ - 'status': 'ok', - 'report': report - }), 200 - - except Exception as e: - logger.error(f'手动扫描失败: {str(e)}', exc_info=True) - return jsonify({'error': str(e)}), 500 - - -if __name__ == '__main__': - # 强制监听所有网络接口 - host = "0.0.0.0" - port = config.get('server', {}).get('port', 5000) - debug = config.get('server', {}).get('debug', True) - - logger.info(f'启动服务: {host}:{port}') - app.run(host=host, port=port, debug=debug) diff --git a/web/index.html b/web/index.html index 0143622..0354850 100644 --- a/web/index.html +++ b/web/index.html @@ -97,30 +97,9 @@ -
AI 智能分析
- - -
- AI 引擎 -
基于大模型智能分析代码质量
-
- 在线 -
-
@@ -289,126 +268,6 @@ - - - - - @@ -660,7 +519,6 @@ if (page === 'dashboard') loadDashboard(); if (page === 'prs') loadPRs(); - if (page === 'ai-quality') loadAIQualityOverview(); } // 加载概览数据 -- 2.49.1 From 51fc1a6aae0c9d667cecf7dafa12a9177d073ee7 Mon Sep 17 00:00:00 2001 From: Dang Zerong Date: Fri, 13 Mar 2026 16:21:39 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=85=88=E5=88=A0=E9=99=A4=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=90=8E=E9=9D=A2=E5=86=8D?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test_demo/demo_flaws.py | 267 ---------------------------------------- 1 file changed, 267 deletions(-) diff --git a/test_demo/demo_flaws.py b/test_demo/demo_flaws.py index a06db6a..e69de29 100644 --- a/test_demo/demo_flaws.py +++ b/test_demo/demo_flaws.py @@ -1,267 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -测试文件:包含常见代码缺陷,用于验证扫描器 -""" - -import os -import sys -import json -import pickle -import subprocess -from ast import parse -from typing import List, Dict - - -# 缺陷1: 未使用的导入 -import unused_module # 未使用 -import collections as col # 使用了 col 但 flake8 可能检测 - - -# 缺陷2: 未使用的变量 -def unused_variable_demo(): - """演示未使用的变量""" - result = calculate() # result 未被使用 - print("Function executed") - - -def calculate(): - """计算并返回结果""" - return 42 - - -# 缺陷3: 未定义的变量 -def undefined_variable_demo(): - """演示未定义的变量""" - print(undefined_var) # undefined_var 未定义 - - -# 缺陷4: 变量在定义前使用 -def use_before_define(): - """在定义前使用变量""" - print(before_var) # before_var 在下面才定义 - before_var = 100 - - -# 缺陷5: 硬编码密码(安全问题) -def connect_database(): - """连接数据库""" - password = "admin123" # 硬编码密码 - username = "root" - return f"Connecting with {username}:{password}" - - -# 缺陷6: 使用 eval(安全问题) -def unsafe_eval(): - """危险使用 eval""" - user_input = "os.system('ls')" - result = eval(user_input) # 危险! - return result - - -# 缺陷7: 使用 pickle 反序列化(安全问题) -def unsafe_pickle(): - """不安全的 pickle 反序列化""" - data = b"..." # 模拟恶意数据 - obj = pickle.loads(data) # 危险! - - -# 缺陷8: 行太长(风格问题) -def long_line(): - """这是一行非常非常非常非常非常非常非常非常非常非常非常非常长的代码超过了 120 个字符的限制""" - - -# 缺陷9: 缺少空格 -def missing_spaces(): - """缺少必要空格""" - x=1+2 - y=3*4 - if x==1: - print(x) - - -# 缺陷10: 多余空格 -def extra_spaces(): - """多余空格""" - x = 1 - y = 2 - - -# 缺陷11: 未捕获的异常 -def unhandled_exception(): - """捕获异常后未处理""" - try: - result = 10 / 0 - except ZeroDivisionError: - pass # 捕获但未处理 - - -# 缺陷12: 过于宽泛的异常 -def broad_exception(): - """捕获所有异常""" - try: - data = json.loads('{"key": "value"}') - except Exception: - pass - - -# 缺陷13: 裸 except 子句 -def bare_except(): - """使用裸 except""" - try: - x = int("abc") - except: - pass - - -# 缺陷14: 重复代码 -def duplicate_code(): - """重复代码示例""" - a = 1 - b = 2 - c = a + b - print(c) - - a = 3 - b = 4 - c = a + b - print(c) - - -# 缺陷15: 变量名与内置函数冲突 -def shadow_builtin(): - """变量名覆盖内置函数""" - list = [1, 2, 3] # 覆盖内置 list - dict = {} # 覆盖内置 dict - str = "hello" # 覆盖内置 str - return list, dict, str - - -# 缺陷16: 不必要的 pass -def unnecessary_pass(): - """不必要的 pass""" - if True: - pass # 可以直接删除 - - -# 缺陷17: 使用 + 进行字符串拼接(推荐用 join) -def string_concat(): - """低效字符串拼接""" - result = "" - for i in range(100): - result = result + str(i) - return result - - -# 缺陷18: 在循环中修改集合 -def modify_during_iteration(): - """在迭代时修改列表""" - items = [1, 2, 3, 4, 5] - for item in items: - if item % 2 == 0: - items.remove(item) # 在迭代时修改 - - -# 缺陷19: 全局变量 -global_counter = 0 # 全局变量 - - -def increment(): - global global_counter # 依赖全局变量 - global_counter += 1 - - -# 缺陷20: 魔法数字 -def calculate_price(): - """使用魔法数字""" - price = 100 - tax = price * 1.1 # 1.1 是什么? - discount = price * 0.9 - return tax, discount - - -# 缺陷21: 函数参数过多 -def bad_function(a, b, c, d, e, f, g, h): - """参数过多的函数""" - return a + b + c + d + e + f + g + h - - -# 缺陷22: 空函数体 -def empty_function(): - """空函数应该使用 pass 或文档字符串""" - pass - - -# 缺陷23: 使用 time.sleep 测试 -def bad_sleep(): - """生产代码中使用 time.sleep""" - import time - time.sleep(5) # 阻塞 - - -# 缺陷24: 注释掉的代码 -def commented_code(): - # print("This is commented out") - pass - - -# 缺陷25: TODO/FIXME 注释 -def todo_comment(): - # TODO: Implement this - # FIXME: This is broken - pass - - -# 缺陷26: 导入顺序错误(应先标准库,再第三方,本地) -import sys # 标准库 -import flask # 第三方 -from . import local # 本地 - - -# 缺陷27: 不必要的列表推导式 -def unnecessary_list_comp(): - """不必要的列表推导式""" - result = [x for x in range(10)] # 可简化为 list(range(10)) - return result - - -# 缺陷28: 条件表达式中的赋值 -def assignment_in_condition(): - """在条件中赋值(不推荐)""" - if (x := get_value()) > 0: # 海象运算符但可能难以阅读 - print(x) - - -def get_value(): - return 5 - - -# 缺陷29: 比较布尔值 -def compare_bool(): - """与布尔值比较""" - flag = True - if flag == True: # 应直接用 if flag: - print("yes") - - -# 缺陷30: 使用 hasattr/getattr 而非异常处理 -def use_hasattr(): - """滥用 hasattr""" - class Foo: - pass - obj = Foo() - if hasattr(obj, 'bar'): # 可直接用 try/except - print(obj.bar) - - -# 主函数入口 -def main(): - """主函数""" - connect_database() - unsafe_eval() - unsafe_pickle() - print("Demo executed") - - -if __name__ == "__main__": - main() -- 2.49.1 From 1876be1777b961f8bc8e1b52c1c5978e6bbeee91 Mon Sep 17 00:00:00 2001 From: Dang Zerong Date: Fri, 13 Mar 2026 16:22:23 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=9A=84=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test_demo/demo_flaws.py | 267 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) diff --git a/test_demo/demo_flaws.py b/test_demo/demo_flaws.py index e69de29..a06db6a 100644 --- a/test_demo/demo_flaws.py +++ b/test_demo/demo_flaws.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +测试文件:包含常见代码缺陷,用于验证扫描器 +""" + +import os +import sys +import json +import pickle +import subprocess +from ast import parse +from typing import List, Dict + + +# 缺陷1: 未使用的导入 +import unused_module # 未使用 +import collections as col # 使用了 col 但 flake8 可能检测 + + +# 缺陷2: 未使用的变量 +def unused_variable_demo(): + """演示未使用的变量""" + result = calculate() # result 未被使用 + print("Function executed") + + +def calculate(): + """计算并返回结果""" + return 42 + + +# 缺陷3: 未定义的变量 +def undefined_variable_demo(): + """演示未定义的变量""" + print(undefined_var) # undefined_var 未定义 + + +# 缺陷4: 变量在定义前使用 +def use_before_define(): + """在定义前使用变量""" + print(before_var) # before_var 在下面才定义 + before_var = 100 + + +# 缺陷5: 硬编码密码(安全问题) +def connect_database(): + """连接数据库""" + password = "admin123" # 硬编码密码 + username = "root" + return f"Connecting with {username}:{password}" + + +# 缺陷6: 使用 eval(安全问题) +def unsafe_eval(): + """危险使用 eval""" + user_input = "os.system('ls')" + result = eval(user_input) # 危险! + return result + + +# 缺陷7: 使用 pickle 反序列化(安全问题) +def unsafe_pickle(): + """不安全的 pickle 反序列化""" + data = b"..." # 模拟恶意数据 + obj = pickle.loads(data) # 危险! + + +# 缺陷8: 行太长(风格问题) +def long_line(): + """这是一行非常非常非常非常非常非常非常非常非常非常非常非常长的代码超过了 120 个字符的限制""" + + +# 缺陷9: 缺少空格 +def missing_spaces(): + """缺少必要空格""" + x=1+2 + y=3*4 + if x==1: + print(x) + + +# 缺陷10: 多余空格 +def extra_spaces(): + """多余空格""" + x = 1 + y = 2 + + +# 缺陷11: 未捕获的异常 +def unhandled_exception(): + """捕获异常后未处理""" + try: + result = 10 / 0 + except ZeroDivisionError: + pass # 捕获但未处理 + + +# 缺陷12: 过于宽泛的异常 +def broad_exception(): + """捕获所有异常""" + try: + data = json.loads('{"key": "value"}') + except Exception: + pass + + +# 缺陷13: 裸 except 子句 +def bare_except(): + """使用裸 except""" + try: + x = int("abc") + except: + pass + + +# 缺陷14: 重复代码 +def duplicate_code(): + """重复代码示例""" + a = 1 + b = 2 + c = a + b + print(c) + + a = 3 + b = 4 + c = a + b + print(c) + + +# 缺陷15: 变量名与内置函数冲突 +def shadow_builtin(): + """变量名覆盖内置函数""" + list = [1, 2, 3] # 覆盖内置 list + dict = {} # 覆盖内置 dict + str = "hello" # 覆盖内置 str + return list, dict, str + + +# 缺陷16: 不必要的 pass +def unnecessary_pass(): + """不必要的 pass""" + if True: + pass # 可以直接删除 + + +# 缺陷17: 使用 + 进行字符串拼接(推荐用 join) +def string_concat(): + """低效字符串拼接""" + result = "" + for i in range(100): + result = result + str(i) + return result + + +# 缺陷18: 在循环中修改集合 +def modify_during_iteration(): + """在迭代时修改列表""" + items = [1, 2, 3, 4, 5] + for item in items: + if item % 2 == 0: + items.remove(item) # 在迭代时修改 + + +# 缺陷19: 全局变量 +global_counter = 0 # 全局变量 + + +def increment(): + global global_counter # 依赖全局变量 + global_counter += 1 + + +# 缺陷20: 魔法数字 +def calculate_price(): + """使用魔法数字""" + price = 100 + tax = price * 1.1 # 1.1 是什么? + discount = price * 0.9 + return tax, discount + + +# 缺陷21: 函数参数过多 +def bad_function(a, b, c, d, e, f, g, h): + """参数过多的函数""" + return a + b + c + d + e + f + g + h + + +# 缺陷22: 空函数体 +def empty_function(): + """空函数应该使用 pass 或文档字符串""" + pass + + +# 缺陷23: 使用 time.sleep 测试 +def bad_sleep(): + """生产代码中使用 time.sleep""" + import time + time.sleep(5) # 阻塞 + + +# 缺陷24: 注释掉的代码 +def commented_code(): + # print("This is commented out") + pass + + +# 缺陷25: TODO/FIXME 注释 +def todo_comment(): + # TODO: Implement this + # FIXME: This is broken + pass + + +# 缺陷26: 导入顺序错误(应先标准库,再第三方,本地) +import sys # 标准库 +import flask # 第三方 +from . import local # 本地 + + +# 缺陷27: 不必要的列表推导式 +def unnecessary_list_comp(): + """不必要的列表推导式""" + result = [x for x in range(10)] # 可简化为 list(range(10)) + return result + + +# 缺陷28: 条件表达式中的赋值 +def assignment_in_condition(): + """在条件中赋值(不推荐)""" + if (x := get_value()) > 0: # 海象运算符但可能难以阅读 + print(x) + + +def get_value(): + return 5 + + +# 缺陷29: 比较布尔值 +def compare_bool(): + """与布尔值比较""" + flag = True + if flag == True: # 应直接用 if flag: + print("yes") + + +# 缺陷30: 使用 hasattr/getattr 而非异常处理 +def use_hasattr(): + """滥用 hasattr""" + class Foo: + pass + obj = Foo() + if hasattr(obj, 'bar'): # 可直接用 try/except + print(obj.bar) + + +# 主函数入口 +def main(): + """主函数""" + connect_database() + unsafe_eval() + unsafe_pickle() + print("Demo executed") + + +if __name__ == "__main__": + main() -- 2.49.1