-1

SOLUTION POSTED AT BOTTOM

Thanks to the commentators for pointing me in the right direction. Between their help and this other thread I was able to come to a robust solution which is posted at the bottom.

Situation

I have a .py script called job.py that relies on data in another .py script called data.py. Both scripts reside in the same folder, 05_scripts. The 05_scripts folder sits under Git version control in a parent folder called project.

Thus, the complete paths to the two scripts are:
project/05_scripts/job.py and
project/05_scripts/data.py.

Problem: I cannot import data.py without renaming the folder 05_scripts.

In job.py I want to source the data.py file. This is problematic because the data.py file sits in a folder whose name begins with a digit, 05_scripts/. If I change the folder name to _05_scripts/ or something else so that the first character is non-numeric, then I achieve my goal and import the data.py script without a problem. However, this is unacceptable since this is part of a much larger project and it is not acceptable to change all references to this folder.

What an acceptable solution must look like

The solution I need is code in job.py that can successfully import data.py without renaming the 05_scripts/ folder.

What I have tried

Attempt 1

Input:

from 05_scripts.data import *

Output:

  File "<stdin>", line 1
    from 05_scripts.data import *
         ^
SyntaxError: invalid token

Attempt 2

Input:

from '05_scripts'.data import *

Output:

  File "<stdin>", line 1
    from '05_scripts'.data import *
                    ^
SyntaxError: invalid syntax

Attempt 3

Input:

from '05_scripts.data' import *

Output:

  File "<stdin>", line 1
    from '05_scripts.data' import *
                         ^
SyntaxError: invalid syntax

Attempt 4

Input:

from data import *

Output:

ModuleNotFoundError: No module named 'data'

Attempt 5

Input:

import data

Output:

ModuleNotFoundError: No module named 'data'

Other attempts

I also tried variations of the solutions posted here. This included different variations of using __import__ and importlib.import_module() but could not get a working solution that did not include renaming the parent folder.

Recall, this works but is not an acceptable solution for my use case:

After renaming 05_scripts/ to _05_scripts,

Input:

from _05_scripts.data import *

SOLUTION

# Getting the path for the project and doing string manipulation.
import os
import re
working_dir = re.sub("\\\\", "/", os.getcwd())
scripts_dir = working_dir + "/05_scripts"

# Importing all from the data.py script
import site
site.addsitedir(scripts_dir)
from data import *
Jayden.Cameron
  • 499
  • 4
  • 17

3 Answers3

1
import os
import sys
syspath_05scripts = os.path.join(os.path.dirname(os.path.abspath(__file__)), "05_scripts")
sys.path.insert(0, syspath_05scripts)

import something_from_05
krimeo
  • 86
  • 3
  • Does not work: sys.path.insert("/05_scripts") Traceback (most recent call last): File "", line 1, in TypeError: insert() takes exactly 2 arguments (1 given) – Jayden.Cameron Jul 31 '20 at 13:43
  • 1
    sys.path.insert(0, "path_to/05_scripts") # :-D – krimeo Jul 31 '20 at 13:59
  • This gets me 90% to where I want to be, :). How do I make the path relative to the project folder? Project folders may move, so I want to be able to have the sys.path.insert(0, "/05_scripts") robust enough to handle when project folders move. Also, `import data` does not work. However, `from data import *` does work. – Jayden.Cameron Jul 31 '20 at 14:15
  • You can use `os.path.dirname(__file__)` to get the path to the directory where your script resides. I will edit the answer. – krimeo Jul 31 '20 at 15:10
  • I already posted a solution that is robust and covers my need. Thank you! – Jayden.Cameron Jul 31 '20 at 15:20
1

You can use site package to add custom locations to be included to for module search path

>>> import site
>>> site.addsitedir('05_scripts')
>>> import data
>>> data
<module 'data' from '<removed>/05_scripts/data.py'>
Prem Anand
  • 2,469
  • 16
  • 16
  • You need to create a empty `__init__.py` file under 05_scripts. Do `touch path/05_scripts/__init__.py` and try again – Prem Anand Jul 31 '20 at 14:13
  • I had a mistake in my code (the file is not really called `data.py` in my real example). Removing previous comments now. – Jayden.Cameron Jul 31 '20 at 14:22
  • `/opt` was just the full path to the directory. I have now updated the answer for relative path. Go to the directory where you `05_scripts`, start a python shell and it would work – Prem Anand Jul 31 '20 at 14:22
  • Similar to the proposed solution by krimeo, this gets me 90% of the way to where I want to be if I use `from data import *` instead of `import data`. However, how do I make this more robust in case the project folder moves (as it will)? I do not want to hardcode the path since the project folder is bound to move. – Jayden.Cameron Jul 31 '20 at 14:23
  • I posted a solution that is robust and covers my need. Thank you! – Jayden.Cameron Jul 31 '20 at 15:21
0

Assuming that you have a folder structure like this the following code should work for you.

project/main.py
project/05_scripts/
project/05_scripts/__init__.py
project/05_scripts/job.py
project/05_scripts/data.py

project/05_scripts/data.py

what_i_want_to_get = {'hello': 'there'}

project/main.py

from importlib import import_module

# this is the same as calling "import 05_scripts.data as data"
data = import_module('05_scripts.data')

print(data.what_i_want_to_get)

# this should print {'hello': 'there'}
  • Does not work: data = getattr(import_module('05_scripts'), 'data') Traceback (most recent call last): File "", line 1, in AttributeError: module '05_scripts' has no attribute 'data' – Jayden.Cameron Jul 31 '20 at 13:40
  • Jayden, could you perhaps share what what 05_scripts/ contents are? Does it contain an `__init__.py` file? – Steffen Andersland Jul 31 '20 at 13:49
  • The error persists with or without the presence of `init.py`,`_init_.py` or `__init__.py` files in the 05_scripts/ folder. The contents of the folder are somewhat sensitive, so I cannot share details. However, I just need a solution that can generalize for how to get the `job.py` file to source the `data.py` file when they reside together in a folder with a name that begins with a digit. – Jayden.Cameron Jul 31 '20 at 13:56
  • Jayden please see my revised answer, I tried the above on my end and I believe this should work for you. – Steffen Andersland Jul 31 '20 at 14:28
  • Thanks for trying, but the purpose is to source `data.py` using `job.py`, not `main.py`. I do not have any program called `main.py`. In fact, the main programming language in the parent folder is not Python in this project, but another language which calls `job.py`. – Jayden.Cameron Jul 31 '20 at 14:33
  • Got it, that's what was missing. I should had specifically asked about your entrypoint. Are you certain that `from data import *` at the top of your `job.py` isn't working for you? I tried it on my end and was able to `print(what_i_want_to_get)` – Steffen Andersland Jul 31 '20 at 14:48
  • I posted a solution that is robust and covers my needs. Thank you! – Jayden.Cameron Jul 31 '20 at 15:21