Article
· Mar 24 8m read

Python BPL in preview

BPL from 10,000 feet

BPL stands for Business Process Language.
This is an XML format for describing complex information orchestration interactions between systems.
InterSystems Integration engine has for two decades, provided a visual designer to build, configure, and maintain, BPL using a graphical interface.
Think of it like drawing a process flow diagram that can be compiled and deployed.

An example: Make a cup of tea

BPL components are added to Integration productions like any other built-in or custom business component.

Test example input and output

There can be a mixed reception to using BPL diagrams from developers, who sometimes favor code-only business processes.
However when the solution experience is opened up to other skill sets in a team ( Analysts, Project managers, Testing and Support ),  these diagrams become more accessible and visually self-describing than code comments. Simply more people can read and understand a high level picture than follow code. It reduces need for developer time to explain an existing solution. A BPL diagram is the technical summary that is always up to date.
Visually:

  • Evaluate what has been implemented
  • Understand how existing solutions could accommodate new business need
  • See testing collaboration dependencies, criteria, and scope
  • Remind and guide support intervention to deployed solutions

A BPL diagram provides several important constructs:

Request An initial message type from an upstream Service or Process that initiates work. This could be for example an Admission message from a Hospital Information System
Response An optional message type that can be populated during, to transmit to a final message to a downstream process on completion of other work.
Context A collection of properties used to store state between logical activity steps within a BPL diagram
Activities From assignment, running SQL, branching and decision logic to calling other production processes

Opening the designer from Management Portal

Considerations for Python in BPL

An essential principle for adding the new Python capability to BPL is:


        Empower existing BPL solutions to be incrementally enhanced with new Python functionality
 

Consider a single BPL process that interacts with 5 different external systems. If a python only BPL approach had been taken, a complete existing BPL rewrite and retest would be unavoidable.

Even if a full BPL conversion from ObjectScript to Python was trivial, a full UAT retest of a solution may be challenging. This can be expensive in time and constrained by availability of upstream and downstream test systems and departmental domain specialists. So wholesale "converting to Python" may not be cost-effective to enhance existing BPL.
Therefore a Mixed-Language approach has been pursued.
Previously BPL could be implemented in only Object Script or Basic.
Now a BPL can have a top level Language of Object Script but within that is free to implement / configure specific activities in Python using language override. Facilitates access to available Python library capabilities for existing BPL.

Language combinations:

Main Language Language Override Comment
Object Script  -  
Basic Not available  
Python  -  
Object Script Python Mixed
Python Object Script Mixed

New main language option for Python

New Language Override for Activities to mix Object Script and Python.

BPL diagrams now include a new Python Language Icon. A discrete but familiar hint  where Python language is used by activities. Useful during incremental development, but also helps guide future enhancement / support queries. This icon will appear whenever the respective Activity Language Override is set to Python.

Python Import statement reuse

Expressions for Activities in the designer have limited space. For example:

In Python the expectation is to leverage some library. However expressions and conditions have previously been short.
Therefore in the General Tab of the BPL, there is a new import section for python import statements.
Behind the scenes the imports are automatically federated to the context for each Python expression or code activity.

  • So this is providing reuse by managing common import statements in one place
  • Keeps Python expressions short

Additionally when code is deployed to a production system there is a chance that a custom or third party python library is not available. In that case a special error is written to the normal integration event log for the support team.
For example: import library missing in production

When a Python library is missing, by default the business process will be terminated by integration engine. However the support team can find it useful to handle specific errors in a particular way, while a longer term remediation is provided. With this in mind, the Python Import has a specific error that can be handled by standard production settings. For example:

This catches the import error and writes a warning to the integration event  log. Keeps BPL process running in production.

Reply Action "S", suspends the current message and moves on to next message. Keeps process running.

 

Code happens

Instead of discouraging Python code activities, thought has gone into making Python code entry in the BPL designer more productive.
Behind the scenes, each Python code block is wrapped by a Python Try-Except that returns a specific integration error.
In a similar way to code imports, support can manage python runtime code errors by configuring reply code action E#2603.
This allows alerting reporting to differentiate between package import ( DevOps) and run time ( developer code ) errors, for support to engage the right second-line resource for resolution. ie:
Example: A Code Activity in Python that will throw a divide by zero error at runtime.

Configure process to suspend message to handle when runtime error occurs:

Example of error detail captured in Integration Event Log

 

Code Indentation

The BPL designer helps normalize the character used for indentation. This is necessary to wrap developer code in try-except blocks.
So if code is copied and pasted into the designer, the indentation character will be normalized to single whitespace, which keeps Python compilers happy.
The designer provides forward auto-indentation, as you type, to assist the entry of Python code.
For example the following code can be entered without using the space-bar key to indent.

If code indentation is incorrect, the designer validates during save and points out which code line has the problem.
This indentation validation is provided both in the Activity panel and the pop-out Value Editor.

The validation error shows:

  • The source code line number with the problem
  • The actual source code
  • The Python syntax error

 

Code switching ( Object Script to Python )

Object Script uses a single "=" operator for both equality test and assignment.
Where as Python uses "=" for assignment and " == " for equality test.
To mitigate this kind of language context switching problem, the Python code is validated for well formed syntax so any helpful error guidance is displayed through the editor.
Example: Python suggests use of " == " instead of "=".

The error shows:

  • The source code line number with the problem
  • The actual source code
  • The Python syntax error and possible remediation.

IRIS Classname and Method name spell check and hinting

There is no intellisense prompting for Classname and Method names.
Therefore the editor validation has been extended to trap and suggest correct names when the Python code is saved.
This should reduce number of save / compile operations during development, reduce incremental testing and give more confidence in code quality.
The meaning of spell check in this context is to help with US versus UK common spelling differences.
For example consider the word "Color" in US is spelled "Colour" in the UK.
Class and method names are case sensitive and these are validated on save.
Example: Wrong capitalization in class name.

Example: Using "s" instead of "z" in method name.

Substitution hint operations:

Name sequence partial Match hint suggestions
$ or _ %
ise ize
tor ter
cie cei
our or
1 l

The detection of numeric "1" for substitution letter "l" is quite difficult to notice manually.
If IRIS classes or method are missing, these will be flagged.

This behavior works whether single or double quotes are used to specify Classnames in Python code.
The validation skipped for single and multiline comments, so it doesn't get in the way of code entry iteration.
Single line ignore:

Multiline ignore:

Code activity variables

The designer provides Context tab to configure the type for request, response and context base, and context properties.

The following variables are in scope for Python to use in code and expressions:#

Variable Name Type
process Ens.BusinessProcess
context Ens.BP.Context or subclass
request %Library.Persistent or subclass
response %Library.Persistent or subclass
status Ens.Util.PyByRef

These can discovered in generated code and are used like any other embedded python method.
Note that methods may be generated on both the thread and context classes.

The status variable is backed by a new Integration type PyByRef. This allows status values to be passed back to the integration BPL handling code.
To manually set status to a new error message for example in Python code:

status.value=iris.cls('%SYSTEM.Status').Error(5001,"My custom error message")

Notice that "iris" package is availble in python code / expression without explicit import. This is provided automatically by integration BPL handling ie:

import iris
import traceback

Python capable BPL activities:

  • Alert
  • Assign
  • Code
  • Trace
  • If
  • Case
  • Branch
  • Milestone
  • While
  • Until

Some change to be aware of

The BPL schema now supports a new attribute for LanguageOverride

The web application csp static file for supporting the BPL designer have changed to support new Python editing and validation capability.

Conclusions

Whether object script or Python or a mix is chosen for integration implementation, BPL can make the solution more accessible and supportable to a mix of skill types and teams.
BPL is about delegating the container of code, that would normally be a class, to the integration engine in order to focus more on activities representing the business domain problem.
The Python import reuse helps simplify action expressions. This automatically gives error handling that helps to inform the support team and manage workarounds for missing Python dependencies in production.
The designer helps via validation on save, to enter quality Python code blocks and expressions by highlighting the location of detected problems and where possible provide a syntax or IRIS type name spelling code hint.This should reduce iterative testing and improve first draft code productivity during implementation.

To further explore Python BPL capabilities, check out the preview on containers.intersystems.com

Discussion (3)3
Log in or sign up to continue

Many thanks @Alex Woodhead for your article.

For those who want to start with Alex's example, you can use the code below or online (process + production)

/// 
Class python.process.demo Extends Ens.BusinessProcessBPL
{

/// BPL Definition
XData BPL [ XMLNamespace = "http://www.intersystems.com/bpl" ]
{
<process language='python' request='Ens.StringRequest' response='Ens.StringResponse' height='2000' width='2000' >
<pyFromImport>
import requests
</pyFromImport>
<sequence xend='200' yend='1050' >
<switch name='What Drink' xpos='200' ypos='250' xend='200' yend='500' >
<annotation><![CDATA[looking for Drink keyword in request]]></annotation>
<case condition='request.StringValue.lower().find("coffee")&gt;0' name='is coffee' languageOverride='python' >
<assign name="Coffe" property="response.StringValue" value="&quot;Coffee&quot;" action="set" languageOverride="objectscript" xpos='200' ypos='400' />
</case>
<case condition='request.StringValue.lower().find("tea")&gt;0' name='is tea' languageOverride='python' >
<assign name="Tea" property="response.StringValue" value="&quot;Tea&quot;" action="set" languageOverride="objectscript" xpos='470' ypos='400' />
</case>
<default>
<assign name="Chocolate" property="response.StringValue" value="&quot;Chocolate&quot;" action="set" languageOverride="objectscript" xpos='740' ypos='400' />
</default>
</switch>
<if name='Is White' condition='request.StringValue.lower().find("black")==-1' languageOverride="python" xpos='200' ypos='600' xend='200' yend='850' >
<annotation><![CDATA[looking for absence of keyword "black" in request]]></annotation>
<true>
<assign name="Add Milk" property="response.StringValue" value="response.StringValue + &quot; MILK&quot;" action="set" languageOverride="python" xpos='335' ypos='750' />
</true>
</if>
<assign name="Add Hot Water" property="response.StringValue" value="response.StringValue + &quot; HOT WATER&quot;" action="set" languageOverride="python" xpos='200' ypos='950' />
</sequence>
</process>
}

Storage Default
{
<Type>%Storage.Persistent</Type>
}

}