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.
1 Answer 1
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:
os.path.join(f, inputDirectory)
should beos.path.join(inputDirectory, f)
.- You need to use
desc.dataType
to retrieve the data type anddesc.file
for the file name. - 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
.
-
1I was expecting an answer that addressed the concern of dynamically getting properties out of a Describe object (via
hasattr
andgetattr
). All the properties you have here are hard-coded, so this seems to answer a different Question.Vince– Vince2021年11月03日 23:13:24 +00:00Commented Nov 3, 2021 at 23:13 -
1The 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.Thomas– Thomas2021年11月03日 23:30:12 +00:00Commented Nov 3, 2021 at 23:30
hasattr
andgetattr
built-in functions of Python to dynamically explore the properties of ageoprocessing describe data object