问题描述
在执行某个测试模块时出现提示,显示自定义模块data
不存在,但是在PyCharm下运行正常。错误信息如下:
Traceback (most recent call last):
File "/run/channelnterface-autocase/testcases/test_chanel_detail.py", line 2, in <module>
from data.chanel_detail_makecase import *
ModuleNotFoundError: No module named 'data'
问题原因
大部分情况下,此类问题是由于包的路径没有设置正确所致。通过打印 PyCharm 和命令行下的 sys.path
路径信息对比,可以发现以下差异:
在当前目录下__init__
添加
import sys
print("系统路径",sys.path)
分别用PyCharm与命令行执行
-
PyCharm
包含了当前的目录以及这个代码的根目录(前提是需要将这个根目录设置为Sources Root)
结果:系统路径 [‘D:\uitest\channelnterface-autocase\testcases’, ‘D:\uitest’, ‘D:\uitest\channelnterface-autocase’… -
使用Pyhton命令行执行
结果为系统路径 [‘D:\uitest\channelnterface-autocase\testcases’…
在PyCharm设置了Sources Root,向系统变量增加了当前目录的根目录,所以PyCharm运行时能找到自定义包的。但Pyhton命令行执行时少了添加根目录路径的步骤,导致找不到包了。
解决方法
向执行代码中添加根目录路径,一般添加在头部
方法一:写死绝对路径
import sys
sys.path.append('xxx/xxx/xxx/')
方法二:使用os获取
os.path.dirname
获取目录,此处就是获取目录的父目录。如果目录层级更多,就需要多加一层 os.path.dirname
import os,sys
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_root)
方法三:os获取+/…/
如果层级更多,则需要多加"…/" ,看起来比方法二更加简洁点
import os,sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
方法四,直接加到环境变量path中
输入以下命令
export PYTHONPATH=$PYTHONPATH:/xxx/
export 命令输入只临时生效,重新连接会失效,或者直接修改环境配置~/.bashrc等配置加上这句可以实现永久解决问题,如果这个不能实现,考虑自己手动去执行添加
方法五,subprocess.run 使用env变量
有些人是在subprocess去执行脚本,这个时候用上述的方法就不太能永久解决问题。我们可以使用subprocess的env参数去做,代码如下
def run_script(self, script_path, *args):
# 运行 Python 脚本
path_parts = script_path.split('/')
export_commands = []
for i in range(1, len(path_parts)):
path_part = '/'.join(path_parts[:i])
export_commands.append(f'{path_part}')
env = os.environ.copy()
env['PYTHONPATH'] = ':'.join(export_commands) + ':' + env.get('PYTHONPATH', '')
# print(f"env{env}")
script_dir = os.path.dirname(script_path)
command = [f'{self.venv_path}/bin/python3', script_path] + list(args)
return self.run_command(command,cwd=script_dir,env=env)
def run_command(self, command, shell=False,cwd=None,env=None) -> Tuple[int, str]:
# 执行命令
result = subprocess.run(command, shell=shell, capture_output=True, text=True,cwd=cwd,env=env)
print(f"returncode:{result.returncode}")
return result.returncode
通过script_path地址变量解析,添加所有的路径到环境变量中,然后给subprocess.run做继承,subprocess.run如果不继承的,每开一个会话,都是新的变量环境。
总结:
可能还有其他方法,但大体上找不到module的问题,大部分是路径变量问题,按照这个思路去解决就可以解决大部分类似问题。