[英]File “<string>” in python traceback
I am in the middle of refactoring a huge py module to packages - to not break existing code I moved its contents to package/__init__.py
module ( Adding code to __init__.py ) and went on splitting it from there. 我正在将一个庞大的py模块重构为包-为了不破坏现有代码,我将其内容移至package/__init__.py
模块( 向__init__.py添加代码 ),然后从那里进行拆分。 I noticed at some point that in my tracebacks I get: 我注意到在某些时候我得到了回溯:
Traceback (most recent call last):
File "<string>", line 656, in DoItemMenu
File "bash\balt.py", line 2109, in PopupMenu
link.AppendToMenu(menu,parent,*args)
File "bash\balt.py", line 2225, in AppendToMenu
for link in self.links: link.AppendToMenu(subMenu,window,data)
...
where the lines in File "<string>"
correspond to the particular package/__init__.py
module. 其中File "<string>"
对应于特定的package/__init__.py
模块。 Moreover PyCharm's debugger displays a "frame not available" line and does not step into the lines in the __init__.py
. 而且,PyCharm的调试器会显示“ frame not available”行,并且不会进入__init__.py
的行。 Why? 为什么? Is it related to the import pattern? 它与导入模式有关吗?
The code is imported by a launcher class : 该代码由启动器类导入:
class UnicodeImporter(object):
def find_module(self,fullname,path=None):
if isinstance(fullname,unicode):
fullname = fullname.replace(u'.',u'\\')
exts = (u'.pyc',u'.pyo',u'.py')
else:
fullname = fullname.replace('.','\\')
exts = ('.pyc','.pyo','.py')
if os.path.exists(fullname) and os.path.isdir(fullname):
return self
for ext in exts:
if os.path.exists(fullname+ext):
return self
def load_module(self,fullname):
if fullname in sys.modules:
return sys.modules[fullname]
else:
sys.modules[fullname] = imp.new_module(fullname)
if isinstance(fullname,unicode):
filename = fullname.replace(u'.',u'\\')
ext = u'.py'
initfile = u'__init__'
else:
filename = fullname.replace('.','\\')
ext = '.py'
initfile = '__init__'
if os.path.exists(filename+ext):
try:
with open(filename+ext,'U') as fp:
mod = imp.load_source(fullname,filename+ext,fp)
sys.modules[fullname] = mod
mod.__loader__ = self
return mod
except:
print 'fail', filename+ext
raise
mod = sys.modules[fullname]
mod.__loader__ = self
mod.__file__ = os.path.join(os.getcwd(),filename)
mod.__path__ = [filename]
#init file
initfile = os.path.join(filename,initfile+ext)
if os.path.exists(initfile):
with open(initfile,'U') as fp:
code = fp.read()
exec code in mod.__dict__
return mod
The code is not imported in a traditional manner; 该代码不是以传统方式导入的。 instead the launcher code uses an exec
statement for loading __init__.py
files. 相反, 启动器代码使用exec
语句加载__init__.py
文件。
Paring down the flow in the launcher load_module()
function for a package (so not a path to a module) you get this: 减少启动程序的load_module()
函数中包的流(而不是模块的路径),您会得到以下信息:
# the fullname module isn't yet loaded
sys.modules[fullname] = imp.new_module(fullname)
initfile = '__init__' # or u'__init__' if a unicode path was used
# if no .py file was found, so not a module
mod = sys.modules[fullname]
mod.__loader__ = self
mod.__file__ = os.path.join(os.getcwd(),filename)
mod.__path__ = [filename]
#init file
initfile = os.path.join(filename,initfile+ext)
if os.path.exists(initfile):
with open(initfile,'U') as fp:
code = fp.read()
exec code in mod.__dict__
return mod
This creates an empty module object, loads the source manually and executes it as a string, passing in the module namespace as the globals for the executed code. 这将创建一个空的模块对象,手动加载源并将其作为字符串执行,将模块名称空间作为已执行代码的全局变量传入。 The resulting code object is always going to list <string>
in tracebacks: 生成的代码对象将始终在回溯中列出<string>
:
>>> import imp
>>> mod = imp.new_module('foo.bar')
>>> mod.__file__ = r'C:\some\location\foo\bar'
>>> mod.__path__ = [r'foo\bar']
>>> exec 'raise ValueError("oops")' in mod.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
ValueError: oops
Because there is no filename associated with the code, PyCharm cannot find the original source either. 由于没有与该代码关联的文件名,因此PyCharm也无法找到原始源。
The work-around is to use the compile()
function to create a code object first , and attaching a filename to that: 的解决办法是使用compile()
函数 首先创建一个代码对象,并附加文件名,其:
>>> exec compile('raise ValueError("oops")', r'C:\some\location\foo\bar\__init__.py', 'exec') in mod.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\some\location\foo\bar\__init__.py", line 1, in <module>
ValueError: oops
Note that I included __init__.py
in the filename; 注意,我在文件名中包含了__init__.py
。 translating that back to the launcher you'd use: 将其翻译回您要使用的启动器:
if os.path.exists(initfile):
with open(initfile,'U') as fp:
code = fp.read()
exec compile(code, initfile, 'exec') in mod.__dict__
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.