I am trying to run this code in the background (from command line) on Windows using python 2.7:
import httpimport
mod = httpimport.load('module name','URL')
Everything works, but the process lingers when launched and only ctrl + c will end it. I am looking to start an independent process from this in the background.
I have read that multiprocess can come useful here but I would need some pointers if I may.
Any suggestions ?
EDIT: I may add this is a script which is calling another python script from URL. From the answers below I gathered that I might need to change my remote script first.
if you want to run your process in the background you can use spawnl
import os
os.spawnl(os.P_DETACH, 'python code.py "module name" "url"')
but you need to be cautious, you can't kill the process if you don't knew it's pid or check where it is running via task manager
check for more: https://docs.python.org/2/library/os.html#os.spawnl
for your code (for exemple code.py):
import httpimport
from sys import argv
name, module_name, URL = argv # here you get the module name and URL from the argument given from before
mod = httpimport.load(module_name , URL)
Related
I have two Python files (main.py and main_test.py). The file main_test.py is executed within main.py. When I do not use a log file this is what gets printed out:
Main file: 17:41:18
Executed file: 17:41:18
Executed file: 17:41:19
Executed file: 17:41:20
When I use a log file and execute main.py>log, then I get the following:
Executed file: 17:41:18
Executed file: 17:41:19
Executed file: 17:41:20
Main file: 17:41:18
Also, when I use python3 main.py | tee log to print out and log the output, it waits and prints out after finishing everything. In addition, the problem of reversing remains.
Questions
How can I fix the reversed print out?
How can I print out results simultaneously in terminal and log them in a correct order?
Python files for replication
main.py
import os
import time
import datetime
import pytz
python_file_name = 'main_test'+'.py'
time_zone = pytz.timezone('US/Eastern') # Eastern-Time-Zone
curr_time = datetime.datetime.now().replace(microsecond=0).astimezone(time_zone).time()
print(f'Main file: {curr_time}')
cwd = os.path.join(os.getcwd(), python_file_name)
os.system(f'python3 {cwd}')
main_test.py
import pytz
import datetime
import time
time_zone = pytz.timezone('US/Eastern') # Eastern-Time-Zone
for i in range(3):
curr_time = datetime.datetime.now().replace(microsecond=0).astimezone(time_zone).time()
print(f'Executed file: {curr_time}')
time.sleep(1)
When you run a script like this:
python main.py>log
The shell redirects output from the script to a file called log. However, if the script launches other scripts in their own subshell (which is what os.system() does), the output of that does not get captured.
What is surprising about your example is that you'd see anything at all when redirecting, since the output should have been redirected and no longer echo - so perhaps there's something you're leaving out here.
Also, tee waits for EOF on standard in, or for some error to occur, so the behaviour you're seeing there makes sense. This is intended behaviour.
Why bother with shells at all though? Why not write a few functions to call, and import the other Python module to call its functions? Or, if you need things to run in parallel (which they didn't in your example), look at multiprocessing.
In direct response to your questions:
"How can I fix the reversed print out?"
Don't use redirection, and write to file directly from the script, or ensure you use the same redirection when calling other scripts from the first (that will get messy), or capture the output from the subprocesses in the subshell and pipe it to the standard out of your main script.
"How can I print out results simultaneously in terminal and log them in a correct order?"
You should probably just do it in the script, otherwise this is not a really a Python question and you should try SuperUser or similar sites to see if there's some way to have tee or similar tools write through live.
In general though, unless you have really strong reasons to have the other functionality running in other shells, you should look at solving your problems in the Python script. And if you can't, use you can use something like Popen or derivatives to capture the subscript's output and do what you need instead of relying on tools that may or may not be available on the host OS running your script.
I try to write a programm in python that notifies me, when a shell like cmd gets opened.
Until now I did the following in python.
Check for new starting processes, get the name of the process and check if its name is cmd.exe.
This works if I start a cmd process manually myself.
But it Turns out if i open a shell with subprocess.getoutput(command) from the subprocess library in python there is no shell listed in the prosesses and I also cant see it in taskmanager.
So I assumed its a childprocess of the pythonscripts process running?
My next Idea was to list all the modules a process is using and check for cmd.exe in the modules.
It turns out the pythonscript with subprocess.getoutput(command) does not use cmd.exe in the modules. Strange.
So right now I am not sure how I could detect the shell or if I am even on the right way.
Maybe I need to find the childprocesses of a the pythonprocess? Or is it possible to get a shell without calling cmd.exe I honestly dont know enough about it.
Maybe its better to check for chertain dlls in the used methods by a process?
I also tried to look in the subprocess.py library but it is difficult for me to understand and it seems to atleast pass over cmd as a parameter for subprocess.getoutput() method.
Can somebody help?
Thank you.
UPDATE:
I use this code to detect the process:
import wmi
c = wmi.WMI()
process_watcher = c.Win32_Process.watch_for("creation")
while True:
new_process = process_watcher()
print(new_process.Caption, new_process.ProcessId)
if new_process.Caption =="cmd.exe":
pid = new_process.ProcessID
break
But if I run this code
import subprocess
output = subprocess.getoutput("ipconfig")
print(output)
The only process detected is pythonw.exe
But if I run
import subprocess
while True:
output = subprocess.getoutput("ipconfig")
print(output)
At some point it find cmd.exe.
So I assume that wmi takes to long to detect the process. So cmd is already closed and does not get found.
Any Ideas how to do this a better way?
I didnt know practic version of solution.But you can use pyautogui for it if you want.You can write a program with pyautogui that notifies you when it find cmd logo at task bar.Example:
import pyautogui
cmdlogo = pyautogui.locateOnScreen('get screenshot of cmd logo and write file name here example:'cmd.png'')
While True:
if cmdlogo:
print('write here what yo want to say when it finds cmd')
else:
pyautogui.sleep(5)
Is it possible to make a python script that will delete the .py file at the end of its execution (self-delete) in windows?
This way makes your program non OS dependant.
from os import remove
from sys import argv
remove(argv[0])
Bonus points:
When parsing arguments the very first argument that you get in sys.argv is equals to "path-to-filename/filename.py"
Neomind's answer seems to do the trick. But if deleting the file while it's in memory bothers you, and you're looking for a pure python solution, then you could use subprocess to create a new process with the explicit purpose of deleting your original script file. Something like this should work:
import sys, subprocess
subprocess.Popen("python -c \"import os, time; time.sleep(1); os.remove('{}');\"".format(sys.argv[0]))
sys.exit(0)
You probably wouldn't need the timeout in there but I've added it just to make sure that the process from the original script has been given enough time to close itself.
I'm not sure deleting a file while it's in memory would be a good idea. Try running a batch file from the script which closes the script process, then deletes the script file.
There may be a native method to self destruct a script, but I am not aware of it.
EDIT: Here is a simple example of how you could accomplish this using the method I described:
In the script
# C:\test.py
import os
os.startfile(r"C:\sampleBatch.bat")
In the batch
# C:\sampleBatch.bat
TASKKILL /IM "process name" #For me, this was "ipy64.exe" because I use IronPython.
DEL "C:\test.py"
You may not even need to kill the process to delete the file, but it is safer to do so. Hope this helps.
Yes, you could use the following:
import os
import sys
import subprocess
# execute and remove after run
(Your python code)
# end of file
dir = os.getcwd()
os.remove(dir+'\%s' % sys.argv[0])
This script can be modified of course, but besides that this should work
You could also make use of the atexit module.
import os, atexit
atexit.register(lambda file = __file__: os.remove(file))
There is a rather simple method:
import os
os.remove("insert the file's path")
If you're facing problems, place an 'r' before the starting quotations mark.
I have a python script which when run, logs information on the terminal, i want to send this logging information to a text file,
To achieve this in the beginning of the file i am inserting
import subprocess
subprocess.call(['script', 'logfile'])
and at the end of the file,i put in,
subprocess.call(['exit'])
The problem with this is when it calls the first commandscript logfile,it terminates the script,
Any suggestions on how i could make this work would be really helpful,Thanks in advance
The problem is that subprocess.call isn't returning until the shell spawned by script exits, at which point your Python script will resume.
The simplest way to do what you want is to call script itself with your Python script as an argument. Instead of
#!/usr/bin/python
import subprocess
subprocess.call(['script', 'logfile'])
# Rest of your Python code
subprocess.call(['exit'])
you will use
#!/usr/bin/python
import os
import sys
if '_underscript' not in os.environ:
os.environ['_underscript'] = "yes"
cmd_args = ['script', 'logfile', 'python'] + sys.argv
os.execvp('script', cmd_args)
# Rest of your Python code
The environment variable prevents your script from entering an infinite loop of re-running itself with script. When you run your Python script, it first checks its environment for a variable that should not yet exist. If it doesn't, it sets that variable, then runs script to re-run the Python script. execvp replaces your script with the call to script; nothing else in the Python script executes. This second time your script runs, the variable _underscript does exist, meaning the if block is skipped and the rest of your script runs as intended.
Seems like that's the expected behaviour of subprocess.call(...). If you want to capture the output of the script to a file, you'll need to open a new file handler in write mode, and tell the subprocess.call where to direct the stdout, which is the terminal output you typically would see.
Try:
import subprocess
f = open('/tmp/mylogfile.log', 'w')
subprocess.call(['/path/to/script'], stdout=f)
f.close()
Then in the terminal you can run tail /tmp/mylogfile.log to confirm.
I'm not sure the last exit call is required for what you're trying to achieve.
You can read more in the python docs, depending which version of Python you're using. https://docs.python.org/2/library/subprocess.html
The file doesn't need to pre-exist. Hope that helps!
Is it possible to make a python script that will delete the .py file at the end of its execution (self-delete) in windows?
This way makes your program non OS dependant.
from os import remove
from sys import argv
remove(argv[0])
Bonus points:
When parsing arguments the very first argument that you get in sys.argv is equals to "path-to-filename/filename.py"
Neomind's answer seems to do the trick. But if deleting the file while it's in memory bothers you, and you're looking for a pure python solution, then you could use subprocess to create a new process with the explicit purpose of deleting your original script file. Something like this should work:
import sys, subprocess
subprocess.Popen("python -c \"import os, time; time.sleep(1); os.remove('{}');\"".format(sys.argv[0]))
sys.exit(0)
You probably wouldn't need the timeout in there but I've added it just to make sure that the process from the original script has been given enough time to close itself.
I'm not sure deleting a file while it's in memory would be a good idea. Try running a batch file from the script which closes the script process, then deletes the script file.
There may be a native method to self destruct a script, but I am not aware of it.
EDIT: Here is a simple example of how you could accomplish this using the method I described:
In the script
# C:\test.py
import os
os.startfile(r"C:\sampleBatch.bat")
In the batch
# C:\sampleBatch.bat
TASKKILL /IM "process name" #For me, this was "ipy64.exe" because I use IronPython.
DEL "C:\test.py"
You may not even need to kill the process to delete the file, but it is safer to do so. Hope this helps.
Yes, you could use the following:
import os
import sys
import subprocess
# execute and remove after run
(Your python code)
# end of file
dir = os.getcwd()
os.remove(dir+'\%s' % sys.argv[0])
This script can be modified of course, but besides that this should work
You could also make use of the atexit module.
import os, atexit
atexit.register(lambda file = __file__: os.remove(file))
There is a rather simple method:
import os
os.remove("insert the file's path")
If you're facing problems, place an 'r' before the starting quotations mark.