Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting Attempted relative import in non-package error in spite of having __init__.py

I have a package cclogger. This directory has a __init__.py file with some code to load the configuration. When I try to run the file api_main.py in that directory using the following command...

python -m cclogger.api_main

I get the following erro:-

config loaded
Instantiating DB with: cclogger/test123@localhost:x
Instantiated ParseCentral
Register parser called by : CitiIndia
Registered parser for email:  [email protected]
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

The messages displayed above the error are from modules in the same package which were imported by __init__.py.

The code in api_main.py is:-

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()

I have python 2.7.1.

What am I doing wrong? You can see the full code at https://github.com/applegrew/cclogger/tree/master/cclogger

like image 706
AppleGrew Avatar asked Sep 19 '13 07:09

AppleGrew


People also ask

How does Python handle relative imports?

Relative imports make use of dot notation to specify location. A single dot means that the module or package referenced is in the same directory as the current location. Two dots mean that it is in the parent directory of the current location—that is, the directory above.

How do I create a relative import in Python?

Relative imports use dot(.) notation to specify a location. A single dot specifies that the module is in the current directory, two dots indicate that the module is in its parent directory of the current location and three dots indicate that it is in the grandparent directory and so on.

Should I use relative or absolute imports Python?

Note that relative imports are based on the name of the current module. Since the name of the main module is always “main”, modules intended for use as the main module of a Python application must always use absolute imports.


1 Answers

You cannot run a python module directly as a script (I don't really know the reason why).

EDIT : The reason is explained in the PEP338 which is the spec for the "-m" option.

The release of 2.5b1 showed a surprising (although obvious in retrospect) interaction between this PEP and PEP 328 - explicit relative imports don't work from a main module. This is due to the fact that relative imports rely on __name__ to determine the current module's position in the package hierarchy. In a main module, the value of __name__ is always __main__ , so explicit relative imports will always fail (as they only work for a module inside a package).

For the 2.5 release, the recommendation is to always use absolute imports in any module that is intended to be used as a main module

To test your application, encapsulate api_main in a function and create a top-level main.py file which will run the main loop :

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()

And /main.py :

from cclogger import api_main


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

You can run your application by typing python main.py, python -m main or python -c "import cclogger.api_main; api_main.main()" .

PS : thanks for linking the complete source, it's always much more helpful than the stubs provided with the question.

like image 112
lucasg Avatar answered Oct 20 '22 11:10

lucasg