有没有一种可靠的方法从Sphinx conf.py中执行的Python函数获取调用者模块的路径?

时间:2016-09-02 19:19:47

标签: python python-sphinx

我在Sphinx中运行一些自定义Python代码,需要获取调用者模块的路径。 (基本上这是调用者的__file__对象;我需要解释相对于此位置的文件名。)

我可以根据How to use inspect to get the caller's info from callee in Python?inspect.stack()获取文件名,但显然我需要在Python启动目录的上下文中解释此文件名。 (有时inspect.stack()[k][1]是一个绝对路径,但有时它是一个相对路径,如conf.py; inspect.stack()函数似乎没有记录这个,但是unutbu claims in a comment它是相对于Python启动目录。)

狮身人面像做了一些无意中邪恶的事情,比如评论:

# This file is execfile()d with the current directory set to its
# containing dir.

因此os.path.abspath(filename)无效,

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('extensions'))

所以sys.path[0]因我的代码到达它而被破坏。

如果sys.path已被修改,我如何在Python中找到启动目录?

或者是否有其他方法可以获得调用者模块的路径?

如果我运行Jean-François Fabre's answer

for file,line,w1,w2 in traceback.extract_stack():
    sys.stdout.write('  File "{}", line {}, in {}\n'.format(file,line,w1))

我明白了:

File "c:\app\python\anaconda\1.6.0\Scripts\sphinx-build-script.py", line 5, in <module>
File "c:\app\python\anaconda\1.6.0\lib\site-packages\Sphinx-1.4.1-py2.7.egg\sphinx\__init__.py", line 51, in main
File "c:\app\python\anaconda\1.6.0\lib\site-packages\Sphinx-1.4.1-py2.7.egg\sphinx\__init__.py", line 92, in build_main
File "c:\app\python\anaconda\1.6.0\lib\site-packages\Sphinx-1.4.1-py2.7.egg\sphinx\cmdline.py", line 243, in main
File "c:\app\python\anaconda\1.6.0\lib\site-packages\Sphinx-1.4.1-py2.7.egg\sphinx\application.py", line 155, in __init__
File "conf.py", line 512, in setup
[more lines elided, the conf.py is the one that matters]

所以问题是我需要找到conf.py的路径,但是当前目录已被Sphinx更改,所以我不能os.path.abspath(caller_filename)

2 个答案:

答案 0 :(得分:3)

您可以使用traceback模块获得所需内容。我在PyScripter中编写了这个示例代码:

import traceback,sys

def demo():
   for file,line,w1,w2 in traceback.extract_stack():
       sys.stdout.write('  File "{}", line {}, in {}\n'.format(file,line,w1))

def foo():
    demo()

foo()

在我的Windows PC上运行PyScripter:

  File "C:\Users\dartypc\AppData\Roaming\PyScripter\remserver.py", line 63, in <module>
  File "C:\Users\dartypc\AppData\Roaming\PyScripter\remserver.py", line 60, in main
  File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\utils\server.py", line 227, in start
  File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\utils\server.py", line 139, in accept
  File "C:\Users\dartypc\AppData\Roaming\PyScripter\remserver.py", line 14, in _accept_method
  File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\utils\server.py", line 191, in _serve_client
  File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\protocol.py", line 391, in serve_all
  File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\protocol.py", line 382, in serve
  File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\protocol.py", line 350, in _dispatch
  File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\protocol.py", line 298, in _dispatch_request
  File "C:\Program Files\PyScripter\Lib\rpyc.zip\rpyc\core\protocol.py", line 528, in _handle_call
  File "<string>", line 420, in run_nodebug
  File "C:\DATA\jff\data\python\stackoverflow\simple_traceback.py", line 10, in <module>
  File "C:\DATA\jff\data\python\stackoverflow\simple_traceback.py", line 8, in foo
  File "C:\DATA\jff\data\python\stackoverflow\simple_traceback.py", line 4, in demo

答案 1 :(得分:0)

Bah,我只是通过允许呼叫者传递__file__值来解决这个问题: - (

我的职能:

def do_something(app, filename, relroot=None):
   if relroot is None:
      relroot = '.'
   else:
      relroot = os.path.dirname(relroot)
   path = os.path.join(relroot, filename)
   ...
在conf.py中

def setup(app):
   mymodule.do_something(app, 'path/to/file', relroot=__file__)