修复路径
This commit is contained in:
parent
b96137d807
commit
a9f13e2607
@ -267,6 +267,7 @@ class CodeGenerateInterface(QWidget):
|
||||
"""生成所有代码,包括未加载页面"""
|
||||
try:
|
||||
# 先收集所有页面名(从CSV配置文件读取)
|
||||
from app.tools.code_generator import CodeGenerator # 在方法内重新导入确保可用
|
||||
csv_path = os.path.join(CodeGenerator.get_assets_dir("User_code"), "config.csv")
|
||||
all_class_names = []
|
||||
if os.path.exists(csv_path):
|
||||
@ -344,6 +345,7 @@ class CodeGenerateInterface(QWidget):
|
||||
return "未找到.ioc文件"
|
||||
|
||||
def _load_csv_and_build_tree(self):
|
||||
from app.tools.code_generator import CodeGenerator # 在方法内重新导入确保可用
|
||||
csv_path = os.path.join(CodeGenerator.get_assets_dir("User_code"), "config.csv")
|
||||
print(f"加载CSV路径: {csv_path}")
|
||||
if not os.path.exists(csv_path):
|
||||
|
||||
@ -1235,6 +1235,9 @@ class bsp(QWidget):
|
||||
@staticmethod
|
||||
def generate_bsp(project_path, pages):
|
||||
"""生成所有BSP代码"""
|
||||
# 在方法开始时导入CodeGenerator以确保可用
|
||||
from app.tools.code_generator import CodeGenerator
|
||||
|
||||
# 自动添加 bsp.h
|
||||
src_bsp_h = os.path.join(CodeGenerator.get_assets_dir("User_code/bsp"), "bsp.h")
|
||||
dst_bsp_h = os.path.join(project_path, "User/bsp/bsp.h")
|
||||
|
||||
@ -286,6 +286,9 @@ class component(QWidget):
|
||||
@staticmethod
|
||||
def generate_component(project_path, pages):
|
||||
"""生成所有组件代码,处理依赖关系"""
|
||||
# 在方法开始时导入CodeGenerator以确保可用
|
||||
from app.tools.code_generator import CodeGenerator
|
||||
|
||||
# 自动添加 component.h
|
||||
src_component_h = os.path.join(CodeGenerator.get_assets_dir("User_code/component"), "component.h")
|
||||
dst_component_h = os.path.join(project_path, "User/component/component.h")
|
||||
@ -318,7 +321,6 @@ class component(QWidget):
|
||||
components_to_generate.add(dep_name)
|
||||
|
||||
# 为没有对应页面但需要生成的依赖组件创建临时页面
|
||||
from ..tools.code_generator import CodeGenerator
|
||||
user_code_dir = CodeGenerator.get_assets_dir("User_code")
|
||||
for comp_name in components_to_generate:
|
||||
if comp_name not in component_pages:
|
||||
|
||||
@ -41,6 +41,7 @@ def get_available_bsp_devices(project_path, bsp_type, gpio_type=None):
|
||||
|
||||
def generate_device_header(project_path, enabled_devices):
|
||||
"""生成device.h文件"""
|
||||
from app.tools.code_generator import CodeGenerator
|
||||
device_dir = CodeGenerator.get_assets_dir("User_code/device")
|
||||
template_path = os.path.join(device_dir, "device.h")
|
||||
|
||||
@ -318,6 +319,7 @@ class DeviceSimple(QWidget):
|
||||
def get_device_page(device_name, project_path):
|
||||
"""根据设备名返回对应的页面类"""
|
||||
# 加载设备配置
|
||||
from app.tools.code_generator import CodeGenerator
|
||||
device_dir = CodeGenerator.get_assets_dir("User_code/device")
|
||||
config_path = os.path.join(device_dir, "config.yaml")
|
||||
device_configs = load_device_config(config_path)
|
||||
|
||||
@ -7,6 +7,11 @@ import os
|
||||
class CodeGenerator:
|
||||
"""通用代码生成器"""
|
||||
|
||||
# 添加类级别的缓存
|
||||
_assets_dir_cache = None
|
||||
_assets_dir_initialized = False
|
||||
_template_dir_logged = False
|
||||
|
||||
@staticmethod
|
||||
def load_template(template_path: str) -> str:
|
||||
"""加载代码模板"""
|
||||
@ -66,8 +71,12 @@ class CodeGenerator:
|
||||
# 使用统一的get_assets_dir方法来获取路径
|
||||
template_dir = CodeGenerator.get_assets_dir("User_code/bsp")
|
||||
|
||||
print(f"模板目录路径: {template_dir}")
|
||||
if not os.path.exists(template_dir):
|
||||
# 只在第一次或出现问题时打印日志
|
||||
if not hasattr(CodeGenerator, '_template_dir_logged'):
|
||||
print(f"模板目录路径: {template_dir}")
|
||||
CodeGenerator._template_dir_logged = True
|
||||
|
||||
if template_dir and not os.path.exists(template_dir):
|
||||
print(f"警告:模板目录不存在: {template_dir}")
|
||||
|
||||
return template_dir
|
||||
@ -80,31 +89,78 @@ class CodeGenerator:
|
||||
Returns:
|
||||
str: 完整的assets路径
|
||||
"""
|
||||
if getattr(sys, 'frozen', False):
|
||||
# 打包后的环境 - 使用可执行文件所在目录而不是临时目录
|
||||
exe_dir = os.path.dirname(sys.executable)
|
||||
assets_dir = os.path.join(exe_dir, "assets")
|
||||
print(f"打包环境:尝试使用路径: {assets_dir}")
|
||||
# 使用缓存机制,避免重复计算和日志输出
|
||||
if not CodeGenerator._assets_dir_initialized:
|
||||
assets_dir = ""
|
||||
|
||||
# 如果exe_dir/assets不存在,尝试使用sys._MEIPASS作为后备
|
||||
if not os.path.exists(assets_dir) and hasattr(sys, '_MEIPASS'):
|
||||
base_path = getattr(sys, '_MEIPASS')
|
||||
assets_dir = os.path.join(base_path, "assets")
|
||||
print(f"后备路径: {assets_dir}")
|
||||
if getattr(sys, 'frozen', False):
|
||||
# 打包后的环境
|
||||
print("检测到打包环境")
|
||||
|
||||
# 优先使用sys._MEIPASS(PyInstaller的临时解包目录)
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
base_path = getattr(sys, '_MEIPASS')
|
||||
assets_dir = os.path.join(base_path, "assets")
|
||||
print(f"使用PyInstaller临时目录: {assets_dir}")
|
||||
else:
|
||||
# 后备方案:使用可执行文件所在目录
|
||||
exe_dir = os.path.dirname(sys.executable)
|
||||
assets_dir = os.path.join(exe_dir, "assets")
|
||||
print(f"使用可执行文件目录: {assets_dir}")
|
||||
|
||||
# 如果都不存在,尝试其他可能的位置
|
||||
if not os.path.exists(assets_dir):
|
||||
# 尝试从当前工作目录查找
|
||||
cwd_assets = os.path.join(os.getcwd(), "assets")
|
||||
if os.path.exists(cwd_assets):
|
||||
assets_dir = cwd_assets
|
||||
print(f"从工作目录找到assets: {assets_dir}")
|
||||
else:
|
||||
print(f"警告:无法找到assets目录,使用默认路径: {assets_dir}")
|
||||
else:
|
||||
# 开发环境
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# 向上查找直到找到MRobot目录或到达根目录
|
||||
while current_dir != os.path.dirname(current_dir): # 防止无限循环
|
||||
if os.path.basename(current_dir) == 'MRobot':
|
||||
break
|
||||
parent = os.path.dirname(current_dir)
|
||||
if parent == current_dir: # 已到达根目录
|
||||
break
|
||||
current_dir = parent
|
||||
|
||||
assets_dir = os.path.join(current_dir, "assets")
|
||||
print(f"开发环境:使用路径: {assets_dir}")
|
||||
|
||||
# 如果找不到,尝试从当前工作目录
|
||||
if not os.path.exists(assets_dir):
|
||||
cwd_assets = os.path.join(os.getcwd(), "assets")
|
||||
if os.path.exists(cwd_assets):
|
||||
assets_dir = cwd_assets
|
||||
print(f"开发环境后备:使用工作目录: {assets_dir}")
|
||||
|
||||
# 缓存基础assets目录
|
||||
CodeGenerator._assets_dir_cache = assets_dir
|
||||
CodeGenerator._assets_dir_initialized = True
|
||||
else:
|
||||
# 开发环境
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
while os.path.basename(current_dir) != 'MRobot' and current_dir != '/':
|
||||
current_dir = os.path.dirname(current_dir)
|
||||
assets_dir = os.path.join(current_dir, "assets")
|
||||
print(f"开发环境:使用路径: {assets_dir}")
|
||||
# 使用缓存的路径
|
||||
assets_dir = CodeGenerator._assets_dir_cache or ""
|
||||
|
||||
# 构建完整路径
|
||||
if sub_path:
|
||||
full_path = os.path.join(assets_dir, sub_path)
|
||||
else:
|
||||
full_path = assets_dir
|
||||
|
||||
if not os.path.exists(full_path):
|
||||
# 规范化路径(处理路径分隔符)
|
||||
full_path = os.path.normpath(full_path)
|
||||
|
||||
# 只在第一次访问某个路径时检查并警告
|
||||
safe_sub_path = sub_path.replace('/', '_').replace('\\', '_')
|
||||
warning_key = f"_warned_{safe_sub_path}"
|
||||
if full_path and not os.path.exists(full_path) and not hasattr(CodeGenerator, warning_key):
|
||||
print(f"警告:资源目录不存在: {full_path}")
|
||||
setattr(CodeGenerator, warning_key, True)
|
||||
|
||||
return full_path
|
||||
136
code_generator_usage_check.md
Normal file
136
code_generator_usage_check.md
Normal file
@ -0,0 +1,136 @@
|
||||
# CodeGenerator 使用情况完整检查报告
|
||||
|
||||
## 检查目标
|
||||
确保 `CodeGenerator` 类在开发环境和打包exe环境中都能正常工作,不会出现 `local variable 'CodeGenerator' referenced before assignment` 错误。
|
||||
|
||||
## 已修复的问题
|
||||
|
||||
### 1. 静态方法中的导入问题
|
||||
✅ **已修复** - 以下静态方法已添加本地导入:
|
||||
|
||||
- `app/code_generate_interface.py`
|
||||
- `generate_code()` - 第270行已添加本地导入
|
||||
- `_load_csv_and_build_tree()` - 第348行已添加本地导入
|
||||
|
||||
- `app/code_page/component_interface.py`
|
||||
- `component.generate_component()` - 第289行已添加本地导入
|
||||
|
||||
- `app/code_page/bsp_interface.py`
|
||||
- `bsp.generate_bsp()` - 第1240行已添加本地导入
|
||||
|
||||
- `app/code_page/device_interface.py`
|
||||
- `generate_device_header()` - 第44行已添加本地导入
|
||||
- `get_device_page()` - 第321行已添加本地导入
|
||||
|
||||
### 2. 相对导入问题
|
||||
✅ **已修复** - 统一使用绝对导入:
|
||||
- `app/code_page/component_interface.py` 第321行的相对导入已改为绝对导入
|
||||
|
||||
### 3. 缓存和性能优化
|
||||
✅ **已优化**:
|
||||
- 添加了 `_assets_dir_cache` 和 `_assets_dir_initialized` 缓存机制
|
||||
- 优化了 `get_template_dir()` 方法,减少重复日志输出
|
||||
- 改进了路径计算,避免重复的文件系统操作
|
||||
|
||||
## 安全的使用场景
|
||||
|
||||
### 1. 实例方法中的使用(✅ 安全)
|
||||
这些使用 `CodeGenerator` 的地方都是在类的实例方法中,可以正常使用顶层导入:
|
||||
|
||||
- `ComponentSimple.__init__()` - 第108行
|
||||
- `ComponentSimple._generate_component_code_internal()` - 第172行
|
||||
- `ComponentSimple._get_component_template_dir()` - 第182行
|
||||
- `ComponentSimple._save_config()` - 第186, 191行
|
||||
- `ComponentSimple._load_config()` - 第195行
|
||||
- `DevicePageBase.__init__()` 及相关方法
|
||||
- `BspPeripheralBase` 各种实例方法
|
||||
- `DataInterface.show_user_code_files()` - 已有本地导入
|
||||
- `DataInterface.generate_code()` - 已有本地导入
|
||||
- `DataInterface.generate_task_code()` - 已有本地导入
|
||||
|
||||
### 2. 模块级别函数(需要验证)
|
||||
以下独立函数需要确认是否使用了 `CodeGenerator`:
|
||||
|
||||
- `load_device_config()`
|
||||
- `get_available_bsp_devices()`
|
||||
- `load_descriptions()` (bsp)
|
||||
- `get_available_*()` 系列函数
|
||||
|
||||
## 打包环境优化
|
||||
|
||||
### 1. 路径处理优化
|
||||
✅ **已优化** `get_assets_dir()` 方法:
|
||||
- 优先使用 `sys._MEIPASS`(PyInstaller临时目录)
|
||||
- 后备使用可执行文件目录
|
||||
- 增加工作目录查找作为最后选择
|
||||
- 改进了开发环境的目录查找逻辑
|
||||
- 添加了路径规范化处理
|
||||
|
||||
### 2. 错误处理改进
|
||||
✅ **已改进**:
|
||||
- 更好的错误提示信息
|
||||
- 只在第一次访问路径时显示警告
|
||||
- 防止重复日志输出
|
||||
|
||||
## 建议的进一步改进
|
||||
|
||||
### 1. 添加环境检测工具方法
|
||||
```python
|
||||
@staticmethod
|
||||
def is_frozen():
|
||||
"""检测是否在打包环境中运行"""
|
||||
return getattr(sys, 'frozen', False)
|
||||
|
||||
@staticmethod
|
||||
def get_base_path():
|
||||
"""获取基础路径,自动适配开发/打包环境"""
|
||||
if CodeGenerator.is_frozen():
|
||||
return getattr(sys, '_MEIPASS', os.path.dirname(sys.executable))
|
||||
else:
|
||||
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
```
|
||||
|
||||
### 2. 配置验证方法
|
||||
```python
|
||||
@staticmethod
|
||||
def validate_assets():
|
||||
"""验证assets目录是否存在并包含必要文件"""
|
||||
assets_dir = CodeGenerator.get_assets_dir()
|
||||
required_dirs = ["User_code/bsp", "User_code/component", "User_code/device"]
|
||||
|
||||
for req_dir in required_dirs:
|
||||
path = os.path.join(assets_dir, req_dir)
|
||||
if not os.path.exists(path):
|
||||
return False, f"缺少必要目录: {path}"
|
||||
return True, "Assets目录验证通过"
|
||||
```
|
||||
|
||||
## 测试清单
|
||||
|
||||
### 开发环境测试
|
||||
- [ ] 启动应用程序无错误
|
||||
- [ ] 生成BSP代码功能正常
|
||||
- [ ] 生成Component代码功能正常
|
||||
- [ ] 生成Device代码功能正常
|
||||
- [ ] 路径解析正确
|
||||
- [ ] 无重复日志输出
|
||||
|
||||
### 打包环境测试
|
||||
- [ ] 使用PyInstaller打包成exe
|
||||
- [ ] exe启动无错误
|
||||
- [ ] 所有代码生成功能正常
|
||||
- [ ] assets目录正确定位
|
||||
- [ ] 模板文件正确加载
|
||||
- [ ] 配置文件读写正常
|
||||
|
||||
## 总结
|
||||
|
||||
经过完整检查和修复,现在的代码应该能够在开发环境和打包环境中都正常工作。主要改进包括:
|
||||
|
||||
1. **导入安全性**:所有静态方法都添加了本地导入
|
||||
2. **路径处理**:优化了assets目录的查找逻辑
|
||||
3. **性能优化**:添加了缓存机制,减少重复计算
|
||||
4. **错误处理**:改进了错误提示和日志输出
|
||||
5. **兼容性**:确保开发和打包环境的兼容性
|
||||
|
||||
建议在发布前进行完整的功能测试,特别是在打包后的exe环境中测试所有代码生成功能。
|
||||
Loading…
Reference in New Issue
Block a user