0

I have a github actions workflow where I run many different files, for which I append to the PYTHONPATH all the paths I need for the scripts to work. To do so, I created another program called workflow_import.py in the same directory as my main scripts where I simply add a function of this sort:

def load_modules():
    if 'SOURCES_PATH' in os.environ:
        print('SOURCES_PATH') # debug line
        sources_path_list = eval(os.environ['SOURCES_PATH'])
        sys.path.extend(sources_path_list)

I add this function to each of my scripts as in

from workflow_import import load_modules

Herein, I work with a environment variable called 'SOURCES_PATH' (aka. variables.SOURCES_PATH, don't know if saving it as a secret is more convenient) storing all the modules' location. Running the main script doesn't invoke any ModuleNotFindError. However, one of my scripts generates a new subfolder called \ref, and since it most certainly changes to that directory all of the subsequent scripts fail to find workflow_import.py or any other module from load_modules().

I thought this was due to the sys.path() changing once \ref is created, but I don't know how to make it so it stays consistent within the workflow. As an example, I run the scripts in this manner:

    - name: Library Test
      shell: powershell
      run: |
        & $env:PYTHON_ENV_PATH ./libraries/library/tests/generate_reffiles.py 

Where PYTHON_ENV_PATH is another secret containing the python.exe path of my desired environment.

Edit:

An example of SOURCES_PATH:

[
'C:\\actions-runner\\_work\\repo\\module1', 
'C:\\actions-runner\\_work\\repo\\module2', 
...
]

Update

I think I managed to solve the issue. In my case, as I was working with a conda-environment I had to activate first the environment and then update the PYTHONPATH with:

"PYTHONPATH=${env:SOURCES_PATH}" >> $env:RUNNER_ENV

However, as I run a cmd routine containing a python script each time, there is another solution consisting in prepending sys.path.extend(sources_path_list), in a way like PyCharm does it.

4
  • 1
    eval() around os.environ does not make any sense - that most likely will SyntaxError Commented May 22 at 9:30
  • 2
    @rasjani I suspect his SOURCES_PATH looks like a python list such as ['./foo','./bar'] which eval() will process correctly.. it's a huge security risk though as anyone who can modify that env variable can make the script do whatever they want. Commented May 22 at 9:52
  • Probably the best way forward is to change the SOURCES_PATH items into only absolute paths, that way it will not matter what the current working directory is. You could for example have a pre-process step which writes an env file to /tmp with absolute paths and then have each script load the env file. Or a dozen other options. Commented May 22 at 9:57
  • @vaizki that's precisely the case. Let me edit the post to show an example of SOURCES_PATH's content. Is it risky if the env var can only be modified by repo's admins? Anyway, I presume these paths are absolute within the C: drive, so that's why I don't get the nature of the issue. Ussing sys.expand() on a local python runner doesn't present any errors. Commented May 22 at 12:12

1 Answer 1

0

Suggestion: Add __init__.py files to all your package directories and use absolute imports for cleaner module resolution.

Here’s a minimal example using the src layout:

.
├── .github
├── environment.yml
├── README.md
├── src
│   ├── __init__.py
│   └── hello.py
└── tests
    ├── __init__.py
    └── test_hello.py

src/hello.py

def hello():
    return "Hello!"

tests/test_hello.py

from src.hello import hello

def test_hello():
    assert hello() == "Hello!"

When running pytest, the test environment will treat src and tests as packages, avoiding import errors. Without __init__.py, imports work on my local machine but fail in CI environments. For example I was getting the following error:

ImportError while importing test module '/home/runner/work/python-testing/python-testing/tests/test_hello.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
.pixi/envs/default/lib/python3.12/importlib/__init__.py:90: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tests/test_hello.py:1: in <module>
    from src.hello import hello
E   ModuleNotFoundError: No module named 'src'
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.