estruttura 4.0.0
Abstract data structures.
Requires Python: >= 2.7, != 3.0.*, != 3.1.*, != 3.2.*, != 3.3.*, != 3.4.*, != 3.5.*, != 3.6.*

Estruttura
==========

.. image:: https://github.com/brunonicko/estruttura/workflows/MyPy/badge.svg
   :target: https://github.com/brunonicko/estruttura/actions?query=workflow%3AMyPy

.. image:: https://github.com/brunonicko/estruttura/workflows/Lint/badge.svg
   :target: https://github.com/brunonicko/estruttura/actions?query=workflow%3ALint

.. image:: https://github.com/brunonicko/estruttura/workflows/Tests/badge.svg
   :target: https://github.com/brunonicko/estruttura/actions?query=workflow%3ATests

.. image:: https://readthedocs.org/projects/estruttura/badge/?version=stable
   :target: https://estruttura.readthedocs.io/en/stable/

.. image:: https://img.shields.io/github/license/brunonicko/estruttura?color=light-green
   :target: https://github.com/brunonicko/estruttura/blob/main/LICENSE

.. image:: https://static.pepy.tech/personalized-badge/estruttura?period=total&units=international_system&left_color=grey&right_color=brightgreen&left_text=Downloads
   :target: https://pepy.tech/project/estruttura

.. image:: https://img.shields.io/pypi/pyversions/estruttura?color=light-green&style=flat
   :target: https://pypi.org/project/estruttura/

Overview
--------
Abstract data structures.

Motivation
----------
`estruttura` was born out of the need for a similar interface between the `datta <https://github.com/brunonicko/datta>`_
and `objetto <https://github.com/brunonicko/objetto>`_ packages.

Relationship
------------
`estruttura` provides a `Relationship` class that contains information about the values stored in the `Structures`_,
such as typing (with support for runtime type checking), serialization, validation, conversion, etc.

.. code:: python

    >>> from six import string_types
    >>> from estruttura import Relationship, exceptions
    >>> def converter(value):
    ...     if isinstance(value, string_types) and "." in value:
    ...         return float(value)
    ...     elif not isinstance(value, float):
    ...         return int(value)
    ...
    >>> def validator(value):
    ...     if value > 10:
    ...         raise exceptions.ValidationError(value)
    ...
    >>> relationship = Relationship(types=(int, float), converter=converter, validator=validator)
    >>> relationship.process_value("3.3")
    3.3

Structures
----------
`estruttura` offers all the class combinations of the concepts described below.

Private Structure
^^^^^^^^^^^^^^^^^
Holds data internally and only allow for changes privately.

User Structure
^^^^^^^^^^^^^^
Allows for changing of the data by external clients (public).

Immutable Structure
^^^^^^^^^^^^^^^^^^^
Only allows data changes through copying.
Immutable structures are hashable.

.. code:: python

    >>> from estruttura.examples import ImmutableList
    >>> l_a = ImmutableList()
    >>> l_b = l_a.extend(range(3))
    >>> list(l_b) == [0, 1, 2]
    True

Mutable Structure
^^^^^^^^^^^^^^^^^
Allows in-place data changes.
Mutable structures are not hashable.

.. code:: python

    >>> from estruttura.examples import MutableList
    >>> l = MutableList()
    >>> l.extend(range(3))
    >>> list(l) == [0, 1, 2]
    True

Dict Structure
^^^^^^^^^^^^^^
Dictionary-like data structure class.

.. code:: python

    >>> from estruttura import Relationship
    >>> from estruttura.examples import MutableDict
    >>> class StrIntDict(MutableDict):
    ...     relationship = Relationship(converter=str)
    ...     value_relationship = Relationship(converter=int)
    ...
    >>> StrIntDict({1: "1"})
    StrIntDict({'1': 1})

List Structure
^^^^^^^^^^^^^^
List-like data structure class.

.. code:: python

    >>> from estruttura import Relationship
    >>> from estruttura.examples import MutableList
    >>> class IntList(MutableList):
    ...     relationship = Relationship(converter=int)
    ...
    >>> IntList(["1", 1, 1.0])
    IntList([1, 1, 1])

Set Structure
^^^^^^^^^^^^^
Set-like data structure class.

.. code:: python

    >>> from estruttura import Relationship
    >>> from estruttura.examples import MutableSet
    >>> class IntSet(MutableSet):
    ...     relationship = Relationship(converter=int)
    ...
    >>> IntSet({"1", 1, 1.0})
    IntSet({1})

Structure
^^^^^^^^^
Dataclass-like structure class that has a schema defined by attributes.

.. code:: python

    >>> import math
    >>> from estruttura import Attribute, Relationship, getter
    >>> from estruttura.examples import ImmutableClass
    >>> class Point(ImmutableClass):
    ...     x = Attribute()
    ...     y = Attribute()
    ...     d = Attribute(serializable=True, repr=True)
    ...     @getter(d, dependencies=(x, y))
    ...     def _(self):
    ...         return math.sqrt(self.x**2 + self.y**2)
    ...
    >>> Point(3, 4)
    Point(3, 4, <d=5.0>)
    >>> Point(3, 4).serialize() == {"x": 3, "y": 4, "d": 5.0}
    True
    >>> Point.deserialize({"x": 3, "y": 4})
    Point(3, 4, <d=5.0>)