AddMessage from SearchCursor

722
8
06-25-2020 10:15 AM
ModernElectric
Occasional Contributor III

I am working on fine-tuning my collection of Python Scripts and one thing I want to do is to add the AddMessage feature to my script. I have a particular script that produces a series of .PDF Graphs from a SearchCursor function. What I want to be able to do is each time an individual .PDF is created, I want to use the built-in SearchCursor with AddMessage to print a message to the screen showing the name of the .PDF created.

Here is a portion of my script.

list = []

rows = arcpy.SearchCursor(table)
for row in rows:
list.append(row.SERVICE_IDENTIFIER) # Double

del row, rows

# Remove duplicates from list
list = dict.fromkeys(list)
list = list.keys()

for n in list:
arcpy.TableSelect_analysis(table, r"in_memory\table_sel", "SERVICE_IDENTIFIER = " + str(n)) # Double

# Get TWACs_Number value
for row in arcpy.SearchCursor(r"in_memory\table_sel"):
SERVICE_ADDRESS = row.getValue("SERVICE_ADDRESS") # String

out_graph_name = n
out_graph_pdf = r"Z:\Operations\Maps and Records\GeoDatabase\MEWCO GIS System\GIS Attachments\Electric System\Electric Usage Demand Graphs\F1 Feeder ALL" + "\\" + str(n)[:-2] + ".pdf"
input_template = r"Y:\MEWCo GIS System - LOCAL\ELECTRIC SYSTEM\ELECTRIC GRAPHS - CONSTRUCT\GIS Graph Temps\ELECTRIC METER DEMAND - UPDATED 2020.grf"
input_data = r"in_memory\table_sel"

Thank You

0 Kudos
8 Replies
JoshuaBixby
MVP Esteemed Contributor

Please use /blogs/dan_patterson/2016/08/14/script-formatting?sr=search&searchId=aa94a9ad-7958-4b07-bd14-3b3f5be...‌, it makes reading code and providing feedback much easier.

0 Kudos
ModernElectric
Occasional Contributor III
env.workspace = r"Y:\MEWCo GIS System - LOCAL\ELECTRIC SYSTEM\ELECTRIC DATASET\MEWCo ELECTRIC SYSTEM\MEWCo ELECTRIC SYSTEM.gdb"

table = "ELECTRIC_METER_READING_F1FEEDER_RC30"

list = []

rows = arcpy.SearchCursor(table)
for row in rows:
    list.append(row.SERVICE_IDENTIFIER) # Double
    
del row, rows

# Remove duplicates from list
list = dict.fromkeys(list)
list = list.keys()

for n in list:
    arcpy.TableSelect_analysis(table, r"in_memory\table_sel", "SERVICE_IDENTIFIER = " + str(n)) # Double

    # Get TWACs_Number value
    for row in arcpy.SearchCursor(r"in_memory\table_sel"):
        SERVICE_ADDRESS = row.getValue("SERVICE_ADDRESS") # String
    
    out_graph_name = n
    out_graph_pdf = r"Z:\Operations\Maps and Records\GeoDatabase\MEWCO GIS System\GIS Attachments\Electric System\Electric Usage Demand Graphs\F1 Feeder ALL" + "\\" + str(n)[:-2] + ".pdf"
    input_template = r"Y:\MEWCo GIS System - LOCAL\ELECTRIC SYSTEM\ELECTRIC GRAPHS - CONSTRUCT\GIS Graph Temps\ELECTRIC METER DEMAND - UPDATED 2020.grf"
    input_data = r"in_memory\table_sel"
0 Kudos
JoshuaBixby
MVP Esteemed Contributor

Although list isn't a reserved word in Python, it is a built-in class, and people are strongly discouraged from naming variables after built-in objects.

In terms of ArcPy, I recommend switching to SearchCursor—Data Access module | Documentation.  Not only are Data Access cursors more Pythonic, they perform much faster on larger data sets.

For finding unique values, instead of creating a list and then using a dict, you can just create a Set - Built-in Types — Python 3.8.3 documentation from the beginning and populate it within the cursor.

Where are you having issues with AddMessage, I don't see it anywhere in your code?

0 Kudos
ModernElectric
Occasional Contributor III

Joshua:

   I appreciate your feedback. I will take a look at what you recommended. Regarding the AddMessage, its not in the code because I am not really sure how to write/include it. With each .PDF created, I would like a message displayed saying something along the lines of file created and the file name.

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

You can just stick AddMessage right before the code where you generate the PDF.  Speaking of which, where is the code that generates the PDF?

0 Kudos
DanPatterson
MVP Esteemed Contributor

AddMessage isn't going to reveal anything unless you are running this inside Pro, use something that covers both inside and standalone scripts.

def tweet(msg):
    """Print a message for both arcpy and python."""
    m = "\n{}\n".format(msg)
    AddMessage(m)
    print(m)

... sort of retired...
0 Kudos
JoshuaBixby
MVP Esteemed Contributor

I can't say when the behavior changed, or even if it ever did, but AddMessage from a stand-alone script or outside of Pro prints the message to the console:

>>> from arcpy import AddMessage
>>>
>>> print("Hello World")
Hello World
>>> AddMessage("Hello World")
Hello World
>>>
0 Kudos
JoeBorgione
MVP Emeritus

I like to create log files that can capture when events take place; typically every geoprocessing step I do is in it's own def and the heavy lifting is in a try/except block: if the process is successful the try block writes a message to the log file saying so; if the process fails the except block logs the error and also sends me an email saying something went wrong.

If you are just running the script from a console, you don't need to bother with a log file, but I still suggest the try/accept approach and just print() the appropriate message.  Here is some sample code:

import arcpy, sys, os, smtplib, shutil, time

def sendEmail(errMessage):   # if errors send email
    from_addr = "errors@YOUR.org"
    to_addr = "SOMEONE@YOUR.org"
    subject = "SOMETHING WENT WRONG IN SOME SCRIPT"
    msg_text = errMessage
    msg = "From: %s\nTo: %s\nSubject: %s\n\n%s" % (from_addr, to_addr, subject, msg_text)
    server = YOUR MAIL SERVER"
    server = smtplib.SMTP(server)
    server.sendmail(from_addr, to_addr, msg)
    server.quit()


def createLocator(locator_style, reference_data, field_map, out_address_locator):
    try:
        arcpy.CreateAddressLocator_geocoding(locator_style, reference_data, field_map, out_address_locator, "", "ENABLED")  
        printf'Success: Created Locator: {out_address_locator}')
    except Exception as err:
        print(f'Error: could not create locator: {out_address_locator}')
        print (err)
        sendEmail(err)

def main():

    logFile r"SomeDrive:\path\to\processName.log"
    logoutput = open(logFile,'w')
    beginTime = time.strftime('%Y-%m-%d %H:%M:%S')
    logoutput.write("Began at # " + beginTime + "\n")
    sys.stdout = logoutput

    createLocator(locator_style, reference_data, field_map, out_address_locator)

    logoutput.write("Ended at # " + time.strftime('%Y-%m-%d %H:%M:%S') + "\n")
    logoutput.close()   

In the real script, my arguments for createLocator() are spelled out in the main().  Also note line 30; this allows me to use print() statements to get info into the log file.  The error that is tossed and subsequently caught in the except block gets written to the log and sent in the email...

That should just about do it....