Source code for amaptor.functions

import os
import tempfile
import warnings

import arcpy

from amaptor.version_check import log, mp, PRO, mapping
from amaptor.errors import LayerNotFoundError, NotSupportedError
from amaptor.constants import _PRO_BLANK_TEMPLATE


def _import_mxd_to_new_pro_project(mxd, blank_pro_template=_PRO_BLANK_TEMPLATE, default_gdb="TEMP"):
	"""
		Handles importing an ArcMap Document into an ArcGIS Pro Project. Default Geodatabase is "TEMP" by default, indicating
		a temporary gdb should be created. It can also be "KEEP" to leave it alone, or it can be a path
	:param mxd:
	:param blank_pro_template:
	:param default_gdb:
	:return:
	"""

	log.warning("WARNING: Importing MXD to new Pro Project - if you call .save() it will not save back to original MXD. Use .save_a_copy('new_path') instead.")

	# can safely assume that if this is called, we're running on Pro and that's already been checked

	# copy blank project to new location - template is 1.3+
	blank_project = mp.ArcGISProject(blank_pro_template)
	new_temp_project = tempfile.mktemp(".aprx", "pro_project_import")
	blank_project.saveACopy(new_temp_project)
	del(blank_project)

	# strictly speaking, we don't need to destroy and recreate - should be able to edit original without saving - doing this just to keep things clear
	project = mp.ArcGISProject(new_temp_project)
	project.importDocument(mxd, include_layout=True)

	if default_gdb != "KEEP":  # if we're supposed to modify it
		if default_gdb == "TEMP":
			new_default_gdb = tempfile.mktemp(prefix="amaptor_default_geodatabase", suffix=".gdb")
			arcpy.CreateFileGDB_management(os.path.split(new_default_gdb)[0], os.path.split(new_default_gdb)[1])
			project.defaultGeodatabase = new_default_gdb
		else:  # if it's not KEEP or TEMP it must be a path
			project.defaultGeodatabase = default_gdb

	project.save()

	# return the project path, setup will continue from here
	return new_temp_project


[docs]def make_layer_with_file_symbology(feature_class, layer_file, layer_name=None): """ Given a feature class or raster and a template layer file with symbology, returns a new Layer object that has the layer from the layer file with the feature class as its data source. Optionally, layer can be renamed with layer_name This function will be scheduled for deprecation as it's superceded by using the Layer object with a template layer. More testing needs to be done and maybe more code written in ArcMap to make the alternative apply to both cases. This will be deprecated when that's complete :param feature_class: :param layer_file: :param layer_name: :return: """ #if PRO: # we'll actually issue the warning once there's a better cross-platform solution. For now, comment it out # warnings.warn("make_layer_with_file_symbology is deprecated in ArcGIS - use Layer objects with a template layer instead", DeprecationWarning) layer = None if PRO: layer_file = mp.LayerFile(layer_file) for layer in layer_file.listLayers(): # gets the first layer in the layer file break else: layer = mapping.Layer(layer_file) if layer is None: raise LayerNotFoundError("No layer available for copying from layer file") elif not layer.supports("DATASOURCE"): raise NotSupportedError("Provided layer file doesn't support accessing or setting the data source") if PRO: layer.dataSource = feature_class else: desc = arcpy.Describe(feature_class) if desc.extension and desc.extension != "": # get the name with extension for replacing the data source name = "{}.{}".format(desc.baseName, desc.extension) else: name = desc.baseName layer.replaceDataSource(desc.path, get_workspace_type(feature_class), name) if layer_name: layer.name = layer_name return layer
[docs]def reproject_extent(extent, current_extent): """ Changes an extent from its current spatial reference to the spatial reference on another extent object :param extent: :param current_extent: :return: """ return extent.projectAs(current_extent.spatialReference)
[docs]def get_workspace_type(dataset_path, factory_type=False): """ Gives us a workspace type that's usable for layer.replaceDataSource in ArcMap based on a dataset path :param dataset_path: path to dataset to return workspace type from :param factory_type: boolean flag indicating whether to return the workspace_factory type or the standard dataset type - workspace factory values are not yet fully implemented :return: """ """ Full list of possible factory values is the following in Pro, per Craig Williams: Access, De-limited Text File, File Geodatabase, OLE Database, Raster, ArcInfo, SDE, Shape File, LASDataset, Sql, TrackingServer, NetCDF, SqlLite, FeatureService, Cad, Excel, Street Map, SDC, Custom, WFS """ if factory_type: attr = "factory" else: attr = "workspace_type" prog_id_mapping = { "esriDataSourcesGDB.AccessWorkspaceFactory": { "workspace_type": "ACCESS_WORKSPACE", "factory": "Access" # not positive this is what this value is - can confirm by loading a MDB layer and testing layer.connectionProperties }, "esriDataSourcesGDB.FileGDBWorkspaceFactory": { "workspace_type": "FILEGDB_WORKSPACE", "factory": "File Geodatabase" }, "esriDataSourcesGDB.InMemoryWorkspaceFactory": { "workspace_type": "NONE", "factory": "", }, "esriDataSourcesGDB.SdeWorkspaceFactory": { "workspace_type": "SDE_WORKSPACE", "factory": "SDE" } } type_mapping = { "SHAPEFILE": { "workspace_type": "SHAPEFILE_WORKSPACE", "factory": "Shape File" # found by loading a shapefile layer and testing layer.connectionProperties }, "EXCEL": { "workspace_type": "EXCEL_WORKSPACE", "factory": "Excel" }, "TEXT": { "workspace_type": "TEXT_WORKSPACE", "factory": "De-limited Text File" }, "RASTER": { "workspace_type": "RASTER_WORKSPACE", "factory": "Raster" }, "TIN": { "workspace_type": "TIN_WORKSPACE", "factory": "" } } dataset_desc = arcpy.Describe(dataset_path) workspace = dataset_desc.path workspace_desc = arcpy.Describe(workspace) if workspace_desc.workspaceFactoryProgID.replace(".1", "") in prog_id_mapping: # if we have the specific name for it here, return that first return prog_id_mapping[workspace_desc.workspaceFactoryProgID][attr] elif workspace_desc.workspaceType == "FileSystem": if dataset_desc.extension == "shp": return type_mapping["SHAPEFILE"][attr] elif dataset_desc.extension in ("xls", "xlsx"): return type_mapping["EXCEL"][attr] elif dataset_desc.extension in ("tab", "csv", "txt"): # probably not the best way to handle this return type_mapping["TEXT"][attr] elif dataset_desc.dataType == "Raster": return type_mapping["RASTER"][attr] elif dataset_desc.dataType == "Tin": return type_mapping["TIN"][attr] elif workspace_desc.workspaceFactoryProgID == "": return type_mapping["SHAPEFILE"][attr] # if we get to here without returning, it's likely a shapefile - there are a few items missing from this conditional - CAD, VPF, etc
[docs]def get_workspace_factory_of_dataset(dataset_path): """ Provides the workspace factory type of a provided dataset - a convenience function that calls get_workspace type with the appropriate flag in the backgroun :param dataset_path: path to dataset to return workspace_factory value of :return: """ return get_workspace_type(dataset_path=dataset_path, factory_type=True)