I'm a beginner programmer and my goal is to design a utility that can accept an sms command and run a corresponding function on my main pc remotely. I'm using a variety of tools to do this (IFTTT, Dropbox, Twilio, Task Scheduler), but I've run into a little trouble along the way.
Most recently I've tried running the main code through a function which I've named 'main()'. However, when I attempt to call the function, command line throws an error:
Traceback (most recent call last):
File "C:\Python_Files\WIP\Check.py", line 104, in <module>
main()
NameError: name 'main' is not defined
I will post my code here for context (some info is edited for security):
#DESCRIPTION:
#Check if C:/Users/Thermaltake/Dropbox/Remote_Control contains a .txt file
#set count to corresponding integer
#delete file
#call function of corresponding integer
#reset count
#Set Task Scheduler to run this program every 5 minutes when idle.
import os
import time
import subprocess
import sys
import collections
import webbrowser
import logging
from twilio.rest import Client
#Twilio Account Info
account_sid = 'id'#not included for security
auth_token = 'token'#not included for security
client = Client(account_sid, auth_token)
myTwilioNumber = '+myTwilioNumber'#not included for security
myCellPhone = '+MyCellPhone'#not included for security
##FUNCTIONS##
#shutdown command
def shutdown():
os.system('shutdown -s')
#restart command
def restart():
os.system('shutdown -r')
#wake up computer and launch core programs
def wakeup():
subprocess.Popen('C:/Users/Thermaltake/AppData/Roaming/Spotify/Spotify.exe')
webbrowser.open('https://us-mg6.mail.yahoo.com/neo/launch')
webbrowser.open('https://www.rescuetime.com/dashboard')
#Launch main coding applications
def code():
webbrowser.open('http://somafm.com/player/#/now-playing/groovesalad')
subprocess.Popen('C:\Windows\system32\cmd.exe')
subproces.Popen('C:\Python_Files\Sublime Text 3\sublime_text.exe')
#Launch Remote Desktop and automatically log in
def logmein():
def main(): #main code
x=0 #counter
#checks for txt file in Remote_Control folder and assigns value to x
if os.path.isfile('C:/Users/Thermaltake/Dropbox/Remote_Control/shutdown.txt')==True:
x=1
elif os.path.isfile('C:/Users/Thermaltake/Dropbox/Remote_Control/wakeup.txt')==True:
x=2
elif os.path.isfile('C:/Users/Thermaltake/Dropbox/Remote_Control/restart.txt')==True:
x=3
elif os.path.isfile('C:/Users/Thermaltake/Dropbox/Remote_Control/code.txt')==True:
x=4
else:
print('No File Found')
#Checks x value and executes function
if x==1:
os.remove('C:/Users/Thermaltake/Dropbox/Remote_Control/shutdown.txt')
shutdown()
#print('Shutdown')#Placeholder for testing
message = client.messages.create(body='Shutdown Initiated', from_=, to=)#not included for security
elif x==2:
os.remove('C:/Users/Thermaltake/Dropbox/Remote_Control/wakeup.txt')
wakeup()
#print ('Spotify') #Placeholder. Define function to wake up PC and launch core programs
message = client.messages.create(body='Waking Up', from_=, to=)#not included for security
elif x==3:
os.remove('C:/Users/Thermaltake/Dropbox/Remote_Control/restart.txt')
restart()
#print ('Restart') #Placeholder.
message = client.messages.create(body='Restart Initiated', from_=, to=)#not included for security
elif x==4:
os.remove('C:/Users/Thermaltake/Dropbox/Remote_Control/code.txt')
code()
print('Happy Coding!')
message = client.messages.create(body='Ready to Code!', from_=, to=)#not included for security
else:
print ('No command entered')
#End Sequence (prints value and resets counter)
print (x)
x=0
os.system('pause') #Placeholder for testing
if __name__ == '__main__': #Runs main function
main()
'''
TODO:
Twilio not yet working. try different iterations of body and message. try assigning it to its own function
subprocess failing to launch programs. research alternatives. SMTP is a possibility.
possibly need to add Enter keystroke to the end of shutdown() and restart(). maybe even log in to log off.
add 'send to-do list to phone' function.
cleanup indentation and remove unnecessary modules
add 'flvto' function
add 'remote in' function.
+ Version 1.1 7/6/17 +
WORKING:
subprocess.Popen('C:\Windows\system32\cmd.exe')
webbrowser.open('http://somafm.com/player/#/now-playing/groovesalad')
os.remove
wakeup()
NOT WORKING:
subproces.Popen('C:\Python_Files\Sublime Text 3\sublime_text.exe')
Twilio return message
Task Scheduler: "Check_Dropbox on Lock"
BUGS:
IFTTT is buggy and sometimes unresponsive
Task Scheduler to check file is too slow. Need something faster. (Possibly 'Watch 4 Folder')
shutdown() waits til logon to initialize.
restart() waits til logon to initialize.
'''
Any help would be enormously appreciated. Keep in mind I have no formal education in CS, but I'm just trying to get my feet wet before starting a CS major this fall. I've only been programming for about 3 months.
also, if anything in this code can be done more elegantly, I will happily take advice.
-Jake
remove main() from inside logmein() so its in the global scope. The error you are getting is because when you call main from the global scope it isn't defined.
Related
I'm relatively new to python so please forgive early level understanding!
I am working to create a kind of flag file. Its job is to monitor a Python executable, the flag file is constantly running and prints "Start" when the executable started, "Running" while it runs and "Stop" when its stopped or crashed, if a crash occurs i want it to be able to restart the script. so far i have this down for the Restart:
from subprocess import run
from time import sleep
# Path and name to the script you are trying to start
file_path = "py"
restart_timer = 2
def start_script():
try:
# Make sure 'python' command is available
run("python "+file_path, check=True)
except:
# Script crashed, lets restart it!
handle_crash()
def handle_crash():
sleep(restart_timer) # Restarts the script after 2 seconds
start_script()
start_script()
how can i implement this along with a flag file?
Not sure what you mean with "flag", but this minimally achieves what you want.
Main file main.py:
import subprocess
import sys
from time import sleep
restart_timer = 2
file_path = 'sub.py' # file name of the other process
def start():
try:
# sys.executable -> same python executable
subprocess.run([sys.executable, file_path], check=True)
except subprocess.CalledProcessError:
sleep(restart_timer)
return True
else:
return False
def main():
print("starting...")
monitor = True
while monitor:
monitor = start()
if __name__ == '__main__':
main()
Then the process that gets spawned, called sub.py:
from time import sleep
sleep(1)
print("doing stuff...")
# comment out to see change
raise ValueError("sub.py is throwing error...")
Put those files into the same directory and run it with python main.py
You can comment out the throwing of the random error to see the main script terminate normally.
On a larger note, this example is not saying it is a good way to achieve the quality you need...
I am writing a script intended to be used by members of a project team. As part of the script, I am launching a 3rd party proprietary application run through Citrix. I am going to use the script mostly to send keys to this application, but the first step once it launches is for the user to log in.
Because I would like the user to log in while the script is running, rather than asking for user/pass from some kind of GUI input earlier, and because the time it takes Citrix to launch varies, I would like to include some kind of logic that detects when the user has logged in and then resume the script from there, rather than including an obnoxiously long implicit wait or risking the script timing out.
Is there a way to detect user keystrokes using win32com.client (or to detect a change in state of the application itself)? See below for the relevant code to launch the app:
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
shell.Run('C:\Citrix\[rest of path])
EDIT:
Per Vasily's suggestion in the comments below, I attempted to adapt the "hook and listen" code to my scenario, but was unsuccessful. When I launch my file, I don't even get an exception message in my terminal, I get a Windows pop-up that says Python encountered a problem and needs to quit.
This is how I adapted it:
#[omitting import lines for brevity]
def on_timer():
"""Callback by timer out"""
win32api.PostThreadMessage(main_thread_id, win32con.WM_QUIT, 0, 0);
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
for i in range(1,100):
time.sleep(1)
if args.pressed_key == 'Lcontrol':
break
def init():
hk = Hook()
hk.handler = on_event
main_thread_id = win32api.GetCurrentThreadId()
t = Timer(55.0, on_timer) # Quit after 55 seconds
t.start()
hk.hook(keyboard=True, mouse=True)
At the point when the 3rd party Citrix app begins to launch in my main script, I call hookandlisten.init().
As a reminder, my goal is to wait until the user sends a certain keystroke (here I chose Control) before proceeding with the rest of the main script.
Solved this by eliminating the timer and unhooking the keyboard upon the correct keystroke:
import win32api
import win32con
from pywinauto.win32_hooks import Hook
from pywinauto.win32_hooks import KeyboardEvent
from pywinauto.win32_hooks import MouseEvent
def on_event(args):
"""Callback for keyboard and mouse events"""
if isinstance(args, KeyboardEvent):
if args.current_key == 'Lcontrol' and args.event_type == 'key down':
print("Success")
hk.unhook_keyboard()
return
def init():
hk.handler = on_event
hk.hook(keyboard=True, mouse=False)
hk = Hook()
Given this code:
from time import sleep
class TemporaryFileCreator(object):
def __init__(self):
print 'create temporary file'
# create_temp_file('temp.txt')
def watch(self):
try:
print 'watching tempoary file'
while True:
# add_a_line_in_temp_file('temp.txt', 'new line')
sleep(4)
except (KeyboardInterrupt, SystemExit), e:
print 'deleting the temporary file..'
# delete_temporary_file('temp.txt')
sleep(3)
print str(e)
t = TemporaryFileCreator()
t.watch()
during the t.watch(), I want to close this application in the console..
I tried using CTRL+C and it works:
However, if I click the exit button:
it doesn't work.. I checked many related questions about this but it seems that I cannot find the right answer..
What I want to do:
The console can be exited while the program is still running.. to handle that, when the exit button is pressed, I want to make a cleanup of the objects (deleting of created temporary files), rollback of temporary changes, etc..
Question:
how can I handle console exit?
how can I integrate it on object destructors (__exit__())
Is it even possible? (how about py2exe?)
Note: code will be compiled on py2exe.. "hopes that the effect is the same"
You may want to have a look at signals. When a *nix terminal is closed with a running process, this process receives a couple signals. For instance this code waits for the SIGHUB hangup signal and writes a final message. This codes works under OSX and Linux. I know you are specifically asking for Windows but you might want to give it a shot or investigate what signals a Windows command prompt is emitting during shutdown.
import signal
import sys
def signal_handler(signal, frame):
with open('./log.log', 'w') as f:
f.write('event received!')
signal.signal(signal.SIGHUP, signal_handler)
print('Waiting for the final blow...')
#signal.pause() # does not work under windows
sleep(10) # so let us just wait here
Quote from the documentation:
On Windows, signal() can only be called with SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, or SIGTERM. A ValueError will be raised in any other case.
Update:
Actually, the closest thing in Windows is win32api.setConsoleCtrlHandler (doc). This was already discussed here:
When using win32api.setConsoleCtrlHandler(), I'm able to receive shutdown/logoff/etc events from Windows, and cleanly shut down my app.
And if Daniel's code still works, this might be a nice way to use both (signals and CtrlHandler) for cross-platform purposes:
import os, sys
def set_exit_handler(func):
if os.name == "nt":
try:
import win32api
win32api.SetConsoleCtrlHandler(func, True)
except ImportError:
version = “.”.join(map(str, sys.version_info[:2]))
raise Exception(”pywin32 not installed for Python ” + version)
else:
import signal
signal.signal(signal.SIGTERM, func)
if __name__ == "__main__":
def on_exit(sig, func=None):
print "exit handler triggered"
import time
time.sleep(5)
set_exit_handler(on_exit)
print "Press to quit"
raw_input()
print "quit!"
If you use tempfile to create your temporary file, it will be automatically deleted when the Python process is killed.
Try it with:
>>> foo = tempfile.NamedTemporaryFile()
>>> foo.name
'c:\\users\\blah\\appdata\\local\\temp\\tmpxxxxxx'
Now check that the named file is there. You can write to and read from this file like any other.
Now kill the Python window and check that file is gone (it should be)
You can simply call foo.close() to delete it manually in your code.
I wanted to add a filter to the python logger in my Django project; the filter has a while loop in it (there to wait and allow the user to provide a response). However, when I try to implement my filter the server seems to immediately break and my view goes into an infinite loop (which doesn't happen when I test the filter in a terminal window).
My code I have looks like this:
import logging, time, os
# in my Utils.py file:
def ErrorReport(msg, notify=False, warnOnly=False):
logger.exception("ErrorReport:%s" % msg, exc_info=True)
raise RuntimeError('Aborting execution. Terrible things might happen. Check logs for more information')
# in my views.py file:
class ErrorFilter(logging.Filter):
def __init__(self,level):
self.level = level
print level
def filter(self,record):
if record.levelno == self.level:
os.environ["ERROR_FLAG"] = "True"
timeout = time.time() + 60*1 #set the timeout to 1 minute
while True:
print "waiting..."
keep_going = os.environ.get("CONTINUE_FLAG")
#wait for user to respond
if keep_going == "False" or time.time() > timeout:
Utils.ErrorReport("There's a problem, quiting current process.")
if keep_going == "True":
break
logger = Utils.getLogger() #I format the logger in another python script called Utils
logger.addFilter(ErrorFilter(logging.ERROR))
def home(request):
context_dict = {'boldmessage': "--> To view logs, please turn off any popup blockers <--",'version':"1.1.6"}
logger.error("faking an error to test new filter")
return render(request, 'InterfaceApp/home.html', context_dict)
I've tested a simpler version of this filter in a terminal window and didn't have any problems with it getting stuck in an infinite loop. When I try to open the home page of my django site it looks like it's loading forever, and when I look at the developers window I can see that I've lost the connection to my server. In the terminal window where I'm running the server, I get the print statement waiting... forever, even though I've set and tested the timeout on the while loop.
Is there a fundamental problem with running while loops in a django project, or have I missed something?
I'm wondering how I would go about having a function refresh itself every minute, and check if a certain file it open. I don't exactly know how to go about this, but heres an example of what I'm looking for:
def timedcheck():
if thisgame.exe is open:
print("The Program is Open!")
else:
print("The Program is closed!")
*waits 1 minute*
timedcheck()
I would also like the script to refresh the function "def timedcheck():" every minute, so it keeps checking if thisgame.exe is open.
I searched through the site already, all suggestions recommended using "import win32ui", which gives me an error when I do.
To repeat this check every minute:
def timedcheck():
while True:
if is_open("thisgame.exe"):
print("The Program is Open!")
else:
print("The Program is closed!")
sleep(60)
Since it's a .exe file, I assume that by "check if this file is open" you mean "check if thisgame.exe" is running. psutil should be helpful - I haven't tested the below code, so it may need some tweaking, but shows the general principle.
def is_open(proc_name):
import psutil
for process in psutil.process_iter():
if proc_name in process.name:
return True
return False
You can use sleep from the time module with an input of 60 for 1 minute delay between checks. You can open the file temporarily and close it if not needed. An IOError will occur if the file is already opened. Catch the error with an exception and the program will wait for another minute before trying again.
import time
def timedcheck():
try:
f = open('thisgame.exe')
f.close()
print("The Program is Closed!")
except IOError:
print("The Program is Already Open!")
time.sleep(60) #*program waits 1 minute*
timedcheck()
Here's a variation on #rkd91's answer:
import time
thisgame_isrunning = make_is_running("thisgame.exe")
def check():
if thisgame_isrunning():
print("The Program is Open!")
else:
print("The Program is closed!")
while True:
check() # ignore time it takes to run the check itself
time.sleep(60) # may wake up sooner/later than in a minute
where make_is_running():
import psutil # 3rd party module that needs to be installed
def make_is_running(program):
p = [None] # cache running process
def is_running():
if p[0] is None or not p[0].is_running():
# find program in the process list
p[0] = next((p for p in psutil.process_iter()
if p.name == program), None)
return p[0] is not None
return is_running
To install psutil on Windows for Python 2.7, you could run psutil-0.6.1.win32-py2.7.exe.