1

I can't seem to figure out how to fix the error below when trying to import a file from one directory up and it's making me crazy. Python 3.6.7.

Here's how The Internet says it should be done, one directory up:

from .. import app

Here's the error:

Traceback (most recent call last):
  File "module1.py", line 16, in <module>
    from .. import app
ValueError: attempted relative import beyond top-level package

Here's the dir structure (It should be noted that I'm calling the script module1.py from inside package1):

--- project/
    --- __init__.py
    --- app.py
    --- package1/
        --- __init__.py
        --- module1.py

Here's what I've tried to fix it:

Method 1 (same error)

import sys

HERE = Path(__file__).parent
sys.path.append(str(HERE / '../'))
from .. import app

Method 2 (found here, same error)

import os
import sys

sys.path.append(os.path.join(os.path.dirname(__file__)))
from .. import app

Method 3 ( also found here, same error)

import sys

sys.path.append('.')
from .. import app
ChumiestBucket
  • 868
  • 4
  • 22
  • 51
  • try this SO: https://stackoverflow.com/questions/1054271/how-to-import-a-python-class-that-is-in-a-directory-above – jose_bacoy Apr 24 '19 at 16:39
  • @âńōŋŷXmoůŜ all those solutions are in my question – ChumiestBucket Apr 24 '19 at 16:40
  • Your right. Let me try it on my own and will update you. Thanks. – jose_bacoy Apr 24 '19 at 16:49
  • Have you tried `import ..app`? – thebjorn Apr 24 '19 at 16:54
  • I'm not sure what you mean when you say "I'm calling the script module1.py from inside package1"? Are you importing module1 when the error happens, or are you trying to call module1 as a script (python doesn't want you to do this -- create a setup.py file and define a console_scripts entry_point instead). – thebjorn Apr 24 '19 at 17:00
  • @thebjorn I'm importing `app` from `module1.py`, and running `python module1.py` from inside the `package1` dir – ChumiestBucket Apr 24 '19 at 17:11
  • 1
    Sorry, but Python doesn't really support that usage pattern and you'll end up with the kind of hacks you're using all over the place -- i.e. you can delete your `__init__.py` files because you're not using them (instead you have to manipulate the path for every import). What you should do instead, and for which Python has excellent support, is to create a setup.py script with a `console_scripts` declaration (cf. https://python-packaging.readthedocs.io/en/latest/command-line-scripts.html#the-console-scripts-entry-point), then you can use imports the normal way. – thebjorn Apr 24 '19 at 19:16

2 Answers2

2

A standard package structure for Python looks like this:

c:\srv\tmp> tree project
project
|-- project
|   |-- __init__.py
|   |-- app.py
|   `-- package1
|       |-- __init__.py
|       `-- module1.py
`-- setup.py

where the project-root c:\srv\tmp\project contains a setup.py file and a subdirectory that is also named project containing the source code.

The contents of module1.py:

from .. import app

def module1_fn():
    print("In module1, have imported app as:", app)

and the contents of setup.py:

from setuptools import setup

setup(
    name='project',
    packages=['project'],    # where to find sources
    entry_points={
        'console_scripts': """
            module1-fn = project.package1.module1:module1_fn
        """
    }
)

now the "magic" part, from the directory containing setup.py run (note the . at the end):

c:\srv\tmp\project> pip install -e .
Obtaining file:///C:/srv/tmp/project
Installing collected packages: project
  Running setup.py develop for project
Successfully installed project

And now, from any directory, you can run:

c:\srv\tmp\project> module1-fn
In module1, have imported app as: <module 'project.app' from 'c:\srv\tmp\project\project\app.pyc'>

ie. module1-fn can be called directly from the shell(!), and from .. import app works directly(!!)

thebjorn
  • 26,297
  • 11
  • 96
  • 138
1

I got this working on my laptop so I hope it works on your side as well.

module1.py

import sys
from os import path

sys.path.append(path.join(path.dirname(__file__), '..'))
from app import print_app


print_app()

app.py:

def print_app():
    print('success')
    return None

Result:

$python module1.py 

'success'
jose_bacoy
  • 12,227
  • 1
  • 20
  • 38
  • you're importing in the reverse direction and in different files, but I tried your solution (only corrected) and I'm still getting the error. I'm thinking I need to restructure my project such that the entry point allows for this kind of importing. – ChumiestBucket Apr 24 '19 at 17:14