Skip to main content

Code generators for immutable structured data, including algebraic data types, and functions to destructure them.

Project description

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

The adt module provides a class decorator and annotation type for converting a class into an algebraic data type.

The match module provides a Pattern class that can be used to build match structures, and a Matchable 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 adt subclasses.

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

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

The @ operator allows binding both the outside and the inside of a structure. Indexing is forwarded to a matches attribute, which is None if the last match was not successful, and otherwise contains an instance of a custom mapping type, which allows building the matched values back up into simple structures.

The adt 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 adt 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:

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

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

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

    Left: adt.Ctor[E]
    Right: adt.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. (NOTE: In Python 3.8, the fast access to namedtuple members means that they bypass user-defined __getitem__ methods, thereby allowing factory consumers to customize indexing without breaking attribute access. It looks like it does still rely on iteration behavior for various convenience methods.)

  • 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 adt 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

0.9.0 (2019-03-20)

Changed

  • Removed the facade.

  • Added stability guarantee to Ctor.

0.8.0 (2019-03-19)

Changed

  • Rewrote the facade.

0.7.0 (2019-03-19)

Changed

  • Tried to put up a facade for type analysis. It didn’t work.

0.6.1 (2019-03-18)

Added

  • Bind class for attaching extra data to a match structure.

  • PEP 561 support.

Changed

  • As-patterns are now formed with indexing instead of the @ operator.

  • AttrPattern and DictPattern now take keyword arguments instead of a dict argument, and form new versions of themselves with an alter method.

  • Actually. Change DictPattern back, stop trying to keep these things in synch.

0.6.0 (2018-07-27)

Added

  • AttrPattern and DictPattern classes that take a dict argument and perform destructuring match against arbitrary objects, and mappings, respectively.

Changed

  • Added special handling for matching AsPatterns against different AsPatterns. This is subject to change, as it’s definitely an edge case.

0.5.0 (2018-07-22)

Added

  • Matchable class is now callable and indexable. Calling is forwarded to the match method, and indexing forwards to the matches attribute, if it exists, and raises an error otherwise.

  • Matchable class now has custom coercion to bool: False if the last match attempt failed, True otherwise.

Changed

  • Renamed enum to adt to avoid confusion.

  • Renamed ValueMatcher to Matchable.

  • Matchable.match now returns the Matchable instance, which can then be coerced to bool, or indexed directly.

0.4.0 (2018-07-21)

Added

  • Mapping class especially for match values. It’s capable of quickly and concisely pulling out groups of variables, but it also properly supports extracting just a single value.

  • Mapping class can now index from a dict to a dict, in order to support **kwargs unpacking.

Fixed

  • A bug (not present in any released version) that caused the empty tuple target to accept any tuple value. This is included partly because this was just such a weird bug.

Removed

  • Unpublished the MatchFailure exception type, and the desugar function.

0.3.0 (2018-07-15)

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

structured-data-0.9.0.tar.gz (36.2 kB view details)

Uploaded Source

Built Distribution

structured_data-0.9.0-py2.py3-none-any.whl (18.5 kB view details)

Uploaded Python 2Python 3

File details

Details for the file structured-data-0.9.0.tar.gz.

File metadata

  • Download URL: structured-data-0.9.0.tar.gz
  • Upload date:
  • Size: 36.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.11.0 pkginfo/1.4.2 requests/2.19.1 setuptools/40.8.0 requests-toolbelt/0.8.0 tqdm/4.23.4 CPython/3.7.2

File hashes

Hashes for structured-data-0.9.0.tar.gz
Algorithm Hash digest
SHA256 96649da1af3539bb553263486991f190ad0833f5823f303cfdad03ca094edbf8
MD5 ed095da912a790ad975303c264b49fec
BLAKE2b-256 33ee4d6023fd748ed7ef017c8313e6e492b9692909a9043161530239c34c5dc1

See more details on using hashes here.

File details

Details for the file structured_data-0.9.0-py2.py3-none-any.whl.

File metadata

  • Download URL: structured_data-0.9.0-py2.py3-none-any.whl
  • Upload date:
  • Size: 18.5 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.11.0 pkginfo/1.4.2 requests/2.19.1 setuptools/40.8.0 requests-toolbelt/0.8.0 tqdm/4.23.4 CPython/3.7.2

File hashes

Hashes for structured_data-0.9.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 61bebc565c1dc76584f48adf75f86bd4807c492571ca89992165dd812cb04afa
MD5 1cdb89a6e2fda1853d38ecaca6f2a559
BLAKE2b-256 81593fcbae326489e3b679c56f2beeeb52b98b5edb077dcb7c1c646b33e7ea2b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page