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).
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)
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))
Recommended Posts