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)
Related
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" )
I've tried for hours to attempt to solve this myself so I can learn. I'm able to get the Family I want out of Revit (called familyToUpdate) and list the family (symbol) types, but I can't get the type name itself only their ID's. I want to compare the actual Type Name against a text parameter I called (typeToDelete) so that I can delete only the types I know are not being used. I've been through numerous examples but can never get them to work.
Here is my code to date:
import Autodesk.Revit.DB as DB
from Autodesk.Revit.DB import *
uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
app = doc.Application
familyToUpdate = "MyFamily"
typeToDelete = "MyFamilyType"
print "Family Name = " + familyToUpdate
print "Type To Delete = " + typeToDelete
#Delete Family Type
Elements = FilteredElementCollector(doc).OfClass(Family).ToElements()
for m in Elements:
try:
if m.Name.startswith((familyToUpdate)):
symbols = list(m.GetFamilySymbolIds())
for i in symbols:
print "Family Type Id = " + str(i)
famsymbol = doc.GetElement(i)
print "famsymbol = " + str(famsymbol)
#symbolName = famsymbol.Family.Name
#print symbolName
#if symbolName == typeToDelete:
# print "I found the type name"
except:
pass
Answered it myself. Work on it for hours, then FINALLY post a question. Take one more look at it, and there it is!!!
Here's the code for anyone else in the future fumbling through what I did:
import Autodesk.Revit.DB as DB
from Autodesk.Revit.DB import *
uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
app = doc.Application
familyToUpdate = "VA Titleblock Consultant Logo (PIN07)"
typeToDelete = "VA Titleblock Consultant Logo (PIN07) (Hagerman)"
print "Family Name = " + familyToUpdate
print "Type To Delete = " + typeToDelete + "\n\n"
#Delete Family Type
Elements = FilteredElementCollector(doc).OfClass(Family).ToElements()
for m in Elements:
try:
if m.Name.startswith((familyToUpdate)):
symbols = list(m.GetFamilySymbolIds())
for i in symbols:
#print "Family Type Id = " + str(i)
famsymbol = doc.GetElement(i)
#print "Symbol ID = " + str(famsymbol)
symbolName = famsymbol.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()
print "SymbolName = " + symbolName
except:
pass
Thank you for the solution. In it, you are retrieving the symbol name from the SYMBOL_NAME_PARAM built-in parameter. That is perfectly valid. An easier and more direct way to read the symbol name is to simply query the Element.Name property. Element is the parent class of all Revit database resident objects, including FamilySymbol.
Element.Name will not work because of multi-level inheritance. try the following instead:
name = Element.Name.GetValue(familysymbol)
I am using two different ways to get current weather and I have got different data from two API.
I suspect PyOWM doesn't work properly because if I changed a city and run a script several times, it hangs with the same data and shows the same cyphers no matter what a city I type in the script. But at least pyowm shows weather pretty close to real if it is launched for first time. Webapi from https://openweathermap.org/ works pretty accurately and I don't have problems with it's JSON response. But PyOWM's response seems to be shows random data. Surely, I could forget about PyOWM and never use it but I am new with this sort of api responses discrepancy and I would like to know whether I do something wrong or I don't understand where I screwed up.
web API https://openweathermap.org/current
import json, requests
place = "London"
apikey = "e4784f34c74efe649018567223752b21"
lang = "en"
r = requests.get("http://api.openweathermap.org/data/2.5/weather?q=" + place + "&appid=" + apikey + "&lang=" + lang + "&units=metric", timeout=20)
api_answer = json.dumps(r.json())
weather_is = "Now in " + place + ": " + json.loads(api_answer)["weather"][0]["description"] + ".\n"
t_txt = "Temperature:\n"
t_now = "now: " + str(json.loads(api_answer)["main"]["temp"]) + "\n"
t_max = "maximum: " + str(json.loads(api_answer)["main"]["temp_max"]) + "\n"
t_min = "minimum: " + str(json.loads(api_answer)["main"]["temp_min"])
final_txt = weather_is + t_txt + t_now + t_max + t_min
print(final_txt)
PyOWM API https://pyowm.readthedocs.io/en/latest/usage-examples-v2/weather-api-usage-examples.html
import pyowm
owm = pyowm.OWM('e4784f34c74efe649018567223752b21', language = "en")
place = "London"
observation = owm.weather_at_place('place')
w = observation.get_weather()
print("Now in " + place + ": " + w.get_detailed_status() + ".")
temperature_at_place_now = w.get_temperature('celsius')["temp"]
temperature_at_place_max = w.get_temperature('celsius')["temp_max"]
temperature_at_place_min = w.get_temperature('celsius')["temp_min"]
print ("Temperature:")
print ("now: " + str(temperature_at_place_now))
print ("maximum: " + str(temperature_at_place_max))
print ("minimum: " + str(temperature_at_place_min))
[web api output] 1 [pyowm api output] 2
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
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())