这几天在写ryu的app是需要导入其他的文件夹下的程序,像这样:
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.ofproto.StartModel import StartIdentify
from Cnn_Identify_Model.RyuNetwork.test import test
在pycharm下的terminal输入:
ryu-manager Cnn_Identify_Model/RyuNetwork/StartNetwork.py是发现模块导入失败:
Traceback (most recent call last):
File "/root/PycharmProjects/HuaWeiBei/venv/bin/ryu-manager", line 11, in <module>
load_entry_point('ryu==4.32', 'console_scripts', 'ryu-manager')()
File "/root/PycharmProjects/HuaWeiBei/venv/lib/python3.5/site-packages/ryu/cmd/manager.py", line 100, in main
app_mgr.load_apps(app_lists)
File "/root/PycharmProjects/HuaWeiBei/venv/lib/python3.5/site-packages/ryu/base/app_manager.py", line 416, in load_apps
cls = self.load_app(app_cls_name)
File "/root/PycharmProjects/HuaWeiBei/venv/lib/python3.5/site-packages/ryu/base/app_manager.py", line 392, in load_app
mod = utils.import_module(name)
File "/root/PycharmProjects/HuaWeiBei/venv/lib/python3.5/site-packages/ryu/utils.py", line 104, in import_module
return _import_module_file(modname)
File "/root/PycharmProjects/HuaWeiBei/venv/lib/python3.5/site-packages/ryu/utils.py", line 92, in _import_module_file
return load_source(modname, abspath)
File "/root/PycharmProjects/HuaWeiBei/venv/lib/python3.5/site-packages/ryu/utils.py", line 44, in load_source
return loader.load_module(name)
File "<frozen importlib._bootstrap_external>", line 388, in _check_name_wrapper
File "<frozen importlib._bootstrap_external>", line 809, in load_module
File "<frozen importlib._bootstrap_external>", line 668, in load_module
File "<frozen importlib._bootstrap>", line 268, in _load_module_shim
File "<frozen importlib._bootstrap>", line 693, in _load
File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 665, in exec_module
File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
File "/root/PycharmProjects/HuaWeiBei/Cnn_Identify_Model/RyuNetwork/StartNetwork.py", line 11, in <module>
from Cnn_Identify_Model.RyuNetwork.test import test
ImportError: No module named 'Cnn_Identify_Model'
难受,只能去解决。按照他提示的错误一步一步的去跟踪并输出一些中间结果。
app_lists:['Cnn_Identify_Model/RyuNetwork/StartNetwork.py']
app_mgr.load_apps(app_lists)
app_cls_name:Cnn_Identify_Model/RyuNetwork/StartNetwork.py
cls = self.load_app(app_cls_name)
mod = utils.import_module(name)
modname:Cnn_Identify_Model/RyuNetwork/StartNetwork.py
return _import_module_file(modname)
#下面要多输出一些
def _import_module_file(path):
abspath = os.path.abspath(path)
# Backup original sys.path before appending path to file
original_path = list(sys.path)
sys.path.append(os.path.dirname(abspath))
modname = chop_py_suffix(os.path.basename(abspath))
print(list(sys.path))
sys.path
['/root/PycharmProjects/HuaWeiBei/venv/bin', '/usr/lib/python35.zip', '/usr/lib/python3.5', '/usr/lib/python3.5/plat-x86_64-linux-gnu', '/usr/lib/python3.5/lib-dynload', '/root/PycharmProjects/HuaWeiBei/venv/lib/python3.5/site-packages', '/root/PycharmProjects/HuaWeiBei/venv/lib/python3.5/site-packages/setuptools-40.8.0-py3.5.egg', '/root/PycharmProjects/HuaWeiBei/venv/lib/python3.5/site-packages/pip-19.0.3-py3.5.egg', '/root/PycharmProjects/HuaWeiBei/Cnn_Identify_Model/RyuNetwork']
try:
return load_source(modname, abspath)
finally:
# Restore original sys.path
sys.path = original_path
是什么原因导致了这个问题,他说那个模块不存在,那么python是如何检查一个model是否存在的?于是在网上搜了一下找到了结果,他说需要在sys.path里要有相关的路径。就是之前在中间过程里打印出来的sys.path。但是可以看到
/root/PycharmProjects/HuaWeiBei/Cnn_Identify_Model/RyuNetwork已经再里面了。后来发现不是这样的,我只是把RyuNetwork导入进来了。并没有将Cnn_Identify_Model放置到sys.path当中。于是这个就需要手动的来添加。
可以使用sys.path.append()来添加相应的model路径。
当然还有两个不需要添加这个路径的方法。
第一个就是将需要导入的文件放入到sys.path的检查路径中。之前我就是通过此方法,将文件放置到ryu的ofproto的文件夹下来解决问题的。
第二个就是只是用一个文件夹,比如我的是RyuNetwork,那么所有的程序都放到这个文件夹下,那么就不会有问题。原因是上面的_import_module_file(utils)里向sys.path添加了这个文件夹的路径。
所以总而言之三种方法:
1.使用sys.path.append(),比如sys.path.append(“root/PycharmProjects/HuaWeiBei/”)这样就不用考虑导入问题了,这个项目文件夹都在path路径中了。
2.只是用一个文件夹。ryu会在load_model是向sys.path添加上此文件所在目录的。
3.将需要导入的文件放置到sys.path中。(可以使用print(sys.path)来查看sys.path与那些路径)
可是使用sys.path有一个问题就是ryu-manage是先导入模块,再去执行相应的代码,如果在代码中执行sys.path那就迟了。于是我给出一种解决思路就是在utils中添加函数来解决问题。添加的函数中传入的是ryu程序的绝对路径,通过解析绝对路径来阻隔向sys.path来添加路径,这样就解决了sys.path不能执行的问题,也解决了不知道项目名字和具体的文件夹的问题。
def addtosyspath(path):
kk = path.split('/')[1:-1]
str = '/'
for i in range(len(kk)):
str += kk[i] + '/'
#逐个添加路径
sys.path.append(str)
def _import_module_file(path):
abspath = os.path.abspath(path)
# Backup original sys.path before appending path to file
original_path = list(sys.path)
addtosyspath(abspath)
sys.path.append(os.path.dirname(abspath))
sys.path.append(rootdir)
print(sys.path)
modname = chop_py_suffix(os.path.basename(abspath))
try:
return load_source(modname, abspath)
finally:
# Restore original sys.path
sys.path = original_path
但是黑有一个问题就是如果导入的文件在同文件夹下的子文件夹,这时便遍历不到相应的文件夹了。如果使用每个文件并判断其是否是文件夹,那么就不值得了,原因是文件夹将会非常长的多,一次性检查这么多的文件夹会耗时,而且后面执行文件需要依据此sys.path来查找具体的导入文件也是一个耗时过程。
后来发现在manager.py的代码中有这么一段:
app_lists = CONF.app_lists + CONF.app
经检测CONF.app_lists有用,所以打印出来看一下:
[‘Cnn_Identify_Model/RyuNetwork/StartNetwork.py’],这下终于知道了ryu拿到的其实是相对路径,那么就可以根据绝对路径找到ryu的app所在的项目的项目名了。再依据项目名来遍历其下的文件夹,如果是文件夹,在判断其是否在sys.path中,若在就不添加了。这个时候还是要改下ryu的代码的,方便其传输CONF.app。
需要改的地方为:
manage的app_mgr.load_apps(app_lists),添加一个参数,为了方便与之前的系统兼容参数默认为None
像这样:
app_mgr.load_apps(app_lists,app_list)
def load_app(self, name,relativepath=None):
#在这里添加得到项目路径方法
#获取文件的绝对路径
abspath = sys.path.abspath(name)
#由于relativepath是一个列表且只有一个值所以需要将其取出来再传值
self.addpath(abspath,relativepath[0])
mod = utils.import_module(name)
def addpath(self,abspath,relativepath):
#分割路径,取出中间的必要信息
absp = abspath.split('/')[1:-1]
relativep = relativepath.split('/')[:-1]
path = '/'
for i in range(len(absp)):
#这样做的原因是相对路径的绝对路径的一个子路径
#只需要取到相对路径前面的那一段路径就可以了,那个就是项目的路径
if absp[i] == relativep[0]:
break
path+=absp[i]+"/"
#将其添加到系统的路径列表中。
sys.path.append(path)
经检测import导入是看最外面的包是否在sys.path的路径中所以只要找出项目文件名就可以解决问题了。相关代码很简单这里就略过了。
至此关于ryu的关于import导入失败问题解决。