Data Module
Provides utilities for inspecting, transforming, and querying nested data structures.
Includes path-based value lookup and mutation, deep equality comparison,
removal of empty elements or duplicates, comment stripping, and syntax-highlighted rendering.
count_chars()
def count_chars(data: DataObjType, /) -> intThe sum of all the characters amount including the keys in dictionaries.
data– The data structure to count the characters from.
strip()
Removes leading and trailing whitespaces from the data structure's items.
data– The data structure to strip the items from.
remove_empty_items()
Removes empty items from the data structure.
data– The data structure to remove empty items from.spaces_are_empty– If true, it will count items with only spaces as empty.
remove_duplicates()
Removes all duplicates from the data structure.
data– The data structure to remove duplicates from.
remove_comments()
Remove comments from a list, tuple or dictionary.
data– List, tuple or dictionary, where the comments should get removed from.comment_start– The string that marks the start of a comment insidedata.comment_end– The string that marks the end of a comment insidedata.comment_sep– The string with which a comment will be replaced, if it is in the middle of a value.
Example Usage
import xulbux as xx
data = {
"key1": [
">> Comment in the beginning of the string. << value1",
"value2 >> Comment in the end of the string.",
"val>> Comment in the middle of the string. <<ue3",
">> Full value is a comment. value4",
],
">> Full key + all its values are a comment. key2": [
"value",
"value",
"value",
],
"key3": ">> All the keys values are comments. value",
}
processed_data = xx.data.remove_comments(
data,
comment_start=">>",
comment_end="<<",
comment_sep="__",
){
"key1": [
"value1",
"value2",
"val__ue3"
],
"key3": None
}- For
key1, all the comments will just be removed, except atvalue3andvalue4:value3The comment is removed and the parts left and right are joined throughcomment_sep.value4The whole value is removed, since the whole value was a comment.
- For
key2, the key, including its whole values will be removed. - For
key3, since all its values are just comments, the key will still exist, but with a value ofNone.
is_equal()
def is_equal(
data_a: DataObjType,
data_b: DataObjType,
/,
ignore_paths: str | list[str] = "",
*,
path_sep: str = "->",
comment_start: str = ">>",
comment_end: str = "<<",
) -> boolCompares two structures and returns True if they are equal and False otherwise.
⇾ Will not detect, if a key-name has changed, only if removed or added.
data_a– The first data structure to compare.data_b– The second data structure to compare.ignore_paths– A path or list of paths to key/s and item/s to ignore during comparison:
Comments are not ignored when comparing.comment_startandcomment_endare only used to correctly recognize the keys in theignore_paths.path_sep– The separator between the keys/indexes in theignore_paths.comment_start– The string that marks the start of a comment insidedata_aanddata_b.comment_end– The string that marks the end of a comment insidedata_aanddata_b.
The paths from ignore_paths and the path_sep parameter work exactly the same way as for
get_path_id(). See its documentation for more details.
Example Usage
import xulbux as xx
dict_a = {"user": "alice", "timestamp": 1600000000, "role": "admin"}
dict_b = {"user": "alice", "timestamp": 1700000000, "role": "admin"}
# Compare while ignoring volatile fields:
result = xx.data.is_equal(dict_a, dict_b, ignore_paths="timestamp")Trueget_path_id()
def get_path_id(
data: DataObjType,
value_paths: str | list[str],
/,
*,
path_sep: str = "->",
comment_start: str = ">>",
comment_end: str = "<<",
ignore_not_found: bool = False,
) -> str | list[str | None] | NoneGenerates a unique ID based on the path to a specific value within a nested data structure.
data– The list, tuple, or dictionary, which the id should be generated for.value_paths– A path or list of paths to the value/s to generate the id for (explained below).path_sep– The separator between the keys/indexes in thevalue_paths.comment_start– The string that marks the start of a comment insidedata.comment_end– The string that marks the end of a comment insidedata.ignore_not_found– If true, the function will returnNoneif the value is not found instead of raising an error.
Example Usage
import xulbux as xx
data = {
"server": {
"host": "localhost",
"ports": [80, 443],
}
}
# Generate path ID for the HTTPS port:
path_id = xx.data.get_path_id(data, "server->ports->1")"1011"get_value_by_path_id()
def get_value_by_path_id(data: DataObjType, path_id: str, /, *, get_key: bool = False) -> AnyRetrieves the value from data using the provided path_id,
as long as the data structure hasn't changed since creating the path ID.
data– The list, tuple, or dictionary to retrieve the value from.path_id– The path ID to the value to retrieve, created before usingget_path_id().get_key– If true and the final item is in a dict, it returns the key instead of the value.
Example Usage
import xulbux as xx
data = {"server": {"host": "localhost", "ports": [80, 443]}}
path_id = xx.data.get_path_id(data, "server->ports->1")
# Retrieve the value at the generated path ID:
port = xx.data.get_value_by_path_id(data, path_id)443set_value_by_path_id()
Updates the value/s from update_values in the data, as long as the
data structure hasn't changed since creating the path ID to that value.
data– The list, tuple, or dictionary to update the value/s in.update_values– A dictionary where keys are path IDs and values are the new values to insert.
The path IDs should have been created usingget_path_id().
Example Usage
import xulbux as xx
data = {"server": {"host": "localhost", "ports": [80, 443]}}
path_id = xx.data.get_path_id(data, "server->ports->1")
# Update the value at the generated path ID:
updated = xx.data.set_value_by_path_id(data, {path_id: 8443}){
"server": {
"host": "localhost",
"ports": [80, 8443], # 2nd port updated from 443 to 8443
}
}render()
Get nicely formatted data structures as an S object.
data– The data structure to format.indent– The amount of spaces to use for indentation.compactness– The level of compactness for the output (explained below – section 1).max_width– The maximum width of a line before expanding (only used ifcompactnessis1).sep– The separator between items in the data structure.as_json– if true, the output will be in valid JSON format.syntax_highlighting– A dictionary defining the syntax highlighting styles (explained below – section 2) orTrueto apply default syntax highlighting styles orFalse/Noneto disable syntax highlighting.
There are three different levels of compactness:
0expands everything possible.1expands only when necessary (based element complexity and themax_widthparameter).2keeps everything collapsed (all on one line).
The syntax_highlighting dictionary has 5 keys for each part of the data.
The key's values are the S style attributes (or combined style groups)
to apply to this data part.
The styling can be changed by simply adding the key with the new value
inside the syntax_highlighting dictionary.
The keys with their default values are:
str: S.BR.BLUEnumber: S.BR.MAGENTAliteral: S.MAGENTAtype: S.ITALIC | S.GREENpunctuation: S.BR.BLACK
The returned S object exposes the rendered ANSI string via .ansi (or str(…))
and the plain, un-styled text via .raw.
For more detailed information about styling, see the ansi module documentation.
Example Usage
import xulbux as xx
data = {
"name": "xulbux",
"version": 2.0,
"items": ["ansi", "data"],
"ok": True,
}
# Format and print with syntax highlighting:
styled_output = xx.data.render(data, indent=2, max_width=60, syntax_highlighting=True)
styled_output.print(){
"name": "xulbux",
"version": 2.0,
"items": ["ansi", "data"],
"ok": True
}