""" describe_reporter.py Andrew Ortego 8/24/2016 TODO * Alter output with pprint so that it's all aligned (see output formatting) * Web-scrape script which gathering all Desc. object properties * Handle properties that have no attributes (currently commented) DESCRIPTION Creates a report of all arcpy describe-object properties for an object. INPUT Command line arguments must include a verbose or terse flag (-v or -t) as the first arguement. The difference between the two is that verbose will show you the attributes that have no value, whereas terse will not. Subsequent arguements are each of the describe properties being asked for in the report. These are optional, and all properties will be reported if these arguements are not provided. CAVEATS * The output will be overwritten unless you change the output's path. SAMPLE USAGE > python describe_reporter.py -v > python describe_reporter.py -t > python describe_reporter.py -v "General Describe" "Layer" "Table" > python describe_reporter.py -t "General Describe" "Workspace" SAMPLE OUTPUT (in terse mode) { Filename 1: { Describe Object Class 1: { Property 1: output, Propetry 2: {}, } } Filename 2: 'FILE NOT FOUND' } """ import arcpy import pickle, os, sys, time from pprint import pprint from functools import wraps from collections import OrderedDict as od try: from file_list import user_files except ImportError as e: print("ERROR: Could not find list of files to be scanned. Please verify") print("that file_list.py is in the same directory as this script, and") print("that it contains a list called user_files which holds each path") print("to your files.") print("EXAMPLE: user_files = [u'C:\\Users\\andr7495\\Desktop\\KML.kml']") raise SystemExit properties = { 'General Describe': { 'baseName', 'catalogPath', 'children', 'childrenExpanded', 'dataElementType', 'dataType', 'extension', 'file', 'fullPropsRetrieved', 'metadataRetrieved', 'name', 'path', }, 'ArcInfo Workstation Item': { 'alternateName', 'isIndexed', 'isPseudo', 'isRedefined', 'itemType', 'numberDecimals', 'outputWidth', 'startPosition', 'width', }, 'ArcInfo Workstation Table': { 'itemSet', }, 'CAD Drawing Dataset': { 'is2D', 'is3D', 'isAutoCAD', 'isDGN', }, #'CAD FeatureClass': {}, 'Cadastral Fabric': { 'bufferDistanceForAdjustment', 'compiledAccuracyCategory', 'defaultAccuracyCategory', 'maximumShiftThreshold', 'multiGenerationEditing', 'multiLevelReconcile', 'pinAdjustmentBoundary', 'pinAdjustmentPointsWithinBoundary', 'surrogateVersion', 'type', 'version', 'writeAdjustmentVectors', }, 'Coverage FeatureClass': { 'featureClassType', 'hasFAT', 'topology', }, 'Coverage': { 'tolerances', }, 'Dataset': { 'canVersion', 'changeTracked', 'datasetType', 'DSID', 'extent', 'isArchived', 'isVersioned', 'MExtent', 'spatialReference', 'ZExtent', }, #'dBase': {}, 'FeatureClass': { 'featureType', 'hasM', 'hasZ', 'hasSpatialIndex', 'shapeFieldName', 'shapeType', }, 'GDB FeatureClass': { 'areaFieldName', 'geometryStorage', 'lengthFieldName', 'representations', }, 'GDB Table': { 'aliasName', 'defaultSubtypeCode', 'extensionProperties', 'globalIDFieldName', 'hasGlobalID', 'modelName', 'rasterFieldName', 'relationshipClassNames', 'subtypeFieldName', 'versionedView', }, 'Geometric Network': { 'featureClassNames', 'networkType', 'orphanJunctionFeatureClassName', }, 'LAS Dataset': { 'constraintCount', 'fileCount', 'hasStatistics', 'needsUpdateStatistics', 'pointCount', 'usesRelativePath', }, 'Layer': { 'dataElement', 'featureClass', 'FIDSet', 'fieldInfo', 'layer', 'nameString', 'table', 'whereClause', }, #'Map Document': {}, 'Moscaic Dataset': { 'allowedCompressionMethods', 'allowedFields', 'allowedMensurationCapabilities', 'allowedMosaicMethods', 'applyColorCorrection', 'blendWidth', 'blendWidthUnits', 'cellSizeToleranceFactor', 'childrenNames', 'clipToBoundary', 'clipToFootprint', 'defaultCompressionMethod', 'defaultMensurationCapability', 'defaultMosaicMethod', 'MosaicOperator', 'defaultResamplingMethod', 'SortAscending', 'endTimeField', 'footprintMayContainNoData', 'GCSTransforms', 'JPEGQuality', 'LERCTolerance', 'maxDownloadImageCount', 'maxDownloadSizeLimit', 'maxRastersPerMosaic', 'maxRecordsReturned', 'maxRequestSizeX', 'maxRequestSizeY', 'minimumPixelContribution', 'orderBaseValue', 'orderField', 'rasterMetadataLevel', 'referenced', 'startTimeField', 'timeValueFormat', 'useTime', 'viewpointSpacingX', 'viewpointSpacingY', }, 'Network Analyst Layer': { 'network', 'nameString', 'solverName', 'impedance', 'accumulators', 'restrictions', 'ignoreInvalidLocations', 'uTurns', 'useHierarchy', 'hierarchyAttribute', 'hierarchyLevelCount', 'maxValueForHierarchyX', 'locatorCount', 'locators', 'findClosest', 'searchTolerance', 'excludeRestrictedElements', 'solverProperties', 'children', 'parameterCount', 'parameters', }, 'Prj File': { 'spatialReference', }, 'Raster Band': { 'height', 'isInteger', 'meanCellHeight', 'meanCellWidth', 'noDataValue', 'pixelType', 'primaryField', 'tableType', 'width', }, 'Raster Catalog': { 'rasterFieldName', }, 'Raster Dataset': { 'bandCount', 'compressionType', 'format', 'permanent', 'sensorType', }, 'RecordSet and FeatureSet': { 'json', 'pjson', }, 'RelationshipClass': { 'backwardPathLabel', 'cardinality', 'classKey', 'destinationClassKeys', 'destinationClassNames', 'forwardPathLabel', 'isAttachmentRelationship', 'isAttributed', 'isComposite', 'isReflexive', 'keyType', 'notification', 'originClassNames', 'originClassKeys', 'relationshipRules', }, 'RepresentationClass': { 'backwardPathLabel', 'cardinality', 'classKey', 'destinationClassKeys', 'destinationClassNames', 'forwardPathLabel', 'isAttachmentRelationship', 'isAttributed', 'isComposite', 'isReflexive', 'keyType', 'notification', 'originClassNames', 'originClassKeys', 'relationshipRules', }, #'Schematic Dataset': {}, 'Schematic Diagram': { 'diagramClassName', }, #'Schematic Folder': {}, #'SDC FeatureClass': {}, #'Shapefile FeatureClass': {}, 'Table': { 'hasOID', 'OIDFieldName', 'fields', 'indexes', }, 'TableView': { 'table', 'FIDSet', 'fieldInfo', 'whereClause', 'nameString', }, #'Text File': {}, 'Tin': { 'fields', 'hasEdgeTagValues', 'hasNodeTagValues', 'hasTriangleTagValues', 'isDelaunay', 'ZFactor', }, #'Tool': {}, #'Toolbox': {}, 'Topology': { 'clusterTolerance', 'featureClassNames', 'maximumGeneratedErrorCount', 'ZClusterTolerance', }, #'VPF Coverage': {}, #'VPF FeatureClass': {}, #VPF Table': {}, 'Workspace': { 'connectionProperties', 'connectionString', 'currentRelease', 'domains', 'release', 'workspaceFactoryProgID', 'workspaceType', }, } def timethis(func): """ Decorator that reports the execution time. """ @wraps(func) def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print("Created {0} in {1}s".format( os.path.join(os.getcwd(), u'Describe Report.txt'), round(end-start))) return result return wrapper def set_mode(user_input): """ Check whether the user has select verbose or terse mode. This is set with the -v or -t flags, respectively. """ try: if user_input[1] not in ["-v", "-t"]: print("ERROR : Report mode not selected.") print("SOLUTION: Use -v or -t (verbose or terse) as first arguement.") print("EXAMPLE : > python describe_reporter.py -v Layer Table Workspace") raise SystemExit except IndexError: print("ERROR : Report mode not selected.") print("SOLUTION: Use -v or -t (verbose or terse) as first arguement.") print("EXAMPLE : > python describe_reporter.py -v Layer Table Workspace") raise SystemExit return user_input[1] == "-v" def check_prop_list(user_types): """ Verify that the user has entered valid Describe Object types/classes and print a warning message for any invalid choices. If no arguments are provided, the report will print all Describe properties.Returns a list of Describe properties whose attributes will be included in the report. """ if not user_types: queried_types = [p for p in properties] else: invalid_types = list() queried_types = list() [queried_types.append(k) if k in properties else invalid_types.append(k) for k in user_types] if invalid_types: print("WARNING! Describe Types will not be included in report:") for t in invalid_types: print(t) return queried_types @timethis def generate_report(verbose_mode, property_list, user_files): """ Generates the report containing each file and its associated Describe-object attributes. Report is a dictionary and can be useful for other scripts. """ report_results = {} report_path = open(os.path.join(os.getcwd(), u'Describe Report.txt'), 'wt') for f in user_files: if arcpy.Exists(f): desc_dict = od() for d_class in sorted(property_list): desc_dict[d_class] = {} for p in properties[d_class]: try: desc_dict[d_class][p] = eval("arcpy.Describe(f).{0}".format(p)) except AttributeError: if verbose_mode: desc_dict[d_class][p] = 'ATTRIBUTE ERROR: Method not found' else: pass report_results[f] = desc_dict else: report_results[f] = 'FILE NOT FOUND' pprint(report_results, report_path, width=400) if __name__ == "__main__": """ Collect user input, check report mode, clean list of properties to be reported, and generate the report. """ user_input = [arg for arg in sys.argv] verbose_mode = set_mode(user_input) cleaned_user_types = check_prop_list(user_input[2:]) generate_report(verbose_mode, cleaned_user_types, user_files) print('\nfin.')