compose-operator


Namecompose-operator JSON
Version 1.0.3 PyPI version JSON
download
home_pagehttps://github.com/mentalisttraceur/python-compose-operator
SummaryOperator overload for function composition.
upload_time2023-11-02 00:30:53
maintainer
docs_urlNone
authorAlexander Kozhevnikov
requires_python>=3.8
license0BSD
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            compose-operator
================

This module allows adding function composition with the ``|``
operator to any function, method, class, or other callable.

|compose|_ is used for the function composition.
|wrapt|_ is used to add the operator as transparently
and unintrusively as possible. This ensures that:

1. The ``|`` composition operator does not interfere at
   runtime with any introspection, other operators, and
   (optionally) Python 3.10's ``|`` type union operator.

2. ``|``-composed functions still work with signature
   introspection, method binding, pickling, and so on.

.. |compose| replace:: ``compose``
.. _compose: https://pypi.org/project/compose
.. |wrapt| replace:: ``wrapt``
.. _wrapt: https://pypi.org/project/wrapt


Versioning
----------

This library's version numbers follow the `SemVer 2.0.0
specification <https://semver.org/spec/v2.0.0.html>`_.


Installation
------------

::

    pip install compose-operator


Usage
-----

Basics
~~~~~~

Import ``composable``:

.. code:: python

    >>> from compose_operator import composable

A simple inline composition:

.. code:: python

    >>> stringify_as_integer = composable(int) | str
    >>> stringify_as_integer(12.3)
    '12'

Naturally, the result of ``|`` on a composable
function is also composable, so you can chain it:

.. code:: python

    >>> (composable(int) | str | list)(12.3)
    ['1', '2']

You can also use ``composable`` as a decorator:

.. code:: python

    >>> @composable
    ... def my_stringify(thing):
    ...     return f'hello {thing}'
    ... 
    >>> stringify_as_integer = int | my_stringify
    >>> stringify_as_integer(12.3)
    'hello 12'


``composable`` is "sticky"
~~~~~~~~~~~~~~~~~~~~~~~~~~

``composable`` will stick to callable return
values, so it **works out-of-the-box with
currying**, partial application, and so on:

.. code:: python

    >>> import functools
    >>> import operator
    >>> import toolz
    >>> 
    >>> partial = composable(functools.partial)
    >>> add1 = partial(operator.add, 1)
    >>> (add1 | str)(2)
    '3'
    >>> curry = composable(toolz.curry)
    >>> add = curry(operator.add)
    >>> (add(2) | float)(2)
    4.0

``composable`` also sticks to the results of
method binding, so if you make a composable
method, or assign a function composed with
the ``|`` operator as a method, it "just works":

.. code:: python

    >>> class Adder:
    ...     def __init__(self, value):
    ...         self._value = value
    ... 
    ...     @composable
    ...     def add(self, thing):
    ...         return thing + self._value
    ... 
    ...     add_then_stringify = add | str
    ... 
    >>> adder = Adder(42)
    >>> (adder.add | str)(8)
    '50'
    >>> adder.add_then_stringify(9)
    '51'


Composable Classes
~~~~~~~~~~~~~~~~~~

If you want to decorate a class so that the class
is composable, use ``@composable_constructor`` -
that way, normal class functionality such as ``|``
for **type unions** still works:

.. code:: python

    >>> from compose_operator import composable_constructor
    >>> 
    >>> from dataclasses import dataclass
    >>> 
    >>> @composable_constructor
    ... @dataclass
    ... class MyClass:
    ...     x: int
    ... 
    >>> isinstance(1, int | MyClass)
    True
    >>> isinstance("hello!", int | MyClass)
    False
    >>> isinstance(MyClass(0), int | MyClass)
    True
    >>> (operator.add | MyClass)(3, 2)
    MyClass(x=5)

``composable`` takes precedence over
``composable_constructor``, so you can
still force ``|`` to do composition
instead of type union if you need to:

.. code:: python

    >>> (composable(int) | MyClass)("6")
    MyClass(x=6)
    >>> (int | composable(MyClass))("7")
    MyClass(x=7)


Composable Callable Objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you are defining a class with a ``__call__`` method,
you can make its instances automatically ``composable``
by using ``composable_instances``:

.. code:: python

    >>> from compose_operator import composable_instances
    >>> 
    >>> @composable_instances
    ... class Greeter:
    ...     def __init__(self, target):
    ...         self._target = target
    ...     def __call__(self):
    ...         return f"Hello, {self._target}!"
    ... 
    >>> world_greeter = Greeter("world")
    >>> world_greeter()
    'Hello, world!'
    >>> (world_greeter | list)()
    ['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!']

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/mentalisttraceur/python-compose-operator",
    "name": "compose-operator",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "",
    "author": "Alexander Kozhevnikov",
    "author_email": "mentalisttraceur@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/42/4c/2fd84e289c0715ed498aac900c51081f096def084c75bb45b631826b117f/compose-operator-1.0.3.tar.gz",
    "platform": null,
    "description": "compose-operator\n================\n\nThis module allows adding function composition with the ``|``\noperator to any function, method, class, or other callable.\n\n|compose|_ is used for the function composition.\n|wrapt|_ is used to add the operator as transparently\nand unintrusively as possible. This ensures that:\n\n1. The ``|`` composition operator does not interfere at\n   runtime with any introspection, other operators, and\n   (optionally) Python 3.10's ``|`` type union operator.\n\n2. ``|``-composed functions still work with signature\n   introspection, method binding, pickling, and so on.\n\n.. |compose| replace:: ``compose``\n.. _compose: https://pypi.org/project/compose\n.. |wrapt| replace:: ``wrapt``\n.. _wrapt: https://pypi.org/project/wrapt\n\n\nVersioning\n----------\n\nThis library's version numbers follow the `SemVer 2.0.0\nspecification <https://semver.org/spec/v2.0.0.html>`_.\n\n\nInstallation\n------------\n\n::\n\n    pip install compose-operator\n\n\nUsage\n-----\n\nBasics\n~~~~~~\n\nImport ``composable``:\n\n.. code:: python\n\n    >>> from compose_operator import composable\n\nA simple inline composition:\n\n.. code:: python\n\n    >>> stringify_as_integer = composable(int) | str\n    >>> stringify_as_integer(12.3)\n    '12'\n\nNaturally, the result of ``|`` on a composable\nfunction is also composable, so you can chain it:\n\n.. code:: python\n\n    >>> (composable(int) | str | list)(12.3)\n    ['1', '2']\n\nYou can also use ``composable`` as a decorator:\n\n.. code:: python\n\n    >>> @composable\n    ... def my_stringify(thing):\n    ...     return f'hello {thing}'\n    ... \n    >>> stringify_as_integer = int | my_stringify\n    >>> stringify_as_integer(12.3)\n    'hello 12'\n\n\n``composable`` is \"sticky\"\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n``composable`` will stick to callable return\nvalues, so it **works out-of-the-box with\ncurrying**, partial application, and so on:\n\n.. code:: python\n\n    >>> import functools\n    >>> import operator\n    >>> import toolz\n    >>> \n    >>> partial = composable(functools.partial)\n    >>> add1 = partial(operator.add, 1)\n    >>> (add1 | str)(2)\n    '3'\n    >>> curry = composable(toolz.curry)\n    >>> add = curry(operator.add)\n    >>> (add(2) | float)(2)\n    4.0\n\n``composable`` also sticks to the results of\nmethod binding, so if you make a composable\nmethod, or assign a function composed with\nthe ``|`` operator as a method, it \"just works\":\n\n.. code:: python\n\n    >>> class Adder:\n    ...     def __init__(self, value):\n    ...         self._value = value\n    ... \n    ...     @composable\n    ...     def add(self, thing):\n    ...         return thing + self._value\n    ... \n    ...     add_then_stringify = add | str\n    ... \n    >>> adder = Adder(42)\n    >>> (adder.add | str)(8)\n    '50'\n    >>> adder.add_then_stringify(9)\n    '51'\n\n\nComposable Classes\n~~~~~~~~~~~~~~~~~~\n\nIf you want to decorate a class so that the class\nis composable, use ``@composable_constructor`` -\nthat way, normal class functionality such as ``|``\nfor **type unions** still works:\n\n.. code:: python\n\n    >>> from compose_operator import composable_constructor\n    >>> \n    >>> from dataclasses import dataclass\n    >>> \n    >>> @composable_constructor\n    ... @dataclass\n    ... class MyClass:\n    ...     x: int\n    ... \n    >>> isinstance(1, int | MyClass)\n    True\n    >>> isinstance(\"hello!\", int | MyClass)\n    False\n    >>> isinstance(MyClass(0), int | MyClass)\n    True\n    >>> (operator.add | MyClass)(3, 2)\n    MyClass(x=5)\n\n``composable`` takes precedence over\n``composable_constructor``, so you can\nstill force ``|`` to do composition\ninstead of type union if you need to:\n\n.. code:: python\n\n    >>> (composable(int) | MyClass)(\"6\")\n    MyClass(x=6)\n    >>> (int | composable(MyClass))(\"7\")\n    MyClass(x=7)\n\n\nComposable Callable Objects\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you are defining a class with a ``__call__`` method,\nyou can make its instances automatically ``composable``\nby using ``composable_instances``:\n\n.. code:: python\n\n    >>> from compose_operator import composable_instances\n    >>> \n    >>> @composable_instances\n    ... class Greeter:\n    ...     def __init__(self, target):\n    ...         self._target = target\n    ...     def __call__(self):\n    ...         return f\"Hello, {self._target}!\"\n    ... \n    >>> world_greeter = Greeter(\"world\")\n    >>> world_greeter()\n    'Hello, world!'\n    >>> (world_greeter | list)()\n    ['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!']\n",
    "bugtrack_url": null,
    "license": "0BSD",
    "summary": "Operator overload for function composition.",
    "version": "1.0.3",
    "project_urls": {
        "Homepage": "https://github.com/mentalisttraceur/python-compose-operator"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6d58865c86ed667ea462ad07a621e99094719198c43bb847f216832ab37c75ac",
                "md5": "0c5984021f93b6275950ed9517f3c0ad",
                "sha256": "102bc9525d50e3ca9f294aa6f143b7c2c406a7809914559ec628cc319deefa21"
            },
            "downloads": -1,
            "filename": "compose_operator-1.0.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0c5984021f93b6275950ed9517f3c0ad",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 5121,
            "upload_time": "2023-11-02T00:30:50",
            "upload_time_iso_8601": "2023-11-02T00:30:50.886309Z",
            "url": "https://files.pythonhosted.org/packages/6d/58/865c86ed667ea462ad07a621e99094719198c43bb847f216832ab37c75ac/compose_operator-1.0.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "424c2fd84e289c0715ed498aac900c51081f096def084c75bb45b631826b117f",
                "md5": "fecf0d515831c2b0cb971fafa5745a63",
                "sha256": "22d6847897543c01672ac3107472dc454e81cfcf46fe6d42c15cca52796564c3"
            },
            "downloads": -1,
            "filename": "compose-operator-1.0.3.tar.gz",
            "has_sig": false,
            "md5_digest": "fecf0d515831c2b0cb971fafa5745a63",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 4916,
            "upload_time": "2023-11-02T00:30:53",
            "upload_time_iso_8601": "2023-11-02T00:30:53.365199Z",
            "url": "https://files.pythonhosted.org/packages/42/4c/2fd84e289c0715ed498aac900c51081f096def084c75bb45b631826b117f/compose-operator-1.0.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-11-02 00:30:53",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "mentalisttraceur",
    "github_project": "python-compose-operator",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "compose-operator"
}
        
Elapsed time: 0.27346s