Skip to content

Instantly share code, notes, and snippets.

@AlexArcPy
Last active September 28, 2016 07:51
Show Gist options
  • Save AlexArcPy/47f75f217de827b2c03d17cded653cba to your computer and use it in GitHub Desktop.
Save AlexArcPy/47f75f217de827b2c03d17cded653cba to your computer and use it in GitHub Desktop.
Iterating through the properties of arcpy objects
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import arcpy"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Many of ArcGIS users need to iterate the propeties of `arcpy` objects, such as `Describe` objects or `Layer` objects. The purpose of iterating is to get all the information available either for reporting purposes or during the troubleshooting time. Speaking of `Layer` objects, let's see what Python code is needed for iterating through their properties.\n",
"\n",
"First, we need to obtain the `Layer` object. This is how we can get hands at the obj which represents the `Layer` object. "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"<map layer u'GridLayer'>"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import arcpy\n",
"\n",
"mxd_path = r'C:\\GIS\\introspect.mxd'\n",
"mxd = arcpy.mapping.MapDocument(mxd_path)\n",
"df = arcpy.mapping.ListDataFrames(mxd, \"Layers\")[0]\n",
"obj = arcpy.mapping.ListLayers(mxd, \"GridLayer\", df)[0]\n",
"obj"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"obj.isFeatureLayer"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A naïve way to list all the properties of this object is to do something like this:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"data source -- C:\\GIS\\Temp\\test.gdb\\GridFeatures\n",
"dataset name -- GridFeatures\n",
"workspace path -- C:\\GIS\\Temp\\test.gdb\n"
]
}
],
"source": [
"print \"data source --\", obj.dataSource\n",
"print \"dataset name --\", obj.datasetName\n",
"print \"workspace path --\", obj.workspacePath"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This could of course be shortened a bit to something like this with the help of `getattr()` method ([help link](https://docs.python.org/2/reference/datamodel.html#object.__getattr__)):"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"dataSource C:\\GIS\\Temp\\test.gdb\\GridFeatures\n",
"datasetName GridFeatures\n",
"workspacePath C:\\GIS\\Temp\\test.gdb\n"
]
}
],
"source": [
"props = ['dataSource','datasetName','workspacePath']\n",
"for p in props:\n",
" print p, getattr(obj,p)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This implies, however, that you still need to create and maintain the list of available properties for each type of object (`Layer` object has different kind of properties than the `Describe` object).\n",
"\n",
"A more elegant solution to this is to access all the properties of an object using the Python built-in `dir()` command. `dir(obj)` will return all the attributes and methods that an instance of the class has. This includes private methods and attributes which could be ignored as they are not `arcpy` specific."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['brightness', 'contrast', 'credits', 'dataSource', 'datasetName', 'definitionQuery', 'description', 'findAndReplaceWorkspacePath', 'getExtent', 'getSelectedExtent', 'getSelectionSet', 'isBroken', 'isFeatureLayer', 'isGroupLayer', 'isNetworkAnalystLayer', 'isRasterLayer', 'isRasterizingLayer', 'isServiceLayer', 'labelClasses', 'longName', 'maxScale', 'minScale', 'name', 'replaceDataSource', 'save', 'saveACopy', 'serviceProperties', 'setSelectionSet', 'showLabels', 'supports', 'symbology', 'symbologyType', 'time', 'transparency', 'updateLayerFromJSON', 'visible', 'workspacePath']\n"
]
}
],
"source": [
"props = [prop for prop in [prop for prop in dir(obj) if '_' not in prop]]\n",
"print props"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is great! We can probably just use the `getattr()` method now and list all the values of every property this `Layer` object has."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "ValueError",
"evalue": "LayerObject: Layer does not support brightness",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-7-7adcfb79fb31>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mprop\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mprops\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mprint\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mprop\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;31mValueError\u001b[0m: LayerObject: Layer does not support brightness"
]
}
],
"source": [
"for prop in props:\n",
" print getattr(obj,prop)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Not so fast. Not all properties are supported by this particular map layer of `Feature Layer` type. `Raster Layer` type, for instance, would support other properties, so we have to distinguish between those. There is `supports()` method that does just that:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"False\n",
"True\n"
]
}
],
"source": [
"print obj.supports('brightness')\n",
"print obj.supports('transparency')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"OK, let's check then whether a property is supported for this type of map layer:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"credits \n",
"dataSource C:\\GIS\\Temp\\test.gdb\\GridFeatures\n",
"datasetName GridFeatures\n",
"definitionQuery \n",
"description \n"
]
},
{
"ename": "ValueError",
"evalue": "Invalid value for layer_property: 'FINDANDREPLACEWORKSPACEPATH' (choices are: ['CREDITS', 'DATASETNAME', 'WORKSPACEPATH', 'DESCRIPTION', 'BRIGHTNESS', 'SHOWLABELS', 'LONGNAME', 'MAXSCALE', 'SYMBOLOGY', 'SYMBOLOGYTYPE', 'SERVICEPROPERTIES', 'VISIBLE', 'DEFINITIONQUERY', 'DATASOURCE', 'TRANSPARENCY', 'TIME', 'MINSCALE', 'LABELCLASSES', 'CONTRAST', 'NAME'])",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-9-4ef8a62e6fa7>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mprop\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mprops\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mif\u001b[0m \u001b[0mobj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msupports\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mprop\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;32mprint\u001b[0m \u001b[0mprop\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mprop\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mValueError\u001b[0m: Invalid value for layer_property: 'FINDANDREPLACEWORKSPACEPATH' (choices are: ['CREDITS', 'DATASETNAME', 'WORKSPACEPATH', 'DESCRIPTION', 'BRIGHTNESS', 'SHOWLABELS', 'LONGNAME', 'MAXSCALE', 'SYMBOLOGY', 'SYMBOLOGYTYPE', 'SERVICEPROPERTIES', 'VISIBLE', 'DEFINITIONQUERY', 'DATASOURCE', 'TRANSPARENCY', 'TIME', 'MINSCALE', 'LABELCLASSES', 'CONTRAST', 'NAME'])"
]
}
],
"source": [
"for prop in props:\n",
" if obj.supports(prop):\n",
" print prop, getattr(obj,prop)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Hm. Apparently, you cannot throw any string as an input argument for the `supports()` method. In this particular case, we are trying to check whether this layer supports `findAndReplaceWorkspacePath` property. Well, this is actually a method (i.e., a function), not a property. \n",
"\n",
"As we are not interested in methods, we have to filter them out of our `props` list. This can be done using the `callable()` function ([help link](https://docs.python.org/2/library/functions.html#callable)). "
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"False\n"
]
}
],
"source": [
"print callable(getattr(obj,'getExtent'))\n",
"print callable(getattr(obj,'datasetName'))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"credits \n",
"dataSource C:\\GIS\\Temp\\test.gdb\\GridFeatures\n",
"datasetName GridFeatures\n",
"definitionQuery \n",
"description \n"
]
},
{
"ename": "ValueError",
"evalue": "Invalid value for layer_property: 'FINDANDREPLACEWORKSPACEPATH' (choices are: ['CREDITS', 'DATASETNAME', 'WORKSPACEPATH', 'DESCRIPTION', 'BRIGHTNESS', 'SHOWLABELS', 'LONGNAME', 'MAXSCALE', 'SYMBOLOGY', 'SYMBOLOGYTYPE', 'SERVICEPROPERTIES', 'VISIBLE', 'DEFINITIONQUERY', 'DATASOURCE', 'TRANSPARENCY', 'TIME', 'MINSCALE', 'LABELCLASSES', 'CONTRAST', 'NAME'])",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-11-b1452789c1be>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mprop\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mprops\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mif\u001b[0m \u001b[0mobj\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msupports\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mprop\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mcallable\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mprop\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;32mprint\u001b[0m \u001b[0mprop\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mprop\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mValueError\u001b[0m: Invalid value for layer_property: 'FINDANDREPLACEWORKSPACEPATH' (choices are: ['CREDITS', 'DATASETNAME', 'WORKSPACEPATH', 'DESCRIPTION', 'BRIGHTNESS', 'SHOWLABELS', 'LONGNAME', 'MAXSCALE', 'SYMBOLOGY', 'SYMBOLOGYTYPE', 'SERVICEPROPERTIES', 'VISIBLE', 'DEFINITIONQUERY', 'DATASOURCE', 'TRANSPARENCY', 'TIME', 'MINSCALE', 'LABELCLASSES', 'CONTRAST', 'NAME'])"
]
}
],
"source": [
"for prop in props: \n",
" if obj.supports(prop):\n",
" if not callable(getattr(obj,prop)): \n",
" print prop, getattr(obj,prop)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But as you see, the problem remains because we cannot check whether `obj.property` is a callable or not without getting a `ValueError` trying to access `obj.property` first.\n",
"\n",
"In such a case, one could use a very handy technique of supressing the exceptions using the `try/except` statement. So, if a property is not supported by this layer and if it is a callable, we don't want to keep this property. We will be able to continue running the `for` loop leaving in the `supported_props` list only valid properties."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Unsupported properties: ['brightness', 'contrast', 'findAndReplaceWorkspacePath', 'getExtent', 'getSelectedExtent', 'getSelectionSet', 'replaceDataSource', 'save', 'saveACopy', 'serviceProperties', 'setSelectionSet', 'supports', 'symbology', 'updateLayerFromJSON']\n",
"\n",
"Supported properties: ['credits', 'dataSource', 'datasetName', 'definitionQuery', 'description', 'isBroken', 'isFeatureLayer', 'isGroupLayer', 'isNetworkAnalystLayer', 'isRasterLayer', 'isRasterizingLayer', 'isServiceLayer', 'labelClasses', 'longName', 'maxScale', 'minScale', 'name', 'showLabels', 'symbologyType', 'time', 'transparency', 'visible', 'workspacePath']\n"
]
}
],
"source": [
"unsupported_props = []\n",
"supported_props = []\n",
"\n",
"#get all props for Layer object\n",
"for prop in [prop for prop in dir(obj) if '_' not in prop]:\n",
" try: \n",
" if callable(getattr(obj,prop)): #exclude methods\n",
" unsupported_props.append(prop)\n",
" continue\n",
" else:\n",
" getattr(obj,prop) #check whether obj.supports(prop) raises ValueError\n",
" supported_props.append(prop)\n",
" except:\n",
" unsupported_props.append(prop)\n",
" \n",
"print 'Unsupported properties:', unsupported_props\n",
"print\n",
"print 'Supported properties:', supported_props"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can safely iterate through every property of this particular map layer:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"credits >>> \n",
"dataSource >>> C:\\GIS\\Temp\\test.gdb\\GridFeatures\n",
"datasetName >>> GridFeatures\n",
"definitionQuery >>> \n",
"description >>> \n",
"isBroken >>> False\n",
"isFeatureLayer >>> True\n",
"isGroupLayer >>> False\n",
"isNetworkAnalystLayer >>> False\n",
"isRasterLayer >>> False\n",
"isRasterizingLayer >>> False\n",
"isServiceLayer >>> False\n",
"labelClasses >>> [<LabelClass object at 0x5af5950[0x51e0ed8]>]\n",
"longName >>> GridLayer\n",
"maxScale >>> 0.0\n",
"minScale >>> 0.0\n",
"name >>> GridLayer\n",
"showLabels >>> False\n",
"symbologyType >>> OTHER\n",
"time >>> <geoprocessing Layer Time object object at 0x0368E900>\n",
"transparency >>> 0\n",
"visible >>> True\n",
"workspacePath >>> C:\\GIS\\Temp\\test.gdb\n"
]
}
],
"source": [
"for prop in supported_props:\n",
" print prop, \">>>\", getattr(obj,prop)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Another way to list out the values only for valid properties is to use the `hasattr()` method:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"dataSource >>> C:\\GIS\\Temp\\test.gdb\\GridFeatures\n",
"datasetName >>> GridFeatures\n",
"isFeatureLayer >>> True\n",
"labelClasses >>> [<LabelClass object at 0x5dbdb70[0x37dbe90]>]\n",
"longName >>> GridLayer\n",
"name >>> GridLayer\n",
"symbologyType >>> OTHER\n",
"time >>> <geoprocessing Layer Time object object at 0x0541F030>\n",
"visible >>> True\n",
"workspacePath >>> C:\\GIS\\Temp\\test.gdb\n"
]
}
],
"source": [
"for prop in [prop for prop in dir(obj) if '_' not in prop]:\n",
" if hasattr(obj,prop):\n",
" if not callable(getattr(obj,prop)):\n",
" if getattr(obj,prop):\n",
" print prop, '>>>', getattr(obj,prop)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.10"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment