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.

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
    – Vince
    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.

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.
    – Vince
    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.
    – Thomas
    Commented Nov 3, 2021 at 23:30

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.