尽管有__init__.py,但尝试在非包装错误中尝试相对导入

时间:2013-09-19 07:03:50

标签: python python-2.7 osx-lion

我有一个包cclogger。该目录有一个__init__.py文件,其中包含一些用于加载配置的代码。当我尝试使用以下命令在该目录中运行文件api_main.py时...

python -m cclogger.api_main

我得到以下错误: -

config loaded
Instantiating DB with: cclogger/test123@localhost:x
Instantiated ParseCentral
Register parser called by : CitiIndia
Registered parser for email:  CitiAlert.India@citicorp.com
Instantiated SmsParseCentral
Register parser called by : Citi Bank
Registered sms parser for address:  lm-citibk
Register parser called by : HDFC Bank
Registered sms parser for address:  am-hdfcbk
Traceback (most recent call last):
  File "/Users/applegrew/Dropbox/Credit Expense/cclogger/cclogger/api_main.py", line 4, in <module>
    from .bottle import run, default_app, debug, get
ValueError: Attempted relative import in non-package

错误上方显示的消息来自__init__.py导入的同一包中的模块。

api_main.py中的代码是: -

import re
import os

from .bottle import run, default_app, debug, get
from .common_util import date_str_to_datetime, UTCOffset, date_filter

#app = Bottle()

default_app().router.add_filter('date', date_filter)

from . import api, dev

@get('/index')
def index():
    return "CCLogger API main live and kicking."

if dev:
    debug(True)
    run(reloader=True, port=9000)
else:
    os.chdir(os.path.dirname(__file__))
    application = default_app()

我有python 2.7.1。

我做错了什么?您可以在https://github.com/applegrew/cclogger/tree/master/cclogger

查看完整代码

2 个答案:

答案 0 :(得分:7)

你不能直接将python模块作为脚本运行(我真的不知道原因)。

编辑:原因在PEP338中解释,这是"-m"选项的规范。

  

2.5b1的发布显示出令人惊讶的结果(虽然显而易见)   回顾这个PEP和PEP 328之间的相互作用 - 明确的   相对导入不适用于主模块。这是由于   事实上相对进口依靠__name__来确定当前   模块在包层次结构中的位置。在一个主要模块中,   __name__的值始终为__main__,因此显式相对导入   将永远失败(因为它们只适用于包内的模块)。

     

对于2.5版本,建议始终在任何打算用作主模块的模块中使用绝对导入

要测试你的应用程序,请在函数中封装api_main并创建一个运行主循环的顶级main.py文件:

cclogger / api_main.py:

import re
import os


from .bottle import run, default_app, debug, get
from .common_util import date_str_to_datetime, UTCOffset, date_filter

#app = Bottle()


def main():
    default_app().router.add_filter('date', date_filter)

    from . import api, dev

    @get('/index')
    def index():
        return "CCLogger API main live and kicking."

    if dev:
        debug(True)
        run(reloader=True, port=9000)
    else:
        os.chdir(os.path.dirname(__file__))
        application = default_app()

/main.py

from cclogger import api_main


if __name__ == '__main__':
    api_main.main()

您可以通过键入python main.pypython -m mainpython -c "import cclogger.api_main; api_main.main()"来运行您的应用。

PS:感谢您链接完整的源代码,它总是比问题提供的存根更有帮助。

答案 1 :(得分:0)

自Python 2.6起,使用python -m执行的模块中的相对导入工作正常。如http://www.python.org/dev/peps/pep-0366中所述,当以这种方式执行时,__package__属性会自动设置在模块上,以便相对导入起作用。导致失败的部分是重新加载器,显然无法设置__package__

编辑:看一下代码,我看到这是一个瓶子API。我没有检查瓶子,但它可能与Flask的重新加载器有同样的问题,它通过信任sys.argv中的内容来尝试重新启动。问题是处理python -m的代码(位于runpy模块中)会修改sys.argv,删除&#34; -m&#34;并将模块名称翻译成文件名(这非常令人沮丧,但我确信他们有充分的理由)。因此,重新加载器实际执行的内容没有&#34; -m&#34;并且设置__package__的位永远不会触发,导致不支持相对导入。