###  1 Create a package  ï


Optionally, you can set a descriptor for the parameter. Descriptors allow you
to specify a text description of the parameter and its constraints, like
making it read-only, specifying a range, etc. For that to work, the ` __init__
` code has to be changed to:


Real Python
Start Here
 Learn Python
More
Search
— FREE Email Series —


yamllint: A linter for YAML, which can check the syntax and more
yq: A command-line YAML processor based on jq, for filtering data
shyaml: An alternative command-line YAML processor
These are all Python tools, but there’s also a widespread Go implementation of yq, which has a slightly different command-line interface. If you can’t or don’t want to install those programs, then you can always use one of the tools available online, such as:


import sys


numbers: !!set
  ? 5
  ? 8
  ? 13


Fun Fact: The official yaml.org website is written as a valid YAML document.


    def main():
        rclpy.init()
        node = MinimalParam()
        rclpy.spin(node)

    if __name__ == '__main__':
        main()


You know it went well if you get the output ` Set  parameter  successful  ` .
If you look at the other terminal, you should see the output change to `
[INFO]  [minimal_param_node]:  Hello  earth!  `


**[ Check out the course here ](https://rbcknd.com/ros2-for-beginners) **


Output.yaml
CopyName: John Doe
Position: DevOps Engineer
Location: England
Age: '26'
Experience:
  GitHub: Software Engineer
  Google: Technical Engineer
  Linkedin: Data Analyst
Languages:
  Markup:
  - HTML
  Programming:
  - Python
  - JavaScript
  - Golang
You can also create multiple blocks of yaml data from a Python object, such as a list of dictionaries into a single stream, where each dictionary is represented as a YAML document. To do this, you can use the dump_all() function.


ros2 run python_parameters minimal_param_node


Taking a Crash Course in YAML
In this section, you’re going to learn the basic facts about YAML, including its uses, syntax, and some of its unique and powerful features. If you’ve worked with YAML before, then you can skip ahead and continue reading from the next section, which covers using YAML in Python.


A great thing about ROS2 params, is that you can modify them at any time. And
there is a simple way to notify your node when a param is modified.


Use the ` get_parameter(name) ` method to get the value for one declared
parameter. In fact, this method won’t return the value, it will return a
Parameter object. The value is stored in the “value” attribute of the
Parameter, as you can see when we print the params with the rclpy logger.


>>> with open("sample.yaml", mode="rt", encoding="utf-8") as file:
...     print(yaml.safe_load(file))
...
{'name': 'Иван'}


from dataclasses import dataclass


script.py
Copydef read_and_modify_one_block_of_yaml_data(filename, key, value):
    with open(f'{filename}.yaml', 'r') as f:
        data = yaml.safe_load(f)
        data[f'{key}'] = f'{value}'
        print(data)
    print('done!')

read_and_modify_one_block_of_yaml_data('output', key='Age', value=30)
Output{'Name': 'John Doe', 'Position': 'DevOps Engineer', 'Location': \
'England', 'Age': '30', 'Experience': {'GitHub': 'Software Engineer', \
'Google': 'Technical Engineer', 'Linkedin': 'Data Analyst'}, \
'Languages': {'Markup': ['HTML'], 'Programming': \
['Python', 'JavaScript', 'Golang']}}
done!
You can optionally write the modified data into another file. The code below writes the modified data into another file output5.yaml.


Cookie Settings  Accept All


Open another terminal, source the setup files from inside ` ros2_ws  ` again,
and enter the following line:


To resolve potential ambiguities, you can cast values to specific data types by using YAML tags, which start with the double exclamation point (!!). There are a few language-independent tags, but different parsers might provide additional extensions only relevant to your programming language. For example, the library that you’ll be using later lets you convert values to native Python types and even serialize your custom classes:


ros2 pkg create --build-type ament_python python_parameters --dependencies rclpy


42

pi

3.14

e

2.72

A single list item gets wrapped between the
 and
 tags, while a key-value mapping takes advantage of the description list (
), which contains alternating terms (
) and definitions (
). This is the tricky part because it requires counting the subsequent YAML events on a given nesting level to determine whether an event should become a term or a definition in HTML.


####  Privacy Overview


>>> print(yaml.dump(3.14, Dumper=yaml.CDumper))
3.14
For example, the pure Python dumper appends optional dots at the end of a YAML document, while a similar wrapper class for the LibYAML library doesn’t. However, these are cosmetic differences that have no real impact on serialized or deserialized data.


Menu


Master Real-World Python Skills
With Unlimited Access to Real Python


>_pip3 show pyyaml
If the PyYAML installation was successful, you should get a similar output.


That’s when JSON entered the picture. It was built from the ground up with data serialization in mind. Web browsers could parse it effortlessly because JSON is a subset of JavaScript, which they already supported. Not only was JSON’s minimalistic syntax appealing to developers, but it also made porting to other platforms easier than XML did. To this day, JSON remains the slimmest, fastest, and most versatile textual data interchange format on the Internet.


Functional


Declaring a parameter does not mean you set a value, it just means that this
parameter exists.


>>> yaml.safe_load(io.BytesIO(b"name: \xd0\x98\xd0\xb2\xd0\xb0\xd0\xbd"))
{'name': 'Иван'}
As you can see, the loading functions in PyYAML are quite versatile. Compare this with the json module, which provides different functions depending on the type of your input argument. However, PyYAML bundles yet another set of functions that may help you read more than one document from a stream. You’ll learn about those functions now.


Let’s add parameters when we start the node with ` ros2 run ` :


import codecs


How to Read YAML Files With safe_load()
The safe_load() function is used to read YAML files with the PyYAML library. The other loader you can use but is not recommended is the load() function.


Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.


To leverage PyYAML tags, which are provided by the library, use either FullLoader or UnsafeLoader because they’re the only loaders that can handle Python-specific tags:


If you’d like to only fold lines with indentation determined by the first line in a paragraph, then use the greater than sign (>) indicator:


>>> from colorize import tokenize
>>> for token in tokenize("key: !!str value"):
...     print(token)
...
(0, 3, KeyToken())
(5, 10, TagToken(value=('!!', 'str')))
(11, 16, ValueToken())
Neat! You can take advantage of these tuples to annotate tokens in the original text using a third-party library or ANSI escape sequences as long as your terminal supports them. Here are a few sample colors with their escape sequences:


[INFO] [custom_minimal_param_node]: Hello earth!


At the same time, YAML lets you leverage an alternative inline-block syntax borrowed from JSON. You can rewrite the same document in the following way:


def visit(node):
    if isinstance(node, yaml.ScalarNode):
        return node.value
    elif isinstance(node, yaml.SequenceNode):
        return [visit(child) for child in node.value]
    elif isinstance(node, yaml.MappingNode):
        return {visit(key): visit(value) for key, value in node.value}
Place this function in a Python script named tree.py, as you’ll be developing the code. The function takes a single node and, depending on its type, returns its value or enters a relevant subtree. Note that mapping keys must also be visited, because they can be non-scalar values in YAML.


XML	JSON	YAML
Adoption and support	⭐⭐⭐⭐	⭐⭐⭐⭐	⭐⭐
Readability	⭐⭐	⭐⭐⭐	⭐⭐⭐⭐
Read and Write Speed	⭐⭐	⭐⭐⭐⭐	⭐
File Size	⭐	⭐⭐⭐	⭐⭐
When you look at Google Trends to track interest in the three search phrases, then you’ll conclude that JSON is the current winner. However, XML isn’t far behind, with YAML attracting the least interest. Also, it looks like XML’s popularity has been on a steady decline ever since Google started collecting data.


In another terminal:


In those rare cases, the library exposes its inner workings to you through several low-level functions. There are four ways to read a YAML stream:


Updated: October 18, 2023


exercises:
  - muscles: &push-up
      - pectoral
      - triceps
      - biceps
  - muscles: &squat
      - glutes
      - quadriceps
      - hamstrings
  - muscles: &plank
      - abs
      - core
      - shoulders


Taking a Crash Course in YAML
Historical Context
Comparison With XML and JSON
Practical Uses of YAML
YAML Syntax
Unique Features
Getting Started With YAML in Python
Serialize YAML Documents as JSON
Install the PyYAML Library
Read and Write Your First YAML Document
Loading YAML Documents in Python
Choose the Loader Class
Compare Loaders’ Features
Explore Loaders’ Insecure Features
Load a Document From a String, a File, or a Stream
Load Multiple Documents
Dumping Python Objects to YAML Documents
Choose the Dumper Class
Dump to a String, a File, or a Stream
Dump Multiple Documents
Tweak the Formatting With Optional Parameters
Dump Custom Data Types
Parsing YAML Documents at a Low Level
Tokenize a YAML Document
Parse a Stream of Events
Build a Tree of Nodes
Conclusion
Remove ads
 Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: YAML: Python's Missing Battery


Most loaders are smart about deserializing scalars into auxiliary types, which are more specific than a basic string, list, or dictionary:


Line 6 defines a variable to hold the last token instance. Only the scalar and tag tokens contain a value, so you must remember their context somewhere to choose the right color later. The initial value accounts for when the document contains only a scalar without any context.
Line 7 loops over the scanned tokens.
Lines 8 and 9 extract the token’s position within the text from the index markers available on all tokens. The token’s position is delimited with start and end.
Lines 10 to 13 check the current token type and yield the indices and a token instance. If the token is a tag, then it gets yielded. If the token is a scalar, then last_token is yielded because scalars can appear in different contexts, and you need to know what the current context is to select the appropriate color.
Lines 14 and 15 update the context if the current token is either a mapping key or a value. Other token types get ignored, as they don’t have a meaningful visual representation.
When you import your function into an interactive Python interpreter session, then you should be able to start iterating over the subset of tokens with their relevant indices:


{"!model!": "tag:yaml.org,2002:python/object:models."}
Specifying such a mapping will add a relevant tag directive into your dumped document. Tag handles always begin and end with an exclamation point. They’re a shorthand notation for full tag names. For example, these are all equivalent ways of using the same tag in a YAML document:


>>> with open("/path/to/file.yaml", mode="wb") as file:
...     yaml.dump(data, file, encoding="utf-8")
When you open a file in text mode, then it’s always a good practice to explicitly set the character encoding. Otherwise, Python will assume your platform’s default encoding, which might be less portable. Character encoding has no meaning in binary mode, which deals with bytes that are already encoded. Still, you should set the encoding through the yaml.dump() function, which accepts many more optional parameters, which you’ll learn about soon.


Note: Had your YAML contained multiple documents, then load() or its wrappers would raise an exception.


# yaml2html.py


# models.py


Let’s define a list of dictionaries called data2.


Naturally, you’ve only scratched the surface here, as YAML has plenty of much more advanced features to offer. You’ll learn about some of them now.


Explore Loaders’ Insecure Features
PyYAML lets you serialize and deserialize any picklable Python object by tapping into its interface. Bear in mind that this allows for arbitrary code execution, as you’ll soon find out. However, if you don’t care about compromising your application’s security, then this capability can be pretty convenient.


The safe_load() function is one of several shorthand functions that encapsulate the use of various YAML loader classes under the hood. In this case, that single function call translates to the following more explicit yet equivalent code snippet:


>>> import yaml
>>> for token in yaml.scan("Lorem ipsum", yaml.SafeLoader):
...     print(token)
...     print(token.start_mark)
...     print(token.end_mark)
...
StreamStartToken(encoding=None)
  in "<unicode string>", line 1, column 1:
    Lorem ipsum
    ^
  in "<unicode string>", line 1, column 1:
    Lorem ipsum
    ^
ScalarToken(plain=True, style=None, value='Lorem ipsum')
  in "<unicode string>", line 1, column 1:
    Lorem ipsum
    ^
  in "<unicode string>", line 1, column 12:
    Lorem ipsum
               ^
StreamEndToken()
  in "<unicode string>", line 1, column 12:
    Lorem ipsum
               ^
  in "<unicode string>", line 1, column 12:
    Lorem ipsum
               ^
The token’s .start_mark and .end_mark attributes contain all the relevant information. That’s perfect if you want to implement a YAML syntax highlighter plugin for your favorite code editor, for example. In fact, why don’t you go ahead and build a bare-bones command-line tool for printing YAML content in color?


Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: YAML: Python's Missing Battery


Sequences in YAML are just like Python lists or JSON arrays. They use the standard square bracket syntax ([]) in the inline-block mode or the leading dashes (-) at the start of each line when they’re block indented:


YAML	Python	Description
Don''t\n	Don''t\\n	Unquoted strings are parsed literally so that escape sequences like \n become \\n.
'Don''t\n'	Don't\\n	Single-quoted strings only interpolate the double apostrophe (''), but not the traditional escape sequences like \n.
"Don''t\n"	Don''t\n	Double-quoted (") strings interpolate escape sequences like \n, \r, or \t, known from the C programming language, but not the double apostrophe ('').
Don’t worry if that looks confusing. You’ll want to specify unquoted string literals in YAML for the most part, anyway. One notable exception would be declaring a string that the parser could misinterpret as the wrong data type. For example, True written without any quotation marks might be treated as a Python Boolean.


Therefore, you might consider using a different library than PyYAML in your production code for peace of mind.


text: Lorem ipsum
   dolor sit amet


It’s a dynamic web page that uses JavaScript to communicate over the network with a minimal HTTP server written in FastAPI. The server expects a JSON object with all but the tags keyword argument and calls yaml.dump() against the following test object:


class User:
    __slots__ = ["name"]


import datetime
import json


>>> yaml.safe_load("""
... married: false
... spouse: null
... date_of_birth: 1980-01-01
... age: 42
... kilograms: 80.7
... """)
{
    'married': False,
    'spouse': None,
    'date_of_birth': datetime.date(1980, 1, 1),
    'age': 42,
    'kilograms': 80.7
}
Here, you have a mix of types, including a bool, a None, a datetime.date instance, an int, and a float. Again, BaseLoader is the only loader class that treats all scalars as strings at all times.


Reading Function	Return Value	Lazy?
yaml.scan()	Tokens	✔
yaml.parse()	Events	✔
yaml.compose()	Node
yaml.compose_all()	Nodes	✔
All of these functions accept a stream and an optional loader class, which defaults to yaml.Loader. In addition to this, most of them return a generator object, letting you process YAML in a streaming fashion, which wasn’t possible up to this point. You’ll learn about the differences between tokens, events, and nodes a bit later.


The terminal should return the following message every second:


    entry_points={
        'console_scripts': [
            'minimal_param_node = python_parameters.python_parameters_node:main',
        ],
    },


Moreover, you can use the !!binary tag to embed Base64-encoded binary files such as images or other resources, which will become instances of bytes in Python. The tags prefixed with !!python/ are provided by PyYAML.


Choose the Loader Class
If you want the best possible parsing performance, then you’ll need to manually import the suitable loader class and pass it to the generic yaml.load() function, as shown before. But which one should you choose?


    def timer_callback(self):
        my_param = self.get_parameter('my_parameter').get_parameter_value().string_value

        self.get_logger().info('Hello %s!' % my_param)

        my_new_param = rclpy.parameter.Parameter(
            'my_parameter',
            rclpy.Parameter.Type.STRING,
            'world'
        )
        all_new_parameters = [my_new_param]
        self.set_parameters(all_new_parameters)


Remove ads
© 2012–2024 Real Python ⋅ Newsletter ⋅ Podcast ⋅ YouTube ⋅ Twitter ⋅ Facebook ⋅ Instagram ⋅ Python Tutorials ⋅ Search ⋅ Privacy Policy ⋅ Energy Policy ⋅ Advertise ⋅ Contact
 Happy Pythoning!


  * allow_undeclared_parameters.
  * automatically_declare_parameters_from_overrides.


>>> with open("/path/to/file.yaml", mode="wt", encoding="utf-8") as file:
...     yaml.dump(data, file)


    * [ Building ROS 2 with tracing instrumentation ](../../How-To-Guides/Building-ROS-2-with-Tracing-Instrumentation.html)
    * [ Topics vs Services vs Actions ](../../How-To-Guides/Topics-Services-Actions.html)
    * [ Using variants ](../../How-To-Guides/Using-Variants.html)
    * [ Using the ` ros2  param  ` command-line tool ](../../How-To-Guides/Using-ros2-param.html)
    * [ ROS 2 on Raspberry Pi ](../../How-To-Guides/Installing-on-Raspberry-Pi.html)
    * [ Using Callback Groups ](../../How-To-Guides/Using-callback-groups.html)
    * [ Setup ROS 2 with VSCode and Docker [community-contributed] ](../../How-To-Guides/Setup-ROS-2-with-VSCode-and-Docker-Container.html)
    * [ Building RQt from source ](../../How-To-Guides/RQt-Source-Install.html)
      * [ Building RQt from source on macOS ](../../How-To-Guides/RQt-Source-Install-MacOS.html)
      * [ Building RQt from source on Windows 10 ](../../How-To-Guides/RQt-Source-Install-Windows10.html)
  * [ Concepts ](../../Concepts.html)
    * [ The ROS_DOMAIN_ID ](../../Concepts/About-Domain-ID.html)
    * [ About different ROS 2 DDS/RTPS vendors ](../../Concepts/About-Different-Middleware-Vendors.html)
    * [ About logging and logger configuration ](../../Concepts/About-Logging.html)
    * [ About Quality of Service settings ](../../Concepts/About-Quality-of-Service-Settings.html)
    * [ About ROS 2 client libraries ](../../Concepts/About-ROS-2-Client-Libraries.html)
    * [ About ROS 2 interfaces ](../../Concepts/About-ROS-Interfaces.html)
    * [ About parameters in ROS 2 ](../../Concepts/About-ROS-2-Parameters.html)
    * [ Executors ](../../Concepts/About-Executors.html)
    * [ About topic statistics ](../../Concepts/About-Topic-Statistics.html)
    * [ Introspection with command line tools ](../../Concepts/About-Command-Line-Tools.html)
    * [ Overview and usage of RQt ](../../Concepts/About-RQt.html)
    * [ About Composition ](../../Concepts/About-Composition.html)
    * [ On the mixing of ament and catkin (catment) ](../../Concepts/About-Catment.html)
    * [ About Cross-compilation ](../../Concepts/About-Cross-Compilation.html)
    * [ About tf2 ](../../Concepts/About-Tf2.html)
    * [ About the build system ](../../Concepts/About-Build-System.html)
    * [ About internal ROS 2 interfaces ](../../Concepts/About-Internal-Interfaces.html)
    * [ About ROS 2 middleware implementations ](../../Concepts/About-Middleware-Implementations.html)
    * [ About ROS 2 client libraries ](../../Concepts/About-ROS-2-Client-Libraries.html)
  * [ Contact ](../../Contact.html)
  * [ The ROS 2 Project ](../../The-ROS2-Project.html)
    * [ Contributing ](../../The-ROS2-Project/Contributing.html)
      * [ ROS 2 developer guide ](../../The-ROS2-Project/Contributing/Developer-Guide.html)
      * [ Code style and language versions ](../../The-ROS2-Project/Contributing/Code-Style-Language-Versions.html)
      * [ Quality guide: ensuring code quality ](../../The-ROS2-Project/Contributing/Quality-Guide.html)
      * [ Migration guide from ROS 1 ](../../The-ROS2-Project/Contributing/Migration-Guide.html)
        * [ Python migration guide from ROS 1 ](../../The-ROS2-Project/Contributing/Migration-Guide-Python.html)
      * [ ROS Build Farms ](../../The-ROS2-Project/Contributing/Build-Farms.html)
      * [ Windows Tips and Tricks ](../../The-ROS2-Project/Contributing/Windows-Tips-and-Tricks.html)


Local installation of Python 3.x
A text editor
The PyYAML Library
The PyYAML library is widely used for working with YAML in Python. It comes with a yaml module that you can use to read, write, and modify contents of a YAML file, serialize YAML data, and convert YAML to other data formats like JSON.


Note: Property names in YAML are pretty flexible, as they can contain whitespace characters and span multiple lines. What’s more, you’re not limited to using only strings. Unlike JSON, but similar to Python dictionaries, a YAML hash allows you to use almost any data type for a key!


Make sure the node is running:


import base64
import datetime
import yaml


Now, run your script and feed its output to one of the command-line YAML parsers mentioned before, such as yq or shyaml, through a Unix pipeline (|):


>>> key
ScalarNode(tag='tag:yaml.org,2002:str', value='pi')


# yaml2html.py


  * Tutorials
    * [ ROS ](https://roboticsbackend.com/category/ros/)
    * [ ROS2 ](https://roboticsbackend.com/category/ros2/)
    * [ Raspberry Pi ](https://roboticsbackend.com/category/raspberry-pi/)
    * [ Arduino ](https://roboticsbackend.com/category/arduino/)
  * [ Youtube ](https://www.youtube.com/channel/UCelRThOKlWMnpjqr5EBq6tg?sub_confirmation=1)
  * [ **Courses** ](https://roboticsbackend.com/courses/)
  * [ Contact ](https://roboticsbackend.com/contact/)


Modifying yaml data with one block of yaml data
To illustrate further, you can modify the output2.yaml file also. The code below, will modify the first block of YAML data and edit the accessMode to be both ‘ReadAccessModes’ and ‘ReadOnlyMany’ and write it to a file output6.yaml


Ultimately, you want to design an HTMLBuilder class to help you with parsing multiple YAML documents from a stream in a lazy manner. Assuming you’ve already defined such a class, you can create the following helper function in a file named yaml2html.py:


Tweak the Formatting With Optional Parameters
The dumping functions in PyYAML accept a few positional arguments and a number of optional keyword arguments, which let you control the output’s formatting. The only required parameter is the Python object or a sequence of objects to serialize, passed as the first argument in all dumping functions. You’ll take a closer look at the available parameters in this section.


Parsing YAML Documents at a Low Level
The classes and a few wrapper functions that you’ve used so far constitute a high-level PyYAML interface, which hides the implementation details of working with YAML documents. This covers most of the use cases and allows you to focus on the data rather than its presentation. However, sometimes you might want more control over the parsing and serialization processes.


In this section, you’ll implement three hands-on examples of these low-level functions in PyYAML. Remember that you can download their source code by following the link below:


**Learn ROS2 in a week**


**Tutorial level:** Beginner


Table of Contents


Note: The YAML specification forbids using tabs for indentation and considers their use a syntax error. This coincides with Python’s PEP 8 recommendation about preferring spaces over tabs.


##  Setup code and declare ROS2 params with rclpy


#  rclpy Params Tutorial – Get and Set ROS2 Params with Python


Boolean Flag	Meaning
allow_unicode	Don’t escape Unicode and don’t double-quote.
canonical	Output YAML in the canonical form.
default_flow_style	Prefer flow style over block style.
explicit_end	End each document with the triple dot (...).
explicit_start	Start each document with the triple dash (---).
sort_keys	Sort the output of dictionaries by key.
There are also several parameters of other data types that give you more freedom:


Here’s what happens with the “my_str” parameter:


if __name__ == "__main__":
    print("".join(yaml2html("".join(sys.stdin.readlines()))))
It’ll let you preview the visual representation of YAML in your terminal when you pipe the HTML output to a text-based web browser like Lynx or the html2text converter:


    for start, end, token in reversed(list(tokenize(text))):
        color = colors.get(type(token), lambda text: text)
        text = text[:start] + color(text[start:end]) + text[end:]


Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. Get tips for asking good questions and get answers to common questions in our support portal.


YAML is a human-readable data-serialization language and stands for “YAML Ain’t Markup Language”, often also referred to as “Yet Another Markup Language”. It is written with a .yml or .yaml (preferred) file extension.


As always, you want to make your script runnable by reading content from the standard input. You also wrap the generated HTML body with some boilerplate in a new html_tree() function:


  * The new parameter we set from command line appears in the list, which means it has been automatically declared. Also it’s value is set.
  * The 3 parameters we’re trying to get from the code are not declared anywhere (from within our outside the node), so we get the default value.


Email…
🔒 No spam. Unsubscribe any time.


Get Source Code: Click here to get the source code you’ll use to work with YAML in Python.


>>> print(jdoe := yaml.dump(Person("John", "Doe")))
!Person
first_name: John
last_name: Doe


Note: To use yq, you must first install jq in your operating system if it’s not already available.


Related
‣ Dependencies with Poetry
‣ Getting Started with PyMongo
‣ SQLAlchemy in Python
‣ PyTest Fixtures
‣ Data Pipelines with Apache ...
Learn More About Earthly
Earthly makes builds super simple. Learn More


    class MinimalParam(rclpy.node.Node):
        def __init__(self):
            super().__init__('minimal_param_node')

            self.declare_parameter('my_parameter', 'world')

            self.timer = self.create_timer(1, self.timer_callback)


rclpy.exceptions.ParameterUninitializedException: The parameter 'my_str' is not initialized


Note: Unlike plain XML and JSON, which can only represent tree-like hierarchies with a single root element, YAML also makes it possible to describe directed graph structures with recursive cycles. Cross-referencing in XML and JSON can be possible, though, with the help of custom extensions or dialects.


script.py
Copyimport yaml
Let’s create a dictionary called data with the following key-value pairs:


Because you used the ` --dependencies  ` option during package creation, you
donât have to manually add dependencies to ` package.xml  ` or `
CMakeLists.txt  ` .


Build a Tree of Nodes
Sometimes you do need to have the entire document held in memory to look ahead and make an informed decision based on what comes next. PyYAML can build an object representation of the YAML element hierarchy that resembles the DOM in XML. By calling yaml.compose(), you’ll get the root node of an element tree:


Installing the PyYAML Library
To parse YAML in Python, you’ll need to install the PyYAML library.


Windows
Linux
macOS
C:\> type data.yaml | python tree.py > index.html
C:\> start index.html
The resulting page will let you expand and collapse the individual key-value pairs interactively when previewed in a web browser:


* Tasks


[ Previous ](Using-Parameters-In-A-Class-CPP.html "Using parameters in a class
\(C++\)") [ Next  ](Getting-Started-With-Ros2doctor.html "Using ros2doctor to
identify issues")


For now, you’re going to stick with PyYAML for the rest of this tutorial because it’s the standard choice for most Python projects. Note that the tools listed earlier—yamllint, yq, and shyaml—use PyYAML under the surface!


Advertisement


# tree.py


{
    "text": "2022-01-16",
    "numbers": {8, 13, 5},
    "image": b"GIF87a\x08\x00\x08\x00\xf0\x00…",
    "pair": ("black", "white"),
    "center_at": (3.14+2.72j),
    "person": <package_name.module_name.ClassName object at 0x7f08bf528fd0>
}
Notice how, with the help of YAML tags, the parser turned property values into various Python data types, including a string, a set, a bytes object, a tuple, a complex number, and even a custom class instance.


Mercy Bassey %
Mercy Bassey
Mercy Bassey is a JavaScript programmer with a passion for technical writing. Her area of expertise is Full-stack web development and DevOps/IT.
Writers at Earthly work closely with our talented editors to help them create high quality content. This article was edited by:
Bala Priya C %
Bala Priya C
Bala is a technical writer who enjoys creating long-form content. Her areas of interest include math and programming. She shares her learning with the developer community by authoring tutorials, how-to guides, and more.


import sys
import yaml


def visit(node):
    if isinstance(node, yaml.ScalarNode):
        return cast(node.value, node.tag)
    elif isinstance(node, yaml.SequenceNode):
        return [visit(child) for child in node.value]
    elif isinstance(node, yaml.MappingNode):
        return {visit(key): visit(value) for key, value in node.value}


__ [ ROS 2 Documentation: Foxy ](../../index.html)


    import rclpy
    import rclpy.node

    class MinimalParam(rclpy.node.Node):
        def __init__(self):
            super().__init__('minimal_param_node')

            self.declare_parameter('my_parameter', 'world')

            self.timer = self.create_timer(1, self.timer_callback)

        def timer_callback(self):
            my_param = self.get_parameter('my_parameter').get_parameter_value().string_value

            self.get_logger().info('Hello %s!' % my_param)

            my_new_param = rclpy.parameter.Parameter(
                'my_parameter',
                rclpy.Parameter.Type.STRING,
                'world'
            )
            all_new_parameters = [my_new_param]
            self.set_parameters(all_new_parameters)

    def main():
        rclpy.init()
        node = MinimalParam()
        rclpy.spin(node)

    if __name__ == '__main__':
        main()


Prerequisites
To follow along you’ll need the following:


You can optionally turn your Python module into an executable script by adding the if __name__ idiom at the bottom:


# see https://docs.ros.org/en/rolling/How-To-Guides/Migrating-from-ROS1/Migrating-Launch-Files.html#rosparam
# and https://docs.ros.org/en/rolling/Tutorials/Beginner-CLI-Tools/Understanding-ROS2-Parameters/Understanding-ROS2-Parameters.html#load-parameter-file-on-node-startup
# and https://docs.ros.org/en/rolling/How-To-Guides/Launch-file-different-formats.html?highlight=yaml%20launch
# and note that copying XML examples where available tends to work for YAML
launch:
- node:
    pkg: "turtlesim"
    exec: "turtlesim_node"
    name: "sim"
    namespace: "turtlesim_dz"
    param:
      -
        from: $(find-pkg-share dz_launch_examples)/config/turtlesim_custom_params.yaml


Querying Relational Databases With SQLAlchemy in Python
25 minute read
Getting Started With PyTest Fixtures
24 minute read
Learn how to use PyTest fixtures to simplify your test setup and improve your testing. Fixtures provide a way to manage test data and resources, making it ea...


A Parameter object takes 3 arguments: name, type, and value. Don’t forget to
add the dependency for the Parameter class.


Loader Class	Anchors, Aliases	YAML Tags	PyYAML Tags	Auxilliary Types	Custom Types	Code Execution
UnsafeLoader (Loader)	✔	✔	✔	✔	✔	✔
FullLoader	✔	✔	✔	✔	error	error
SafeLoader	✔	✔	error	✔	error	error
BaseLoader	✔	ignore	ignore	ignore	ignore	ignore
UnsafeLoader supports all available features and allows arbitrary code execution. FullLoader is similar except for the code execution and the ability to deserialize custom Python classes, which cause a parsing error. SafeLoader additionally errors out on Python-specific tags provided by PyYAML, such as !!python/tuple. On the other hand, BaseLoader remains agnostic about most features by ignoring them.


Read and write YAML documents in Python
Serialize Python’s built-in and custom data types to YAML
Safely read YAML documents from untrusted sources
Take control of parsing YAML documents at a lower-level
To get the source code for the examples in this tutorial, follow the link below:


You’ve already serialized a Python object to YAML before by abusing the built-in json module, but the result wasn’t a canonical form of YAML. Now, you’ll take advantage of the installed third-party PyYAML library to fix this. There’s a corresponding yaml.safe_dump() function, which takes a Python object and turns it into a string. You can feed it the output of yaml.safe_load() in order to reverse the parsing process:


pair: !!python/tuple
  - black
  - white


# colorize.py


Now you can see the default value of your parameter, but you want to be able
to set it yourself. There are two ways to accomplish this.


####  2.1 Examine the code  ï


  * Setup code and declare ROS2 params with rclpy
    * Declare params with rclpy
    * Run your node without params
    * Run your node with params
  * Get params with rclpy
    * Get params one by one
    * Get multiple params at once
    * Set default values
    * Again, if you forget to declare a parameter
  * Set params with rclpy
  * Allow undeclared params with rclpy
  * rclpy parameter callback
  * Going further with ROS2 params


Others


def yaml2html(stream, loader=yaml.SafeLoader):
    builder = HTMLBuilder()
    for event in yaml.parse(stream, loader):
        builder.process(event)
        if isinstance(event, yaml.DocumentEndEvent):
            yield builder.html
            builder = HTMLBuilder()
The code loops over a sequence of parser events and hands them over to your class, which translates YAML to HTML by incrementally building its representation. Once the function detects the end of a YAML document in a stream, it yields an HTML fragment and creates a new empty builder to start over. That avoids blocking during the processing of a potentially infinitely long stream of YAML documents, which might arrive over the wire:


    * [ Demos ](../Demos.html)
      * [ Using quality-of-service settings for lossy networks ](../Demos/Quality-of-Service.html)
      * [ Managing nodes with managed lifecycles ](../Demos/Managed-Nodes.html)
      * [ Setting up efficient intra-process communication ](../Demos/Intra-Process-Communication.html)
      * [ Recording and playing back data with ` rosbag  ` using the ROS 1 bridge ](../Demos/Rosbag-with-ROS1-Bridge.html)
      * [ Understanding real-time programming ](../Demos/Real-Time-Programming.html)
      * [ Experimenting with a dummy robot ](../Demos/dummy-robot-demo.html)
      * [ Logging ](../Demos/Logging-and-logger-configuration.html)
    * [ Miscellaneous ](../Miscellaneous.html)
      * [ Packaging your ROS 2 application as a snap [community-contributed] ](../Miscellaneous/Packaging-your-ROS-2-application-as-a-snap.html)
      * [ Deploying on IBM Cloud Kubernetes [community-contributed] ](../Miscellaneous/Deploying-ROS-2-on-IBM-Cloud.html)
      * [ Using Eclipse Oxygen with ` rviz2  ` [community-contributed] ](../Miscellaneous/Eclipse-Oxygen-with-ROS-2-and-rviz2.html)
      * [ Building a real-time Linux kernel [community-contributed] ](../Miscellaneous/Building-Realtime-rt_preempt-kernel-for-ROS-2.html)
      * [ Building a package with Eclipse 2021-06 ](../Miscellaneous/Building-ROS2-Package-with-eclipse-2021-06.html)
  * [ How-to Guides ](../../How-To-Guides.html)
    * [ Installation troubleshooting ](../../How-To-Guides/Installation-Troubleshooting.html)
    * [ Developing a ROS 2 package ](../../How-To-Guides/Developing-a-ROS-2-Package.html)
    * [ ament_cmake user documentation ](../../How-To-Guides/Ament-CMake-Documentation.html)
    * [ ament_cmake_python user documentation ](../../How-To-Guides/Ament-CMake-Python-Documentation.html)
    * [ Migrating launch files from ROS 1 to ROS 2 ](../../How-To-Guides/Launch-files-migration-guide.html)
    * [ Using Python, XML, and YAML for ROS 2 Launch Files ](../../How-To-Guides/Launch-file-different-formats.html)
    * [ Using ROS 2 launch to launch composable nodes ](../../How-To-Guides/Launching-composable-nodes.html)
    * [ Migrating YAML parameter files from ROS 1 to ROS 2 ](../../How-To-Guides/Parameters-YAML-files-migration-guide.html)
    * [ Passing ROS arguments to nodes via the command-line ](../../How-To-Guides/Node-arguments.html)
    * [ Synchronous vs. asynchronous service clients ](../../How-To-Guides/Sync-Vs-Async.html)
    * [ DDS tuning information ](../../How-To-Guides/DDS-tuning.html)
    * [ rosbag2: Overriding QoS Policies ](../../How-To-Guides/Overriding-QoS-Policies-For-Recording-And-Playback.html)
    * [ Working with multiple ROS 2 middleware implementations ](../../How-To-Guides/Working-with-multiple-RMW-implementations.html)
    * [ Cross-compilation ](../../How-To-Guides/Cross-compilation.html)
    * [ Releasing a Package ](../../How-To-Guides/Releasing/Releasing-a-Package.html)
      * [ First Time Release ](../../How-To-Guides/Releasing/First-Time-Release.html)
      * [ Subsequent Releases ](../../How-To-Guides/Releasing/Subsequent-Releases.html)
      * [ Release Team / Repository ](../../How-To-Guides/Releasing/Release-Team-Repository.html)
      * [ Release Track ](../../How-To-Guides/Releasing/Release-Track.html)
    * [ Using Python Packages with ROS 2 ](../../How-To-Guides/Using-Python-Packages.html)
    * [ Porting RQt plugins to Windows ](../../How-To-Guides/RQt-Port-Plugin-Windows.html)
    * [ Running ROS 2 nodes in Docker [community-contributed] ](../../How-To-Guides/Run-2-nodes-in-single-or-separate-docker-containers.html)
    * [ Visualizing ROS 2 data with Foxglove Studio ](../../How-To-Guides/Visualizing-ROS-2-Data-With-Foxglove-Studio.html)
    * [ ROS 2 Package Maintainer Guide ](../../How-To-Guides/Package-maintainer-guide.html)
    * [ Building a custom Debian package ](../../How-To-Guides/Building-a-Custom-Debian-Package.html)


Advertisement cookies are used to provide visitors with relevant ads and
marketing campaigns. These cookies track visitors across websites and collect
information to provide customized ads.


!!python/name
!!python/module
The first one lets you load a reference to a Python object, such as a class, a function, or a variable, in your code. The second tag allows for referencing a given Python module. In the next section, you’ll take a look at different data sources that PyYAML lets you load documents from.


Great job! You can now visualize YAML in your web browser. However, the presentation is static. Wouldn’t it be nice to spice it up with a little bit of interactivity? Next up, you’ll use a different approach to parsing YAML, which will allow just that!


Or all at once:


    import rclpy
    from rclpy.node import Node
    from rclpy.parameter import Parameter
    from rcl_interfaces.msg import SetParametersResult

    class TestParams(Node):

        def parameter_callback(self, params):
            for param in params:
                if param.name == 'my_str' and param.type_ == Parameter.Type.STRING:
                    self.my_str = param.value
            return SetParametersResult(successful=True)

        def __init__(self):
            super().__init__('test_params_rclpy')

            self.declare_parameter('my_str', 'default value')
            self.my_str = self.get_parameter('my_str').value
            self.get_logger().info("New value set: %s" % self.my_str)
            self.add_on_set_parameters_callback(self.parameter_callback)


>>> import io


##  Background  ï


>>> user.name
'John Doe'
As long as you’ve defined the .__setstate__() method, it’ll always take precedence and give you control over setting an object’s state. That’s why you’re able to restore the original name, 'John Doe', from the encoded text above.


####  3.1 Change via the console  ï


The code below will return a str object that corresponds to a YAML document. As we’ve set sort_keys to False, the original order of the keys is preserved.


Viewing contents of read yaml output.yaml in file output3.yaml
For reading yaml with multiple blocks of YAML data, you’ll use the safe_load_all() function and convert the output to a list:


Dumper Class	Function	Description
BaseDumper	dump(Dumper=BaseDumper)	Doesn’t support any tags and is useful only for subclassing
SafeDumper	safe_dump()	Produces only standard YAML tags like !!str and can’t represent class instances, making it more compatible with other YAML parsers
Dumper	dump()	Supports all standard, library, and custom tags and can serialize an arbitrary Python object, so it may produce a document that other YAML parsers won’t load
In practice, the real choice you have is going to be between Dumper and SafeDumper since BaseDumper is only intended as a base class for subclasses to extend. Generally, you’ll want to stick with the default yaml.Dumper in most cases unless you need to produce portable YAML without Python-specific quirks.


* Background


##  Get params with rclpy


The first line of our ` timer_callback  ` function gets the parameter `
my_parameter  ` from the node, and stores it in ` my_param  ` . Next the `
get_logger  ` function ensures the event is logged. The ` set_parameters  `
function then sets the parameter ` my_parameter  ` back to the default string
value ` world  ` . In the case that the user changed the parameter externally,
this ensures it is always reset back to the original.


Categories  [ ROS2 Tutorials ](https://roboticsbackend.com/category/ros2/)


[ ![ROS2 For Beginners - Step by Step Course](https://roboticsbackend.com/wp-
content/plugins/wp-fastest-cache-premium/pro/images/blank.gif)
](https://rbcknd.com/ros2-for-beginners)


Conclusion
You now know where to find the missing battery in Python to read and write YAML documents. You’ve created a YAML syntax highlighter and an interactive YAML preview in HTML. Along the way, you learned about the powerful and dangerous features found in this popular data format and how to take advantage of them with Python.


script.py
Copy
def read_modify_save_yaml_data(filename,index,key,value,write_file):
    with open(f'{filename}.yaml','r') as f:
        data = yaml.safe_load_all(f)
        loaded_data = list(data)
        loaded_data[index][f'{key}'].append(f'{value}')
    with open(f'{write_file}.yaml', 'w') as file:
        yaml.dump_all(loaded_data,file, sort_keys=False)
    print(loaded_data)

read_modify_save_yaml_data('output2', 0, 'accessModes', \
'ReadOnlyMany', 'output6')
Once this code is executed, you should have the following output:


(For ROS1 users, this is the same mechanism as dynamic_reconfigure in ROS1,
but here it’s directly implemented inside nodes, and much simpler to setup)


Leodanis Pozo Ramos
Leodanis


# yaml2html.py


    output="screen",
    emulate_tty=True,


# tree.py


[ Rolling ](../../../rolling/Tutorials/Beginner-Client-Libraries/Using-Parameters-In-A-Class-Python.html)


# Flow style:
!!python/object:models.Person {first_name: John, last_name: Doe}


>>> yaml.safe_load("""
... number: 3.14
... string: !!str 3.14
... """)
{'number': 3.14, 'string': '3.14'}


Taking a Crash Course in YAML
Getting Started With YAML in Python
Loading YAML Documents in Python
Dumping Python Objects to YAML Documents
Parsing YAML Documents at a Low Level
Conclusion
Share Share Email
 Recommended Video Course
YAML: Python's Missing Battery


fruits: [apple, banana, orange]
veggies:
  - tomato
  - cucumber
  - onion
mushrooms:
- champignon
- truffle
You can keep your list items at the same indentation level as their property name or add more indentation if that improves readability for you.


As always, though, make sure to add the description, maintainer email and
name, and license information to ` package.xml  ` .


You can also set parameters in a launch file, but first you will need to add a
launch directory. Inside the ` ros2_ws/src/python_parameters/  ` directory,
create a new directory called ` launch  ` . In there, create a new file called
` python_parameters_launch.py  `


>>> yaml.dump(Person("John", "Doe"))
!!python/object:__main__.Person
first_name: John
last_name: Doe
Your only option is the unsafe yaml.dump(). However, it’s possible to mark your classes as safe to parse so that even the safe loader will be able to handle them later. To do that, you must make a few changes to your class:


rosdep only runs on Linux, so you can skip ahead to next step.


Modify your function by wrapping the return value of a scalar with a call to a new cast() function:


###  2 Write the Python node  ï


    colcon build --packages-select python_parameters

    colcon build --packages-select python_parameters

    colcon build --merge-install --packages-select python_parameters


Add the following line within the ` console_scripts  ` brackets of the `
entry_points  ` field:


###  Run your node with params


# models.py


As an example, you’ll replace the data dictionary Age key to have a value of 30 instead of 26. The code below will create a function read_and_modify_one_block_of_yaml_data that takes in any YAML file as an argument. Then, it will read that file and modify the Age key to have a value of 30 and output the modified data.


What Do You Think?


First things first: **you have to declare every ROS2 param you’ll use in your
node** . Usually this is one of the first thing you do in the node’s
constructor.


You can add a callback with ` add_on_set_parameters_callback(function) ` that
will be called every time a parameter’s value has been changed from the
outside.


Analytical cookies are used to understand how visitors interact with the
website. These cookies help provide information on metrics the number of
visitors, bounce rate, traffic source, etc.


  * Tutorials
    * [ ROS ](https://roboticsbackend.com/category/ros/)
    * [ ROS2 ](https://roboticsbackend.com/category/ros2/)
    * [ Raspberry Pi ](https://roboticsbackend.com/category/raspberry-pi/)
    * [ Arduino ](https://roboticsbackend.com/category/arduino/)
  * [ Youtube ](https://www.youtube.com/channel/UCelRThOKlWMnpjqr5EBq6tg?sub_confirmation=1)
  * [ **Courses** ](https://roboticsbackend.com/courses/)
  * [ Contact ](https://roboticsbackend.com/contact/)


Kate Finegan
Kate


import yaml


script: |
   #!/usr/bin/env python


Open a new terminal and [ source your ROS 2 installation  ](../Beginner-CLI-
Tools/Configuring-ROS2-Environment.html) so that ` ros2  ` commands will work.


So:


    ...
    self.declare_parameter('my_str', 'default value')
    self.declare_parameter('my_int', 7)
    self.declare_parameter('my_double_array', [1.1, 2.2])
    ...


First, you need to narrow down the token types, as you’ll only be interested in coloring scalar values, mapping keys, and YAML tags. Create a new file named colorize.py and place the following function in it:


What you do inside the callback is up to you and depends on your application
(to go further on this, check out this more complete [ rclpy parameter
callback tutorial ](https://roboticsbackend.com/ros2-rclpy-parameter-
callback/) ). You may wish to store the new parameter’s value, change a
behavior in your node, or simply ignore all changes.


- !!python/object:models.Person
    first_name: John
    last_name: Doe


Read and write YAML documents in Python
Serialize Python’s built-in and custom data types to YAML
Safely read YAML documents from untrusted sources
Take control of parsing YAML documents at a lower level
Later, you’ll learn about YAML’s advanced, potentially dangerous features and how to protect yourself from them. To parse YAML at a low level, you’ll build a syntax highlighter tool and an interactive preview in HTML. Finally, you’ll take advantage of custom YAML tags to extend the data format’s syntax.


Now have a look at a sample document expressed in all three data formats but representing the same person. You can click to expand the collapsible sections and reveal data serialized in those formats:


Looking for a real-time conversation? Visit the Real Python Community Chat or join the next “Office Hours” Live Q&A Session. Happy Pythoning!
Keep Learning


>>> user = yaml.unsafe_load("""
... !!python/object:models.User
... name: Wbua Qbr
... """)


First, make a sample Python script to print out JSON on the standard output:


  * [ ](../../index.html)
  * [ Tutorials ](../../Tutorials.html)
  * [ Beginner: Client libraries ](../Beginner-Client-Libraries.html)
  * Using parameters in a class (Python)
  * [ Edit on GitHub ](https://github.com/ros2/ros2_documentation/blob/foxy/source/Tutorials/Beginner-Client-Libraries/Using-Parameters-In-A-Class-Python.rst)


!!python/object
!!python/object/new
!!python/object/apply
They all must be followed by a fully qualified name of the class to instantiate, which includes the package and module names. The first tag expects a mapping of key-value pairs, in either the flow or block style. Here’s an example:


from yaml import (
    ScalarEvent,
    SequenceStartEvent,
    SequenceEndEvent,
    MappingStartEvent,
    MappingEndEvent,
)


    {
    'apiVersion': 'v1',
    'kind':'persistentVolume',
    'metadata': {'name':'mysql-pv', 'labels':{'type':'local'}},
    'spec':{'storageClassName':'hostpath'},
    'capacity':{'storage':'2Gi'},
    'accessModes':['ReadWriteOnce'],
    'hostpath':{'path':'/mnt/data'}
    }
]
Now call the dump_all() function to decode the Python object as a YAML document:


    $ ros2 param get /test_params_rclpy my_str
    String value is: Set from code


Color	Font Weight	Escape Sequence
Blue	Bold	ESC[34;1m
Cyan	Regular	ESC[36m
Red	Regular	ESC[31m
For example, keys could become blue, values might be cyan, and YAML tags could turn red. Remember that you can’t modify a sequence of elements while iterating over them, because that would shift their indices. What you can do, however, is start the iteration from the other end. That way, inserting the escape sequences won’t affect the remaining part of the text.


%TAG !model! tag:yaml.org,2002:python/object:models.
---
- !model!Person
    first_name: John
    last_name: Doe


Your terminal will return a message verifying the creation of your package `
python_parameters  ` and all its necessary files and folders.


The three fundamental data structures in YAML are essentially the same as in Perl, which was once a popular scripting language. They’re the following:


class HTMLBuilder:
    # ...


###  Again, if you forget to declare a parameter


Remove ads
Unique Features
In this section, you’ll check out some of YAML’s most unique features, including:


When you parse a document with PyYAML, the library yields a sequence of events:


YAML	Python
2022-01-16 23:59:59	datetime.datetime(2022, 1, 16, 23, 59, 59)
2022-01-16	datetime.date(2022, 1, 16)
23:59:59	86399
59:59	3599
YAML understands various date and time formats, including the ISO 8601 standard, and can work with optional time zones. Timestamps such as 23:59:59 get deserialized into the number of seconds elapsed since midnight.


When making your own [ nodes  ](../Beginner-CLI-Tools/Understanding-
ROS2-Nodes/Understanding-ROS2-Nodes.html) you will sometimes need to add
parameters that can be set from the launch file.


Again, remember to import the corresponding dumper class prefixed with the letter C for the best serialization performance, and keep in mind that there might be slight differences between the Python and C implementations:


The ` import  ` statements at the top are used to import the package
dependencies.


    def __setstate__(self, state):
        self.name = codecs.decode(state["name"], "rot13")
You decode the persisted username using a primitive ROT-13 cipher, which rotates characters by thirteen places in the alphabet. For serious encryption, though, you’ll have to look beyond the standard library. Note that you could also use a hashing algorithm from the built-in hashlib module if you wanted to store a password securely.


The final piece of the puzzle is taking YAML from the standard input and presenting it onto the standard output stream:


Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:


The terminal should return the following message every second:


>>> from tree import visit
>>> visit(root)
['42', {'pi': '3.14', 'e': '2.72'}]
You get a Python list as a result, but the individual scalar values contained in it are all strings. PyYAML detects the data type associated with a scalar value and stores it in the node’s .tag attribute, but you have to do the typecasting yourself. The types are encoded using YAML global tags, such as "tag:yaml.org,2002:float", so you may extract the last bit after the second colon (:).


>>> class Person(yaml.YAMLObject):
...     yaml_tag = "!Person"
...     yaml_loader = yaml.SafeLoader
...     def __init__(self, first_name, last_name):
...         self.first_name = first_name
...         self.last_name = last_name
First, let the class inherit from yaml.YAMLObject. Then specify two class attributes. One attribute will represent a custom YAML tag tied to your class, while the second one will be the loader class to use. Now, when you dump a Person object to YAML, you’ll be able to load it back with yaml.safe_load():


Itâs good practice to run ` rosdep  ` in the root of your workspace ( `
ros2_ws  ` ) to check for missing dependencies before building:


As the first kid on the block, XML dominated the scene for many years. It became a mature and trusted data interchange format and helped shape new concepts like building interactive web applications. After all, the letter X in AJAX, a technique for getting data from the server without reloading the page, stands for none other than XML.


    $ ros2 run ros2_tutorials test_params_rclpy --ros-args -p my_str:="Hello world" -p my_int:=5 -p my_double_array:="[4.4, 5.5, 6.6]"
    [INFO] [test_params_rclpy]: str: Hello world, int: 5, double[]: [4.4, 5.5, 6.6]


Here’s a quick line-by-line rundown of the snippet above:


(venv) $ python -m pip install fastapi uvicorn
(venv) $ uvicorn server:app
To run the server, you must provide the module name followed by a colon and the name of the ASGI-compatible callable in that module. The details of implementing such a server and a client are far beyond the scope of this tutorial, but feel free to download the sample materials to study on your own:


In this tutorial you have learned how to get and set parameters from a Python
node, using rclpy. You saw the importance of declaring parameters.


Products
Earthly
Earthly Cloud
Earthly Satellites
Check Status
Content
Blog
Newsletter
Videos & Webinars
Resources
Docs
Pricing
Customer Stories
Solutions
FAQ
About Earthly
Newsroom
Download
Made with 🩵 on Planet Earth | We're hiring!
Terms of Service | Privacy Policy | Security


script.py
Copyyaml_output2 = yaml.dump_all(data2, sort_keys=False)
print(yaml_output2)
Once you execute this code, you should have the following output. The output below shows that the data2 list has been dumped into a single stream—as multiple blocks of YAML separated by - - -.


Sometimes, these tags bypass the normal object creation path, which is typical of object serialization mechanisms in general. Say you wanted to load a user object from YAML and make it an instance of the following class:


In your working directory, run the command below to install PyYAML via pip3:


>>> class Person:
...     def __init__(self, first_name, last_name):
...         self.first_name = first_name
...         self.last_name = last_name
...
>>> yaml.safe_dump(Person("John", "Doe"))
Traceback (most recent call last):
  ...
yaml.representer.RepresenterError: ('cannot represent an object',
  <__main__.Person object at 0x7f55a671e8f0>)


2 things here:


Output<generator object load_all at 0x7f9e0e0b6880>
If you’d like to learn more about generators in Python and how they work, you can check out the docs on Python generator expressions
Similarly, you can also write the loaded data into another file:


Other powerful features of YAML are anchors and aliases, which let you define an element once and then refer to it many times within the same document. Potential use cases include:


When it comes to document size, JSON is a clear winner again. While the extra quotation marks, commas, and curly brackets take up valuable space, you can remove all the whitespace between the individual elements. You can do the same with XML documents, but it won’t overcome the overhead of the opening and closing tags. YAML sits somewhere in the middle by having a comparatively medium size.


However, if you want to impose a parameter’s value from your code, you can use
the ` set_parameters(List[Parameters]) ` method. If the parameter’s value was
already set before, it will be overridden.


Open a new terminal, navigate to ` ros2_ws  ` , and source the setup files:


Now that you have some packages and ROS 2 systems of your own, the [ next
tutorial  ](Getting-Started-With-Ros2doctor.html) will show you how to examine
issues in your environment and systems in case you have problems.


Comparison With XML and JSON
If you’re familiar with XML or JSON, then you might be wondering what YAML brings to the table. All three are major data interchange formats, which share some overlapping features. For example, they’re all text based and more or less human readable. At the same time, they differ in many respects, which you’ll find out next.


When you start your node:


# colorize.py


Here’s how to do.


Note: you also need to provide either a default value (more on that later), or
the type for each parameter. If you have autocompletion, you can easily find
the available types by writing first “rclpy.Parameter.Type”.


If you start this node, and get each parameter in another window with ` ros2
param get ` , you’ll see the values set in the code.


Releases


##  Going further with ROS2 params


This part will use the knowledge you have gained from the [ tutoral about
parameters  ](../Beginner-CLI-Tools/Understanding-
ROS2-Parameters/Understanding-ROS2-Parameters.html) and apply it to the node
you have just created.


script.py
Copydef read_one_block_of_yaml_data(filename):
    with open(f'{filename}.yaml','r') as f:
        output = yaml.safe_load(f)
    print(output)

read_one_block_of_yaml_data('output')
Output{'Name': 'John Doe', 'Position': 'DevOps Engineer', \
'Location': 'England', 'Age': '30', 'Experience': \
{'GitHub': 'Software Engineer', 'Google': 'Technical Engineer', \
'Linkedin': 'Data Analyst'}, 'Languages': {'Markup': ['HTML'],\
 'Programming': ['Python', 'JavaScript', 'Golang']}}
You can also read the contents of a YAML file, copy, and write its contents into another file. The code below will read a file output.yaml and write the content of that file, into another file output3.yaml.


Performance


>>> stream.getvalue()
'name: John\n'
When called with a single argument, the function returns a string representing the serialized object. However, you can optionally pass a second argument to specify the target stream to write to. It can be a file or any file-like object. When you pass this optional argument, the function returns None, and you need to extract data from the stream as necessary.


- !<tag:yaml.org,2002:python/object:models.Person>
    first_name: John
    last_name: Doe
By using a %TAG directive above the YAML document, you declare a custom tag handle called !model!, which gets expanded into the following prefix. The double exclamation point (!!) is a built-in shortcut for the default namespace corresponding to the tag:yaml.org,2002: prefix.


Linux  macOS  Windows


person = {
    "firstName": "John",
    "dateOfBirth": datetime.date(1969, 12, 31),
    "married": False,
    "spouse": None,
    "children": ["Bobby", "Molly"],
}


    import rclpy
    from rclpy.node import Node

    class TestParams(Node):

        def __init__(self):
            super().__init__('test_params_rclpy')

            self.declare_parameter('my_str', rclpy.Parameter.Type.STRING)
            self.declare_parameter('my_int', rclpy.Parameter.Type.INTEGER)
            self.declare_parameter('my_double_array', rclpy.Parameter.Type.DOUBLE_ARRAY)

    # The following is just to start the node
    def main(args=None):
        rclpy.init(args=args)
        node = TestParams()
        rclpy.spin(node)
        node.destroy_node()
        rclpy.shutdown()

    if __name__ == "__main__":
        main()


Loading YAML Documents in Python
Loading YAML boils down to reading a piece of text and parsing it according to the data format’s grammar. PyYAML can make this confusing due to the plethora of functions and classes to choose from. Plus, the library’s documentation doesn’t reliably clearly explain their differences and valid use cases. To save you from debugging the underlying code, you’ll find the most important facts about loading documents with PyYAML in this section.


You can fix this by adding a __slots__ declaration to your class, which forbids adding or removing attributes dynamically once the object exists in memory:


Functional cookies help to perform certain functionalities like sharing the
content of the website on social media platforms, collect feedbacks, and other
third-party features.


The dump_all() Function
💡 The dump_all() function is used to serialize Python objects—in order—into a single stream. It only accepts Python objects represented as lists, such as a list of dictionaries. If you pass in a dictionary object instead of a Python object represented as lists, the dump_all() function will output each item of the dictionary as a YAML document.


It’s important: **if you don’t declare a parameter in your node’s code, you
will get an error when you try to get or set it**
(ParameterNotDeclaredException exception).


    def __init__(self, name):
        self.name = name


>>> print(yaml.dump_all([
...     {"title": "Document #1"},
...     {"title": "Document #2"},
...     {"title": "Document #3"},
... ]))
title: 'Document #1'
---
title: 'Document #2'
---
title: 'Document #3'
Now you get a string containing more than one YAML document separated with the triple dash (---).


def cast(value, tag):
    match tag.split(":")[-1]:
        case "binary":
            return f''
        case _:
            if "\n" in value:
                return f'
{value}
'
            else:
                return f"{value}"
The src attribute of an HTML  element recognizes the encoded data. Note that you don’t need the base64 or the datetime imports anymore, so go ahead and remove them from the top of the file.


!!python/object/apply:models.Person
args: [John]
kwds: {last_name: Doe}
This would still call .__init__() on your class, but one of the arguments would be passed as a keyword argument. In any case, you could define the Person class manually or by taking advantage of data classes in Python:


Suppose you’d like to deserialize a custom class from YAML, make a function call in your Python code, or even execute a shell command while parsing YAML. In that case, your only option is the UnsafeLoader, which accepts a few special library tags. The other loaders either raise an exception or ignore those tags. You’ll learn more about the PyYAML tags now.


###  Run your node without params


Even though XML was initially designed to be a metalanguage for creating markup languages for documents, people quickly adopted it as the standard data serialization format. The HTML-like syntax of angle brackets made XML look familiar. Suddenly, everyone wanted to use XML as their configuration, persistence, or messaging format.


Remove ads
Getting Started With YAML in Python
As you learned in the introduction, working with YAML in Python requires a few extra steps because the language doesn’t support this data format out of the box. You’re going to need a third-party library to serialize Python objects into YAML and the other way around.


    def __init__(self):
        super().__init__('test_params_rclpy')

        # self.declare_parameter('my_str') --> not declared!

        param_str = self.get_parameter('my_str')


In this tutorial, you’ll learn how to:


import yaml


Others


    ...
    self.declare_parameters(
        namespace='',
        parameters=[
            ('my_str', "default value"),
            ('my_int', 7),
            ('my_double_array', [1.1, 2.2])
        ]
    )
    ...


    def __init__(self, name):
        self.name = name
Now, your user objects won’t have the .__dict__ attribute at all. Because there’s no inherent .__dict__, the library falls back to calling setattr() for each key-value pair on the blank object. This ensures that only attributes listed in __slots__ will pass through.


As soon as you start your node – even if you specify a parameter value for
“my_str”, you’ll get an ParameterNotDeclaredException error.


Reading and writing multiple blocks of yaml data
Modifying YAML in Python
Modifying YAML in Python
You can modify the contents of a YAML file using the yaml module with PyYAML. All you have to do is ensure the function takes in the following arguments: a YAML file to read and the key with the new value.


Open the ` setup.py  ` file. Again, match the ` maintainer  ` , `
maintainer_email  ` , ` description  ` and ` license  ` fields to your `
package.xml  ` :


##  Set params with rclpy


Contents


Introducing Earthly Cloud. Consistent, repeatable builds. Advanced caching for speed. Works with any CI. Get 6,000 build min/mth free! Learn more.
Join us on
Slack
Products
Docs
Pricing
Blog
Get Started Free
How to Work with YAML in Python
Blog / Tutorials
Table of contents
The Need for Data Serialization and Why You Should Use YAML
Prerequisites
The PyYAML Library
Installing the PyYAML Library
Creating YAML in Python
The dump() Function
The dump_all() Function
Writing YAML to a File in Python
Reading YAML in Python
How to Read YAML Files With safe_load()
Modifying YAML in Python
How to Convert YAML to JSON in Python
Conclusion
Related
‣ Python on Docker
‣ Control Flow Configuration
‣ Classes and Objects in Python
‣ Read CSV in Python
‣ Python Data Classes
Learn More About Earthly
Earthly makes builds super simple. Learn More


schedule:
  monday:
    - *push-up
    - *squat
  tuesday:
    - *plank
  wednesday:
    - *push-up
    - *plank
Here, you’ve created a workout plan from the exercises that you defined earlier, repeating them across various daily routines. Additionally, the recursive property demonstrates an example of a circular reference. This property is a sequence whose only element is the sequence itself. In other words, recursive[0] is the same as recursive.


© Copyright 2024, Open Robotics.


**You're reading the documentation for a version of ROS 2 that has reached its
EOL (end-of-life), and is no longer officially supported. If you want up-to-
date information, please have a look at[ Iron
](../../../iron/Tutorials/Beginner-Client-Libraries/Using-Parameters-In-A-
Class-Python.html) . **


   if __name__ == "__main__":
       main()
The YAML document above defines a property named script, which holds a short Python script consisting of a few lines of code. Without the pipe indicator, a YAML parser would’ve treated the following lines as nested elements rather than as a whole. Ansible is a notable example that takes advantage of this feature of YAML.


>>> user
<models.User object at 0x7fe8adb12050>


>>> yaml.safe_dump(yaml.safe_load(email_message))
"message:\n  attachments:\n    image1.gif: !!binary |\n  (...)


    $ ros2 param list
    /test_params_rclpy:
      my_double_array
      my_int
      my_str
      use_sim_time
    $ ros2 param get /test_params_rclpy my_other_str
    Parameter not set.


* 2 Write the Python node


Historically, XML has had the best support across a wide range of technologies. JSON is an unbeatable all-around interchange format for transferring data on the Internet. So, who uses YAML and why?


You created a node with a custom parameter that can be set either from a
launch file or the command line. You added the dependencies, executables, and
a launch file to the package configuration files so that you could build and
run them, and see the parameter in action.


Follow [ these instructions  ](Creating-A-Workspace/Creating-A-
Workspace.html#new-directory) to create a new workspace named ` ros2_ws  ` .


>>> from yaml import load, SafeLoader
>>> load(email_message, SafeLoader)
{
    'message': {
        'date': datetime.datetime(2022, 1, 16, 12, 46, 17, tzinfo=(...)),
        'from': 'john.doe@domain.com',
        'to': ['bobby@domain.com', 'molly@domain.com'],
        'cc': ['jane.doe@domain.com'],
        'subject': 'Friendly reminder',
        'content': 'Dear XYZ,\n\nLorem ipsum dolor sit amet...\n',
        'attachments': {
            'image1.gif': b'GIF87a\x08\x00\x08\x00\xf0\x00\x00\x02...'
        }
    }
}
One thing to remember when using the shorthand functions is that they hard-code the pure Python implementation. If you’d like to use the faster C implementation, then you must write a little bit of boilerplate code yourself:


$ ros2 run ros2_tutorials test_params_rclpy --ros-args -p my_str:="Hello world" -p my_int:=5 -p my_double_array:="[4.4, 5.5, 6.6]"


At first glance, XML appears to have the most intimidating syntax, which adds a lot of noise. JSON greatly improves the situation in terms of simplicity, but it still buries information beneath mandatory delimiters. On the other hand, YAML uses Python-style block indentation to define the structure, making it look clean and straightforward. The downside is that you can’t collapse whitespace to reduce size when transferring messages over the wire.


You have to add 2 arguments to the node you’re creating:


    # ...

    class MinimalParam(rclpy.node.Node):
        def __init__(self):
            super().__init__('minimal_param_node')

            from rcl_interfaces.msg import ParameterDescriptor
            my_parameter_descriptor = ParameterDescriptor(description='This parameter is mine!')

            self.declare_parameter('my_parameter', 'world', my_parameter_descriptor)

            self.timer = self.create_timer(1, self.timer_callback)


YAML Parser
YAML Formatter
YAML Validator
Note that you’ll need some of those tools in the following subsection only, while you’ll get your feet wet with YAML in pure Python for the rest of this tutorial.


def _handle_tag(self, close=False):
        if len(self._context) > 0:
            if self._context[-1] is list:
                self._html.append("
" if close else "
")
            else:
                if self._context[-1] % 2 == 0:
                    self._html.append("
" if close else "
")
                else:
                    self._html.append("
" if close else "
")
                if close:
                    self._context[-1] += 1
# ...
If there’s something on the stack already, then you check the last item pushed onto it. If it was a list, then you open or close a list item. Otherwise, depending on the parity of the number of key-value mappings, it’s time to open or close a term or definition from a description list.


To get the most out of this tutorial, you should be familiar with object-oriented programming in Python and know how to create a class. If you’re ready to jump in, then you can follow the link below to get the source code for the examples that you’ll code in this tutorial:


grandparent:
  parent:
    child: {name: Bobby}
    sibling: {'name': "Molly"}
Notice how you can mix the indented and inline blocks in one document. Also, you’re free to enclose both the attributes and their values in single quotes (') or double quotes (") if you want to. Doing so enables one of two interpolation methods of the special character sequences, which are otherwise escaped with another backslash (\) for you. Below, you’ll find Python equivalents alongside the YAML:


You can also get all your parameters with ` get_parameters(List[name]) ` .


Parse a Stream of Events
Another low-level interface provided by PyYAML is an event-driven streaming API, which works similarly to SAX in XML. It translates YAML into a flat sequence of events triggered by the individual elements. The events are evaluated lazily without loading the entire document into memory. You can think of it as peeking through a moving window.


On the surface, this looks like a convenient way of converting timestamps to the number of elapsed seconds. Unfortunately, the rules governing the parsing process of such literals in YAML 1.1 can be confusing and potentially error-prone. When your literal starts with a leading zero (05:59), a YAML 1.1 parser will interpret it as a string instead of a Python datetime object!


Viewing modified yaml
How to Convert YAML to JSON in Python
You can convert YAML to another data-serialization format like JSON.


Analytics


In contrast to flow scalars, block scalars allow for changing how to deal with the newlines, trailing newlines, or indentation. For example, the pipe (|) indicator placed right after the property name preserves the newlines literally, which can be handy for embedding shell scripts in your YAML file:


import base64
import datetime
import yaml


return text


This can be avoided if you set some default values (see more on that later),
or if you specify the params values when you run the node.


Automating Data Pipelines and Workflows Using Apache Airflow
23 minute read
Learn how to automate your data pipelines and workflows using Apache Airflow. This powerful open-source platform simplifies task scheduling, monitoring, and ...


You may want to set default values for parameters which were not set when you
start your node.


For a more detailed breakdown of the features supported by the individual loader classes, check out the table below:


Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet
And, in case you were wondering, Lorem ipsum is a common placeholder text used in writing and web design to fill up the available space. It doesn’t carry any meaning, as it’s deliberately nonsensical and written in improper Latin to let you focus on the form rather than the content.


Python is often marketed as a batteries-included language because it comes with almost everything you’d ever expect from a programming language. This statement is mostly true, as the standard library and the external modules cover a broad spectrum of programming needs. However, Python lacks built-in support for the YAML data format, commonly used for configuration and serialization, despite clear similarities between the two languages.


The “my_other_str” param does not appear in the list!


###  Set default values


The Need for Data Serialization and Why You Should Use YAML
Data serialization is relevant in the exchange of unstructured or semi-structured data effectively across applications or systems with different underlying infrastructures. Data serialization languages use standardized and well-documented syntax to share data across machines.


© 2024 The Robotics Back-End | [ Courses
](https://roboticsbackend.com/courses) | [ Privacy Policy
](https://roboticsbackend.com/privacy-policy/) | [ Contact
](https://roboticsbackend.com/contact/)


Menu


   Lorem ipsum
   dolor sit amet
This will produce the following output:


>>> email_message = """\
... message:
...   date: 2022-01-16 12:46:17Z
...   from: john.doe@domain.com
...   to:
...     - bobby@domain.com
...     - molly@domain.com
...   cc:
...     - jane.doe@domain.com
...   subject: Friendly reminder
...   content: |
...     Dear XYZ,
...
...     Lorem ipsum dolor sit amet...
...   attachments:
...     image1.gif: !!binary
...         R0lGODdhCAAIAPAAAAIGAfr4+SwAA
...         AAACAAIAAACDIyPeWCsClxDMsZ3CgA7
... """
The quickest way of deserializing such a piece of YAML into a Python dictionary would be through the yaml.safe_load() function:


>>> stream = """\
... ---
... 3.14
... ---
... name: John Doe
... age: 53
... ---
... - apple
... - banana
... - orange
... """


Recall that packages should be created in the ` src  ` directory, not the root
of the workspace. Navigate into ` ros2_ws/src  ` and create a new package:


Rate this article:

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.


There you will see the custom parameter ` my_parameter  ` . To change it,
simply run the following line in the console:


You can imagine how these events could naturally translate to opening and closing tags in a hierarchical markup language like HTML. For example, you might represent the structure above with the following markup snippet:


    ...
    (param_str, param_int, param_double_array) = self.get_parameters(
                ['my_str', 'my_int', 'my_double_array'])
    ...


$ ros2 run ros2_tutorials test_params_rclpy --ros-args -p my_other_str:="Guess it won't work"


YAML is characterized by a simple syntax involving line separation and indentation, without complex syntax involving the use of curly braces, parentheses, and tags.


Get Started Free


Navigate back to the root of your workspace, ` ros2_ws  ` , and build your new
package:


# tree.py


The rest of the code remains the same. Once you run the node, you can then run
` ros2  param  describe  /minimal_param_node  my_parameter  ` to see the type
and description.


Tokenizing was great for implementing a syntax highlighter, which must be able to reference symbols in the source YAML file. However, it may be a little too low-level for other applications that don’t care about the exact layout of your input data. Next up, you’ll learn about an alternative way to process YAML, which also involves streaming.


>>> import importlib, tree
>>> importlib.reload(tree)
<module 'tree' from '/home/realpython/tree.py'>


**Want to learn how to program with ROS2?**


Linux  macOS  Windows


🐍 Python Tricks 💌


At the time of writing this tutorial, the official PyYAML documentation as well as the bundled docstrings haven’t been updated to reflect the current code base, and they contain examples that don’t work anymore.


ROS2 params allow you to provide configuration for a node at run time. All
params specified for a node are specific to this node and only exist while the
node is alive.


class HTMLBuilder:
    # ...


We use cookies on our website to give you the most relevant experience by
remembering your preferences and repeat visits. By clicking “Accept All”, you
consent to the use of ALL the cookies. However, you may visit "Cookie
Settings" to provide a controlled consent.


>>> yaml.full_load("""
... list: [1, 2]
... tuple: !!python/tuple [1, 2]
... """)
{'list': [1, 2], 'tuple': (1, 2)}
The !!python/tuple tag in the example above converts an inline list into a Python tuple. Head over to PyYAML documentation for a complete list of supported tags, but be sure to cross-check with the source code on GitHub, as the documentation might not be up to date.


Those parameters are just declared, they are not set yet. If you try to get
one from the terminal – with “ros2 param get”, you’ll get an exception like
this in your node:


This is all great, but what if the User class accepted a password argument? To mitigate data leaks, you most definitely don’t want to serialize passwords in plaintext. And how about serializing stateful attributes, such as file descriptors or database connections? Well, if restoring your object’s state requires some code to run, then you can customize the serialization process with the special .__setstate__() method in your class:


In this rclpy params tutorial you’ll learn how to get and set ROS2 params with
rclpy, inside a Python node.


###  Get multiple params at once


Then source the setup files in a new terminal:


def cast(value, tag):
    match tag.split(":")[-1]:
        case "null":
            return None
        case "bool":
            return bool(value)
        case "int":
            return int(value)
        case "float":
            return float(value)
        case "timestamp":
            return datetime.datetime.fromisoformat(value)
        case "binary":
            return base64.decodebytes(value.encode("utf-8"))
        case _:
            return str(value)
You can leverage the new match and case keywords introduced in Python 3.10 with the structural pattern matching syntax, or you can rewrite this example using a plain old if statement. The bottom line is that you should now be getting values of native Python types when you reload the module in your interactive interpreter session:


_Check out **[ ROS2 For Beginners ](https://rbcknd.com/ros2-for-beginners) **
and learn ROS2 step by step, in 1 week. _


The initializer method in your builder class will define two private fields to keep track of the current context and the HTML content built so far:


Lorem
  ipsum
dolor sit amet
Lorem ipsum dolor sit amet
Finally, you can have multiple YAML documents stored in a single file separated with the triple dash (---). You can optionally use the triple dot (...) to mark the end of each document.


    def __init__(self):
        super().__init__('test_params_rclpy',
                         allow_undeclared_parameters=True,
                         automatically_declare_parameters_from_overrides=True)

        param_str = self.get_parameter_or(
            'my_str', Parameter('str', Parameter.Type.STRING, 'Is there anybody out there?'))
        param_int = self.get_parameter_or(
            'my_int', Parameter('abc', Parameter.Type.INTEGER, 8))
        param_double_array = self.get_parameter_or(
            'my_double_array', Parameter('def', Parameter.Type.DOUBLE_ARRAY, [1.1, 2.2]))

        self.get_logger().info("Params: %s, %s, %s" %
                               (str(param_int.value),
                                str(param_str.value),
                                str(param_double_array.value),))


The library provides a couple of YAML tags recognized by UnsafeLoader to accomplish object creation:


Basically, when you set a parameter from outside the node, the parameter will
be declared for this node, even if you didn’t declare it within the node.


Manage consent


This can help bypass memory limitations that you might face when trying to read a huge file. It can also considerably speed up searching for a very specific piece of information in the ocean of noise. Apart from that, streaming makes it possible to incrementally build an alternative representation for your data. In this section, you’ll create an HTML builder to visualize YAML in a crude way.


In previous tutorials, you learned how to [ create a workspace  ](Creating-A-
Workspace/Creating-A-Workspace.html) and [ create a package  ](Creating-Your-
First-ROS2-Package.html) . You have also learned about [ parameters
](../Beginner-CLI-Tools/Understanding-ROS2-Parameters/Understanding-
ROS2-Parameters.html) and their function in a ROS 2 system.


The YAML document above would translate into the following Python dictionary:


Python Tricks Dictionary Merge


rosdep only runs on Linux, so you can skip ahead to next step.


How to Work with YAML in Python
41 minute read     Updated: October 18, 2023


# Block style:
!!python/object/apply:models.Person
  - John
  - Doe
Both styles achieve a similar effect by calling the .__init__() method in the Person class with the two values passed as positional arguments. Alternatively, you can use a slightly more verbose syntax that allows you to mix positional and keyword arguments, among a few more advanced tricks glossed over for brevity:


Here’s a somewhat subjective comparison of XML, JSON, and YAML to give you an idea of how they stack up against each other as today’s data interchange formats:


YAML Syntax
YAML draws heavy inspiration from other data formats and languages that you might have heard of before. Perhaps the most striking and familiar element of YAML’s syntax is its block indentation, which resembles Python code. The leading whitespace on each line defines the scope of a block, eliminating the need for any special characters or tags to denote where it begins or ends:


There’s a handful of YAML events that you’ll want to process:


**
[ >> Learn ROS2 in 1 Week << ](https://rbcknd.com/ros2-for-beginners) **


Finally, YAML has hashes analogous to Python dicts or JavaScript objects. They’re made of keys, also known as attribute or property names, followed by a colon (:) and a value. You’ve seen a few examples of YAML hashes in this section already, but here’s a more involved one:


    source install/setup.bash

    . install/setup.bash

    call install/setup.bat


Published: December 22, 2022


Return to your code editor now and add another function to the Python source file:


Since the node afterwards set the parameter back to ` world  ` , further
outputs show ` [INFO]  [minimal_param_node]:  Hello  world!  `


You can also pass in optional parameters that specify formatting details for the emitter. The commonly used optional parameters are sort_keys for sorting the keys of a Python object in alphabetical order, and default_flow-style for proper indentation of nested lists, which is set to True by default.


>>> import yaml
>>> root = yaml.compose("[42, {pi: 3.14, e: 2.72}]", yaml.SafeLoader)
>>> root
SequenceNode(
    tag='tag:yaml.org,2002:seq',
    value=[
        ScalarNode(tag='tag:yaml.org,2002:int', value='42'),
        MappingNode(
            tag='tag:yaml.org,2002:map',
            value=[
                (
                    ScalarNode(tag='tag:yaml.org,2002:str', value='pi'),
                    ScalarNode(tag='tag:yaml.org,2002:float', value='3.14')
                ),
                (
                    ScalarNode(tag='tag:yaml.org,2002:str', value='e'),
                    ScalarNode(tag='tag:yaml.org,2002:float', value='2.72')
                )
            ]
        )
    ]
)
The root is traversable through the square brackets syntax. You can reach for any descendant element in the tree using node’s .value attribute and subscripts:


Note: There are other, less popular textual data formats like TOML, which the new build system in Python is based on. Currently, only external packaging and dependency management tools like Poetry can read TOML, but Python 3.11 will soon have a TOML parser in the standard library.


This website uses cookies to improve your experience while you navigate
through the website. Out of these, the cookies that are categorized as
necessary are stored on your browser as they are essential for the working of
basic functionalities of the website. We also use third-party cookies that
help us analyze and understand how you use this website. These cookies will be
stored in your browser only with your consent. You also have the option to
opt-out of these cookies. But opting out of some of these cookies may affect
your browsing experience.


Let’s see what happens when you simply run this node without setting any
parameter value:


    $ start node
    ...
        raise ParameterNotDeclaredException(name)
    rclpy.exceptions.ParameterNotDeclaredException: ('Invalid access to undeclared parameter(s)', 'my_str')


As you continue to explore and expand your Python skills, you might find yourself in need a CI process. If that’s the case, give Earthly a try. It’s a great tool for automating Python builds and can significantly streamline your workflow.


Scalars: Simple values like numbers, strings, or Booleans
Arrays: Sequences of scalars or other collections
Hashes: Associative arrays, also known as maps, dictionaries, objects, or records comprised of key-value pairs
You can define a YAML scalar similarly to a corresponding Python literal. Here are a few examples:


def html_map(node):
    pairs = "".join(
        f'
{visit(key)}: {visit(value)}
'
        if isinstance(value, yaml.ScalarNode) else (
            "
"
            ""
            f'{visit(key)} {visit(value)}'
            ""
            "
"
        )
        for key, value in node.value
    )
    return f"
{pairs}
"
Both helper functions take a node instance and return a piece of HTML string. The html_list() function expects a SequenceNode iterated over with a generator expression, while html_map() iterates over keys and values of a MappingNode. This is where knowing the entire tree structure in advance helps. If the mapping value is a ScalarNode, then you replace it with a  element. Other node types get wrapped in a collapsible  tag.


Scalars in YAML support either a flow style or a block style, which give you different levels of control over the newline handling in multiline strings. Flow scalars can start on the same line as their property name and may span multiple lines:


Always Enabled


In this section, you learned about the high-level functions available in PyYAML to load documents with. Unfortunately, they try to read the entire stream eagerly in one go, which isn’t always feasible. Reading huge files in such a way can take too long or even fail due to limited memory. If you’d like to process YAML in a streaming fashion similar to the SAX interface in XML, then you have to use the low-level API provided by PyYAML.


Earthly Cloud: Consistent, Fast Builds, Any CI
Consistent, repeatable builds across all environments. Advanced caching for faster builds. Easy integration with any CI. 6,000 build minutes per month included.


>>> user.name
Traceback (most recent call last):
  ...
AttributeError: 'User' object has no attribute 'name'
While you’ve undoubtedly created a new User instance, it wasn’t initialized properly, because the .name attribute was missing. However, it does have an unexpected .no_such_attribute, which is nowhere to be found in the class body.


You can also merge (<<) or override attributes defined elsewhere by combining two or more objects:


>>> user.no_such_attribute
42


import yaml


» More about Bartosz
Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:


>>> try:
...     from yaml import CSafeLoader as SafeLoader
... except ImportError:
...     from yaml import SafeLoader


Remove ads
Tokenize a YAML Document
You’ll get the most granular control by scanning a YAML document to obtain a stream of tokens. Each token has a unique meaning and tells you where it starts and where it ends, including the exact line and column number, as well as the offset from the beginning of the document:


Firstly, you’ll need to import the json module from the Python standard library:


@dataclass
class Person:
   first_name: str
   last_name: str
This concise syntax will make Python generate the class initializer as well as a few other methods that you’d have to code yourself.


Note that the cat command isn’t available on Windows. If that’s your operating system, then use its type counterpart, and make sure to run the command through the Terminal application instead of the Command Prompt (cmd.exe) or Windows PowerShell to have the ANSI escape code support enabled by default.


   Lorem ipsum
   dolor sit amet
In such a case, each line’s leading and trailing whitespace will always be folded into a single space, turning paragraphs into lines. This works a bit like HTML or Markdown, resulting in the following piece of text:


Remove ads
Historical Context
YAML, which rhymes with camel, is a recursive acronym that stands for YAML Ain’t Markup Language because it’s not a markup language! Interestingly enough, the original draft for the YAML specification defined the language as Yet Another Markup Language, but later the current backronym was adopted to more accurately describe the language’s purpose.


So, what happened? The node starts and declares a parameter named “my_str” in
its constructor. When launching the node, you also give a value for the
“my_str” parameter. As the parameter is declared, the value is set.


Remove ads
Read and Write Your First YAML Document
Suppose you want to read and parse a hypothetical email message that’s been serialized to the YAML format and stored in a string variable in Python:


>>> with open("sample.yaml", mode="rb") as file:
...     print(yaml.safe_load(file))
...
{'name': 'Иван'}
You create a local file named sample.yaml in your current working directory and write fourteen bytes representing a sample YAML document. Next, you open that file for reading and use safe_load() to get a corresponding dictionary. The file can be open in either text or binary mode. In fact, you may pass any file-like stream of characters or bytes such as the in-memory io.StringIO text buffer or the binary io.BytesIO stream:


Lorem ipsum dolor sit amet...


Inside the ` ros2_ws/src/python_parameters/python_parameters  ` directory,
create a new file called ` python_parameters_node.py  ` and paste the
following code within:


The dump() function optionally accepts a file object as one of its arguments. When you provide this optional file object argument, the dump() function will write the produced YAML document into the file.


####  1.1 Update ` package.xml  ` ï


    $ ros2 param list
    /test_params_rclpy:
      my_double_array
      my_int
      my_str
      use_sim_time


Then, import your function in an interactive Python interpreter session and give it a test drive against the root element that you created before:


# ...
The context is a stack implemented as a Python list, which stores the number of key-value pairs on the given level processed so far. The stack can also contain list markers that indicate a state between SequenceStartEvent and SequenceEndEvent. The other field is a list of HTML tags and their content, joined by a public class property.


Note: Of these three formats, XML and JSON are the only ones that Python supports out of the box, whereas if you wish to work with YAML, then you must find and install a corresponding third-party library. Python isn’t the only language that has better support for XML and JSON than YAML, though. You’re likely to find this tendency across programming languages.


In Development


Reusing the shipping address for invoicing
Rotating meals in a meal plan
Referencing exercises in a training program
To declare an anchor, which you can think of as a named variable, you’d use the ampersand (&) symbol, while to dereference that anchor later on, you’d use the asterisk (*) symbol:


Let’s get started!


{
    "person": {
        "name_latin": "Ivan",
        "name": "Иван",
        "age": 42,
    }
}
The sample object above is a dictionary comprising integer and string fields, which contain Unicode characters. To run the server, you must first install the FastAPI library and an ASGI web server such as uvicorn into your virtual environment, where you had installed PyYAML before:


If you’d like to learn how to work with YAML in the Python programming language, then this tutorial is for you. This tutorial will cover creating, writing, reading, and modifying YAML in Python.


[ ![The Robotics Back-End](https://roboticsbackend.com/wp-
content/uploads/2020/02/cropped-favicon_white-1.png)
](https://roboticsbackend.com/ "The Robotics Back-End")


Managing Dependencies Using Poetry in Python
28 minute read
Learn how to manage dependencies in Python projects using Poetry, a package manager that simplifies the process. From creating virtual environments to adding...


    from launch import LaunchDescription
    from launch_ros.actions import Node

    def generate_launch_description():
        return LaunchDescription([
            Node(
                package='python_parameters',
                executable='minimal_param_node',
                name='custom_minimal_param_node',
                output='screen',
                emulate_tty=True,
                parameters=[
                    {'my_parameter': 'earth'}
                ]
            )
        ])


>>> import yaml
>>> yaml.safe_dump(complex(3, 2))
Traceback (most recent call last):
  ...
yaml.representer.RepresenterError: ('cannot represent an object', (3+2j))


* Summary


Interactive HTML Tree of YAML Nodes
Notice how the web browser renders the Base64-encoded image depicting a smiley face. You’ll find the final code in the collapsible section below:


# Block style:
!!python/object:models.Person
  first_name: John
  last_name: Doe
The other two tags are more complicated, as each one comes in two flavors. However, the two tags are almost identical because !!python/object/new delegates processing to !!python/object/apply. The only difference is that !!python/object/new calls a special method, .__new__(), on the specified class without calling .__init__(), while !!python/object/apply invokes the class itself, which is what you’ll want in most cases.


##  Allow undeclared params with rclpy


PyYAML installed
In your working directory, create a file called script.py and
import the yaml module:


It is used because of its readability to write configuration settings for applications. It is user-friendly and easy to understand.


    from launch import LaunchDescription
    from launch_ros.actions import Node

    def generate_launch_description():
        return LaunchDescription([
            Node(
                package='ros2_tutorials',
                executable='test_params_rclpy',
                parameters=[
                    {'my_str': 'Hello world'},
                    {'my_int': 5},
                    {'my_double_array': [4.4, 5.5, 6.6]}
                ],
                output='screen',
                emulate_tty=True
            )
        ])


In another terminal, run:


The default way to work with parameters is to first declare them, then use
them.


>>> yaml.safe_load("""
... Shipping Address: &shipping |
...     1111 College Ave
...     Palo Alto
...     CA 94306
...     USA
... Invoice Address: *shipping
... """)
{
    'Shipping Address': '1111 College Ave\nPalo Alto\nCA 94306\nUSA\n',
    'Invoice Address': '1111 College Ave\nPalo Alto\nCA 94306\nUSA\n'
}
You define an anchor, &shipping, near the shipping address and then reuse the same address for the invoice with the help of an alias, *shipping. As a result, you only had to specify the address once. This feature works with all loader types.


Skip to content


Get Source Code: Click here to get the source code you’ll use to work with YAML in Python.