Metadata-Version: 2.1
Name: quacks
Version: 0.2.0
Summary: Better duck-typing with mypy-compatible extensions to Protocol
Home-page: https://github.com/ariebovenberg/quacks
License: MIT
Keywords: ducktyping,protocol,mypy,immutability
Author: Arie Bovenberg
Author-email: a.c.bovenberg@gmail.com
Requires-Python: >=3.7.0,<4.0.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Dist: importlib-metadata (>=1,<5); python_version < "3.8"
Requires-Dist: typing-extensions (>3.7,<5)
Project-URL: Repository, https://github.com/ariebovenberg/quacks
Description-Content-Type: text/x-rst

🦆 Quacks
=========

.. image:: https://img.shields.io/pypi/v/quacks.svg
   :target: https://pypi.python.org/pypi/quacks

.. image:: https://img.shields.io/pypi/l/quacks.svg
   :target: https://pypi.python.org/pypi/quacks

.. image:: https://img.shields.io/pypi/pyversions/quacks.svg
   :target: https://pypi.python.org/pypi/quacks

.. image:: https://github.com/ariebovenberg/quacks/actions/workflows/build.yml/badge.svg
   :target: https://github.com/ariebovenberg/quacks/actions/workflows/build.yml

.. image:: https://img.shields.io/readthedocs/quacks.svg
   :target: http://quacks.readthedocs.io/

.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
   :target: https://github.com/psf/black

.. epigraph::

  If it walks like a duck and it quacks like a duck, then it must be a duck


Thanks to `PEP544 <https://www.python.org/dev/peps/pep-0544/>`_, Python now has protocols:
a way to define duck typing statically.
This library gives you some niceties to make common idioms easier.

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

.. code-block:: bash

   pip install quacks

⚠️ For type checking to work with ``mypy``, you'll need to enable the plugin in
your `mypy config file <https://mypy.readthedocs.io/en/latest/config_file.html>`_:

.. code-block:: ini

   [mypy]
   plugins = quacks.mypy

Features
--------

Easy read-only protocols
^^^^^^^^^^^^^^^^^^^^^^^^

Defining read-only protocols is great for encouraging immutability and
working with frozen dataclasses. Use the ``readonly`` decorator:


.. code-block:: python

    from quacks import readonly

    @readonly
    class User(Protocol):
        id: int
        name: str
        is_premium: bool

Without this decorator, we'd have to write quite a lot of cruft,
reducing readability:


.. code-block:: python

    class User(Protocol):
        @property
        def id(self) -> int: ...
        @property
        def name(self) -> str: ...
        @property
        def is_premium(self) -> bool: ...

Partial protocols (work in progress)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

What if you want to reuse parts of a protocol?
Imagine we have several functions who use various properties of ``User``.
With partial protocols you can reuse attributes without having to define
many overlapping protocols.
Inspired by `clojure spec <https://youtu.be/YR5WdGrpoug?t=1971>`_.

(exact syntax TBD)

.. code-block:: python

    class User(Protocol):
        id: int
        name: str
        is_premium: bool
        address: Address

    class Address(Protocol):
        street: str
        city: str
        country: str

    from quacks import _

    def determine_discount(u: User[_.id.is_premium]) -> int:
        ...  # access `id` and `is_premium` attributes

    def greet(u: User[_.name.address[_.country]]) -> None:
        ...  # access `name` and `address.country` attributes

    u: User = ...

    determine_discount(u)
    greet(u)

