[PYTHON] Générez automatiquement des spécifications d'objets avec Blue Prism

introduction

Dans Blue Prism, les parties qui exécutent réellement l'application appelée Object et les parties qui écrivent la logique métier appelée Process sont séparées, et c'est un mécanisme pour améliorer la réutilisabilité. Afin de favoriser la réutilisation des Objets au sein de l'équipe, il est nécessaire de créer et de maintenir un document "Quel type d'objet y a-t-il", mais il est difficile à créer et à maintenir à la main, et le contenu de l'objet a été mis à jour. Il peut y avoir des problèmes tels que l'impossibilité de suivre.

Cet article traite de la génération automatique de documentation pour ces objets importants (ODI: Object Design Instruction dans la terminologie Blue Prism).

Il existe un VBO appelé "Object Inventory"! Ne marche pas. .. ..

J'ai un VBO appelé "Object Inventory" dans Ditigal Exchange (https://digitalexchange.blueprism.com/dx/entry/3439/solution/object-inventory), mais le rognage des chaînes est basé sur l'anglais. Ou, j'ai eu une erreur Excel mystérieuse (Exception: Exception de HRESULT: 0x800A03EC) et cela n'a pas fonctionné. .. ..

Cependant, il y avait la description suivante sur la page d'aide.

This asset is a business object that uses the output from the BP command line /getbod function to create a list of all business objects, pages, descriptions, inputs and outputs.



 Le fait qu'AutomateC.exe dispose d'un commutateur appelé `` / getbod``` signifie que l'aide [Options de ligne de commande](https://bpdocs.blueprism.com/bp-6-8/ja-jp/helpCommandLine. Il n'est pas non plus écrit en htm). .. ..

# Commutateurs appelés / listprocesses et / getbod
 En regardant dans le VBO "Object Inventory" ci-dessus, il semble que le commutateur `` `` / listprocesses``` obtient une liste de processus et d'objets et appelle` `` / getbod``` pour chacun. Si la cible est Process, la chaîne de caractères `` Impossible de trouver l'objet métier '' 'sera renvoyée, il semble donc qu'ils sont exclus de la cible de traitement.

```/getbod```L'interrupteur existait vraiment!

# Essayez de mettre en œuvre avec python

 C'est un mauvais script, mais ça marche. Nous espérons pour votre référence. (Vérifié avec Python 3.7.4)

## Pour les processus de liste, ceux de getbod sont enregistrés dans un fichier texte.

```python
"""
Paramètres BP pour la connexion à Blue Prism_USERNAME, BP_PASSWORD, BP_Définissez-le dans la variable d'environnement DBCONNAME et exécutez-le.

BP_USERNAME :Nom d'utilisateur
BP_PASSWORD :mot de passe
BP_DBCONNAME :Nom de la connexion
"""
import delegator
from pathlib import Path
import logging
import os

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

bp_username = os.environ["BP_USERNAME"]
bp_password = os.environ["BP_PASSWORD"]
bp_dbconname = os.environ["BP_DBCONNAME"]

LISTPROCESSES_CMD = '"C:\Program Files\Blue Prism Limited\Blue Prism Automate\AutomateC.exe" /user {bp_username} {bp_password} /dbconname {bp_dbconname} /listprocesses'
command = LISTPROCESSES_CMD.format(
    bp_username=bp_username, bp_password=bp_password, bp_dbconname=bp_dbconname
)
context = delegator.run(command)
object_list = context.out
object_names = object_list.splitlines()
logger.info(object_names)


GETBOD_CMD = '"C:\Program Files\Blue Prism Limited\Blue Prism Automate\AutomateC.exe" /user {bp_username} {bp_password} /dbconname {bp_dbconname} /getbod "{object_name}"'

for object_name in object_names:
    command = GETBOD_CMD.format(
        bp_username=bp_username,
        bp_password=bp_password,
        bp_dbconname=bp_dbconname,
        object_name=object_name,
    )
    context = delegator.run(command)
    description = context.out
    if (
        len(description.splitlines()) <= 1
    ):  #Le processus est expliqué"L'objet métier XX est introuvable"Une seule ligne est sortie
        logger.info("{} is not a object".format(object_name))
        continue
    #Si une barre oblique est incluse dans le nom du fichier, le fichier ne peut pas être créé, alors remplacez-le.
    description_file_name = object_name.replace("/", "_") + ".txt"
    with open(Path("output_descriptions") / description_file_name, "w") as f:
        f.write(context.out)

Enregistrez le fichier texte getbod en tant que markdown

Veuillez me faire savoir s'il existe une bibliothèque qui peut être analysée plus facilement. .. ..

from typing import List, Optional
from dataclasses import dataclass, field
import re
import enum
import logging
from pathlib import Path

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG)


@dataclass
class VBOActionDescription:
    """
Une classe qui contient des informations sur chaque action VBO
    """

    action_name: str
    description: str = ""
    pre_condition: str = ""
    post_condition: str = ""
    input_params: List[str] = field(default_factory=list)
    output_params: List[str] = field(default_factory=list)

    def as_markdown(self) -> str:
        """
Express au format Markdown
        """
        _md = (
            "###{action_name}\n"
            "{description}\n"
            "\n"
            "####Conditions préalables\n"
            "{pre_condition}\n"
            "\n"
            "####Post-conditions\n"
            "{post_condition}\n"
            "\n"
            "####Paramètres d'entrée\n"
            "{input_params}\n"
            "\n"
            "####Paramètres de sortie\n"
            "{output_params}\n"
            "\n"
        )
        input_params_md = ("\n").join(
            ["* {}".format(input_param) for input_param in self.input_params]
        )
        output_params_md = ("\n").join(
            ["* {}".format(output_param) for output_param in self.output_params]
        )

        out = _md.format(
            action_name=self.action_name,
            description=self.description,
            pre_condition=self.pre_condition,
            post_condition=self.post_condition,
            input_params=input_params_md,
            output_params=output_params_md,
        )
        return out


class VBODescription:
    """
Une classe qui contient des informations VBO. Avoir une petite liste de VBOActionDescription
    """

    def __init__(
        self,
        object_name: str,
        description: Optional[str] = "",
        mode: str = "",
        actions: Optional[List[VBOActionDescription]] = None,
    ):
        self.object_name = object_name
        self.description = description
        self.mode = mode
        self.actions = actions

    def as_markdown(self) -> str:
        """
Express au format Markdown
        """
        _md = (
            "#{object_name}\n"
            "{description}\n"
            "\n"
            "##mode d'action\n"
            "{mode}\n"
            "\n"
            "##action\n"
        )

        out = _md.format(
            object_name=self.object_name, description=self.description, mode=self.mode
        )
        if self.actions:
            out = out + ("\n").join([action.as_markdown() for action in self.actions])

        return out


class DescriptionOfWhat(enum.Enum):
    """
Énumération fournie car des informations telles que "quelle partie vous lisez" étaient nécessaires lors de l'analyse de la description de VBO.
    """

    business_object = "Business Object"
    action = "Action"
    pre_condition = "Pre Conditiion"
    post_condition = "Post Conditiion"


def classify_line(line: str):
    """
Classer les lignes
    """
    line = line.strip()
    # =Objet métier- Utility - File Management=  <=Faites correspondre la ligne comme celle de gauche
    match = re.search("^=(?P<content>[^=]*)=$", line)
    if match:
        return {"type": "object name", "content": match.groupdict()["content"]}
    #Le mode d'exécution de cet objet métier est "arrière-plan"<=Faites correspondre la ligne comme celle de gauche
    match = re.search("^Le mode d'exécution de cet objet métier est "(?P<mode>[^」]+)"est", line)
    if match:
        return {"type": "mode", "content": match.groupdict()["mode"]}
    # ==Append to Text File==  <=Faites correspondre la ligne comme celle de gauche
    match = re.search("^==(?P<content>[^=]*)==$", line)
    if match:
        return {"type": "action name", "content": match.groupdict()["content"]}
    # ===Conditions préalables===  <=Faites correspondre la ligne comme celle de gauche
    match = re.search("^===(?P<content>[^=]*)===$", line)
    if match:
        content = match.groupdict()["content"]
        if content == "Conditions préalables":  #La traduction du côté Blue Prism est étrange. .. ..
            return {"type": "pre condition", "content": content}
        if content == "point final":  #La traduction du côté Blue Prism est étrange. .. ..
            return {"type": "post condition", "content": content}
        #autre que ça
        return {"type": "action attribute", "content": content}
    # *contribution:File Path (texte) - Full path to the file to get the file size   <=Faites correspondre la ligne comme celle de gauche
    match = re.search("^\*contribution:(?P<content>.*)$", line)
    if match:
        return {"type": "input parameter", "content": match.groupdict()["content"]}
    # *production:File Path (texte) - Full path to the file to get the file size  <=Faites correspondre la ligne comme celle de gauche
    match = re.search("^\*production:(?P<content>.*)$", line)
    if match:
        return {"type": "output parameter", "content": match.groupdict()["content"]}
    #Autres lignes
    return {"type": "article", "content": line}


def append_action_to_vbo_description(latest_action, vbo_description):
    actions = vbo_description.actions
    if actions:
        vbo_description.actions.append(latest_action)
    else:
        vbo_description.actions = [
            latest_action,
        ]
    return vbo_description


def convert_to_markdown(bod_description_filepath) -> str:
    """
Le corps du processus de conversion en Markdown
    """
    vbo_description = None
    with open(bod_description_filepath, "r", encoding="shift_jis", newline="\r\n") as f:
        previous_line_type: Optional[DescriptionOfWhat] = None  #Gardez une trace de ce que vous lisez.
        latest_action = None

        for line in f:
            line_class = classify_line(line)
            if line_class["type"] == "object name":
                vbo_description = VBODescription(line_class["content"])
                previous_line_type = DescriptionOfWhat.business_object
                continue
            if line_class["type"] == "mode":
                assert vbo_description, "Le mode d'exécution n'est pas décrit dans la bonne position"
                vbo_description.mode = line_class["content"]
                continue
            if line_class["type"] == "article":
                assert vbo_description, "Pas écrit dans le bon format"
                if previous_line_type == DescriptionOfWhat.business_object:
                    vbo_description.description += line_class["content"]
                    continue
                if previous_line_type == DescriptionOfWhat.action:
                    assert latest_action, "Pas écrit dans le bon format"
                    latest_action.description += line_class["content"]
                    continue
                if previous_line_type == DescriptionOfWhat.pre_condition:
                    assert latest_action, "Pas écrit dans le bon format"
                    latest_action.pre_condition += line_class["content"]
                    continue
                if previous_line_type == DescriptionOfWhat.post_condition:
                    assert latest_action, "Pas écrit dans le bon format"
                    latest_action.post_condition += line_class["content"]
                    continue
            if line_class["type"] == "action name":
                assert vbo_description, "Pas écrit dans le bon format"
                if latest_action:
                    vbo_description = append_action_to_vbo_description(
                        latest_action, vbo_description
                    )
                latest_action = VBOActionDescription(line_class["content"])
                previous_line_type = DescriptionOfWhat.action
                continue
            if line_class["type"] == "input parameter":
                assert vbo_description and latest_action, "Pas écrit dans le bon format"
                latest_action.input_params.append(line_class["content"])
                continue
            if line_class["type"] == "output parameter":
                assert vbo_description and latest_action, "Pas écrit dans le bon format"
                latest_action.output_params.append(line_class["content"])
                continue
            if line_class["type"] == "pre condition":
                assert vbo_description and latest_action, "Pas écrit dans le bon format"
                previous_line_type = DescriptionOfWhat.pre_condition
                continue
            if line_class["type"] == "post condition":
                assert vbo_description and latest_action, "Pas écrit dans le bon format"
                previous_line_type = DescriptionOfWhat.post_condition
                continue
            # debug
            logger.debug("line: {}".format(line.strip()))
            if latest_action:
                logger.debug("latest_action: {}".format(latest_action.as_markdown()))
        else:
            #Dernier dernier restant_Collectez l'action
            if latest_action:
                vbo_description = append_action_to_vbo_description(
                    latest_action, vbo_description
                )

    assert vbo_description, "Pas écrit dans le bon format"
    return vbo_description.as_markdown()


if __name__ == "__main__":
    descriptions_folder = Path("output_descriptions")
    for description_file in descriptions_folder.glob("*.txt"):
        with open(descriptions_folder / (description_file.stem + ".md"), "w") as md_f:
            md_f.write(convert_to_markdown(description_file))

URL de référence

Recommended Posts

Générez automatiquement des spécifications d'objets avec Blue Prism
Générer automatiquement un diagramme de relation de modèle avec Django
Les débutants génèrent automatiquement des documents avec le LSTM de Pytorch
Essayez de générer automatiquement des documents Python avec Sphinx
[Evangelion] Essayez de générer automatiquement des lignes de type Asuka avec Deep Learning
Générez automatiquement une table de distribution de fréquence en un seul coup avec Python
Mesurez et comparez les températures avec Raspberry Pi et générez automatiquement des graphiques