Python Print Output to Email - python

I have a script which prints variables (set by user) perfectly.
os.system('clear')
print "Motion Detection Started"
print "------------------------"
print "Pixel Threshold (How much) = " + str(threshold)
print "Sensitivity (changed Pixels) = " + str(sensitivity)
print "File Path for Image Save = " + filepath
print "---------- Motion Capture File Activity --------------"
I now wish to email this code to myself to confirm when running. I have included in the script email using email.mimieText and multipart. But the output no longer shows the relative variables just the code.
body = """ Motion Detection Started \n Pixel Threshold (How much) = " + str(threshold) \n Sensitivity (changed Pixels) = " + str(sensitivity) \n File Path for Image Save = " + filepath """
Im sure it is the """ wrapper but unclear what i should use instead?

in python """ quotes mean to take everything between them literally.
The easiest solution here would be to define a string myString="", then at every print statement, instead of printing you can append to your string with myString=myString+"whatever I want to append\n"

It should be:
body = " Motion Detection Started \n Pixel Threshold (How much) = " + str(threshold) + \
"\n Sensitivity (changed Pixels) = " + str(sensitivity) + \
"\n File Path for Image Save = " + filepath

When you do the following, you're telling it everything there is part of the string (notice how the code highlights):
body = """ Motion Detection Started \n Pixel Threshold (How much) = " + str(threshold) \n Sensitivity (changed Pixels) = " + str(sensitivity) \n File Path for Image Save = " + filepath """
You need to actually add the variables to the string, like when you concatenated them in your print statement.
body = "Motion Detection Started \n Pixel Threshold (How much) = " + str(threshold) + " \n Sensitivity (changed Pixels) = " + str(sensitivity) + "\n File Path for Image Save = " + filepath
You can also do string formatting:
body = "Motion Detection Started\nPixel Threshold (How much) = {}\nSensitivity (changed Pixels) = {}\nFile Path for Image Save = {}".format(threshold, sensitivity, filepath)

In case you'd like the emails code to be a bit more reusable and robust, Template strings might help you. E.g., save the email text as a template in separate file, template.txt:
Motion Detection Started
------------------------------------------------------
Pixel Threshold (How much) = $threshold
Sensitivity (changed Pixels) = $sensitivity
File Path for Image Save = $filepath
---------- Motion Capture File Activity --------------
and in your code, create a class for sending emails together with 1 or more instances of the class (you can have more than 1 template):
import string
class DebugEmail():
def __init__(self, templateFileName="default_template.txt"):
with open(templateFileName) as f:
self.template = string.Template(f.read())
def send(self, data):
body = self.template.safe_substitute(data)
print(body) # replace by sending email
debugEmail1 = DebugEmail("template.txt")
# and test it like this:
threshold = 1
sensitivity = 1
debugEmail1.send(locals())
sensitivity = 200
filepath = "file"
debugEmail1.send(locals())

Related

Python3 + How to change the output color when using print command [duplicate]

This question already has answers here:
How do I print colored text to the terminal?
(64 answers)
Closed 1 year ago.
as maybe some of you know and regarding to shell scripts - tput is utility uses the terminfo database to make the values of terminal-dependent capabilities and information available to the shell
in my python script I have the following example: ( just a sample from long code )
for TOPIC in list:
if str(val) in TOPIC:
word = TOPIC.split()[1]
print ("Topic " + word + " is successfully configured")
else:
try:
word = TOPIC.split()[1]
print ("Topic " + word + " bad configuration")
except IndexError:
pass
I want to change the color from white to green on the following printing:
print ("Topic " + word + " is successfully configured")
or to change the color from white to red on:
print ("Topic " + word + " bad configuration")
is it possible to change the color in python3 as we did for example in bash scripts?
import os
os.system("")
RED = "\x1B["
GREEN = '\033[32m'
word = "random_topic_name"
print(GREEN+"Topic " + word + "successfully configured" )
print(RED+"Topic " + word + "bad configuration" )

Arcmap script will not print messages in arcmap console

I have a Python script for Arcmap that I wrote. I'm trying to create a tool that reprojects all the feature classes within the workspace to a specified feature class.
The problem that I'm having is that I cannot get Arcmap to print the "completed" messages. The messages that I want to have appear will print when I hard-code the variables and run it as a script, but they will not print in Arcmap. You can see in the code below that I have specific printed messages that I want printed, but they just won't appear.
Code:
#Import modules
import arcpy, os
#Set workspace directory
from arcpy import env
#Define workspace
inWorkspace = arcpy.GetParameterAsText(0)
env.workspace = inWorkspace
env.overwriteOutput = True
try:
#Define local feature class to reproject to:
targetFeature = arcpy.GetParameterAsText(1)
#Describe the input feature class
inFc = arcpy.Describe(targetFeature)
sRef = inFc.spatialReference
#Describe input feature class
fcList = arcpy.ListFeatureClasses()
#Loop to re-define the feature classes and print the messages:
for fc in fcList:
desc = arcpy.Describe(fc)
if desc.spatialReference.name != sRef.name:
print "Projection of " + str(fc) + " is " + desc.spatialReference.name + ", so re-defining projection now:\n"
newFc = arcpy.Project_management(fc, "projected_" + fc, sRef)
newFeat = arcpy.Describe(newFc)
count = arcpy.GetMessageCount()
print "The reprojection of " + str(newFeat.baseName) + " " + arcpy.GetMessage(count-1) + "\n"
#Find out which feature classes have been reprojected
outFc = arcpy.ListFeatureClasses("projected_*")
#Print a custom messagae describing which feature classes were reprojected
for fc in outFc:
desc = arcpy.Describe(fc)
name = desc.name
name = name[:name.find(".")]
name = name.split("_")
name = name[1] + "_" + name[0]
print "The new file that has been reprojected is named " + name + "\n"
except arcpy.ExecuteError:
pass
severity = arcpy.GetMaxSeverity()
if severity == 2:
print "Error occurred:\n{0}".format(arcpy.GetMessage(2))
elif severity == 1:
print "Warning raised:\n{1}".format(arcpy.GetMessage(1))
else:
print "Script complete"
When I upload a script into an Arcmap toolbox, the following lines (From the above code) will NOT print:
print "Projection of " + str(fc) + " is " + desc.spatialReference.name + ", so re-defining projection now:\n"
print "The reprojection of " + str(newFeat.baseName) + " " + arcpy.GetMessage(count-1) + "\n"
print "The new file that has been reprojected is named " + name + "\n"
How can I fix this?
print only prints the messages while your script is running in Python interpreter. In order to print logs while the script is running in ArcGIS Toolbox, you need to use arcpy.AddMessage()
arcpy.AddMessage("Projection of {0} is {1}, so re-defining projection now: ".format(str(fc), desc.spatialReference.name)

Python subprocess doesn't run until calling process finished

EDIT 1 - added more code
I'm not sure that proc.communicate was needed, it was one of the suggestions I found from some other stackoverflow code.(Sorry I was tired last night and didn't think too much before asking the question.)
I should add that I am not an experienced coder (mechanical engineer) as you can probably tell from my code
In my Gui I have a button to call a subprocess
The subprocess (screenshot-cmd.exe) creates a png of a cropped screen shot but it won't actually produce the file until there is an error or if the button click event is over.
This makes me think that the subprocess is not actually run until the event is finished
I want to call the process several times after a single button press and move the files that it produces after each one is produced
if I use proc.wait(), the process hangs indefinitely.
How do I stop this?
# function to take a single image called 'fileName' and place it in directory 'dir'
def takeImage(dir,fileName):
# calculate the view to capture to get the whole display window in.
clientRect = win32gui.GetClientRect(win32gui.GetForegroundWindow())
windowRect = win32gui.GetWindowRect(win32gui.GetForegroundWindow())
print(windowRect)
windowSize = [windowRect[2]-windowRect[0],windowRect[3]-windowRect[1]]
print(windowSize)
print(clientRect)
diffSize = [windowSize[0] -clientRect[2], windowSize[1] - clientRect[3]]
lrbBorder = diffSize[0]/2
topBorder = diffSize[1] - lrbBorder
print("sizeDiff = " + str(diffSize))
windowName = win32gui.GetWindowText(win32gui.GetForegroundWindow())
handleId = win32gui.GetForegroundWindow()
leftMar = designLabel.GetPosition()[0] + lrbBorder
topMar = designLabel.GetPosition()[1] + topBorder + designLabel.GetSize()[1]
rightMar = leftMar + scene.width
bottMar = topMar+scene.height
margins = [leftMar,topMar,rightMar,bottMar]
print(margins)
# now print the view.
#command_line = r"screenshot-cmd -wt '" + windowName + "' -rc " + str(margins[0]) + " " + str(margins[1]) + " " + str(margins[2]) + " " + str(margins[3]) + " -o " + fileName
command_line = r"screenshot-cmd -wt '" + windowName + "' -rc " + str(margins[0]) + " " + str(margins[1]) + " " + str(margins[2]) + " " + str(margins[3]) + " -o " + fileName
print(command_line)
args = shlex.split(command_line)
proc = subprocess.Popen(args)
proc.wait()
wx.Yield()
if not os.path.isdir(dir):
os.makedirs(dir)
newPath = os.path.join(dir,fileName)
if os.path.exists(newPath):
os.remove(newPath)
oldPath = os.path.join(os.getcwd(), fileName)
print("Old Path: " + oldPath)
print("Exists: " + str(os.path.exists(oldPath)))
shutil.move(oldPath,newPath)
return
#event called upon clicking 'takeTenImag' button
def takeTenImgE(evt):
global designNo
global workingDirectory
global numDesigns
fileNameRoot = "test_"
fileExtention = ".png"
# check there are at least 10 designs
if numDesigns > 9 and os.path.exists(workingDirectory):
# find directory path to put images in
dir = os.path.join(workingDirectory, "images")
# for each design
for x in range(10):
print("design =" + str(designNo))
fileName = fileNameRoot + str(designNo) + fileExtention
print("------------------")
print("for x = " + str(x) + " " + fileName)
# create image and save
print(dir)
takeImage(dir,fileName)
#move to next design
wx.PostEvent(forwardDesign, wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, forwardDesign.GetId()) )
wx.Yield()
print("design =" + str(designNo))
return
takeTenImg = wx.Button(p, label='Take Ten Images', pos=(rb + visScaleText.GetSize()[0]+10,takeImg.GetPosition()[1]+5 +takeImg.GetSize()[1]), size = (100,30))
takeTenImg.Bind(wx.EVT_BUTTON, takeTenImgE)
https://code.google.com/p/screenshot-cmd/
Barnaby, you may be over-complicating your subprocess use. Popen is typically used for when you need to communicate with the process during the time it is running. From the sound of it, you don't need to do that, so might want to use a higher level function. See the docs on subprocess' various invocations, and perhaps try using the call method. You'll need shell=True, as detailed in SO questions such as this one.
I've found that the error is in my calling of subprocess.
I was using:
command_line = r"screenshot-cmd -wt '" + windowName + ...."
args = shlex.split(command_line)
subprocess.call(args,shell=True)
changing this to:
command_line = r"screenshot-cmd -wt '" + windowName + ...."
subprocess.call(command_line,shell=True)
solves the hang.
What is peculiar is that both options work when not inside a wx button click event(i.e. a python script launched from the command line), but only the second works when inside the wx button click event.
If anyone could enlighten me why that would be most appreciated.
EDIT:
upon further investigation, the hang is caused by trying to specify the active window in screenshot-cmd.
To solve this I find the position of the window using
windowRect = win32gui.GetWindowRect(win32gui.GetForegroundWindow())
and then use screenshot-cmd without specifying a window.
This solves all issues although it is unclear why this causes problems

Downloading, writing, converting and saving with imagemagick in python (corrupt images)

Okay so I've been trying to solve this for about six hours now and it's just not happening.
I've got this function that grabs a bunch of image (GIF) files from a URL based on a timestamp (using the Requests library. The images get saved to my desktop in a specific directory just fine.
When I try to open that image, rename it and process it then everything breaks.
Here's the initial method that sets everything up:
def createImage():
AB_CODES = ["WHK", "WHN", "WWW", "XBU", "XSM"]
BASE_URL = "http://url_where_I_get_images_from"
orig_dir = "originals/"
new_dir = "processed/"
# Add new image for each code
for code in AB_CODES:
radar_dir = BASE_URL + code
url = requests.head(radar_dir)
#parseUrl creates a valid timestamp corresponding to the latest image.
timestamp = parseUrl(url)
filename = timestamp + "_" + code + "_PRECIP_RAIN.gif"
radar = BASE_URL + code + "/" + filename
radar_img = requests.get(radar, timeout=30.000)
# This is where the file from original source gets saved to my desktop, works.
# Image gets saved in path/originals/img.gif
if (radar_img.status_code == requests.codes.ok):
image = radar_img.content
filepath = os.path.join(orig_dir, filename)
imgfile = open(filepath, "wb")
imgfile.write(image)
imgfile.close()
# This is where I create a new image to be saved and worked on in
# path/processed/new_img.gif
image = radar_img.content
filename = code + "_radar.gif"
convpath = os.path.join(new_dir, filename)
convimg = open(convpath, "wb")
convimg.write(image)
# This is the call to the function where I use imagemagick
# which is not working
image = processImage(convimg.name, "processed/XSM_radar_output.gif")
convimg.close()
Here are the two methods that make up my processing function. Right now it's in more of a testing phase because it won't work.
def formatArg(arg):
if arg.startswith("#") or " " in arg:
return repr(arg)
return arg
def processImage(input, output, verbose=True, shell=True):
args = [
"convert", input,
"-resize", "50x50",
output
]
if verbose:
print("Image: %s" % input)
print(" ".join(formatArg(a) for a in args))
print
if os.path.exists(input):
try:
result = subprocess.check_call(args)
except subprocess.CalledProcessError:
result = False
if result:
print("%s : SUCCESS!" % output)
else:
print("%s : FAIL!" % output)
I've tried it without shell=true. The error message I get is that the image is corrupted:
Image: processed/XSM_radar.gif
convert processed/XSM_radar.gif -resize 50x50 processed/XSM_radar.gif
convert.im6: corrupt image `processed/XSM_radar.gif' # error/gif.c/ReadGIFImage/1356.
convert.im6: no images defined `processed/XSM_radar_output.gif' # error/convert.c/ConvertImageCommand/3044.
processed/XSM_radar.gif : FAIL!
I don't understand why it's telling me that it's corrupted. I've run these exact same commands from the command line and it works just fine.
(I have imported subprocess)
Someone helped me determine the error.
def processImage(input, output, verbose=True, shell=True):
args = [
"convert", input,
"-resize", "50x50",
output
]
if verbose:
print("Image: %s" % input)
print(" ".join(formatArg(a) for a in args))
print
if os.path.exists(input):
try:
**result = subprocess.check_call(args)**
**except subprocess.CalledProcessError:**
**result = False**
**if result:**
print("%s : SUCCESS!" % output)
else:
print("%s : FAIL!" % output)
That section with the results should have been
result_code = subprocess.check_call(args)
and if it returned an error, result_code should have been set equal to 1.
So:
if result_code == 0:
do stuff
Thank you for your attention!
Have a lovely day.

IRC Bot - flood protection (python)

if data.find('PRIVMSG') != -1:
nick = data.split('!')[ 0 ].replace(':','')
text = ''
if data.count(text) >= 200:
sck.send('KICK ' + " " + chan + " :" 'flooding' + '\r\n')
I'm trying to code a flood protection for the bot, I want it to kick a user if he enters more then 200 characters, how can I make it so it can read the other lines instead of just the first line? and the code above doesn't work, it doesnt kick the user but if I change the sck.send() to sck.send('PRIVMSG ' + chan + " :" 'flooding' + '\r\n') it works.
fixed the kicking problem, and the code works now, but it only reads the first line, not sure how to make it read the other lines if the user keeps flooding the channel.
if data.find('PRIVMSG') != -1:
nick = data.split('!')[ 0 ].replace(':','')
text = ''
if data.count(text) >= 200:
sck.send('KICK ' + " " + chan + " " + nick + " :" 'flooding' + '\r\n')
As far as I remember, the colon is a reserved character in the IRC protocol. That is, the first colon in a server message denotes the start of user-supplied data (that's also why ":" is not allowed in nicks/channel names). Hence, it suffices to search for the first colon and calculate the length of the remaining string.
Furthermore, data.find('PRIVMSG') is pretty unreliable. What if a user types the word "PRIVMSG" in regular channel conversation? Go look up the IRC RFC, it specifies the format of PRIVMSGs in detail.
Besides, you should be a little more specific. What exactly is the problem you're facing? Extracting the nick? Calculating the message length? Connecting to IRC?

Categories

Resources