Handler - Expression
Expression handler uses a Python expression in generating a value for the parent attribute. The handler evaluates the expression and returns the result automatically in the parent attribute's data field after the data card is saved. Note that HTML tags within the result are not escaped.
Custom modules can be saved to the directory defined as platform setting python.path. See an example below.
ExpressionHandler doesn't work on required attributes.
ExpressionHandler works on multivalue attributes. On multivalue attributes existing values are replaced by values created by ExpressionHandler. Note that if ExpressionHandler produces multiple values on a single value attribute saving of data card fails.
Default label for Expression handler's button is value of presentation text text_calculate. Label value can be overwritten in template's localization editor.
For information about Python, please visit https://www.python.org . In the following address https://wiki.python.org/moin/BeginnersGuide/ you can find Beginner's Guide to Python.
You can use the Expression handler, for example, to perform calculations on another attribute values denoted by their individual attribute codes in the parent attribute's metadata.
Expression handler can be used on reference attribute. If expression returns a PythonEntity that is used to set reference value. If expression returns String that is used to search target data card.
For example, to calculate an average from the attribute Q1, Q2, Q3, and Q4, attach the Expression handler to an attribute Average and denote the following Python expression in the Average 's metadata: ([attributeCodeQ1]+[attributeCodeQ2]+[attributeCodeQ3]+[attributeCodeQ4])/4 . Expression handler calculates the average of the denoted attribute values and indicates it as the value of the Average attribute as illustrated in following picture.
A value Average generated with Expression handler:

The following tables provide information on the attribute settings and metadata requirements for Expression handler. Compulsory metadata is provided in a Required attribute metadata table.
Configuration of Expression handler varies from other handlers. Needed metadata names are given, admin must give the values only.

Table 1. Attribute Settings
| Handler name | Datatype |
|---|---|
Expression |
Any datatype, except embedded reference or back reference.
|
Table 2. Required Attribute Metadata
| Name | Value | Description |
|---|---|---|
expression |
[Python expression] |
A valid Python expression (or script if If the expression cannot be parsed, a referenced attribute value is empty or an error occurs, the result will be empty. |
isScript |
[Checked | unchecked] |
When this option is checked, expression is interpreted as a Python script. Scripts are more powerful than expressions and can contain multiple lines, loops and other control structures. Also they are more complex to configure. Check examples of scripts below. If you want to interpret the expression as a script, check this box. The result value must be set into a variable More example configurations available below. |
Table 3. Optional Attribute Metadata
| Name | Value | Description |
|---|---|---|
debug |
true/false |
By default, " Note: Do NOT use this in production environment. This may fail all data card stores such as multi edit, move, trashing and emptying trashcan if expression happens to be broken. |
showButton |
true/false |
By default, count button is shown. If this metadata is set to false, the count button will not be shown. Button calculates values (stored in a _result) only for a current attribute. |
alwaysExecute |
true/false |
If this is true, the expression will be executed (as root) always when the data card is saved. Default is false: expression will be executed (as current user) only if the user who saves the card has privileges for this attribute. |
searchAttribute |
attributeCode |
Attribute code of target template(s). Reference search is restricted to this attribute. This setting can be used when Note: This attribute has to be unique in target template(s). Note: If |
createEmptyReferences |
true/false |
If this is true and reference target data card is not found, it will be created and saved into folder configured in referenceTargetFolder metadata. This setting can be used when ExpressionHandler is used on reference attribute and referenceTargetFolder has value. |
referenceTargetFolder |
folderCode |
Code of folder were reference target data cards will be created. This setting can be used when ExpressionHandler is used on reference attribute and createEmptyReferences is true. |
isHtmlOutput |
true/false |
By default, the result of an expression is a regarded as string. If this metadata is set to Note: This setting is meaningful for string and text attributes only. Note: This setting is not available in E6 series product family |
executeEarly |
true/false |
By default, the expression is run at the same time as other handlers after default values are set and conditional attributes (" Note: This metadata is not intended to be used with
When the metadata is set to true, the following is made possible:
Note: The metadata is designed for the use case described above; therefore, other use cases are not supported. |
executeLate |
true/false |
By default, the expression is run at the same time as other handlers after default values are set and conditional attributes (" Note: This metadata is not intended to be used with
When the metadata is set to
Note: The metadata is designed for the use case described above; therefore, other use cases are not supported. |
Expression handler also allows access to referenced data cards. The current card can be referred with this, and other data cards by their the class attribute code configured in the parent card. Currently supported methods for referred data cards are:
Table 4. Data Card Access Methods
| Name | Returns | Example |
|---|---|---|
get(attributecode) |
Single value found in the field with the given attribute code. If the attribute is multivalued, first value is returned. If attribute is a reference, a PythonEntity object is returned. |
this.get("$support_person:email$") |
getAll(attributecode) |
Array containing values found in the field with the given attribute code. If attribute is a reference, an array of PythonEntity object is returned. |
max(getAll("product_prices")) |
getTemplateName() |
Single String value containing the name of the template for the data card. | this.getTemplateName() |
getTemplateCode() |
Single String value containing the code of the template for the data card. | this.getTemplateCode() |
getFolderCode() |
Single String value containing the code of the folder to where the data card is saved. If imported data card xml contains value for this attribute, it will be recalculated to be correct. | this.getFolderCode() |
getFolderName() |
Single String value containing the name of the folder to where the data card is saved. If imported data card xml contains value for this attribute, it will be recalculated to be correct. | this.getFolderName() |
getFolderModuleCode() |
Single String value containing the module's code where this data card is stored. Possible values are: equipment - CMDB; contract - Contract; job - Service Desk; solution - Solution; change - Change Management; procurement - Procurement; client - Organization; admin - Users; system - internal system data cards only. Available modules are enabled by licensing. Some products may be obsolete and not available anymore. |
this.getFolderModuleCode() |
getEntityId() |
Single String value containing the id of the data card. Return value of this method can be used to verify if the data card was saved or not. If the return value is equal to 'none' then data card was not saved yet. |
this.getEntityId() |
getReferrers(templateCode) |
Array containing PythonEntities that are associated with a template specified by templateCode. If the parameter is left blank, then the method is returning an array containing PythonEntities that are associated with all templates. |
this.getReferrers('incident') this.getReferrers() |
isHidden() |
Single true/false value. Return value of this method can be used to verify if the data card is hidden or not. |
this.isHidden() |
Table 5. Data Card Manipulation Methods
| Name | Functionality | Example |
|---|---|---|
set(attributecode, value) |
Changes the value of an attribute. Note: Do not change values of referred data cards or use reference paths. Note: Do not change values of referred data cards or use reference paths.
|
this.set("priority", 1) |
add(attributecode, value) |
Adds a value to an attribute. Note: Do not change values of referred data cards or use reference paths. Please check details from |
this.add("keywords", "email") |
Script Examples
Lets assume: 1) "car" is a multivalue reference of _this_ template 2) "limit" an integer attribute of _car_ template 3) Get a limit from single car reference:
car.get("car_limit")Calculate total sum of cars' limits. This requires the isScript option:
_result=0
for i in car:
_result+=i.get("car_limit")Decide field value based on two others. Requires isScript option:
_result='No'
if client_status=='Accepted' and dealer_status=='Yes':
_result='Yes'Visibility of a data card (either this or data card found with data card access methods) can be checked with method isHidden. Note that if you check the visibility of the data card where the attribute belongs to, the attribute with the DatacardHiddenState handler has to be before the Expression attribute for method to work!
if this.isHidden():
_result = 'This data card is hidden'
car = this.get("car")
if car.isHidden():
_result = 'Car is hidden'
else:
_result = 'Car is visible'With equals function you can find out, e.g., if two references refer to the same data card.
ref1 = this.get("ref1")
ref2 = this.get("ref2")
if ref1 != None and ref2 != None:
if ref1.equals(ref2):
_result = 'Ref1 and ref2 refer to the same data card'
else:
_result = 'Ref1 and ref2 refer to different data cards' Attributes with No Values
The script below demonstrates the way of checking that a certain attribute has a value. If there is no attribute with code myDate1 or myDate2, or if this data card doesn't have a value for both of those attributes, the result will be 0. If both attributes exist and they have a value, 1 is returned.
date1 = this.get("myDate1")
date2 = this.get("myDate2")
if date1 is None or date2 is None:
_result = 0
else:
_result = 1 To use a shorter form of checking if an attribute has a value, use this (here, attr_code is the attribute's code):
if attr_code:
_result = '...'To check if an attribute does not have a value, use this (here, attr_code is the attribute's code):
if not attr_code:
_result = '...'Handling Strings with Special Characters
To avoid producing illegal characters, instead of special characters, it is recommended to always use u prefix before unicode strings For example:
_result = u'Text with some special characters like: ä, ö, ź, ć, ę, ð etc.' It is also essential to use u prefix when comparing strings. Following comparison will always return false value:
string_attribute_value == 'ää' The comparison above should be done like this:
string_attribute_value == u'ää' Generating Random Numbers
Let's assume the code of the attribute is "random_figure" and we want to count the figure once. The script here will give you a number between 1 and 100. isScript option is needed to import modules.
import random
if random_figure is None:
_result = random.randint(1, 100)
else:
_result = random_figure Calculating with Dates
A special DateUtil class can be used to calculate with dates. DateUtil.daysBetween(date1, date2) calculates how many days there are between date1 and date2. Similar methods for all date ranges:
DateUtil.yearsBetween(date1, date2)
DateUtil.monthsBetween(date1, date2)
DateUtil.daysBetween(date1, date2)
DateUtil.hoursBetween(date1, date2)
DateUtil.minutesBetween(date1, date2)
DateUtil.secondsBetween(date1, date2)DateUtil.addDays(date, number) adds given amount of days to the given date and returns the new date. If given number is negative, days will be subtracted from the given date. Similar methods exist for other date ranges too:
DateUtil.addYears(date, number)
DateUtil.addMonths(date, number)
DateUtil.addDays(date, number)
DateUtil.addHours(date, number)
DateUtil.addMinutes(date, number)
DateUtil.addSeconds(date, number)DateUtil.currentDate() returns the current date and current time. This can be used with other methods, as for example in the expression below:
_result = DateUtil.addHours(DateUtil.currentDate(), this.get("priority_high") In this case the expression adds the amount of hours in field "priority_high" to current date.
References and Reference Paths
There are two ways to get values from references. Suggested way is to use reference paths. With this $code1:code2$ notation you don't need to check if the value for code1 really exist. If you're manipulating Company-value, you must add a None check for it. Naturally, all codes must be written correctly. You can use this.getAll("$person:company$") to get multiple values.
this.get("$person:company$") Following example is an old and obsolete way that is not suggested anymore. By getting each path item separately you need to add None-checks for each item (this.get("person") != None).
this.get("person").get("company") Changing Values of Other Attributes
Setting a single value
this.set("priority", 1)
this.set("description", (description or "") + "\n(For more information, contact service desk)") Setting multiple values
this.set("keywords", ["email", "communication"])Adding values
this.add("keywords", "email")
---
this.add("keywords", ["email", "communication"])
---
if this.get("rollback_count") == None:
this.set("rollback_count", 0)
else:
this.set("rollback_count", (this.get("rollback_count")+1)) Copying values from reference paths
this.set("prices", this.getAll("$items:price$"))
this.set("total_price", sum(this.getAll("$items:price$") or []))Emptying values
this.set("keywords", None)
this.set("keywords", [])
# Calling add with the same parameters doesn't do anything.Attributes with CommentHandler
CommentHandler saves comments as data cards. For expressions comments are returned as PythonComments. PythonComment has methods for getting comment message, author and date. Author of a comment is reference to person data card. Author is returned as PythonEntity. Date is returned as date time values for any other entity data. Comments cannot be edited in expressions. Existing comments cannot be set as target values of any reference attribute (i.e. they cannot be moved). CommentUtil can be used to create a new comment. Comment message must be given when creating a comment. New comments can be added to a CommentHandler attribute (set method is not supported). Date is set to timestamp of comment creation. Author is set to be person data card of current user. If current user does not have a person data card, creation of comment fails.
Permissions to comments are given based permissions of CommentHandler attribute. Normally users don't have permissions to comment data cards themselves. Users might not have permissions to authors either. For these reasons it might be necessary to set alwaysExecute metadata in some cases to expressions handling comments.
Table 6. PythonComment Access Methods
| Method | Returns |
|---|---|
getAuthor() |
PythonEntity |
getComment() |
Comment message as String value. |
getDate() |
Timestamp of comment creation as Date. |
getType() |
The comment's type as String value. The value is 'file-attached' for comments that are created automatically when users attach files. Other possible types are 'user-written' and 'pythonapi-generated'. |
setComment |
Sets comment's message. Can be used to change message of an existing comment. Message can be emptied but not set to null. |
Table 7. CommentUtil Methods
| Method | Returns | Example |
|---|---|---|
createComment(message) |
Returns PythonComment that contains comment message given as parameter. Author will be current user's person data card and date the creation timestamp |
CommentUtil.createComment(message) |
createComment(message, date, author, type) |
Creates a
The
The
The |
CommentUtil.createComment(message) |
deleteComment(comment) |
Deletes underlying comment entity represented by PythonComment given as parameter. Deletion makes PythonComment instance unusable (don't call its getters/setters, set it as value of a CommentHandler attribute or try to delete it again). |
CommentUtil.deleteComment(comment) |
Table 8. Comment Related PythonEntity Methods
| Method | Returns | Example |
|---|---|---|
getAllCommentsOrdered(attribute_code) |
Returns comments as PythonComments ordered from latest to oldest from a comment handler attribute |
this.getAllCommentsOrdered("ngss_comments") |
getLatestComment(attribute_code) |
Returns latest comment as PythonComment from a comment handler attribute |
this.getLatestComment("ngss_comments") |
Below are some examples of comments used in expressions.
Sets all non-null authors to another multivalue reference field.
_result = []
comments = this.getAll("ngss_comments")
for comment in comments:
if comment.getAuthor() != None:
_result.append(comment.getAuthor())Creates a new comment and attaches it a CommentHandler attribute:
this.add("ngss_comments", CommentUtil.createComment("Added by expression"))Creates a new comment with a specific date, author and type and attaches it a CommentHandler attribute:
this.add("ngss_comments", CommentUtil.createComment("Added by expression", "2020-01-01", "admin", "pythonapi-generated")) Deletes a comment based on value in comment message:
comments = this.getAll("ngss_comments")
for comment in comments:
if comment.getComment() != None and 'secret' in comment.getComment():
CommentUtil.deleteComment(comment)Empties comment messages based on value in them:
comments = this.getAll("ngss_comments")
for comment in comments:
if comment.getComment() != None and 'secret' in comment.getComment():
comment.setComment('') Fetches all comments from this entity ordered by creation time in descending order:
comments = this.getAllCommentsOrdered("ngss_comments")
for comment in comments:
if comment.getComment() != None:
comment.getComment() Fetches the latest comment:
comment = this.getLatestComment("ngss_comments")
if comment != None and comment.getComment() != None:
comment.getComment()Using Custom Modules
Defining a module: Create file stringutils.py with the following contents into the directory indicated by platform setting python.path:
def reverse(value):
if value is None:
return None
else:
return str(value)[::-1]Importing and using a module. isScript option is needed to import modules.
import stringutils
_result = stringutils.reverse(attribute_to_be_reversed)Importing and using functions form a module. Multiple functions can be imported by separating the function names by commas.
from stringutils import reverse
_result = reverse(attribute_to_be_reversed)While developing modules, use reload(module) to apply changes in the module file. Reloading a module will decrease performance so remove the line when the module is ready to be used in production environment.
import stringutils
reload(stringutils) #remove this line when module is readyPython Version
Python version can be controlled with platform setting python.version. Check current version with this.
import sys
_result = sys.versionTable of Contents