Lesson 15 - 3rd Party Python Packages¶
Goal¶
In this lesson we’ll learn how to import 3rd party Python packages to
use in an operation’s python_action
.
Get Started¶
In this lesson we’ll be installing a 3rd party Python package. In order to do so you’ll need to have Python and pip installed on your machine. You can download Python (version 3.8.7) from here which includes pip by default. If you already have Python but don’t have pip installed on your machine, see the pip documentation for installation instructions.
We’ll also need to add a requirements.txt file to a python-lib folder which is at the same level as the bin folder that the CLI executable resides in. If you downloaded a pre-built CLI the requirements.txt file is already there and we will be appending to its contents.
The folder structure where the CLI executable is should look something like this (other folders omitted for simplicity):
- cslang-cli
- bin
- cslang
- cslang.bat
- content
- CloudSlang ready-made content
- lib
- includes all the Java .jar files for the CLI
- python-lib
- requirements.txt
- bin
And finally, we’ll need a new file, fancy_text.sl in the tutorials/hiring folder, to house a new operation.
Requirements¶
In the requirements.txt file we’ll list all the Python packages we need for our project. In our case we’ll add a package that will allow us to create large lettered strings using ordinary screen characters. The package is called pyfiglet. A quick search on PyPI tells us that the current version (at the time this tutorial was written) is 0.7.2, so we’ll use that one. We also need to install setuptools since pyfiglet depends on it. Each package we need takes up one line in our requirements.txt file.
setuptools
pyfiglet == 0.7.2
Installing¶
Now we need to use pip to download and install our packages.
To do so, run the following command from the python-lib directory:
pip install -r requirements.txt -t .
Note
If your machine is behind a proxy you’ll need to specify the proxy
using pip’s --proxy
flag.
If everything has gone well, you should now see the pyfiglet package’s files in the python-lib folder along with the setuptools files.
Operation¶
Next, let’s write an operation that will let us turn normal text into
something fancy using pyfiglet. All we need to do is import
pyfiglet as we would normally do in Python and use it. We also have
to do a little bit of work to turn the regular string we get from
calling renderText
into something that will look right in our HTML
email.
namespace: tutorials.hiring
operation:
name: fancy_text
inputs:
- text
python_action:
script: |
from pyfiglet import Figlet
f = Figlet(font='slant')
fancy = '<pre>' + f.renderText(text).replace('\n','<br>').replace(' ', ' ') + '</pre>'
outputs:
- fancy
Note
CloudSlang uses the Jython implementation of Python 2.7. For information on Jython’s limitations, see the Jython FAQ.
Step¶
Now we can create a step in the new_hire
flow to send some text to
the fancy_text
operation and publish the output so we can use it in
our email. We’ll put the new step between print_finish
and
send_mail
.
- fancy_name:
do:
fancy_text:
- text: ${first_name + ' ' + last_name}
publish:
- fancy_text: ${fancy}
navigate:
- SUCCESS: send_mail
Use It¶
Finally, we need to change the body of the email to include our new fancy text.
- send_mail:
do:
mail.send_mail:
- hostname: ${get_sp('tutorials.properties.hostname')}
- port: ${get_sp('tutorials.properties.port')}
- from: ${get_sp('tutorials.properties.system_address')}
- to: ${get_sp('tutorials.properties.hr_address')}
- subject: "${'New Hire: ' + first_name + ' ' + last_name}"
- body: >
${fancy_text + '<br>' +
'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '<br>' +
'Missing items: ' + all_missing + ' Cost of ordered items: ' + total_cost + '<br>' +
'Temporary password: ' + password}
navigate:
- FAILURE: FAILURE
- SUCCESS: SUCCESS
Run It¶
We can save the files and run the flow. When the email is sent it should include the new fancy text we added to it.
run --f <folder path>/tutorials/hiring/new_hire.sl --cp <folder path>/tutorials,<content folder path>/base --i first_name=john,last_name=doe --spf <folder path>/tutorials/properties/bcompany.prop.sl
Download the Code¶
Up Next¶
In the next lesson we’ll see how to use a parallel loop.
New Code - Complete¶
new_hire.sl
namespace: tutorials.hiring
imports:
base: tutorials.base
mail: io.cloudslang.base.mail
flow:
name: new_hire
inputs:
- first_name
- middle_name:
required: false
- last_name
- all_missing:
default: ""
required: false
private: true
- total_cost:
default: '0'
private: true
- order_map:
default: '{"laptop": 1000, "docking station": 200, "monitor": 500, "phone": 100}'
workflow:
- print_start:
do:
base.print:
- text: "Starting new hire process"
navigate:
- SUCCESS: create_email_address
- create_email_address:
loop:
for: attempt in range(1,5)
do:
create_user_email:
- first_name
- middle_name
- last_name
- attempt: ${str(attempt)}
publish:
- address
- password
break:
- CREATED
- FAILURE
navigate:
- CREATED: get_equipment
- UNAVAILABLE: print_fail
- FAILURE: print_fail
- get_equipment:
loop:
for: item, price in eval(order_map)
do:
order:
- item
- price: ${str(price)}
- missing: ${all_missing}
- cost: ${total_cost}
publish:
- all_missing: ${missing + not_ordered}
- total_cost: ${str(int(cost) + int(spent))}
break: []
navigate:
- AVAILABLE: check_min_reqs
- UNAVAILABLE: check_min_reqs
- check_min_reqs:
do:
base.contains:
- container: ${all_missing}
- sub: 'laptop'
navigate:
- DOES_NOT_CONTAIN: print_finish
- CONTAINS: print_warning
- print_warning:
do:
base.print:
- text: >
${first_name + ' ' + last_name +
' did not receive all the required equipment'}
navigate:
- SUCCESS: print_finish
- print_finish:
do:
base.print:
- text: >
${'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '\n' +
'Missing items: ' + all_missing + ' Cost of ordered items: ' + total_cost}
navigate:
- SUCCESS: fancy_name
- fancy_name:
do:
fancy_text:
- text: ${first_name + ' ' + last_name}
publish:
- fancy_text: ${fancy}
navigate:
- SUCCESS: send_mail
- send_mail:
do:
mail.send_mail:
- hostname: ${get_sp('tutorials.properties.hostname')}
- port: ${get_sp('tutorials.properties.port')}
- from: ${get_sp('tutorials.properties.system_address')}
- to: ${get_sp('tutorials.properties.hr_address')}
- subject: "${'New Hire: ' + first_name + ' ' + last_name}"
- body: >
${fancy_text + '<br>' +
'Created address: ' + address + ' for: ' + first_name + ' ' + last_name + '<br>' +
'Missing items: ' + all_missing + ' Cost of ordered items: ' + total_cost + '<br>' +
'Temporary password: ' + password}
navigate:
- FAILURE: FAILURE
- SUCCESS: SUCCESS
- on_failure:
- print_fail:
do:
base.print:
- text: "${'Failed to create address for: ' + first_name + ' ' + last_name}"
fancy_text.sl
namespace: tutorials.hiring
operation:
name: fancy_text
inputs:
- text
python_action:
script: |
from pyfiglet import Figlet
f = Figlet(font='slant')
fancy = '<pre>' + f.renderText(text).replace('\n','<br>').replace(' ', ' ') + '</pre>'
outputs:
- fancy