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"
}