7.4.8. Attributes

One can attach attributes to all kinds of elements of a Graph, i.e. the Graph itself, Views, Nodes, and Edges. This is a fundamental concept common to all the elements, so we explain it upfront.

In conjunction with the types of Nodes and Edges, the attributes form the schema of a Graph.

An attribute is characterized by

  • its name (key),

  • the type of element it can bind a value to,

  • the type of the values it is able to bind,

  • and all the values it binds to elements.

Note

The value of an attribute is typed, so attributes differ from the Python principle of duck typing.

The attributes that are valid after source analysis took place are listed in Language Schema. You may also use Gravis in order to get an overview of existing attributes for nodes and edges: Load an RFG file and open the Mark by query... dialog. The <attribute> drop-down menu in the Nodes and Edges tabs show all available attributes for nodes and edges respectively. Alternatively, open a Graph, View, Node, or Edge information window and choose Add attribute... from the context menu over the attribute section of the window. The Key drop-down menu in the Add attribute dialog also shows all available attributes.

7.4.8.1. Attribute Names

The name of an attribute expresses its location within the attribute hierarchy. The different parts of the name of an attribute are separated by dots. The parts need to contain only ASCII characters, the underscore, and digits.

The Gravis UI presents the attributes hierarchically in a pop-up menu structure in its Query dialog.

If you do not use a dot within the name of an attribute, the attribute will be located on top level in the namespace of all attributes.

Note

It is in general a good idea to use the hierarchy because interactive access is improved as well as namespace pollution is reduced.

Caution

Some attributes are used in Gravis and other tools of Axivion Suite . If you destroy such attributes from an RFG, the tools may not operate properly anymore. An example of such an attribute is the node and edge attribute Source.Name.

7.4.8.2. Attributable Elements

There are four different namespaces for attribute names, each for a different kind of element: Graph, View, Node, and Edge. You can create attributes of the same name but with different value type valid for different element kinds.

The following set of operations can be used for manipulating the schema information about attributes at a Graph instance:

element_attribute_names()
element_attribute(attr_name)
is_element_attribute_name(attr_name)
create_element_attribute(new_attr_name, attr_type)
rename_element_attribute(attr_name, new_name)
destroy_element_attribute(attr_name)

You can replace “element” by “graph”, “view”, “node”, and “edge” in order to manipulate the respective namespace.

Method element_attribute_names returns a list of all attribute names (as strings) for the element kind.

Method element_attribute converts a string into an attribute descriptor which in turn can be used for querying and setting the value of an attribute. The operations discussed in this section all take the name of the attribute, not the descriptor.

Note

The use of descriptors is not necessary but may speed up access to attributes if need be. In general, you can use the name of an attribute whenever you could use the descriptor instead.

Method is_element_attribute_name queries if a string denotes a valid element attribute name.

A new attribute can be created using create_element_attribute. The second parameter specifies the type used for the values stored later on. The value type has to be one of the string literals “toggle”, “int”, “float”, and “string”.

7.4.8.3. Attribute Types

Attributes have defined types, so Python’s duck typing does not apply to attributes. You have to be aware of the type of values you can bind using an attribute. Applicable types for attribute values are the following:

toggle

A Toggle is either attached to an element (node, edge, etc.) or not. It does not carry a value.

int

Integers are in the range of -2147483648 and 2147483647.

float

Floats are in the range of -3.40282E+38 and 3.40282E+38.

string

Strings are of unbounded length and are UTF-8 encoded.

Note

Toggle valued attributes are either set or not set for an element but do not carry a value. They differ from a pure boolean in this regard. A toggle valued attribute can have the two states: set and unset.

Note

The former type ’bool’ has been removed in favor of type ’toggle’ in version 5.8.0.

7.4.8.4. Attribute Values

The way of using attributes is similar to the use of Python dictionaries.

has_key(key)
__contains__(key)
__getitem__(key)
__setitem__(key, value)
__delitem__(key)
__iter__()
next()
keys()
items()
get_string_list(key)
set_string_list(key, value)
append_to_string_list(key, value)
These instance methods can be used to query and manipulate the attribute values at a graph.

Caution

A node/edge has to be inserted in at least one view of a graph before one can set values of attributes at that element.

  • has_key or __contains__ check whether attribute key is set.

    Caution

    __contains__ and has_key simply return ’False’ instead of raising an exception in case an attribute specified by name is not a valid attribute.

    __getitem__ gets the stored value for attribute key.

    This method returns the set value of an attribute. The value has the appropriate type. If there is no attribute value for the queried attribute name, exception KeyError is raised. If attribute denotes a toggle valued attribute, you will receive the value True if the value is set. If an attribute is not set, KeyError is raised. If you simply want to test if the toggle is attached or not, use has_key (this is mostly done by way of the in-operator).

  • __setitem__ sets a new value for the attribute. You have to pass in the appropriate type of object, e.g., if an attribute has type string, you may not pass in an integer object.

  • __delitem__ removes an attribute value.

    This is the only way to “unset” a toggle valued attribute.

  • __iter__ and next implement the iterator interface.

  • keys returns a list of the names of all set attributes.

  • items returns the list of all set pairs of names/keys (as strings) and values.

  • get_string_list interprets the value of a string attribute as comma “,” (escape character is the backslash “") separated list and returns it.
    Both an unset attribute and an empty string are interpreted as empty list. This interpretation is only valid for get_string_list and append_to_string_list. The method exists distinguishes between an unset attribute on the one hand and a set attribute (even an empty string representing an empty list) on the other hand.
    A trailing comma is ignored.
    A trailing escape character at the end of the string will throw a RuntimeError.
  • set_string_list creates a string representation of the elements of the iterable value and stores it in the attribute. The elements are escaped accordingly.

  • append_to_string_list escapes the string value accordingly and appends it to the list currently stored in the attribute value. The current value (if available) is checked to be a valid list. If it is not, a RuntimeError is thrown. append_to_string_list can be called on an element which has not yet set the attribute. This is equivalent to appending to an empty list.

One can check the type of an attribute by using the attribute type descriptors type method.

The example shown in Listing Handling of graph attributes illustrates the handling of graph attributes.

Handling of graph attributes
#!/usr/bin/env rfgscript
# Copyright (C) 2025 Axivion GmbH
# Copyright (C) 2025 The Qt Company GmbH, a subsidiary of The Qt Group
# https://www.qt.io

from bauhaus import rfg

my_graph = rfg.Graph()

my_graph.create_graph_attribute("MyOwnAttributes.AnAttribute", "string")
remembered_attribute = my_graph.create_graph_attribute(
    "MyOwnAttributes.AnotherAttribute", "string"
)

# one can use the attribute's name...
my_graph["MyOwnAttributes.AnAttribute"] = "some value here"

# ...and one can also use the attribute descriptor
my_graph[remembered_attribute] = "some other value here"

# make sure the value has been attached to the graph's attribute
if "MyOwnAttributes.AnAttribute" in my_graph:
    print("Yes, there is a value set")
else:
    print("Oh no, this can't be")

print("The set value is:", my_graph["MyOwnAttributes.AnAttribute"])

# iterate all set attributes
for attribute_name in my_graph.keys():
    print("The value for %s is %s" % (attribute_name, my_graph[attribute_name]))

# show a list of all bound pairs (key, value)
print(my_graph.items())

# get rid of the attribute value
del my_graph["MyOwnAttributes.AnAttribute"]
if "MyOwnAttributes.AnAttribute" not in my_graph:
    print("Deleting an attribute value works fine")
else:
    print("Oh no, this can't be")

Note

Toggle valued attributes are either set or not set for an element but do not carry a value. They differ from a pure boolean in this regard. A toggle valued attribute can have the two states: set and unset.

The example in Listing Handling of attributes of type toggle illustrates the handling of toggle valued attributes

Handling of attributes of type toggle
#!/usr/bin/env rfgscript
# Copyright (C) 2025 Axivion GmbH
# Copyright (C) 2025 The Qt Company GmbH, a subsidiary of The Qt Group
# https://www.qt.io

from bauhaus import rfg

g = rfg.Graph()
g.create_graph_attribute('My Attribute', 'toggle')

# use the in operator for testing if a toggle valued attribute
# is attached to an element
if 'My Attribute' in g:
    print('unexpected')

# when accessing the value of a toggle valued attribute, either
# guard using the above if-statement or a try-statement
try:
    print(g['My Attribute'])
except KeyError:
    print('intended flow of things')

# attach the toggle to an element by assigning an expression
# evaluating to True
g['My Attribute'] = (2 - 1) == 1
g['My Attribute'] = True

# assigning other types or False will result in an exception
try:
    g['My Attribute'] = False
except rfg.AttributeTypeMismatch:
    print('intended flow of things, too')

try:
    print(g['My Attribute'])
except KeyError:
    print('unexpected')

# use del to get rid of a toggle value
del g['My Attribute']

try:
    print(g['My Attribute'])
except KeyError:
    print('intended flow of things')

Note

The use of the following operations is discouraged since 5.8.0.

get_value(attribute)
set_value(attribute[, value])
unset_value(attribute)
has_value(attribute)

7.4.8.5. Attribute Classes: GraphAttribute, ViewAttribute, NodeAttribute, and EdgeAttribute

All the four attribute classes have the same interface:

class GraphAttribute (graph, attr_name)
class ViewAttribute (graph, attr_name)
class NodeAttribute (graph, attr_name)
class EdgeAttribute (graph, attr_name)

The constructor takes a graph and the name of an attribute. The name has to denote an existing attribute of the respective kind in the graph. Case matters for attribute names.

Adding new attributes as well as removing and querying existing ones has to be performed by using the instance methods of class Graph.

type()

Instance method type returns the type of the attribute. Valid results are “toggle”, “int”, “float”, and “string”.

graph()

Instance method graph returns the graph the attribute belongs to.

name()

Instance method name returns the name of the attribute.

__str__()

Instance method __str__ returns a textual representation of the attribute (only for debugging purposes).