I have written a script that will keep itself up to date by downloading the latest version from a website and overwriting the running script.
I am not sure what the best way to restart the script after it has been updated.
Any ideas?
I don't really want to have a separate update script.
oh and it has to work on both linux/windows too.
In Linux, or any other form of unix, os.execl and friends are a good choice for this -- you just need to re-exec sys.executable with the same parameters it was executed with last time (sys.argv, more or less) or any variant thereof if you need to inform your next incarnation that it's actually a restart. On Windows, os.spawnl (and friends) is about the best you can do (though it will transiently take more time and memory than os.execl and friends would during the transition).
The CherryPy project has code that restarts itself. Here's how they do it:
args = sys.argv[:]
self.log('Re-spawning %s' % ' '.join(args))
args.insert(0, sys.executable)
if sys.platform == 'win32':
args = ['"%s"' % arg for arg in args]
os.chdir(_startup_cwd)
os.execv(sys.executable, args)
I've used this technique in my own code, and it works great. (I didn't bother to do the argument-quoting step on windows above, but it's probably necessary if arguments could contain spaces or other special characters.)
I think the best solution whould be something like this:
Your normal program:
...
# ... part that downloaded newest files and put it into the "newest" folder
from subprocess import Popen
Popen("/home/code/reloader.py", shell=True) # start reloader
exit("exit for updating all files")
The update script: (e.g.: home/code/reloader.py)
from shutil import copy2, rmtree
from sys import exit
# maybie you could do this automatic:
copy2("/home/code/newest/file1.py", "/home/code/") # copy file
copy2("/home/code/newest/file2.py", "/home/code/")
copy2("/home/code/newest/file3.py", "/home/code/")
...
rmtree('/home/code/newest') # will delete the folder itself
Popen("/home/code/program.py", shell=True) # go back to your program
exit("exit to restart the true program")
I hope this will help you.
The cleanest solution is a separate update script!
Run your program inside it, report back (when exiting) that a new version is available. This allows your program to save all of its data, the updater to apply the update, and run the new version, which then loads the saved data and continues. To the user this can be completely transparent, as they just run the updater-shell which runs the real program.
To additionally support script calls with Python's "-m" parameter the following can be used (based on the Alex's answer; Windows version):
os.spawnl(os.P_WAIT, sys.executable, *([sys.executable] +
(sys.argv if __package__ is None else ["-m", __loader__.name] + sys.argv[1:])))
sys.exit()
Main File:
if __name__ == '__main__':
if os.path.isfile('__config.py'):
print 'Development'
push.update_server()
else:
e = update.check()
if not e: sys.exit()
Update File:
def check():
e = 1.....perform checks, if something needs updating, e=0;
if not e:
os.system("python main.pyw")
return e
Here's the logic:
Main program calls the update function
1) If the update function needs to update, than it updates and calls a new instances of "main"
Then the original instance of "main" exits.
2) If the update function does not need to update, then "main" continues to run
Wouldn't it just be easier to do something like
Very simple, no extra imports needed, and compatible with any OS depending on what you put in the os.system field
def restart_program():
print("Restarting Now...")
os.system('your program here')
You can use reload(module) to reload a module.
Related
I've working on a windows python program and I need it to run once I open an app. Is it possible ? If so how would I implement it ?
We need some information, what did you want to do?
Did you wanna know, if a process is started and then you will continue you python script? Than you can do this:
import psutil
def is_process_running(processName):
for process in psutil.process_iter(): # iterates through all processes from your OS
try:
if processName.lower() in process.name().lower(): # lowers the name, because "programm" != proGramm"
return True # if the process is found, then return true
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): # some failures what could go wrong
pass
return False;
while(!is_process_running('nameOfTheProcess') # only continue as long as the return is False
time.sleep(10) # wait 10 seconds
For further information:
psutil-docs
This can be achieved in multiple ways, following can also be the one.
import subprocess
#sub-process library being part of python doesn't
#require any additional installation and can do all the work.
#For Windows operating system we can use 'tasklist'
#in place of 'ps aux' as the first argument
#(haven't work with windows lately but this is close to something i remember).
#check_output api called when shell=true,returns list of running processes.
running_processes = subprocess.check_output(['ps aux'], shell=True)
#check if the application needed is running, for brevity, I am using firefox,
#if yes, it fires off another python script.
if bytes('firefox',encoding='utf-8') in running_processes:
subprocess.call(['python3', '/path/to/application.py'])
else:
print('it not')
I'm trying to make a file change its name as long as another file is running,
and when i exit the running file i want the changed file name back to its original name
the code i used only seems to open the file and ignore the commands under it,
would really appreciate the help.
import os
import time
if os.startfile(r'C:\Users\Michael\Desktop\test\file.exe'):
time.sleep(3)
os.rename(r'C:\Users\Michael\Desktop\test\name.txt',r'C:\Users\Michael\Desktop\test\name2.txt')
I don't have a Windows computer handy so I can't test this. However, the Python documentation for os.startfile (https://docs.python.org/3/library/os.html) doesn't specify anything regarding the return value. This makes me suspect that the return value is None or something like that. If so, that would explain why your code block isn't being run.
This line from that documentation should be helpful:
startfile() returns as soon as the associated application is launched. There is no option to wait for the application to close, and no way to retrieve the application’s exit status.
Therefore, since you're trying to do something (i.e., revert the file name) once the process terminates, you want to use a different function than os.startfile. I'm not that familiar with Windows so perhaps someone else can point you in the right direction.
Something like this might work, but it probably isn't the best idea:
EDIT: added prints and time.sleep to check every 10 seconds
import os
import psutil
import time
process_name = 'some_process'
file_name = 'some_file_path'
replacement = 'some_replacement_file_name'
while True:
print(f'looking for {process_name}')
time.sleep(10)
if process_name in (p.name() for p in psutil.process_iter()):
print(f'{process_name} started')
os.rename(file_name, replacement)
while True:
time.sleep(10)
if not process_name in (p.name() for p in psutil.process_iter()):
print(f'{process_name} stopped')
os.rename(replacement, file_name)
break
TL;DR: If you have a program that should run for an undetermined amount of time, how do you code something to stop it when the user decide it is time? (Without KeyboardInterrupt or killing the task)
--
I've recently posted this question: How to make my code stopable? (Not killing/interrupting)
The answers did address my question, but from a termination/interruption point of view, and that's not really what I wanted. (Although, my question didn't made that clear)
So, I'm rephrasing it.
I created a generic script for example purposes. So I have this class, that gathers data from a generic API and write the data into a csv. The code is started by typing python main.py on a terminal window.
import time,csv
import GenericAPI
class GenericDataCollector:
def __init__(self):
self.generic_api = GenericAPI()
self.loop_control = True
def collect_data(self):
while self.loop_control: #Can this var be changed from outside of the class? (Maybe one solution)
data = self.generic_api.fetch_data() #Returns a JSON with some data
self.write_on_csv(data)
time.sleep(1)
def write_on_csv(self, data):
with open('file.csv','wt') as f:
writer = csv.writer(f)
writer.writerow(data)
def run():
obj = GenericDataCollector()
obj.collect_data()
if __name__ == "__main__":
run()
The script is supposed to run forever OR until I command it to stop. I know I can just KeyboardInterrupt (Ctrl+C) or abruptly kill the task. That isn't what I'm looking for. I want a "soft" way to tell the script it's time to stop, not only because interruption can be unpredictable, but it's also a harsh way to stop.
If that script was running on a docker container (for example) you wouldn't be able to Ctrl+C unless you happen to be in the terminal/bash inside the docker.
Or another situation: If that script was made for a customer, I don't think it's ok to tell the customer, just use Ctrl+C/kill the task to stop it. Definitely counterintuitive, especially if it's a non tech person.
I'm looking for way to code another script (assuming that's a possible solution) that would change to False the attribute obj.loop_control, finishing the loop once it's completed. Something that could be run by typing on a (different) terminal python stop_script.py.
It doesn't, necessarily, needs to be this way. Other solutions are also acceptable, as long it doesn't involve KeyboardInterrupt or Killing tasks. If I could use a method inside the class, that would be great, as long I can call it from another terminal/script.
Is there a way to do this?
If you have a program that should run for an undetermined amount of time, how do you code something to stop it when the user decide it is time?
In general, there are two main ways of doing this (as far as I can see). The first one would be to make your script check some condition that can be modified from outside (like the existence or the content of some file/socket). Or as #Green Cloak Guy stated, using pipes which is one form of interprocess communication.
The second one would be to use the built in mechanism for interprocess communication called signals that exists in every OS where python runs. When the user presses Ctrl+C the terminal sends a specific signal to the process in the foreground. But you can send the same (or another) signal programmatically (i.e. from another script).
Reading the answers to your other question I would say that what is missing to address this one is a way to send the appropriate signal to your already running process. Essentially this can be done by using the os.kill() function. Note that although the function is called 'kill' it can send any signal (not only SIGKILL).
In order for this to work you need to have the process id of the running process. A commonly used way of knowing this is making your script save its process id when it launches into a file stored in a common location. To get the current process id you can use the os.getpid() function.
So summarizing I'd say that the steps to achieve what you want would be:
Modify your current script to store its process id (obtainable by using os.getpid()) into a file in a common location, for example /tmp/myscript.pid. Note that if you want your script to be protable you will need to address this in a way that works in non-unix like OSs like Windows.
Choose one signal (typically SIGINT or SIGSTOP or SIGTERM) and modify your script to register a custom handler using signal.signal() that addresses the graceful termination of your script.
Create another (note that it could be the same script with some command line paramater) script that reads the process id from the known file (aka /tmp/myscript.pid) and sends the chosen signal to that process using os.kill().
Note that an advantage of using signals to achieve this instead of an external way (files, pipes, etc.) is that the user can still press Ctrl+C (if you chose SIGINT) and that will produce the same behavior as the 'stop script' would.
What you're really looking for is any way to send a signal from one program to another, independent, program. One way to do this would be to use an inter-process pipe. Python has a module for this (which does, admittedly, seem to require a POSIX-compliant shell, but most major operating systems should provide that).
What you'll have to do is agree on a filepath beforehand between your running-program (let's say main.py) and your stopping-program (let's say stop.sh). Then you might make the main program run until someone inputs something to that pipe:
import pipes
...
t = pipes.Template()
# create a pipe in the first place
t.open("/tmp/pipefile", "w")
# create a lasting pipe to read from that
pipefile = t.open("/tmp/pipefile", "r")
...
And now, inside your program, change your loop condition to "as long as there's no input from this file - unless someone writes something to it, .read() will return an empty string:
while not pipefile.read():
# do stuff
To stop it, you put another file or script or something that will write to that file. This is easiest to do with a shell script:
#!/usr/bin/env sh
echo STOP >> /tmp/pipefile
which, if you're containerizing this, you could put in /usr/bin and name it stop, give it at least 0111 permissions, and tell your user "to stop the program, just do docker exec containername stop".
(using >> instead of > is important because we just want to append to the pipe, not to overwrite it).
Proof of concept on my python console:
>>> import pipes
>>> t = pipes.Template()
>>> t.open("/tmp/file1", "w")
<_io.TextIOWrapper name='/tmp/file1' mode='w' encoding='UTF-8'>
>>> pipefile = t.open("/tmp/file1", "r")
>>> i = 0
>>> while not pipefile.read():
... i += 1
...
At this point I go to a different terminal tab and do
$ echo "Stop" >> /tmp/file1
then I go back to my python tab, and the while loop is no longer executing, so I can check what happened to i while I was gone.
>>> print(i)
1704312
I have a script runReports.py that is executed every night. Suppose for some reason the script takes too long to execute, I want to be able to stop it from terminal by issuing a command like ./runReports.py stop.
I tried to implement this by having the script to create a temporary file when the stop command is issued.
The script checks for existence of this file before running each report.
If the file is there the script stops executing, else it continues.
But I am not able to find a way to make the issuer of the stop command aware that the script has stopped successfully. Something along the following lines:
$ ./runReports.py stop
Stopping runReports...
runReports.py stopped successfully.
How to achieve this?
For example if your script runs in loop, you can catch signal http://en.wikipedia.org/wiki/Unix_signal and terminate process:
import signal
class SimpleReport(BaseReport):
def __init__(self):
...
is_running = True
def _signal_handler(self, signum, frame):
is_running = False
def run(self):
signal.signal(signal.SIGUSR1, self._signal_handler) # set signal handler
...
while is_running:
print("Preparing report")
print("Exiting ...")
To terminate process just call kill -SIGUSR1 procId
You want to achieve inter process communication. You should first explore the different ways to do that : system V IPC (memory, very versatile, possibly baffling API), sockets (including unix domain sockets)(memory, more limited, clean API), file system (persistent on disk, almost architecture independent), and choose yours.
As you are asking about files, there are still two ways to communicate using files : either using file content (feature rich, harder to implement), or simply file presence. But the problem using files, is that is a program terminates because of an error, it may not be able to write its ended status on the disk.
IMHO, you should clearly define what are your requirements before choosing file system based communication (testing the end of a program is not really what it is best at) unless you also need architecture independence.
To directly answer your question, the only reliable way to know if a program has ended if you use file system communication is to browse the list of currently active processes, and the simplest way is IMHO to use ps -e in a subprocess.
Instead of having a temporary file, you could have a permanent file(config.txt) that has some tags in it and check if the tag 'running = True'.
To achieve this is quiet simple, if your code has a loop in it (I imagine it does), just make a function/method that branches a check condition on this file.
def continue_running():
with open("config.txt") as f:
for line in f:
tag, condition = line.split(" = ")
if tag == "running" and condition == "True":
return True
return False
In your script you will do this:
while True: # or your terminal condition
if continue_running():
# your regular code goes here
else:
break
So all you have to do to stop the loop in the script is change the 'running' to anything but "True".
I wrote a script in python that takes a few files, runs a few tests and counts the number of total_bugs while writing new files with information for each (bugs+more).
To take a couple files from current working directory:
myscript.py -i input_name1 input_name2
When that job is done, I'd like the script to 'return total_bugs' but I'm not sure on the best way to implement this.
Currently, the script prints stuff like:
[working directory]
[files being opened]
[completed work for file a + num_of_bugs_for_a]
[completed work for file b + num_of_bugs_for_b]
...
[work complete]
A bit of help (notes/tips/code examples) could be helpful here.
Btw, this needs to work for windows and unix.
If you want your script to return values, just do return [1,2,3] from a function wrapping your code but then you'd have to import your script from another script to even have any use for that information:
Return values (from a wrapping-function)
(again, this would have to be run by a separate Python script and be imported in order to even do any good):
import ...
def main():
# calculate stuff
return [1,2,3]
Exit codes as indicators
(This is generally just good for when you want to indicate to a governor what went wrong or simply the number of bugs/rows counted or w/e. Normally 0 is a good exit and >=1 is a bad exit but you could inter-prate them in any way you want to get data out of it)
import sys
# calculate and stuff
sys.exit(100)
And exit with a specific exit code depending on what you want that to tell your governor.
I used exit codes when running script by a scheduling and monitoring environment to indicate what has happened.
(os._exit(100) also works, and is a bit more forceful)
Stdout as your relay
If not you'd have to use stdout to communicate with the outside world (like you've described).
But that's generally a bad idea unless it's a parser executing your script and can catch whatever it is you're reporting to.
import sys
# calculate stuff
sys.stdout.write('Bugs: 5|Other: 10\n')
sys.stdout.flush()
sys.exit(0)
Are you running your script in a controlled scheduling environment then exit codes are the best way to go.
Files as conveyors
There's also the option to simply write information to a file, and store the result there.
# calculate
with open('finish.txt', 'wb') as fh:
fh.write(str(5)+'\n')
And pick up the value/result from there. You could even do it in a CSV format for others to read simplistically.
Sockets as conveyors
If none of the above work, you can also use network sockets locally *(unix sockets is a great way on nix systems). These are a bit more intricate and deserve their own post/answer. But editing to add it here as it's a good option to communicate between processes. Especially if they should run multiple tasks and return values.