Executing Python Files From Another (cont.)

Question:

I’ve written a question about this project I’m working on already (see Executing a python file from another for my project’s structure), but I’ve encountered a new issue. In the previous question, the tip I was given was to either use import statements or subprocesses. When I tried imports, I was able to navigate to each file one time only. Per the answer given to me, I next tried to use subprocesses so I could use each file multiple times. This is the current iteration of my code that I am using. Note that all of my programs are meant to be interactive in the python terminal.

import subprocess
f = open("readme_files/index.txt")
p = open("readme_files/projects.txt")

print(f.read())

func = 0
while True:
    func = int(input("Requested Operation: "))

    if func == 0:
        print(p.read())
    elif func == 1:
        subprocess.run("projects/dice_app.py")
        break
    elif func == 2:
        subprocess.run("projects/text_to_math.py")
        break
    else:
        req_op = ''
        print("Invalid operation. Please try again.")

I don’t really understand how these subprocesses work and the tip I was given didn’t work, returning this set of errors. Note I am using MS VScode with the Python 3.10.6 SDK:

  File "[my user directory]Python Projectsstart_here.py", line 14, in <module>
    subprocess.run("projects/dice_app.py")
  File "C:Program FilesPython310libsubprocess.py", line 501, in run
    with Popen(*popenargs, **kwargs) as process:
  File "C:Program FilesPython310libsubprocess.py", line 969, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "C:Program FilesPython310libsubprocess.py", line 1438, in _execute_child
    hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
OSError: [WinError 193] %1 is not a valid Win32 application

I don’t really understand what any of this means, so any help is much appreciated.

Asked By: Coder man

||

Answers:

Likely, the reason you can only use the imports once is that the imported Python scripts do not contain methods but runnable code. Therefore, adjust your imported Python scripts into defined methods. Then, you can import whole script or specific underlying methods to be called as many times as needed in top level script.

Additionally, consider reading all text files in context managers to ensure they close properly. Be careful you are not reading large amounts of text with read(), otherwise loop across lines. Even encapusulate text reads in functions and call as needed. Finally, consider a dictionary and avoid the the multiple if/elif conditions.

from projects.dice_app import my_dice_app_func
from projects.text_to_math.py import my_text_to_math_func

def print_index():
    with open("readme_files/index.txt") as f:
        print(f.read())

def print_projects():
    with open("readme_files/projects.txt") as p:
        print(p.read())
    return 0

def invalid_input():
    print("Invalid operation. Please try again.")
    return ''

print_index()

func_dict = {
    0 = print_projects,
    1 = my_dice_app_func,
    2 = my_text_to_math_func
}

func = 0
while True:
    func = int(input("Requested Operation: "))

    req_func = func_dict.get(func, invalid_input)
    req_op = req_func()

    if not req_op in [0, '']:
        break
Answered By: Parfait

Subprocesses are not a proper solution for your problem. You said your imports didn’t work (only executed once) – that’s because you used them wrong. Imports are not supposed to be used as a standard piece of code. When you import something, all of the top-level code is executed in order to define the variables. On any further import of the same script, those variables are simply reused, that’s why it is not executed again.

First, make sure your imports have no side effects. All of the top-level code should be moved into a function, e.g. main(). Then you can use very common clause if __name__=="__main__": to make sure this function will not be executed on import.

So, let’s say your script contains the following:

i = 10 
x = 12

print(i / x)

In order to make it work properly with imports, change it to something like that:

def main():
    i = 10 
    x = 12

    print(i / x)

if __name__ == "__main__":
    main()

Now, when you import the script containing this code using e.g. import module1, it will not be run.

But, you can call module1.main() wherever you need to run that code, and it will work as many times as you want.

Answered By: matszwecja
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.