1

Edit: I'm not trying to import from different folders, they're all in the same folder.


This has been asked countless times and there's always contradicting answers.

In my case I have this file structure:

import_test
├── custom_hashing
│   ├── __init__.py
│   ├── hashing_type_a.py
│   ├── hashing_type_b.py
│   └── utils.py
└── main.py

And these are the contents in order:

init.py

from hashing_type_a import hashing_function as hashing_function_a
from hashing_type_b import hashing_function as hashing_function_b

# Only "expose" this function in case we need tu update the real hashing functions in the future
def hash_this(string_to_hash, type='a') -> str:
    if type == 'a':
        return hashing_function_a(string_to_hash)
    if type == 'b':
        return hashing_function_b(string_to_hash)

hashing_type_a.py

from utils import split_and_switch


def hashing_function(string) -> str:
    prepared_string = split_and_switch(string)
    hashed_string = ''.join([chr(ord(character)+2)
                            for character in prepared_string])
    return hashed_string


def main():
    print("Testing hashing_type_a")

    hashed_string = hashing_function("abcdefghijk")

    print(f"{hashed_string=}")


if __name__ == '__main__':
    main()

hashing_type_b.py

from utils import split_and_switch


def hashing_function(string) -> str:
    prepared_string = split_and_switch(string)
    hashed_string = ''.join([chr(ord(character)-2)
                            for character in prepared_string])
    return hashed_string


def main():
    print("Testing hashing_type_b")

    hashed_string = hashing_function("abcdefghijk")

    print(f"{hashed_string=}")


if __name__ == '__main__':
    main()

utils.py

def split_and_switch(string) -> str:
    length = len(string)
    half = int(length/2)
    start_bit = string[:half]
    last_bit = string[half:]
    return last_bit+start_bit

main.py

from custom_hashing import hash_this

def main():
    hashed_string = hash_this("Lorem ipsum dolr sit amet", type="a")
    
    print(f"Hashed string type a is {hashed_string}")
    
    hashed_string = hash_this("Lorem ipsum dolr sit amet", type="b")
    
    print(f"Hashed string type b is {hashed_string}")


if __name__ == '__main__':
    main()

Now, from a terminal window on import_test I can run:

  • python.exe .\custom_hashing\hashing_type_a.py
  • python.exe .\custom_hashing\hashing_type_b.py

And I get the expected output, however if I try to run

  • python.exe .\main.py

I get the error

Traceback (most recent call last):
  File ".\main.py", line 1, in <module>
    from custom_hashing import hash_this
  File "C:\Users\David\import_test\custom_hashing\__init__.py", line 1, in <module>
    from hashing_type_a import hashing_function as hashing_function_a       
ModuleNotFoundError: No module named 'hashing_type_a'

I've been told that, since I'm importing from the same folder, I need to change

from hashing_type_a import hashing_function as hashing_function_a
from hashing_type_b import hashing_function as hashing_function_b

to

from .hashing_type_a import hashing_function as hashing_function_a
from .hashing_type_b import hashing_function as hashing_function_b
#    ^ Added these periods

And sure enough, I get past the first error, but I run into a "new" one

Traceback (most recent call last):
  File ".\main.py", line 1, in <module>
    from custom_hashing import hash_this
  File "C:\Users\David\import_test\custom_hashing\__init__.py", line 1, in <module>
    from .hashing_type_a import hashing_function as hashing_function_a
  File "C:\Users\David\import_test\custom_hashing\hashing_type_a.py", line 1, in <module>
    from utils import split_and_switch
ModuleNotFoundError: No module named 'utils'

which seems like we can fix the same way

from .utils import split_and_switch
#    ^ Added the period on both files

Okay, fixed all the errors, now the program runs:

PS C:\Users\David\import_test> python.exe .\main.py
Hashed string type a is fqnt"ukv"cogvNqtgo"kruwo"
Hashed string type b is bmjpqgr_kcrJmpckgnqsk

But now, if we go back to testing individual modules:

PS C:\Users\David\import_test> python.exe .\custom_hashing\hashing_type_a.py
Traceback (most recent call last):
  File ".\custom_hashing\hashing_type_a.py", line 1, in <module>   
    from .utils import split_and_switch
ImportError: attempted relative import with no known parent package

I guess I could put something like

try:
    from .utils import split_and_switch
except ImportError:
    from utils import split_and_switch

but I feel like there has to be a better way that I just don't know about.

Here's the folder structure with files if anyone doesn't feel like copy&pasting everything

Daviid
  • 630
  • 4
  • 17
  • Does this answer your question? [Importing files from different folder](https://stackoverflow.com/questions/4383571/importing-files-from-different-folder) – Faraaz Kurawle Feb 17 '22 at 12:04
  • @FaraazKurawle I'm not trying to import from different folders. They're all in the same folder. – Daviid Feb 17 '22 at 12:14
  • 1
    Relative imports (starting with `.`) more or less always work. *Absolute* imports require that Python knows where to find those libraries exactly, which depends on where its installed and what its environment configuration is. The environment's `PYTHONPATH` variable is usually what you want to define properly to have a clear absolute starting path. – deceze Feb 17 '22 at 12:19
  • Your link to the folder structure results in "The file you requested has been deleted". – larsks Feb 17 '22 at 12:54
  • 1
    @JonSG yeah, the thing is `from .py_file import class_or_function` works when using the file in which that import is as an import too. But if you execute the file directly the error `ImportError: attempted relative import with no known parent package` happens. – Daviid Feb 17 '22 at 19:31

0 Answers0