Source code for sertit.arcpy

import logging
import logging.handlers

from sertit.logs import deprecation_warning

# Arcpy types from inside a schema
SHORT = "int32:4"
""" 'Short' type for ArcGis GDB """

LONG = "int32:10"
""" 'Long' type for ArcGis GDB """

FLOAT = "float"
""" 'Float' type for ArcGis GDB """

DOUBLE = "float"
""" 'Double' type for ArcGis GDB """

TEXT = "str:255"
""" "Text" type for ArcGis GDB """

DATE = "datetime"
""" 'Date' type for ArcGis GDB """


# flake8: noqa
[docs] def init_conda_arcpy_env(): """ Initialize conda environment with Arcgis Pro. Resolves several issues. """ try: from packaging.version import InvalidVersion, Version try: import fiona from fiona import Env as fiona_env with fiona_env(): gdal_version = fiona.env.get_gdal_release_name() Version(gdal_version) except InvalidVersion: # workaround to https://community.esri.com/t5/arcgis-pro-questions/arcgispro-py39-gdal-version-3-7-0e-is-recognized/m-p/1364021 import geopandas as gpd gpd.options.io_engine = "pyogrio" except ModuleNotFoundError: pass
[docs] class ArcPyLogger: def __init__(self, name=None, prefix_log_file="atools_"): """ This class inits a ready to use python logger for ArcGis pro tool. Be sure that arcpy has been imported before using this class. It uses logging under the hood. It writes outputs to a temporary file and to the ArcGis console. The temporary file is removed when the user closes ArcGis. If you need a logger in an outside module or function, use `logging.getLogger(LOGGER_NAME)` to get your logger. Args: name (str) : The name of the logger prefix_log_file (str) : The log filename is random, but you can prefix a name. The default value is "{{ name }}_". Example: >>> from sertit.arcpy import ArcPyLogger >>> arcpy_logger = ArcPyLogger(name="MyArcgisTool") Outputs written to file: C:\\Users\\bcoriat\\AppData\\Local\\Temp\\ArcGISProTemp15788\\MyArcgisTool_1bv0c1cl >>> logger = logging.getLogger("MyArcgisTool") >>> logger.info("Hello World !") Hello World ! Warning: Python must keep a reference to the instantiated object during the execution of your program. That's why you must init this class once at the top level of your project. This will not work because Python destroys the object class. >>> ArcPyLogger(name="MyArcgisTool") >>> logger = logging.getLogger("MyArcgisTool") >>> logger.info("Hello World !") """ self.name = name self.logger = None self.handler = None if name: self.prefix = name + "_" else: self.prefix = prefix_log_file self._set_logger() def __del__(self): self.logger.removeHandler(self.handler) def _set_logger(self): import tempfile logger = logging.getLogger(self.name) f = tempfile.NamedTemporaryFile(prefix=self.prefix, delete=False) # Create handler max_file_size = 1024 * 1024 * 2 # 2MB log files self.handler = ArcPyLogHandler( f.name, maxBytes=max_file_size, backupCount=10, encoding="utf-8", ) logger.addHandler(self.handler) # Set formatter to handler formatter = logging.Formatter("%(levelname)-8s %(message)s") self.handler.setFormatter(formatter) # Set logger logger.setLevel(logging.DEBUG) self.logger = logger self.logger.info("You can read logs in the file: " + f.name)
[docs] class ArcPyLogHandler(logging.handlers.RotatingFileHandler): """ Custom logging class that bounces messages to the arcpy tool window as well as reflecting back to the file. """
[docs] def emit(self, record): """ Write the log message """ import arcpy try: msg = record.msg % record.args except: try: msg = record.msg.format(record.args) except: msg = record.msg if record.levelno >= logging.ERROR: arcpy.AddError(msg) elif record.levelno >= logging.WARNING: arcpy.AddWarning(msg) elif record.levelno >= logging.INFO: arcpy.AddMessage(msg) super(ArcPyLogHandler, self).emit(record)
[docs] def feature_layer_to_path(feature_layer) -> str: """ .. deprecated:: 1.36.0 Use :py:func:`gp_layer_to_path` instead. Use :func:`gp_layer_to_path` instead. Convert a feature layer to its source path. Args: feature_layer: Feature layer Returns: str: Path to the feature layer source """ deprecation_warning("This function is deprecated. Use gp_layer_to_path instead.") # Get path if hasattr(feature_layer, "dataSource"): path = feature_layer.dataSource else: path = str(feature_layer) return path
[docs] def gp_layer_to_path(feature_layer) -> str: """ Convert a GP layer to its source path. A GP layer in ArcGis is a layer in the content panel. Thus, the user can simply choose the layer in a dropdown menu. This function adds the possibility to get the source path of this layer if the user chose in the dropdown menu or drag and drop from the Windows explorer. Args: feature_layer: Feature layer or Raster layer Returns: str: Path to the feature or raster layer source Examples: For python toolbox, in the getParameterInfo() method use GPLayer, GPFeatureLayer or GPRasterLayer datatype. For vector layer use GPFeatureLayer: >>> import arcpy >>> aoi = arcpy.Parameter( >>> displayName="Aoi", >>> name="aoi", >>> datatype="GPFeatureLayer", >>> parameterType="Required", >>> direction="Input", >>> ) For raster layer, use GPRasterLayer: >>> import arcpy >>> nir_path = arcpy.Parameter( >>> displayName="Nir infrared band", >>> name="nir_path", >>> datatype="GPRasterLayer", >>> parameterType="Optional", >>> direction="Input", >>> ) If your layer may be a feature or raster layer, use GPLayer: >>> import arcpy >>> dem_path = arcpy.Parameter( >>> displayName="DEM path as isoline or raster", >>> name="dem_path", >>> datatype="GPLayer", >>> parameterType="Optional", >>> direction="Input", >>> ) Then in the execute() method, you can use this function to retrieve the real path to the layer. >>> aoi_path = feature_layer_to_path(parameters[0].value) >>> print(aoi_path) D:\data\project\aoi\aoi.shp """ # Get path if hasattr(feature_layer, "dataSource"): path = feature_layer.dataSource else: path = str(feature_layer) return path