0

I'm currently using Python to create a dictionary when given a user input argument, collects the file data types and names in the dictionary determined by the ArcPy Describe function, so the output will look something like:

[u'Shapefile': ['a.shp', 'b.shp'] u'Raster: ['c.jpg,', 'd.jpg'] 

My code below prints items and their describe and their so I have right now:

'a.shp': <geoprocessing describe data object object at 0x06GH998>}

import arcpy, os, sys
inputDirectory = sys.argv[1]
files = os.listdir(inputDirectory)
fDictionary= {}
for f in files:
 desc = arcpy.Describe(os.path.join(f, inputDirectory))
 if f not in fDictionary:
 fDictionary[f] = desc
 else:
 fDictionary[f].append(desc)
print 'fDictionary {0}'.format(fDictionary)

I understand getting the object data type, I will need to use dot notation to add the describe object property to describe (in order to bring out the dataType) and possibly another for statement, but I'm not sure how to implement it in the loop.

Kadir Şahbaz
78.6k57 gold badges260 silver badges407 bronze badges
asked Nov 3, 2021 at 21:44
1
  • 3
    You can use the hasattr and getattr built-in functions of Python to dynamically explore the properties of a geoprocessing describe data object Commented Nov 3, 2021 at 23:17

1 Answer 1

2

You linked to a ArcGIS Pro help page (Python 3.6+) but you use a Python 2.7 print command. The code below is written in Python 3.6+.

In case you are using Python 2.7 with ArcGIS for Desktop which I don't have, you should still be able to run the scripts below but need to change the print command. See What's new in Python 3.0. The rest should be interchangeable but I did not test it.


You have a few issues in your code:

  1. os.path.join(f, inputDirectory) should be os.path.join(inputDirectory, f).
  2. You need to use desc.dataType to retrieve the data type and desc.file for the file name.
  3. If the data type is not already in the dictionary, you'll need to assign a list, and not assigning the desc object.
import os
import arcpy
inputDirectory = "D:\projects\playground\python\stackgis\data" # simulating input
files = os.listdir(inputDirectory)
fDictionary = {}
for f in files:
 desc = arcpy.Describe(os.path.join(inputDirectory, f))
 
 if desc.dataType not in fDictionary:
 fDictionary[desc.dataType] = [desc.file]
 else:
 fDictionary[desc.dataType].append(desc.file)
print('fDictionary {0}'.format(fDictionary))

Output:

fDictionary {'ShapeFile': ['a.dbf', 'a.shp', 'b.dbf', 'b.shp'], 'File': ['a.prj', 'a.shx', 'b.prj', 'b.shx'], 'RasterDataset': ['c.jpg', 'd.jpg']}

In addition, if you only want to process datasets, you may want to consider using arcpy.da.Walk (but also iterates through sub directories) or arcpy.ListFeatureClasses (requires arcpy.env.workspace to be set) to iterate over the datasets. The example below uses arcpy.da.Walk:

import os
import arcpy
inputDirectory = "D:\projects\playground\python\stackgis\data" # simulating input
fDictionary = {}
for root, _, datasets in arcpy.da.Walk(inputDirectory):
 for dataset in datasets:
 
 desc = arcpy.Describe(os.path.join(root, dataset))
 
 if desc.dataType not in fDictionary:
 fDictionary[desc.dataType] = [desc.file]
 else:
 fDictionary[desc.dataType].append(desc.file)
print('fDictionary {0}'.format(fDictionary))

Output:

fDictionary {'ShapeFile': ['a.shp', 'b.shp'], 'RasterDataset': ['c.jpg', 'd.jpg']}

You could use defaultdict to make your code simpler:

import os
import arcpy
from collections import defaultdict
input_folder = "D:\projects\playground\python\stackgis\data" # simulating input
output = defaultdict(list)
for root, _, datasets in arcpy.da.Walk(input_folder):
 for dataset in datasets:
 
 desc = arcpy.Describe(os.path.join(root, dataset))
 output[desc.dataType].append(desc.file)
print(f"Output {output}")

Output:

Output {'ShapeFile': ['a.shp', 'b.shp'], 'RasterDataset': ['c.jpg', 'd.jpg']}

Addendum: According to Vince's comment you may be looking to get the dataType and file properties dynamically from the Describe object. There would be no need to do that. Both properties are always present in any Describe object.

All data, regardless of the data type, will always acquire the generic Describe Object properties.

https://pro.arcgis.com/en/pro-app/latest/arcpy/functions/describe.htm

However, it makes sense to check for properties which are not available for all data types. See Vince's comments where he suggest hasattr and getattr.

Here is an example with the property extent which is not be available for all data types:

desc = arcpy.Describe(r"d:\data\a.shp")
if hasattr(desc, "extent"):
 extent = getattr(desc, "extent")

However, you are accessing only generic properties. Therefore is no need using hasattr and getattr.

answered Nov 3, 2021 at 22:55
2
  • 1
    I was expecting an answer that addressed the concern of dynamically getting properties out of a Describe object (via hasattr and getattr). All the properties you have here are hard-coded, so this seems to answer a different Question. Commented Nov 3, 2021 at 23:13
  • 1
    The OP has an expected and an actual output which doesn't match. They also write "[...] but I'm not sure how to implement it in the loop." This answer does address their code issues. I don't read any concerns of dynamically getting properties but I am also not native in English, so maybe I am wrong. Commented Nov 3, 2021 at 23:30

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.