Metadata-Version: 2.1
Name: kingston
Version: 0.7.6
Summary: Some Python nicieties
Home-page: https://github.com/jacob414/kingston
Author: Jacob Oscarson
Author-email: jacob@414soft.com
License: MIT
Description: Kingston README
        ===============
        
        I use the excellent `Funcy <https://funcy.readthedocs.io/>`__ library
        for Python a lot. This is my collection of extras that I have designed
        to work closely together with funcy. Funcy Kingston (Reference, see
        `here <https://youtu.be/U79o7qwul48>`__).
        
        `Run on Repl.it <https://repl.it/@jacob414/kingston>`__
        
        Kingston is auto-formatted using
        `yapf <https://github.com/google/yapf>`__.
        
        Pattern matching using extended ``dict``'s
        ------------------------------------------
        
        ``match.Match`` objects are callable objects using a ``dict`` semantic
        that also matches calls based on the type of the calling parameters:
        
        .. code:: python
        
           >>> from kingston import match
           >>> foo = match.TypeMatcher({
           ...     int: lambda x: x*100,
           ...     str: lambda x: f'Hello {x}'
           ... })
           >>> foo(10)
           1000
           >>> foo('bar')
           'Hello bar'
           >>>
        
        .. code:: python
        
           >>> from kingston import match
           >>> foo = match.TypeMatcher({
           ...     int: lambda x: x * 100,
           ...     str: lambda x: f'Hello {x}',
           ...     (int, int): lambda a, b: a + b
           ... })
           >>> foo(10)
           1000
           >>> foo('bar')
           'Hello bar'
           >>>
           >>> foo(1, 2)
           3
           >>>
        
        You can use ``typing.Any`` as a wildcard:
        
        .. code:: python
        
           >>> from typing import Any
           >>> from kingston import match
           >>> foo = match.TypeMatcher({
           ...     int: lambda x: x * 100,
           ...     str: (lambda x: f"Hello {x}"),
           ...     (int, Any): (lambda num, x: num * x)
           ... })
           >>> foo(10)
           1000
           >>> foo('bar')
           'Hello bar'
           >>> foo(3, 'X')
           'XXX'
           >>> foo(10, 10)
           100
           >>>
        
        You can also subclass type matchers and use a decorator to declare cases
        as methods:
        
        .. code:: python
        
           >>> from kingston.match import Matcher, TypeMatcher, case
           >>> from numbers import Number
           >>> class NumberDescriber(TypeMatcher):
           ...    @case
           ...    def describe_one_int(self, one:int) -> str:
           ...        return "One integer"
           ...
           ...    @case
           ...    def describe_two_ints(self, one:int, two:int) -> str:
           ...        return "Two integers"
           ...
           ...    @case
           ...    def describe_one_float(self, one:float) -> str:
           ...        return "One float"
           >>> my_num_matcher:Matcher[Number, str] = NumberDescriber()
           >>> my_num_matcher(1)
           'One integer'
           >>> my_num_matcher(1, 2)
           'Two integers'
           >>> my_num_matcher(1.0)
           'One float'
           >>>
        
        Typing pattern matchers
        ~~~~~~~~~~~~~~~~~~~~~~~
        
        ``match.Match`` objects can be typed using Python's standard
        `typing <https://docs.python.org/3/library/typing.html>`__ mechanism. It
        is done using
        `Generics <https://mypy.readthedocs.io/en/stable/generics.html>`__:
        
        The two subtypes are *[argument type, return type]*.
        
        .. code:: python
        
           >>> from kingston import match
           >>> foo:match.Matcher[int, int] = match.TypeMatcher({
           ...    int: lambda x: x+1,
           ...    str: lambda x: 'hello'})
           >>> foo(10)
           11
           >>> foo('bar')  # fails on mypy but would be ok at runtime
           'hello'
           >>>
        
        Match by value(s)
        ~~~~~~~~~~~~~~~~~
        
        ``match.ValueMatcher`` will use the *values* of the parameters to do the
        same as as ``match.Match``:
        
        .. code:: python
        
           >>> from kingston import match
           >>> foo = match.ValueMatcher({'x': (lambda: 'An x!'), ('x', 'y'): (lambda x,y: 3*(x+y))})
           >>> foo('x')
           'An x!'
           >>> foo('x', 'y')
           'xyxyxy'
           >>>
        
        Same as with the type matcher above, ``typing.Any`` works as a wildcard
        with the value matcher as well:
        
        .. code:: python
        
           >>> from kingston import match
           >>> from typing import Any
           >>> foo = match.ValueMatcher({
           ...     'x': lambda x: 'An X!',
           ...     ('y', Any): lambda x, y: 3 * (x + y)
           ... })
           >>> foo('x')
           'An X!'
           >>> foo('y', 'x')
           'yxyxyx'
           >>>
        
        You can also declare cases as methods in a custom ``ValueMatcher``
        subclass.
        
        Use the function ``value_case()`` to declare value cases. **Note:**
        *imported as a shorthand*:
        
        .. code:: python
        
           >>> from kingston.match import Matcher, ValueMatcher
           >>> from kingston.match import value_case as case
           >>> class SimplestEval(ValueMatcher):
           ...     @case(Any, '+', Any)
           ...     def _add(self, a, op, b) -> int:
           ...         return a + b
           ...
           ...     @case(Any, '-', Any)
           ...     def _sub(self, a, op, b) -> int:
           ...         return a - b
           >>> simpl_eval = SimplestEval()
           >>> simpl_eval(1, '+', 2)
           3
           >>> simpl_eval(10, '-', 5)
           5
           >>>
        
        Aspect Oriented Programming with terse syntax
        ---------------------------------------------
        
        Kingston also implement a technique to do
        `AOP <https://en.wikipedia.org/wiki/Aspect-oriented_programming>`__ with
        an opinionated terse syntax that I like. It lives in the
        ``kingston.aop`` module.
        
        It's used in two main ways:
        
        With decorators
        ~~~~~~~~~~~~~~~
        
        Define an ``=Aspects=`` object as an empty object:
        
        .. code:: python
        
           >>> from kingston.aop import Aspects
           >>> when = Aspects()
           >>>
        
        Then declare your aspects using the object as a decorator:
        
        .. code:: python
        
           >>> @when(lambda x: x == 1, y=lambda y: y == 1)
           ... def labbo(x, y=1):
           ...     return 11
           >>> @when(lambda x: x == 1, z=lambda z: z == 2)
           ... def labbo(x, z=2):
           ...     return 12
           >>>
        
        Aspect 1 above will be triggered if you call it with positional
        parameter 0 as ``1`` and a keyword parameter ``y=1``:
        
        .. code:: python
        
           >>> labbo(1, y=1)
           11
           >>>
        
        Aspect 2 is triggered by parameters ``1, z=2``:
        
        .. code:: python
        
           >>> labbo(1, z=2)
           12
           >>>
        
        Any other combination of parameters will raise a ``AspectNotFound``
        exception:
        
        .. code:: python
        
           >>> labbo(123) # doctest: +IGNORE_EXCEPTION_DETAIL
           Traceback (most recent call last):
           AspectNotFound
           >>>
           >>>
        
        With a mapping of aspects
        ~~~~~~~~~~~~~~~~~~~~~~~~~
        
        You might find this better if you want brievity and/or point free style.
        
        .. code:: python
        
           >>> given = Aspects({
           ...     (lambda x: x == 1,): lambda x: 1,
           ...     (lambda x: x > 1,): lambda x: x * x
           ... })
           >>>
        
        Calls work the same as above:
        
        .. code:: python
        
           >>> given(1)
           1
           >>> given(2)
           4
           >>> given(0) # doctest: +IGNORE_EXCEPTION_DETAIL
           Traceback (most recent call last):
           AspectNotFound
           >>>
        
        Nice things
        -----------
        
        dig()
        ~~~~~
        
        Deep value grabbing from almost any object. Somewhat inspired by CSS
        selectors, but not very complete. This part of the API is unstable — it
        will (hopefully) be developed further in the future.
        
        .. code:: python
        
           >>> from kingston import dig
           >>> dig.xget((1, 2, 3), 1)
           2
           >>> dig.xget({'foo': 'bar'}, 'foo')
           'bar'
           >>> dig.dig({'foo': 1, 'bar': [1,2,3]}, 'bar.1')
           2
           >>> dig.dig({'foo': 1, 'bar': [1,{'baz':'jox'},3]}, 'bar.1.baz')
           'jox'
           >>>
        
        The difference between ``dig.dig()`` and ``funcy.get_in()`` is that you
        can use shell-like blob patterns to get several values keyed by similar
        names:
        
        .. code:: python
        
           >>> from kingston import dig
           >>> res = dig.dig({'foo': 1, 'foop': 2}, 'f*')
           >>> res
           [foo=1:int, foop=2:int]
           >>> # (textual representation of an indexable object)
           >>> res[0]
           foo=1:int
           >>> res[1]
           foop=2:int
           >>>
        
        Testing tools
        -------------
        
        Kingston has some testing tools as well. Also, due to Kingston's
        opinionated nature, they are only targeted towards
        `pytest <https://pytest.org>`__.
        
        Shortform for pytest.mark.parametrize
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        I tend to use pytest.mark.parametrize in the same form everywhere. Thus
        I have implemented this short-form:
        
        .. code:: python
        
           >>> from kingston.testing import fixture
           >>> @fixture.params(
           ...     "a, b",
           ...     (1, 1),
           ...     (2, 2),
           ... )
           ... def test_dummy_compare(a, b):
           ...     assert a == b
           >>>
        
        Doctests as fixtures
        ~~~~~~~~~~~~~~~~~~~~
        
        There is a test decorator that generates pytest fixtures from a function
        or an object. Use it like this:
        
        .. code:: python
        
           >>> def my_doctested_func():
           ...   """
           ...   >>> 1 + 1
           ...   2
           ...   >>> mystring = 'abc'
           ...   >>> mystring
           ...   'abc'
           ...   """
           ...   pass
           >>> from kingston.testing import fixture
           >>> @fixture.doctest(my_doctested_func)
           ... def test_doctest_my_doctested(doctest):  # fixture name always 'doctest'
           ...     res = doctest()
           ...     assert res == '', res
           >>>
        
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Provides-Extra: test
