Relative import path for utility module

I have an application snork/Hello.py that has a child page snork/pages/1_Info.py and I would like them to import utility functions from a common snork/utils.py module. A relative import from Hello.py like from utils import load_graph works fine, but a similar import from 1_Info.py like from ..utils import load_graph fails with ImportError: attempted relative import with no known parent package.

I can update the path with sys.path.insert(1, os.path.realpath(os.path.pardir)) before the import, but that gets inserted every time the page runs. I can test to see if it’s there first, but that seems awkward, and maybe there’s a better way.

The load_graph() function is cached and pretty simple, there will be lots of other methods used in multiple pages:

@st.cache_resource
def load_graph():
    graph = rdflib.Graph()
    graph.parse("sample.data.ttl", format="ttl")

    return graph

Hi @Joel,

Thanks for posting!

Can you share the directory tree structure you have?

I have recreated to my best knowledge from your description below. Ensure that every directory has an __init__.py file to mark them as modules and allow relative imports.

snork/
|-- __init__.py
|-- Hello.py
|-- utils.py
|-- pages/
|   |-- __init__.py
|   |-- 1_Info.py

You can then use the import you used before:

from ..utils import load_graph

Let me know if this resolves the issue.

Directory structure is correct:

$ find snork/
snork/
snork/pages
snork/pages/__init__.py
snork/pages/1_Info.py
snork/Hello.py
snork/__init__.py
snork/utils.py

I was missing the __init__.py in the pages directory, however it doesn’t resolve the issue. I have a gist to the files and the init’s are empty.

I’m tried moving utils.py into the pages directory and replacing the import in Hello.py to from pages.utils import load load_graph which works, but then utils shows up as a page. I tried renaming it to _utils.py thinking it’ll skip the page, but it still shows it (blank, of course). I tried replacing pages/__init__.py with utils.py and in Hello.py from pages import load_graph works, but in 1_Info.py from __init__ import load_graph doesn’t work.

I’ll stick to the ā€œhumphā€ and update sys.path until there’s a canonical solution.