User avatar
NPDedyukhin
Posts: 29
Joined: Fri Sep 20, 2019 3:23 am
Location: RU

Parent script termination

Sun Dec 01, 2019 2:19 pm

Good day!

I have a parent script (it iterates over the list items when I press the arrows on the keyboard, and if it reaches the last item, it starts over, and when you press Enter, the following script is launched.):

Code: Select all

lines = ["A","B","C","D","E","F"]

import pygame
pygame.quit()
pygame.init()
screen = pygame.display.set_mode((400,400))

done = False
while not done:
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                if a > 0:
                    a = a - 1
                    print(lines[a])
                else:
                    a = len(lines) - 1
                    print(lines[a])
            if event.key == pygame.K_RIGHT:
                if a < len(lines) - 1:
                    a = a + 1
                    print(lines[a])
                else:
                    a = 0
                    print(lines[a])
            if event.key == pygame.K_RETURN:
                import child_script 
In the child script I want to start performing other tasks.

But I noticed that when the child script is already running, then when you click on the arrows, elements from the previous (parent) script continue to be displayed on the screen. This is wrong, I need the parent script commands to stop running in the child script.

Tell me, please, how can this be done? :|
Respectfully,
Nikita Dedyukhin

User avatar
Paeryn
Posts: 2830
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Parent script termination

Mon Dec 02, 2019 2:49 am

Your understanding of import is flawed and using import like that is not going to do what you want. Import loads a module and makes the definitions available to your program, it isn't supposed to be used to run code directly. Python manual for import

When your program reaches import child_script it will first look to see if it has already been imported. If not then it loads that module (sort of running it) and binds the name to the resultant module object for your program to use. However, if the module has already been imported then it won't re-load it or run any code in it that isn't in functions as all that has already been done, it just binds the name to the already loaded module object.

In your code, after the first time around pressing Enter won't do anything from child_script as the module has already been loaded and you don't call any functions that it contains or anything.
She who travels light — forgot something.

User avatar
Zilla707
Posts: 83
Joined: Fri Aug 23, 2019 11:04 pm

Re: Parent script termination

Mon Dec 02, 2019 2:59 am

You could use threading to import/start the new script, and then "exit()" to quit the original program.

Code: Select all

import threading

def startScript(): 
	# The code for the thread is best in a function or class.
	import child_script

newThread = threading.Thread(target=startScript)
newThread.start()
This imports threading and the starts the new thread, splitting the flow of operations and spinning off a new thread, which imports the child script. Then you can call exit after "newThread.start()" and quit the original program.
P.S.
To Paeryn, that is also how I start a new python program running, do you have any other ideas on how to start a new program besides "import"?
Aim for perfect and you'll hit somewhere near pretty good. (maybe...)
A quick wit is best followed by quick reflexes. (and a Band-Aid...)

User avatar
Paeryn
Posts: 2830
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Parent script termination

Mon Dec 02, 2019 4:40 am

Zilla707 wrote:
Mon Dec 02, 2019 2:59 am
To Paeryn, that is also how I start a new python program running, do you have any other ideas on how to start a new program besides "import"?
Python's import module_name does not, has never and never will "start a new program module_name running". If you want your Python program to start another program then run it. Import just brings the named module into the current program as is implied by its name, it imports a module.

From Python 3.5 subprocess.run() will run a program, prior to Python 3.5 use subprocess.call(). If you need more advanced control than what run() or call() provide then use the class subprocess.Popen

Code: Select all

import subprocess

subprocess.run(['filename_of_program_to_run'])
If you are wanting to run a Python program that doesn't have a shebang line and isn't flagged as executable then you'd need to run it via python3 (or python2 if it's a python2 program)

Code: Select all

subprocess.run(['python3', 'filename_of_program_to_run.py'])
Don't forget to include pathnames to said programs if they aren't in your default PATH. run() will run the named program and wait for it to finish before continuing.
She who travels light — forgot something.

User avatar
Zilla707
Posts: 83
Joined: Fri Aug 23, 2019 11:04 pm

Re: Parent script termination

Mon Dec 02, 2019 8:54 pm

Ok, that makes sense, I was wondering if "subprocess" could be used instead. thx.
Aim for perfect and you'll hit somewhere near pretty good. (maybe...)
A quick wit is best followed by quick reflexes. (and a Band-Aid...)

User avatar
NPDedyukhin
Posts: 29
Joined: Fri Sep 20, 2019 3:23 am
Location: RU

Re: Parent script termination

Tue Dec 03, 2019 3:58 am

Paeryn wrote:
Mon Dec 02, 2019 4:40 am
Zilla707 wrote:
Mon Dec 02, 2019 2:59 am
To Paeryn, that is also how I start a new python program running, do you have any other ideas on how to start a new program besides "import"?
Python's import module_name does not, has never and never will "start a new program module_name running". If you want your Python program to start another program then run it. Import just brings the named module into the current program as is implied by its name, it imports a module.

From Python 3.5 subprocess.run() will run a program, prior to Python 3.5 use subprocess.call(). If you need more advanced control than what run() or call() provide then use the class subprocess.Popen

Code: Select all

import subprocess

subprocess.run(['filename_of_program_to_run'])
If you are wanting to run a Python program that doesn't have a shebang line and isn't flagged as executable then you'd need to run it via python3 (or python2 if it's a python2 program)

Code: Select all

subprocess.run(['python3', 'filename_of_program_to_run.py'])
Don't forget to include pathnames to said programs if they aren't in your default PATH. run() will run the named program and wait for it to finish before continuing.
I tried to do this:

Code: Select all

lines = ["A","B","C","D","E","F"]

import pygame
pygame.quit()
pygame.init()
screen = pygame.display.set_mode((400,400))

done = False
while not done:
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                if a > 0:
                    a = a - 1
                    print(lines[a])
                else:
                    a = len(lines) - 1
                    print(lines[a])
            if event.key == pygame.K_RIGHT:
                if a < len(lines) - 1:
                    a = a + 1
                    print(lines[a])
                else:
                    a = 0
                    print(lines[a])
            if event.key == pygame.K_RETURN:
                import subprocess 
                subprocess.run('child_script.py', shell=True) #added shell = True, since in the compiler without this entry, the script was launched with an error
On the device, when this script is executed, after switching to the child script, the parent continues to execute (when you click on the keyboard arrows, the letters "A", "B", "C" appear again and so on).

Maybe I'm doing something wrong? :|
Respectfully,
Nikita Dedyukhin

scotty101
Posts: 3850
Joined: Fri Jun 08, 2012 6:03 pm

Re: Parent script termination

Tue Dec 03, 2019 9:44 am

Almost certain that both subprocess, threading, import etc are all not the way forward here.

Your main program will have a "main loop" which updates the screen and responds to any key/mouse events. You should keep a record of what mode you are currently in, main program or sub-program. When the main program "calls" the second program, what it should actually do it call the update and key binding functions for the the sub-program.

I'll throw together some non-working "psuedo" code as an example.

Code: Select all

#Main program.
import subprogram

done = False

def main_program_handle(event):
    global program
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                if a > 0:
                    a = a - 1
                    print(lines[a])
                else:
                    a = len(lines) - 1
                    print(lines[a])
            if event.key == pygame.K_RIGHT:
                if a < len(lines) - 1:
                    a = a + 1
                    print(lines[a])
                else:
                    a = 0
                    print(lines[a])
            if event.key == pygame.K_RETURN:
                program = 'subprogram'

def main_program_update():
    #Do stuff here to update the main program like redrawing screens
    pass

while not done:
    for event in pygame.event.get():
        if program = 'main':
            main_program_handle(event)
        elif program = 'subprogram':
            subprogram.sub_program_handle(event)

    if program = 'main':
        main_program_update(event)
    elif program = 'subprogram':
        subprogram.sub_program_update(event)

Code: Select all

#Sub-program
def sub_program_handle(event):
    #Handle the key presses for the subprogram

def sub_program_update():
    #Update the screen etc for the subprogram

Totally un-working but shows a concept for calling functionality from another python module the correct way. subprocess is almost never the correct way to call python code from python code.
Electronic and Computer Engineer
Pi Interests: Home Automation, IOT, Python and Tkinter

User avatar
Zilla707
Posts: 83
Joined: Fri Aug 23, 2019 11:04 pm

Re: Parent script termination

Wed Dec 04, 2019 12:05 am

Does this work? I changed a few things.

Code: Select all

lines = ["A","B","C","D","E","F"]

import pygame
pygame.quit()
pygame.init()
screen = pygame.display.set_mode((400,400))
a = 0

# Starts the new program.
def start():
	subprocess.run('child_script.py', shell=True)

done = False
while not done:
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                if a > 0:
                    a = a - 1
                    print(lines[a])
                else:
                    a = len(lines) - 1
                    print(lines[a])
            if event.key == pygame.K_RIGHT:
                if a < len(lines) - 1:
                    a = a + 1
                    print(lines[a])
                else:
                    a = 0
                    print(lines[a])
            if event.key == pygame.K_RETURN:
                import subprocess, threading, sys # Import threading and sys
                thread = threading.Thread(target=start) # This starts the second program in a thread. 
                thread.start() # Starts the new thread.
                pygame.quit() # Quit pygame
                sys.exit() # Stop the program

                
Hope this helps!
Aim for perfect and you'll hit somewhere near pretty good. (maybe...)
A quick wit is best followed by quick reflexes. (and a Band-Aid...)

User avatar
NPDedyukhin
Posts: 29
Joined: Fri Sep 20, 2019 3:23 am
Location: RU

Re: Parent script termination

Sat Dec 07, 2019 8:00 pm

Zilla707 wrote:
Wed Dec 04, 2019 12:05 am
Does this work? I changed a few things.

Code: Select all

lines = ["A","B","C","D","E","F"]

import pygame
pygame.quit()
pygame.init()
screen = pygame.display.set_mode((400,400))
a = 0

# Starts the new program.
def start():
	subprocess.run('child_script.py', shell=True)

done = False
while not done:
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                if a > 0:
                    a = a - 1
                    print(lines[a])
                else:
                    a = len(lines) - 1
                    print(lines[a])
            if event.key == pygame.K_RIGHT:
                if a < len(lines) - 1:
                    a = a + 1
                    print(lines[a])
                else:
                    a = 0
                    print(lines[a])
            if event.key == pygame.K_RETURN:
                import subprocess, threading, sys # Import threading and sys
                thread = threading.Thread(target=start) # This starts the second program in a thread. 
                thread.start() # Starts the new thread.
                pygame.quit() # Quit pygame
                sys.exit() # Stop the program

                
Hope this helps!
Greetings!

I tried to do as you said.

Everything works well in the compiler on a PC.

But, when I transferred the script to the device, this message appears:

Code: Select all

Exception in thread Thread-1:
Traceback (most recent call last):
   File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
      self.run()
   File "/usr/lib/python2.7/threading.py", line 754, in run
      self.__target(*self.__args, **self._kwargs)
   File "home/pi/Desktop/project/parent_script.py", line 30, in start
      subprocess.run("child_script.py", shell=True)
AttributeError: 'module' object has no attribute 'run'

Apparently, the whole point is that the script runs in version 2.x of python, and not in 3.x.

I just edited the "etc/rc.local" file and added the line "python /home/pi/Desktop/project/parent_script.py" before "exit (0)" there.

I tried changing the line to "python3 /home/pi/Desktop/project/parent_script.py" - this way the script does not start when the device starts.

In this case, you need to understand how to run the script in python version 3.x. Most likely this caused an error. :|

I also tried to run the child script through python3, as Paeryn advised.

For this, I adjusted the line:

Code: Select all

def start ():
   subprocess.run ('child_script.py', shell = True)
On such a line:

Code: Select all

def start ():
   subprocess.run ('python3', 'child_script.py', shell = True)
The same message still comes out (AttributeError: 'module' object has no attribute 'run').
Respectfully,
Nikita Dedyukhin

User avatar
Paeryn
Posts: 2830
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Parent script termination

Sun Dec 08, 2019 12:28 am

NPDedyukhin wrote:
Sat Dec 07, 2019 8:00 pm
Apparently, the whole point is that the script runs in version 2.x of python, and not in 3.x.
...
I also tried to run the child script through python3, as Paeryn advised.

For this, I adjusted the line:

Code: Select all

def start ():
   subprocess.run ('child_script.py', shell = True)
On such a line:

Code: Select all

def start ():
   subprocess.run ('python3', 'child_script.py', shell = True)
The same message still comes out (AttributeError: 'module' object has no attribute 'run').
Did you not read the fairly important part of what I wrote, namely
Paeryn wrote: From Python 3.5 subprocess.run() will run a program, prior to Python 3.5 use subprocess.call().
If you absolutely need it to run under Python 2 (which is definitely prior to Python 3.5) then use subprocess.call() as subprocess.run() was only introduced in Python 3.5, hence the error about run not being present in the module subprocess (Python 2's error is slightly bad in that it only tells you it wasn't found in a module rather than naming the module).
She who travels light — forgot something.

User avatar
Zilla707
Posts: 83
Joined: Fri Aug 23, 2019 11:04 pm

Re: Parent script termination

Sun Dec 08, 2019 1:40 am

Well, if the change in the subprocess.call/run didn't work, I am assuming that the child script had a shebang "#!/usr/bin/env pyhon3" or "#!/usr/bin/env python". If the script doesn't have the shebang telling it how to run, that might be the problem. If it's trying to run the script in py2 then change the VERY FIRST LINE of the program to "#!/usr/bin/env python3". That *should* tell it to run the child script in python3, and make it able to be run by calling "subprocess.run(child_script.py, shell=True).
Aim for perfect and you'll hit somewhere near pretty good. (maybe...)
A quick wit is best followed by quick reflexes. (and a Band-Aid...)

User avatar
paddyg
Posts: 2493
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Parent script termination

Sun Dec 08, 2019 8:25 am

I would reiterate scotty101 here you should not be attempting to use subprocess or to "execute" a child python script for this.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

User avatar
Paeryn
Posts: 2830
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Parent script termination

Sun Dec 08, 2019 5:04 pm

paddyg wrote:
Sun Dec 08, 2019 8:25 am
I would reiterate scotty101 here you should not be attempting to use subprocess or to "execute" a child python script for this.
Possibly so, I took it from the OP that the child script was a separate program being that they imported it but never referenced anything from it in a manner that appeared as though they were trying to run another Python program.
She who travels light — forgot something.

User avatar
paddyg
Posts: 2493
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Parent script termination

Sun Dec 08, 2019 6:20 pm

To be fair, in your first reply you were pretty explicit about the OP needing to put the functionality in the imported file into functions, then importing the file only once and calling the functions in the parent program (at the point where the OP was trying to do repeated imports).
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

User avatar
Zilla707
Posts: 83
Joined: Fri Aug 23, 2019 11:04 pm

Re: Parent script termination

Sun Dec 08, 2019 6:36 pm

This could be simpler. I didn't think about this, but it might make more sense than using threading and subprocess. Here's an example of a loop that can be stopped.

Code: Select all

#!/usr/bin/env python3

import time, pygame
from pygame.locals import *
pygame.init()

running = True
WIDTH = 400
HEIGHT = 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))

while running:
    for event in pygame.event.get():
        if event.type == KEYUP:
            if event.key == K_RETURN:
                running = False
                print('Loop finished.')
    print('Main loop running.')

# Child script starts here.
print('Start child script here.')

Aim for perfect and you'll hit somewhere near pretty good. (maybe...)
A quick wit is best followed by quick reflexes. (and a Band-Aid...)

User avatar
Paeryn
Posts: 2830
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Parent script termination

Sun Dec 08, 2019 7:01 pm

paddyg wrote:
Sun Dec 08, 2019 6:20 pm
To be fair, in your first reply you were pretty explicit about the OP needing to put the functionality in the imported file into functions, then importing the file only once and calling the functions in the parent program (at the point where the OP was trying to do repeated imports).
Ah yes, the subprocess stuff was in response to Zilla707 saying that using import was how they "start a new python program running". I mixed up the OP (NPDedyukhin) with Zilla707.
She who travels light — forgot something.

User avatar
NPDedyukhin
Posts: 29
Joined: Fri Sep 20, 2019 3:23 am
Location: RU

Re: Parent script termination

Tue Dec 10, 2019 6:57 pm

Paeryn wrote:
Sun Dec 08, 2019 7:01 pm
paddyg wrote:
Sun Dec 08, 2019 6:20 pm
To be fair, in your first reply you were pretty explicit about the OP needing to put the functionality in the imported file into functions, then importing the file only once and calling the functions in the parent program (at the point where the OP was trying to do repeated imports).
Ah yes, the subprocess stuff was in response to Zilla707 saying that using import was how they "start a new python program running". I mixed up the OP (NPDedyukhin) with Zilla707.
Good day to all!

Recently, I studied the pygame FAQ.

The first question is the question of why in IDLE the Pygame window does not close correctly?

The answer was that it was called by the Python IDLE interpreter, which seems to somehow store links. Make sure you call "pygame.quit ()" when you exit the application or game.

We didn’t use pygame.quit () correctly.

The article recommended that you correctly exit pygame like this:

Code: Select all

# ... running = True
while running:
    event = pygame.event.wait ()
    if event.type == pygame.QUIT:
        running = False  # Be IDLE friendly
pygame.quit ()
After, I corrected our code, and it began to look like this:

Code: Select all

lines = ["A","B","C","D","E","F"]

import pygame
pygame.quit()
pygame.init()
screen = pygame.display.set_mode((400,400))
a = 0

done = False
while not done:
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                if a > 0:
                    a = a - 1
                    print(lines[a])
                else:
                    a = len(lines) - 1
                    print(lines[a])
            if event.key == pygame.K_RIGHT:
                if a < len(lines) - 1:
                    a = a + 1
                    print(lines[a])
                else:
                    a = 0
                    print(lines[a])
            if event.key == pygame.K_RETURN:                
                pygame.quit() # Quit pygame
                done = True
                import child_script
pygame.quit()
Thank you all for your help. Now everything works exactly as it was necessary. It took me a lot of effort.
Respectfully,
Nikita Dedyukhin

User avatar
Paeryn
Posts: 2830
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Parent script termination

Tue Dec 10, 2019 11:44 pm

NPDedyukhin wrote:
Tue Dec 10, 2019 6:57 pm
Recently, I studied the pygame FAQ.

The first question is the question of why in IDLE the Pygame window does not close correctly?

The answer was that it was called by the Python IDLE interpreter, which seems to somehow store links. Make sure you call "pygame.quit ()" when you exit the application or game.
Normally when a Python program ends everything gets freed up but when running from within IDLE (and possibly Thonny et al) the interpreter just drops into interactive mode rather than clearing up & quitting. This helps debugging as you will still have access to any bound names and their objects (indeed it is very helpful when your program crashes as you don't loose the state that it was in).
She who travels light — forgot something.

Return to “Python”