1

I'm trying to save output processed by Python to a text file. I started with approach #1 described below. It didn't work (details below), so I tried to isolate the failing function and launch it with predefined array to be processed (approach #2). It didn't work either. So, I tried to completely extract the code and put it into a separate module: it worked as intended (approach #3). However, the working approach is not usable in the context of the process I'm trying to design: the list of arguments will be dynamic and it should be processed the way it works in the approach #1 (importing a function, then feeding it with a dynamically generated list).

Folder structure:

root
  +- containers
       +- processed
            output.txt
  +- controllers
       main_controller.py
       save_output_to_file.py
       test.py

Please keep in mind that all of the files with discussed code exist in the same directory, so in theory they should share the same relative path to the output.txt file. Directories containers and controllers are siblings.

Now, the following things happen when I try to save the output to the file:

  1. When called from main_controller.py this way:
from controllers.save_output_to_file import save_output_to_file

[...]

print(urls)

save_output_to_file(urls)

Output:

['url1', 'url2', 'url3']  # printed urls
Traceback (most recent call last):
  File "C:\Users\aqv\root\controllers\main_controller.py", line 113, in <module>
    save_output_to_file(urls)
  File "C:\Users\aqv\root\controllers\save_output_to_file.py", line 19, in save_output_to_file
    with open(output_file, 'w+', encoding='utf-8') as f:
FileNotFoundError: [Errno 2] No such file or directory: '..\\containers\\processed\\output.txt'

Process finished with exit code 1

It happens no matter if output.txt exists in the directory or not.

  1. When called from save_output_to_file.py (with predefined urls):
from pathlib import Path


output_folder = Path('../containers/processed')
output_source = 'output.txt'
output_file = output_folder / output_source

urls = ['url4', 'url5', 'url6']

print(urls)


def save_output_to_file(urls):
    """Save URLs to a text file for further processing by bash script."""
    with open(output_file, 'w+', encoding='utf-8') as f:
        for url in urls:
            f.write(f'{url}\n')

Output:

['url4', 'url5', 'url6']  # printed urls

URLs get printed to the console, no errors are reported, and the file doesn't get created. For this piece of code, it doesn't matter whether the file exists or not - it's never reached.

  1. When called from test.py file:
from pathlib import Path


output_folder = Path('../containers/processed')
output_source = 'models.txt'
output_file = output_folder / output_source

urls = ['url7', 'url8', 'url9']

print(urls)

with open(output_file, 'w+', encoding='utf-8') as f:
    for url in ssh_urls:
        f.write(f'{url}\n')

Now, everything works as intended:

['url7', 'url8', 'url9']  # printed urls

URLs get printed to the console, no errors are reported, and the file gets created if doesn't exist, or overwritten if it does.

All of the examples were launched in WSL2 environment.

The question: how should I call the file creation so that it works correctly when called using approach #1? And if it's a problem related to WSL, how to make it system-independent?

AbreQueVoy
  • 1,748
  • 8
  • 31
  • 52
  • Are you located under `/root/controllers` directory when you run `main_controller.py`? And what happens if in `save_output_to_file.py` you use an absolute path instead? – Martin Tovmassian Jan 02 '23 at 08:31
  • 1. It's run by IDE, so it uses the absolute path. 2. When I updated the path to be absolute, the same `FileNotFoundError` occurred: the only difference was the full path reported by the error dump: `C\\Users\\aqv\\...`. – AbreQueVoy Jan 02 '23 at 14:03

1 Answers1

0

OK, so I figured out how to make it work.

After seeing this answer, I decided to apply some changes in the path:

from pathlib import Path


output_folder = Path('containers/processed')
output_source = 'output.txt'
output_file = (Path.cwd() / output_folder / output_source).resolve()

Don't know if the resolve() method is needed in every case, but in this specific one it works fine.

And more important: the main_controller.py was refactored and moved to the parent directory, so the current structure looks this way:

root
  +- containers
       +- processed
            output.txt
  +- controllers
       __init__.py
       save_output_to_file.py
       test.py
  main.py

Linked answer suggests, that you can construct a path using two dots, like ../containers/processed, etc., but it's not the case here, so leaving this comment just in case you encounter such situation.

AbreQueVoy
  • 1,748
  • 8
  • 31
  • 52