Personnalisation du comportement d'un outil de script

Vous pouvez personnaliser le comportement de la boîte de dialogue de votre outil de script, par exemple l'activation ou la désactivation des paramètres, la fourniture de valeurs par défaut ou la mise à jour des mots-clés d'une chaîne. Pour personnaliser le comportement de votre outil de script, cliquez avec le bouton droit de la souris sur l'outil de script, sélectionnez Propriétés, puis cliquez sur l'onglet Validation. Dans le volet Validation, vous pouvez indiquer le code Python qui implémente une classe Python nommée ToolValidator. Si vous ajoutez le code Python, vous pouvez

Fonctionnement de ToolValidator

La classe ToolValidator est un bloc de code Python utilisé par le géotraitement pour contrôler la manière dont la boîte de dialogue et la fenêtre Python de l'outil changent en fonction des informations saisies par l'utilisateur. La classe ToolValidator permet également de décrire les données en sortie de l'outil, ce qui est important pour la création de modèles. Les outils système (ceux fournis par ESRI) ont toujours eu la capacité de réagir aux informations saisies par les utilisateurs pour modifier la boîte de dialogue de l'outil en conséquence, comme décrit ci-dessus.

HéritageHéritage :

Jusqu'à la version ArcGIS 9.3, les outils de script n'avaient pas cette capacité : la boîte de dialogue de l'outil était statique et la sortie de l'outil de script ne contenait pas de description actualisée, ce qui rendait difficile l'utilisation d'outils de script dans ModelBuilder. La classe ToolValidator est disponible pour vous offrir toutes les fonctionnalités d'un outil système.

Bien que la classe ToolValidator soit implémentée à l'aide du code Python, vous pouvez utiliser n'importe quel langage de script pour accomplir le travail de l'outil.

ToolValidator et validation

La validation consiste à vérifier que tous les paramètres d'outil sont corrects et fournissent des messages utiles si ce n'est pas le cas. La validation se compose de deux parties :

  • La partie dont vous pouvez vous charger en ajoutant le code à la classe ToolValidator.
  • La partie qu'ArcGIS effectue automatiquement. Cette partie de la validation est connue sous le nom de validation interne (ou validation de base), puisqu'il s'agit de la validation de base faite en interne par géotraitement dans ArcGIS.

Tout d'abord, examinez ce que fait la validation interne :

  • Si un paramètre est requis, vérifie s'il est vide (rien n'a encore été saisi) et, si tel est le cas, envoie le message "Valeur requise" à la boîte de dialogue de l'outil (en utilisant un point vert au lieu d'une croix rouge).
  • Vérifie que la valeur saisie par l'utilisateur est du type adéquat (par exemple, un raster au lieu d'une classe d'entités ou des caractères alphabétiques au lieu d'un nombre.)
  • Vérifie l'appartenance du filtre. Par exemple, si un filtre Liste de valeurs contient des mots-clés tels que ROUGE, ORANGE et JAUNE, et que vous saisissez BLEU, un message d'erreur s'affiche, car BLEU ne figure pas dans le filtre Liste de valeurs.
  • Vérifie l'existence de jeux de données en entrée.
  • Génère un chemin d'accès au catalogue par défaut pour les jeux de données en sortie.
  • Met à jour la description des données en sortie en fonction d'un ensemble de règles contenues dans l'objet spécial, Schema.
  • Vérifie l'existence de jeux de données en sortie par rapport au paramètre d'environnement overwriteOutput. Si le jeu de données existe et que la valeur d'overwriteOutput est False, une erreur est produite ; sinon, un avertissement est généré.
  • Si le paramètre est un type de données de champ, vérifie que le champ existe dans la table associée.
  • Vérifie que le jeu de données en sortie n'est pas le même que le jeu de données en entrée (à moins que la sortie soit dérivée, comme Ajouter un champ).
  • Pour les paramètres contenant des types de données linéaire et d'unités surfaciques, définissez leurs valeurs par défaut en examinant les valeurs correspondantes dans ArcMap (en cas d'exécution à partir d'ArcMap).
  • Si la sortie est une couverture, une grille ou une table INFO, vérifiez que les noms de fichier de ces jeux de données ne dépassent pas la limite de 13 caractères.

La validation interne n'effectue pas les opérations suivantes (contrairement à une classe ToolValidator) :

  • Mettre à jour les filtres en fonction de l'interaction avec d'autres paramètres. Par exemple, si votre utilisateur entre une classe d'entités ponctuelles dans le premier paramètre, la boîte de dialogue de l'outil doit afficher ROUGE, ORANGE et JAUNE dans le troisième paramètre. Si l'utilisateur entre une classe d'entités surfaciques, vous voulez afficher BLEU, INDIGO et VIOLET dans le troisième paramètre.
  • Activer/Désactiver les paramètres.
  • Calculer les valeurs par défaut.
  • Effectuer toute interaction de paramètre spécifique à l'outil.

Le code que vous ajoutez à la classe ToolValidator fonctionne conjointement avec la validation interne, de la façon suivante :

  • Vous pouvez fournir un ensemble de règles que la validation interne utilise pour mettre à jour la description des jeux de données en sortie. Ces règles sont contenues dans un objet Schéma.
  • Vous pouvez mettre à jour les filtres avant la validation interne. D'après l'exemple ci-dessus, si vous entrez une classe d'entités ponctuelles, vous devrez mettre à jour le filtre pour contenir ROUGE, ORANGE et JAUNE. La validation interne vérifie la valeur saisie par l'utilisateur par rapport aux valeurs trouvées dans le filtre.

De plus, comme mentionné, votre ToolValidator peut calculer les valeurs par défaut, activer et désactiver les paramètres et personnaliser les messages. Ces types d'actions n'ont aucune conséquence sur la validation interne ; ils affectent uniquement l'apparence de la boîte de dialogue de l'outil.

Utilisation de la classe ToolValidator pour personnaliser la boîte de dialogue de l'outil

ToolValidator est une classe Python qui contient trois méthodes : initializeParameters(self), updateParameters(self) et updateMessages(self). Elle contient également la méthode d'initialisation de la classe Python standard, __init__(self). Pour afficher et modifier la classe ToolValidator, cliquez avec le bouton droit sur votre outil de script, cliquez sur Propriétés, puis sur l'onglet Validation. L'illustration suivante montre l'onglet Validation avec le code de la classe ToolValidator par défaut. Cliquez sur le bouton Modifier pour modifier le code, puis cliquez sur OK ou Appliquer pour appliquer vos modifications.

Volet Validation

Méthode

Description

__init__

Initialise la classe ToolValidator. Importez les bibliothèques dont vous avez besoin et initialisez l'objet (self).

initializeParameters

Appelée lors de la première ouverture de la boîte de dialogue de l'outil ou lorsque l'outil est utilisé pour la première fois dans la ligne de commande.

updateParameters

Appelée à chaque fois que l'utilisateur modifie un paramètre dans la boîte de dialogue de l'outil ou dans la ligne de commande. Après le renvoi à partir d'updateParameters, le géotraitement appelle sa routine de validation interne.

updateMessages

Appelée après le renvoi à partir de la routine de validation interne. Vous pouvez examiner les messages créés à partir de la validation interne et les modifier si vous le souhaitez.

Vue d'ensemble des méthodes ToolValidator
RemarqueRemarque :

n'appelez pas d'autres outils de géotraitement ou jeux de données ouverts dans ToolValidator, car la classe ToolValidator est exécutée à chaque fois qu'un utilisateur modifie un élément dans la boîte de dialogue de l'outil. Utilisez des outils de géotraitement dans votre script et non dans ToolValidator.

RemarqueRemarque :

vous devez implémenter les trois méthodes, initializeParameters(self), updateParameters(self) et updateMessages(self). Elles n'ont rien à faire à part le renvoi, mais elles doivent être présentes pour que ToolValidator constitue une classe Python valide.

Voici quelques exemples de code ToolValidator. Pour une description complète de toutes les méthodes et pour plus d'exemples, consultez la rubrique Programmation d'une classe ToolValidator.

Activer ou désactiver un paramètre

L'exemple ci-dessous provient de l'outil Hot Spot Analysis.

def updateParameters(self):

  # If the option to use a weights file is selected (the user chose
  #  "Get Spatial Weights From File", enable the parameter for specifying 
  #  the file, otherwise disable it
  #
  if self.params[3].value == "Get Spatial Weights From File":
    self.params[8].enabled = 1
  else:
    self.params[8].enabled = 0

Remarque de codage : lorsque vous définissez des variables booléennes, telles que Enabled, vous pouvez utiliser ces syntaxes :

self.params[8].enabled = 1
self.params[8].enabled = bool(1)
self.params[8].enabled = True  # Note upper case: "True", not "true"

Tout nombre ou valeur non nul(le) est considéré(e) comme vrai(e).

Définir une valeur par défaut

Cet exemple provient également de l'outil Hot Spot Analysis.

def updateParameters(self):
  # Set the default distance threshold to 1/100 of the larger of the width
  #  or height of the extent of the input features.  Do not set if there is no 
  #  input dataset yet, or the user has set a specific distance (Altered is true).
  # 
  import string

  if self.params[0].value:
    if not self.params[6].altered:
      extent = string.split(arcpy.Describe(self.params[0].value).extent, " ")
      width = float(extent[2]) - float(extent[0])
      height = float(extent[3]) - float(extent[1])
      if width > height:
        self.params[6].value = width / 100
      else:
        self.params[6].value = height / 100
                
        return

Mettre à jour un filtre

Voici un exemple de mise à jour dynamique d'un filtre Liste de valeurs contenant une liste de mots-clés. Si l'utilisateur saisit "OLD_FORMAT" dans le deuxième paramètre, le troisième paramètre contient "POINT, LIGNE et POLYGONE". Si "NEW_FORMAT" est saisi, le troisième paramètre contient trois choix supplémentaires.

class ToolValidator:
  def __init__(self): 
    import arcpy 
    self.params = arcpy.GetParameterInfo()

  def initializeParameters(self):
    return

  def updateParameters(self):
    # Provide default values for "file format type" and 
    #  "feature type in file"
    #
    if not self.params[1].altered:
      self.params[1].value = "OLD_FORMAT"
    if not self.params[2].altered:
      self.params[2].value = "POINT"

    # Update the value list filter of the "feature type in file" parameter 
    #   depending on the type of file (old vs. new format) input
    #
    if self.params[1].value == "OLD_FORMAT":
      self.params[2].filter.list = ["POINT", "LINE", "POLYGON"]
    elif self.params[1].value == "NEW_FORMAT":
      self.params[2].filter.list = ["POINT", "LINE", "POLYGON",
                                    "POINT_WITH_ANNO",
                                    "LINE_WITH_ANNO",
                                    "POLYGON_WITH_ANNO"]

    return

  def updateMessages(self):
    return

Voici un autre exemple où le filtre Liste de valeurs dans le second paramètre change en fonction du type de forme présent dans le premier paramètre, une classe d'entités.

  def updateParameters(self):
    # Update the value list filter in the second parameter based on the 
    #   shape type in the first parameter
    #
    stringFilter = self.params[1].filter
    fc = self.params[0].value
    if fc:
        shapetype = arcpy.Describe(fc).shapeType.lower()
        if shapetype == "point" or shapetype == "multipoint":
            stringFilter.list = ["RED", "GREEN", "BLUE"]
        elif shapetype == "polygon":
            stringFilter.list = ["WHITE", "GRAY", "BLACK"]
        else:
            stringFilter.list = ["ORANGE", "INDIGO", "VIOLET"]
    else:
        stringFilter.list = ["RED", "GREEN", "BLUE"]

    # If the user hasn't changed the keyword value, set it to the default value
    #  (first value in the value list filter).
    #
    if not self.params[1].altered:
        self.params[1].value = stringFilter.list[0]
        
    return

Personnaliser un message

def updateMessages(self):
  self.params[6].clearMessage()

  # Check to see if the threshold distance contains a value of zero and the user has
  #  specified a fixed distance band.
  #
  if self.params[6].value <= 0:
    if self.params[3].value == "Fixed Distance Band":
      self.params[6].setErrorMessage("Zero or a negative distance is invalid \
                                      when using a fixed distance band. Please \
                                      use a positive value greater than zero." )
      elif self.params[6].value < 0:
        self.params[6].setErrorMessage("A positive distance value is required \
                                        when using a fixed distance band. \
                                        Please specify a distance.")

  return

Mise à jour de la description de données en sortie à l'aide de l'objet de schéma

Outre la personnalisation du comportement de la boîte de dialogue de l'outil, vous pouvez utiliser ToolValidator pour mettre à jour les descriptions de variables de données en sortie pour ModelBuilder. Les variables de données dans ModelBuilder peuvent être considérées comme de brèves descriptions des jeux de données, comme illustré ci-dessous. Les variables de données contiennent toutes les propriétés auxquelles vous avez accès à l'aide de la fonction Describe dans Python.

Description des données de base

Tous les outils doivent mettre à jour la description de leurs données en sortie pour leur utilisation dans ModelBuilder. En mettant à jour la description, les processus suivants dans ModelBuilder peuvent voir les modifications des données en attente avant l'exécution de tout processus. Les deux exemples ci-dessous montrent comment les processus suivants considèrent les modifications en attente.

Le premier exemple, illustré ci-dessous, montre un modèle contenant les outils Ajouter un champ et Calculer un champ. Dans Ajouter un champ, la variable de données en sortie, Parks (2), est mise à jour pour contenir le nouveau champ, TrackingID. Du fait de la mise à jour de la sortie, la boîte de dialogue Calculer un champ affiche TrackingID dans la liste des noms de champs.

Modèle avec l'outil Découper

Le second exemple (non illustré) est un modèle où la sortie de l'outil Découper est utilisée comme entrée de l'outil Polygone vers raster. Etant donné que l'outil Découper utilise simplement une approche à l'emporte-pièce pour créer les entités en entrée, la classe d'entités en sortie a les mêmes propriétés que la classe d'entités en entrée, à une exception près : son étendue géographique. L'étendue géographique de la classe d'entités en sortie correspond à l'intersection géométrique de l'entrée et des étendues d'entités de découpage. L'outil Polygone vers raster utilise la nouvelle étendue géographique pour déterminer une taille de cellule par défaut.

Dans la classe ToolValidator, vous pouvez utiliser un objet Schema pour établir des règles pour créer la description de la sortie. Par exemple, vous pouvez établir les règles suivantes :

Les paramètres en sortie ont un objet Schema

L'objet Schema est créé par géotraitement. Chaque paramètre de type classe d'entités, table, raster ou espace de travail en sortie dispose d'un objet Schema. Seules les données de type classe d'entités, table, raster et espace de travail en sortie disposent d'un objet Schema, tous les autres types de données n'en ont pas. Vous pouvez accéder à cette structure via l'objet Parameter et définir les règles de description de la sortie. Lors du renvoi à partir d'updateParameters, la routine de validation interne examine les règles que vous avez définies et actualise la description de la sortie.

Définition des dépendances

Chaque fois que vous créez une règle telle que "copier les champs du jeu de données dans le paramètre 3, puis ajouter un champ", vous devez dire à l'objet Schema à partir de quel paramètre vous souhaitez effectuer la copie (paramètre 3) en ajoutant des dépendances à l'objet Parameter. Vous pouvez ajouter plusieurs dépendances.

def initializeParameters(self):
  # Set the dependencies for the output and its schema properties
  #
  self.params[2].parameterDependencies = [0, 1]

ParameterDependencies prend une liste Python.

Si vous n'avez jamais utilisé de listes ou de liste de listes, elles peuvent paraître confuses de prime abord, mais vous vous y habituerez rapidement et les trouverez utiles pour toutes sortes de choses. Voici quelques exemples de code Python qui présente des listes et des listes de listes. Ces exemples sont affichés en mode interactif (la fenêtre Python, la fenêtre interactive dans PythonWin ou Python Shell dans IDLE), où vous saisissez le code et obtenez des résultats immédiats.

Exemple 1 : dans Python, toute variable ou valeur littérale entourée par des crochets devient une liste. Lorsque vous imprimez une liste, les crochets sont toujours ajoutés.

>>> a = [1]
>>> print a
[1]
>>> b = 2
>>> c = [b]
>>> print c
[2]

Exemple 2 : une liste peut contenir n'importe quel nombre d'éléments de tout type. Pour accéder à un élément d'une liste, vous utilisez des crochets qui contiennent l'index de l'élément. Le premier élément d'une liste est toujours [0].

>>> a = [1, "two", 12.6]
>>> print a
[1, 'two', 12.6]
>>> print a[0]	
1

Exemple 3 : une liste ordinaire de listes

>>> listOfLists = [ [1,2,3], ["one", "two", "three"] ]
>>> print listOfLists
[[1, 2, 3], ['one', 'two', 'three']]
>>> print listOfLists[0]
[1, 2, 3]
>>> print listOfLists[0][2]
3
>>> print listOfLists[1][2]
three

Exemple 4 : une autre liste de listes. Notez que les listes de membres ne doivent pas être nécessairement de la même longueur.

>>> listA = [1, 2, 3]
>>> listB = ["a", "b", "C", "Z"]
>>> listOfLists = [listA, listB]
>>> print listOfLists
[[1, 2, 3], ['a', 'b', 'C', 'Z']]
>>> print listOfLists[1][3]
Z

Exemple 5 : créez une liste vide, puis ajoutez et supprimez des éléments.

>>> a = []
>>> a.append("zero")
>>> print a
['zero']
>>> b = [1, 2, 3]
>>> a.append(b)
>>> print a
['zero', [1, 2, 3]]
>>> a.remove([1, 2, 3])
>>> print a
['zero']

Pour en savoir plus sur les listes Python (ou obtenir d'autres informations sur Python), visitez le site http://docs.python.org/.

Les exemples suivants montrent comment définir et utiliser des dépendances.

Exemples de définition de dépendances : Découper et Ajouter un champ

Rappelez-vous que l'outil Découper copie la définition des entités en entrée, puis définit l'étendue sur l'intersection des entités en entrée et des entités de découpage. L'exemple suivant montre comment cette règle est appliquée dans ToolValidator. (L'outil Découper étant un outil intégré et non un script, il n'utilise pas de classe ToolValidator Python. Les outils intégrés procèdent à leur validation à l'aide de routines internes qui sont essentiellement les mêmes que ToolValidator. Toutefois, si une classe ToolValidator Python avait été utilisée, cela ressemblerait à ça.)

def initializeParameters(self):
  # Set the dependencies for the output and its schema properties
  #
  self.params[2].parameterDependencies = [0, 1]

  # Feature type, geometry type, and fields all come from the first 
  #  dependent (parameter 0), the input features
  #
  self.params[2].schema.featureTypeRule = "FirstDependency"
  self.params[2].schema.geometryTypeRule = "FirstDependency"
  self.params[2].schema.fieldsRule = "FirstDependency"

  # The extent of the output is the intersection of the input features and 
  #  the clip features (parameter 1)
  #
  self.params[2].schema.extentRule = "Intersection"

  return

def updateParameter(self):
  return

L'outil Ajouter un champ copie la définition d'un paramètre en entrée et ajoute le champ spécifié par l'utilisateur. Le lien ci-dessous montre comment Ajouter un champ serait implémenté dans ToolValidator.

Afficher un exemple d'utilisation de AdditionalFields

Définition d'une structure dans initializeParameters et updateParameters

Notez que l'exemple de Découper ci-dessus modifie l'objet Schema dans initializeParameters et que updateParameters ne fait rien que renvoyer. En revanche, l'outil Ajouter un champ doit modifier l'objet Schema dans updateParameters car il ne possède pas la définition du champ à ajouter tant que l'utilisateur n'a pas fourni ces informations (updateParameters est alors appelé).

Ces deux cas peuvent être considérés comme statique et dynamique. Le découpage s'appuie uniquement sur les jeux de données figurant dans les paramètres dépendants (cas statique), tandis que l'outil Ajouter un champ doit examiner d'autres paramètres (tels que le nom de champ et le type de champ) qui ne sont pas des paramètres dépendants (cas dynamique).

Ce comportement statique et dynamique est évident dans la façon dont une classe ToolValidator est appelée :

  1. Lors de la première ouverture de la boîte de dialogue de l'outil, initializeParameters est appelé. Vous définissez les règles statiques pour décrire la sortie. Aucune description en sortie n'est créée à ce moment, puisque l'utilisateur n'a spécifié aucune valeur pour les paramètres.
  2. Une fois que l'utilisateur a interagi d'une manière quelconque avec la boîte de dialogue de l'outil, updateParameters est appelé.
  3. updateParameters peut modifier la structure pour prendre en compte le comportement dynamique qui ne peut pas être déterminé à partir des dépendances de paramètres, comme par exemple l'ajout d'un nouveau champ tel qu'Ajouter un champ.
  4. Après avoir été renvoyées à partir d'updateParameters, les routines de validation internes sont appelées et les règles figurant dans l'objet Schema sont appliquées pour mettre à jour la description des données en sortie.
  5. updateMessages est alors appelé. Vous pouvez examiner les messages d'avertissement et d'erreur que la validation interne a pu créer et les modifier ou ajouter des messages d'avertissements et d'erreurs.

Nom du jeu de données en sortie : clonage de sortie dérivée et de sortie requise

Lorsque vous définissez la propriété Schema.Clone sur true, vous indiquez au géotraitement de faire une copie exacte (clone) de la description dans le premier paramètre dépendant de la liste des dépendances de paramètres. En règle générale, vous définissez Clone sur true dans initializeParameters plutôt que dans updateParameters, puisqu'il n'a besoin d'être défini qu'une fois.

Si le ParameterType du paramètre en sortie est défini sur Derived, une copie exacte est faite. C'est le comportement de l'outil Ajouter un champ.

Si le ParameterType est défini sur Required, une copie exacte est également faite, mais le chemin d'accès du catalogue au jeu de données est modifié. Etant donné que la plupart des outils créent de nouvelles données, c'est le comportement le plus courant.

Pour en savoir plus

La rubrique Programmation d'une classe ToolValidator fournit des informations sur les objets Parameter, Schema et Filter et donne des exemples de code.

Tous les outils système basés sur des scripts, tels que les anneaux concentriques multiples, disposent d'un code ToolValidator que vous pouvez examiner et étudier. De nombreux outils de la boîte à outils Spatial Statistics sont des outils de script, et vous pouvez examiner leur implémentation dans ToolValidator.

Vous ferez certainement des erreurs dans votre implémentation de ToolValidator : des erreurs de syntaxe, d'exécution ou de logique. La rubrique Débogage d'une classe ToolValidator vous montre comment le géotraitement repère et signale les erreurs et vous donne des stratégies de débogage.


7/10/2012