Best practices in creating Python robots
TL;DR
Do:
- Always keep readability in mind.
- Keep functions short and sweet.
- Use classes and modules as namespaces to separate concerns.
Don't:
- Create heavily nested loops.
- Write functions that do many things.
What is pythonic code?
When googling around and reading about Python, you very quickly see the term pythonic. It means code that follows the established conventions of the language. Pythonic Python code is clean, uses Python idioms, and follows Python style guidelines.
With Robot Framework, you can write task suites using almost natural language (e.g., English). Python's syntax is very close to written English too, and that's why it's so easy to start writing code in it.
Embracing best practices is equally important when writing pure Python robots, as it is when writing Python keyword libraries for your Robot Framework robot.
See also the article on naming best practices.
Why?
You might ask: What does all of this matter? Isn't it enough that the code works?
Short answer: Not really.
Nitpicking about idioms and code style might seem like unnecessary work, but really, it's not! When following established conventions, your code will be:
- Readable (by other Python programmers).
- Maintainable (by you or by your colleagues).
- Testable.
- Robust.
Python style and idioms
Python has well-established ways of writing code. Obligatory reading for every Python programmer is the Python Style Guide (PEP8).
When writing PEP8-compliant code, you know your code will look familiar and readable for other Python programmers too.
Useful tools to help with Python style are (among others):
- pycodestyle (PEP8 checker)
- pylint (more general linter)
- black (autoformats your code)
You can find these as editor plugins for your favorite code editor too.
Robot Framework specifics
Something to note when using Robot Framework: when creating a Python
keyword library, the module name must correspond to the class name (in CamelCase
). This goes against PEP8 but is a Robot Framework convention.
Here's an example module DoNothingLibrary.py
:
Idioms
When coming from another language, e.g., Java, it might be tempting to start writing Python code that looks like Java. Instead, it's good practice to start learning pythonic idioms from the beginning, like list comprehensions:
So for example, instead of writing:
You would write:
Read more about Python code style.
Code structuring
The basic unit of code in Python is a function. Functions can be grouped together in a module. You create your application by calling these functions.
There are also many reasons to put your functions inside a class (inside a module).
For example, in Robot Framework, the convention is to put the Python keywords inside a class, which is a natural way to tightly group functionality.
Example:
Module AccountingSystem.py
:
Module EmailComposer.py
:
Module tasks.py
:
Unit testing
When creating Python robots or Python libraries, it's a very good practice to write unit tests for your code.
Writing a unit test is not difficult per se. Writing good unit tests requires some thought and, most essentially, a testable codebase. Writing unit tests helps you write better code.
Try to avoid any shared state between objects and global variables. Ideal code (at least from the perspective of testing) is purely functional code. A pure function is deterministic and has no side effects.
An example of a not very testable function:
The function multiply
does not return the same value every time (because of the use of randint
). It also uses a variable value outside its scope. Of course, a shared state is sometimes needed, but then you should use classes and still be very careful with handling the state.
To make this testable, you could refactor the code like this:
To test this code, you would then write:
Now our code is pulled out into a deterministic function with no side effects. Testing this trivial function is, well, trivial. Testing function_representing_some_outside_system
is not unit testing at all, as it represents an external system (e.g., a system under RPA).
The testing framework that we recommend is Pytest.
Exception handling
If in your code there is a possibility for failure, you should prepare for it. Use try-except
blocks.
The most simple case in the context of RPA follows this pattern:
At its simplest, action_on_fail
might be "do nothing".
Logging
When using Python with Robot Framework, you can use Robot Framework's logger:
These will be printed in the Robot Framework log file.
When writing pure Python robots, you will have to take care of logging yourself.
Here is an example of how to configure your logger:
Summary
Following best practices makes your Python-based robots more readable, maintainable, testable, and robust. Once you have learned the best practices, you can apply them in all your future projects, even outside the automation domain. A worthy investment indeed!