Metadata-Version: 2.1
Name: structured-data
Version: 0.3.0
Summary: Code generators for immutable structured data, including algebraic data types, and functions to destructure them.
Home-page: https://github.com/mwchase/python-structured-data
Author: Max Woerner Chase
Author-email: max.chase@gmail.com
License: MIT license
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Unix
Classifier: Operating System :: POSIX
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Utilities
Requires-Python: >=3.7
Requires-Dist: astor

========
Overview
========



Code generators for immutable structured data, including algebraic data types, and functions to destructure them.
Structured Data provides three public modules: ``structured_data.enum``, ``structured_data.match``, and ``structured_data.data``.

The ``enum`` module provides a class decorator and annotation type for converting a class into an algebraic data type; the name is taken from its use in Rust.

The ``match`` module provides a ``Pattern`` class that can be used to build match structures, and a ``ValueMatcher`` class that wraps a value, and attempts to apply match structures to it.
If the match succeeds, the bindings can be extracted and used.
It includes some special support for ``enum`` subclasses.

The match architecture allows you tell pull values out of a nested structure:

.. code-block:: python3

    structure = (match.pat.a, match.pat.b @ (match.pat.c, match.pat.d), 5)
    my_value = (('abc', 'xyz'), ('def', 'ghi'), 5)
    value_matcher = match.ValueMatcher(my_value)
    if value_matcher.match(structure):
        # The format of the matches is not final.
        print(value_matcher.matches['a'])  # ('abc', 'xyz')
        print(value_matcher.matches['b'])  # ('def', 'ghi')
        print(value_matcher.matches['c'])  # 'def'
        print(value_matcher.matches['d'])  # 'ghi'

The ``@`` operator allows binding both the outside and the inside of a structure.
The contents of the ``matches`` attribute will change once there's been some real-world usage.

The ``enum`` decorator exists to create classes that do not necessarily have a single fixed format, but do have a fixed set of possible formats.
This lowers the maintenance burden of writing functions that operate on values of an ``enum`` class, because the full list of cases to handle is directly in the class definition.

Here are implementations of common algebraic data types in other languages:

.. code-block:: python3

    @enum.enum
    class Maybe(typing.Generic[T]):

        Just: enum.Ctor[T]
        Nothing: enum.Ctor

    @enum.enum
    class Either(typing.Generic[E, R]):

        Left: enum.Ctor[E]
        Right: enum.Ctor[R]

The ``data`` module provides classes based on these examples.

* Free software: MIT license

Should I Use This?
==================

Until there's a major version out, probably not.

There are several alternatives in the standard library that may be better suited to particular use-cases:

- The ``namedtuple`` factory creates tuple classes with a single structure; the ``typing.NamedTuple`` class offers the ability to include type information. The interface is slightly awkward, and the values expose their tuple-nature easily.
- The ``enum`` module provides base classes to create finite enumerations. Unlike NamedTuple, the ability to convert values into an underlying type must be opted into in the class definition.
- The ``dataclasses`` module provides a class decorator that converts a class into one with a single structure, similar to a namedtuple, but with more customization: instances are mutable by default, and it's possible to generate implementations of common protocols.
- The Structured Data ``enum`` decorator is inspired by the design of ``dataclasses``. (A previous attempt used metaclasses inspired by the ``enum`` module, and was a nightmare.) Unlike ``enum``, it doesn't require all instances to be defined up front; instead each class defines constructors using a sequence of types, which ultimately determines the number of arguments the constructor takes. Unlike ``namedtuple`` and ``dataclasses``, it allows instances to have multiple shapes with their own type signatures. Unlike using regular classes, the set of shapes is specified up front.
- If you want multiple shapes, and don't want to specify them ahead of time, your best bet is probably a normal tree of classes, where the leaf classes are ``dataclasses``.

Installation
============

::

    pip install structured-data

Documentation
=============

https://python-structured-data.readthedocs.io/

Development
===========

To run the all tests run::

    tox


Changelog
=========

Unreleased
----------

Added
~~~~~

- Simpler way to create match bindings.
- Dependency on the ``astor`` library.
- First attempt at populating the annotations and signature of the generated constructors.
- ``data`` module containing some generic algebraic data types.
- Attempts at monad implementations for ``data`` classes.

Changed
~~~~~~~

- Broke the package into many smaller modules.
- Switched many attributes to use a ``WeakKeyDictionary`` instead.
- Moved prewritten methods into a class to avoid defining reserved methods at the module level.
- When assigning equality methods is disabled for a decorated class, the default behavior is now ``object`` semantics, rather than failing comparison and hashing with a ``TypeError``.
- The prewritten comparison methods no longer return ``NotImplemented``.

Removed
~~~~~~~

- Ctor metaclass.

0.2.1 (2018-07-13)
------------------

Fixed
~~~~~

- Removed an incorrect classifier. This code cannot run on pypy.

0.2.0 (2018-07-13)
------------------

Added
~~~~~

- Explicit ``__bool__`` implementation, to consider all constructor instances as truthy, unless defined otherwise.
- Python 3.7 support.

Changed
~~~~~~~

- Marked the enum constructor base class as private. (``EnumConstructor`` -> ``_EnumConstructor``)
- Switched scope of test coverage to supported versions. (Python 3.7)

Removed
~~~~~~~

- Support for Python 3.6 and earlier.
- Incidental functionality required by supported Python 3.6 versions. (Hooks to enable restricted subclassing.)

0.1.0 (2018-06-10)
------------------

- First release on PyPI.


