Dumb question - can I write standalone python script to run without arcgis?

8155
31
05-18-2010 11:54 PM
jimparsons
New Contributor III
I need to open a raster, thin it, and save it. Can I do that in a script outside of arcgis, or does arcgis need to be running for the script to work? I have it installed on the system, so it would obviously be running on my computer.

Sorry this question is really simple. I don't really understand how to run a script outside of arcgis...or even if it's possible. I'm hoping someone will say yes or no! Thanks
0 Kudos
31 Replies
BartKowalski
New Contributor
"With python it's easy to access the toolbox, but how would we access a) the zoom to layer command, and b) the file export map tool, which is a very handy way to effectively merge lots of 24 bit color rasters simply by opening them all and exporting the overall map at great resolution."

Hi Jim,

I was wandering if you were successful in writing that python script.I am trying to do something similar. I'd apprecaite you reply, thanks.
0 Kudos
DanPatterson_Retired
MVP Emeritus
It just needs to be present on the computer.  It need not be running but arcpy needs to be imported which means it must be on the computer.  gp.Addmessage statements need to be replaced with print statements.  The following is an example
'''
CreatePolyDemo.py

Demonstrates calculating various properties for polygons

'''
import arcpy
pnt = arcpy.Point()

triangle = [[0,0],[0,1],[1,0]]
square = [[0,0],[0,1],[1,1],[1,0]]
rectangle = [[0,0],[0,1],[2,1],[2,0]]
polygons = [triangle, square, rectangle]
labels = ["Triangle", "Square", "Rectangle"]
array = arcpy.Array()
polys = []
for i in range(len(polygons)):
  a_poly = polygons
  print "\n", labels," Coordinates: ", a_poly
  for pair in a_poly:
    pnt.X = pair[0]
    pnt.Y = pair[1]
    array.add(pnt)
    print " X %20.16f  Y %20.16f" % (pnt.X, pnt.Y)
  array.add(array.getObject(0))
  poly = arcpy.Polygon(array)
  print "Polygon properties:"
  print " area %20.16f\n length %s" % (poly.area, poly.length)
  print " centroid %s\n true centroid %s " % (poly.centroid, poly.trueCentroid) 
  print " first point %s\n last point %s " % (poly.firstPoint, poly.lastPoint)
  print " extent %s " % (poly.extent)
  print " hull %s\n " % (poly.hullRectangle)
  array.removeAll()
  polys.append(poly)
0 Kudos
ChrisMathers
Occasional Contributor III
Bart, Those are methods of the arcpy.mapping class. Its actually very easy once you read over the docs.

http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/Geoprocessing_scripts_for_map_document...
0 Kudos
FrankPerks
New Contributor II
It just needs to be present on the computer.  It need not be running but arcpy needs to be imported which means it must be on the computer.  gp.Addmessage statements need to be replaced with print statements.  The following is an example
'''
CreatePolyDemo.py

Demonstrates calculating various properties for polygons

'''
import arcpy
pnt = arcpy.Point()

triangle = [[0,0],[0,1],[1,0]]
square = [[0,0],[0,1],[1,1],[1,0]]
rectangle = [[0,0],[0,1],[2,1],[2,0]]
polygons = [triangle, square, rectangle]
labels = ["Triangle", "Square", "Rectangle"]
array = arcpy.Array()
polys = []
for i in range(len(polygons)):
  a_poly = polygons
  print "\n", labels," Coordinates: ", a_poly
  for pair in a_poly:
    pnt.X = pair[0]
    pnt.Y = pair[1]
    array.add(pnt)
    print " X %20.16f  Y %20.16f" % (pnt.X, pnt.Y)
  array.add(array.getObject(0))
  poly = arcpy.Polygon(array)
  print "Polygon properties:"
  print " area %20.16f\n length %s" % (poly.area, poly.length)
  print " centroid %s\n true centroid %s " % (poly.centroid, poly.trueCentroid) 
  print " first point %s\n last point %s " % (poly.firstPoint, poly.lastPoint)
  print " extent %s " % (poly.extent)
  print " hull %s\n " % (poly.hullRectangle)
  array.removeAll()
  polys.append(poly)


gp.addmessage() will just print to console if the script was not called from ArcMap
0 Kudos
DanPatterson_Retired
MVP Emeritus
Frank...unfortunately it doesn't print to other IDE's output...don't use console...too dark and gloomy and reminds me of the old DOS days
0 Kudos
LoganPugh
Occasional Contributor III
Frank...unfortunately it doesn't print to other IDE's output...don't use console...too dark and gloomy and reminds me of the old DOS days


It's for that reason that I wrote my own message(), warning() and error() methods. In addition to logging to a text file, it's exactly 3 places that I need to change if I need print statements or not, not dozens of lines littered throughout the script.

Most of the time I don't need print messages, but if I'm debugging in PyScripter or PythonWin (but not winpdb which runs the script in a separate console window from the GUI), I'll uncomment my print statement in each of the 3 methods.

# Helper methods for writing messages, warnings and errors to the geoprocessor as well as a logfile
# By default, prepends a timestamp to the message; set second argument to 0 or False to disable
def message(strMessage, stamp = True):
    global gp, logFile
    if stamp == True:
        strMessage = time.asctime() + " - " + strMessage
    #print strMessage
    gp.AddMessage(strMessage)
    if logFile:
        logFile.write(strMessage + "\n")
        logFile.flush()

def warning(strMessage, stamp = True):
    global gp, logFile
    if stamp == True:
        strMessage = time.asctime() + " - " + strMessage
    #print strMessage
    gp.AddWarning(strMessage)
    if logFile:
        logFile.write(strMessage + "\n")
        logFile.flush()

def error(strMessage, stamp = True):
    global gp, logFile
    if stamp == True:
        strMessage = time.asctime() + " - " + strMessage
    #print strMessage
    gp.AddError(strMessage)
    if logFile:
        logFile.write(strMessage + "\n")
        logFile.flush()
0 Kudos
DanPatterson_Retired
MVP Emeritus
Logan
good suggestion...and you need not even comment out the print statement, in fact you could get ready for python 3.0 by adding these blocks
    try
       print strMessage     #pre 3.0
    except
       print (strMessage)   #3.0 +
    gp.AddMessage(strMessage)
the print statement will simply become heat energy if gp is being used and vica versa.
0 Kudos
FrankPerks
New Contributor II
Frank...unfortunately it doesn't print to other IDE's output...don't use console...too dark and gloomy and reminds me of the old DOS days




Pycharm / Komodo python IDE's are fine with the message printing(I assume wingide is too) :cool: IDLE/pywin32 is not an IDE, they are mistakes.

If you really want a decent Python IDE i honestly suggest looking into PyCharm (try it for 30 days, its also 50% off right now). If you don't want to spend money then i suggest NetBeans, or PyScripter. (I refuse to acknowledge pydev since its based off the horror that is known as eclipse).

It's for that reason that I wrote my own message(), warning() and error() methods. In addition to logging to a text file, it's exactly 3 places that I need to change if I need print statements or not, not dozens of lines littered throughout the script.

Most of the time I don't need print messages, but if I'm debugging in PyScripter or PythonWin (but not winpdb which runs the script in a separate console window from the GUI), I'll uncomment my print statement in each of the 3 methods.

# Helper methods for writing messages, warnings and errors to the geoprocessor as well as a logfile
# By default, prepends a timestamp to the message; set second argument to 0 or False to disable
def message(strMessage, stamp = True):
    global gp, logFile
    if stamp == True:
        strMessage = time.asctime() + " - " + strMessage
    #print strMessage
    gp.AddMessage(strMessage)
    if logFile:
        logFile.write(strMessage + "\n")
        logFile.flush()

def warning(strMessage, stamp = True):
    global gp, logFile
    if stamp == True:
        strMessage = time.asctime() + " - " + strMessage
    #print strMessage
    gp.AddWarning(strMessage)
    if logFile:
        logFile.write(strMessage + "\n")
        logFile.flush()

def error(strMessage, stamp = True):
    global gp, logFile
    if stamp == True:
        strMessage = time.asctime() + " - " + strMessage
    #print strMessage
    gp.AddError(strMessage)
    if logFile:
        logFile.write(strMessage + "\n")
        logFile.flush()


You should really look into the python logging, its wonderful: http://docs.python.org/library/logging.html

However you need to create a gp friendly logger... heres an example:

import logging
import sys


_GP_MESSAGE_DEFS = {
        logging.CRITICAL : "AddError",
        logging.ERROR : "AddError",
        logging.WARNING : "AddWarning",
        logging.INFO : "AddMessage",
        logging.DEBUG : "AddMessage",
    }

class GPHandler(logging.Handler):
    """
        Geoprocessor friendly logging module
    """
    def __init__(self, level=logging.NOTSET, gp=None):
        self.gp = gp
        logging.Handler.__init__(self, level)

    def emit(self, record):
        """
            Woop.
        """
        message = self.format(record)
        if self.gp:
            source = gp
        else:
            source = __import__("arcpy")

        # retrive the functor and call it with the message
        getattr(source, _GP_MESSAGE_DEFS[record.levelno])(message)

_logger = logging.getLogger("test")
_logger.setLevel(logging.DEBUG)

# sadily i have no idea where this object type is located
if type(sys.stdout) != "<type 'geoprocessing sys.stdout object'>":
    handler = logging.StreamHandler()
else:
    # change for arc9.3
    handler = GPHandler()

handler.setFormatter(logging.Formatter("%(asctime)10s | %(name)s | %(message)s",
                                       "%Y%m%d %H:%M:%S"))
_logger.addHandler(handler)

_logger.debug("Message")
_logger.info("Info message")
_logger.warning("Warning")
_logger.error("error")
_logger.critical("error")


This gives an output of:

20101103 21:36:45 | test | Message
20101103 21:36:52 | test | Info message
WARNING: 20101103 21:36:52 | test | Warning
ERROR: 20101103 21:36:52 | test | error
ERROR: 20101103 21:36:52 | test | error


If you run it from not within arcmap it goes to normal console streams. If you run it via arcgis it goes to the gp addmessage/etc.
0 Kudos
JasonScheirer
Occasional Contributor III
print x is a syntax error in Python 3.0, so you're not future-proofing your code nearly as well as you think.

Starting from 2.6, you can import print as a function from the future with from __future__ import print_function directive and use print as a 3.x style function across the board in your script.
0 Kudos
FrankPerks
New Contributor II
print x is a syntax error in Python 3.0, so you're not future-proofing your code nearly as well as you think. 

Starting from 2.6, you can import print as a function from the future with   from __future__ import print_function directive and use print as a 3.x style function across the board in your script.


Also by doing the from __future__ import print_function, you add some amazing functionality in the form of completely breaking any chance of the 9.3 or less crowd from using your script (which is a big reality considering how many people probably still use < 10.0)

If you reallllyyyyyy want to futureproof print (because esri is bound to go to python 3.0 any day now :o). Don't use it. Use logging. Or use sys.stdout.write(). Or even just use ESRI's AddMessage.

Print is evil.
0 Kudos