Skip to content

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() ​

python
def count_chars(data: DataObjType, /) -> int

The sum of all the characters amount including the keys in dictionaries.


  • data – The data structure to count the characters from.

strip() ​

python
def strip[DataObj: DataObjType](data: DataObj, /) -> DataObj

Removes leading and trailing whitespaces from the data structure's items.


  • data – The data structure to strip the items from.

remove_empty_items() ​

python
def remove_empty_items[DataObj: DataObjType](data: DataObj, /, *, spaces_are_empty: bool = False) -> DataObj

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() ​

python
def remove_duplicates[DataObj: DataObjType](data: DataObj, /) -> DataObj

Removes all duplicates from the data structure.


  • data – The data structure to remove duplicates from.

remove_comments() ​

python
def remove_comments[DataObj: DataObjType](
    data: DataObj,
    /,
    *,
    comment_start: str = ">>",
    comment_end: str = "<<",
    comment_sep: str = "",
) -> DataObj

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 inside data.
  • comment_end – The string that marks the end of a comment inside data.
  • comment_sep – The string with which a comment will be replaced, if it is in the middle of a value.

Example Usage ​

python
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="__",
)
Processed data
python
{
    "key1": [
        "value1",
        "value2",
        "val__ue3"
    ],
    "key3": None
}
  • For key1, all the comments will just be removed, except at value3 and value4:
    • value3 The comment is removed and the parts left and right are joined through comment_sep.
    • value4 The 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 of None.

is_equal() ​

python
def is_equal(
    data_a: DataObjType,
    data_b: DataObjType,
    /,
    ignore_paths: str | list[str] = "",
    *,
    path_sep: str = "->",
    comment_start: str = ">>",
    comment_end: str = "<<",
) -> bool

Compares 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_start and comment_end are only used to correctly recognize the keys in the ignore_paths.
  • path_sep – The separator between the keys/indexes in the ignore_paths.
  • comment_start – The string that marks the start of a comment inside data_a and data_b.
  • comment_end – The string that marks the end of a comment inside data_a and data_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 ​

python
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")
Result
python
True

get_path_id() ​

python
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] | None

Generates 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 the value_paths.
  • comment_start – The string that marks the start of a comment inside data.
  • comment_end – The string that marks the end of a comment inside data.
  • ignore_not_found – If true, the function will return None if the value is not found instead of raising an error.

Example Usage ​

python
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")
Generated Path ID
python
"1011"

get_value_by_path_id() ​

python
def get_value_by_path_id(data: DataObjType, path_id: str, /, *, get_key: bool = False) -> Any

Retrieves 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 using get_path_id().
  • get_key – If true and the final item is in a dict, it returns the key instead of the value.

Example Usage ​

python
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)
Retrieved Port Value
python
443

set_value_by_path_id() ​

python
def set_value_by_path_id[DataObj: DataObjType](data: DataObj, update_values: dict[str, Any], /) -> DataObj

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 using get_path_id().

Example Usage ​

python
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})
Updated Structure
python
{
    "server": {
        "host": "localhost",
        "ports": [80, 8443],  # 2nd port updated from 443 to 8443
    }
}

render() ​

python
def render(
    data: DataObjType,
    /,
    *,
    indent: int = 4,
    compactness: Literal[0, 1, 2] = 1,
    max_width: int = 127,
    sep: str = ", ",
    as_json: bool = False,
    syntax_highlighting: dict[str, AnyStyle] | bool | None = False,
) -> S

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 if compactness is 1).
  • 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) or True to apply default syntax highlighting styles or False/None to disable syntax highlighting.

There are three different levels of compactness:

  • 0 expands everything possible.
  • 1 expands only when necessary (based element complexity and the max_width parameter).
  • 2 keeps 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.BLUE
  • number: S.BR.MAGENTA
  • literal: S.MAGENTA
  • type: S.ITALIC | S.GREEN
  • punctuation: 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 ​

python
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()
terminal
{
"name": "xulbux",
"version": 2.0,
"items": ["ansi", "data"],
"ok": True
}

Released under the MIT License.