Metadata-Version: 2.1
Name: serializable-trees
Version: 0.5.0
Summary: Serializable tree datatypes for Python
Author-email: Rainer Schwarzbach <undisclosed@example.com>
License: MIT License
        
        Copyright (c) 2023 Rainer Schwarzbach
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://gitlab.com/blackstream-x/serializable-trees
Project-URL: Documentation, https://blackstream-x.gitlab.io/serializable-trees
Project-URL: CI, https://gitlab.com/blackstream-x/serializable-trees/-/pipelines
Project-URL: Bug Tracker, https://gitlab.com/blackstream-x/serializable-trees/-/issues
Project-URL: Source Code, https://gitlab.com/blackstream-x/serializable-trees.git
Keywords: json,yaml,tree,node,datatype
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML >=6.0.1

# Serializable Trees

_Easy-to-use serializable tree datatypes for Python_


## Installation


You can install the [package from PyPI](https://pypi.org/project/serializable-trees/):

```bash
pip install --upgrade serializable-trees
```

Using a [virtual environment](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment)
is strongly recommended.


## Notable changes

### v0.5.0

**ListNode** is a subclass of **list**,
and **MapNode** is a subclass of **dict**.


### v0.4.0

---
> **⚠ Possible infinite loops with releases prior to 0.4.0**

> In early releases, **ListNode** and MapNode contents were not
> checked for circular references, which could lead to infinite loops.

> Starting with release 0.4.0, all **Node** subclass instances
> implement additional checks that prevent the creation of
> circular node references.

---


## Package contents and basic usage

The **serializable_trees** package contains the modules

- **serializable\_trees.basics** implementing a low-level API
  with the **ListNode** and **MapNode** classes and some helper functions
- **serializable\_trees.trees** implementing a high-level API
  with the **TraversalPath** and **Tree** classes.

Both high-level API classes from the **trees** module
are aliased in the base module so they can simply be imported using

```
>>> from serializable_trees import TraversalPath, Tree
```

Loading a data structure from a file is easy,
but its representation is slightly hard to read.

Using the `to_yaml()` or `to_json()` methods
and printing the results improves readability:

```
>>> gitlab_ci = Tree.from_file(".gitlab-ci.yml")
>>> gitlab_ci
Tree({'include': {'project': 'blackstream-x/building-blocks', 'file': '/Pipelines/python/pip/package+docs.gitlab-ci.yml'}, 'variables': {'MODULE_NAME': 'serializable_trees'}, 'python:mypy': {'variables': {'EXTRA_REQUIREMENTS': 'types-pyyaml'}}, 'python:pylint': {'variables': {'CODESTYLE_TARGET': 'src'}}})
>>> 
>>> print(gitlab_ci.to_yaml())
include:
  project: blackstream-x/building-blocks
  file: /Pipelines/python/pip/package+docs.gitlab-ci.yml
variables:
  MODULE_NAME: serializable_trees
python:mypy:
  variables:
    EXTRA_REQUIREMENTS: types-pyyaml
python:pylint:
  variables:
    CODESTYLE_TARGET: src

>>> 
```

**Tree** contents can be accessed directly under the `root` attribute:

```
>>> gitlab_ci.root.include
{'project': 'blackstream-x/building-blocks', 'file': '/Pipelines/python/pip/package+docs.gitlab-ci.yml'}
>>> gitlab_ci.root.include.project
'blackstream-x/building-blocks'
>>> gitlab_ci.root.include.file
'/Pipelines/python/pip/package+docs.gitlab-ci.yml'
>>>
```

Using **TraversalPath** objects, you can manipulate the tree.
In this case, remove a portion from the tree and return it
using the **.crop()** method:

```
>>> include_path = TraversalPath("include")
>>> old_include_contents = gitlab_ci.crop(include_path)
>>> old_include_contents
{'project': 'blackstream-x/building-blocks', 'file': '/Pipelines/python/pip/package+docs.gitlab-ci.yml'}
>>> 
>>> print(gitlab_ci.to_yaml())
variables:
  MODULE_NAME: serializable_trees
python:mypy:
  variables:
    EXTRA_REQUIREMENTS: types-pyyaml
python:pylint:
  variables:
    CODESTYLE_TARGET: src

>>> 
```

**ListNode** and **MapNode** objects can be used to define new items.
In this case, the Tree object’s **.graft()** method is used:

```
>>> from serializable_trees.basics import ListNode, MapNode
>>> gitlab_ci.graft(include_path, ListNode([MapNode(template="Security/Secret-Detection.gitlab-ci.yml")]))
>>> 
>>> print(gitlab_ci.to_yaml())
variables:
  MODULE_NAME: serializable_trees
python:mypy:
  variables:
    EXTRA_REQUIREMENTS: types-pyyaml
python:pylint:
  variables:
    CODESTYLE_TARGET: src
include:
- template: Security/Secret-Detection.gitlab-ci.yml

>>> 
```

You can also manipulate the **Node** instances directly –
in this case, using the **.append()** method of the **ListNode** instance:

```
>>> gitlab_ci.root.include.append(old_include_contents)
>>> 
>>> print(gitlab_ci.to_yaml())
variables:
  MODULE_NAME: serializable_trees
python:mypy:
  variables:
    EXTRA_REQUIREMENTS: types-pyyaml
python:pylint:
  variables:
    CODESTYLE_TARGET: src
include:
- template: Security/Secret-Detection.gitlab-ci.yml
- project: blackstream-x/building-blocks
  file: /Pipelines/python/pip/package+docs.gitlab-ci.yml

>>> 
>>> gitlab_ci.root.include
[{'template': 'Security/Secret-Detection.gitlab-ci.yml'}, {'project': 'blackstream-x/building-blocks', 'file': '/Pipelines/python/pip/package+docs.gitlab-ci.yml'}]
>>> 
```

## Further reading

[→ Full documentation](https://blackstream-x.gitlab.io/serializable-trees/)

