# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['koda']

package_data = \
{'': ['*']}

setup_kwargs = {
    'name': 'koda',
    'version': '1.3.1',
    'description': 'Type-safe functional tools for Python',
    'long_description': '# Koda\n\nKoda is a collection of practical type-safe tools for Python.\n\nAt its core are a number of datatypes that are common in functional programming.\n\n## Maybe\n\n`Maybe` is similar to Python\'s `Optional` type. It has two variants: `Nothing` and `Just`, and they work in similar ways\nto what you may have seen in other languages.\n\n```python3\nfrom koda import Maybe, Just, nothing\n\na: Maybe[int] = Just(5)\nb: Maybe[int] = nothing\n```\n\nTo know if a `Maybe` is a `Just` or a `Nothing`, you\'ll need to inspect it.\n\n```python3\nfrom koda import Just, Maybe\n\nmaybe_str: Maybe[str] = function_returning_maybe_str()\n\n# python 3.10 +\nmatch maybe_str:\n    case Just(val):\n        print(val)\n    case Nothing:\n        print("No value!")\n\n# python 3.9 and earlier\nif isinstance(maybe_str, Just):\n    print(maybe_str.val)\nelse:\n    print("No value!")\n```\n\n`Maybe` has methods for conveniently stringing logic together.\n\n#### Maybe.map\n\n```python3\nfrom koda import Just, nothing\n\ndef add_10(x: int) -> int:\n    return x + 10\n\n\nJust(5).map(add_10)  # Just(15)\nnothing.map(add_10)  # nothing \nJust(5).map(add_10).map(lambda x: f"abc{x}")  # Just("abc15")\n```\n\n#### Maybe.flat_map\n\n```python3\nfrom koda import Maybe, Just, nothing\n\n\ndef safe_divide(dividend: int, divisor: int) -> Maybe[float]:\n    if divisor != 0:\n        return Just(dividend / divisor)\n    else:\n        return nothing\n\nJust(5).flat_map(lambda x: safe_divide(10, x))  # Just(2)\nJust(0).flat_map(lambda x: safe_divide(10, x))  # nothing\nnothing.flat_map(lambda x: safe_divide(10, x))  # nothing\n```\n\n## Result\n\n`Result` provides a means of representing whether a computation succeeded or failed. To represent success, we can use `OK`;\nfor failures we can use `Err`. Compared to `Maybe`, `Result` is perhaps most useful in that the "failure" case also returns data,\nwhereas `Nothing` contains no data.\n\n```python3\nfrom koda import Ok, Err, Result \n\n\ndef safe_divide_result(dividend: int, divisor: int) -> Result[float, str]:\n    if divisor != 0:\n        return Ok(dividend / divisor)\n    else:\n        return Err("cannot divide by zero!")\n\n\nOk(5).flat_map(lambda x: safe_divide_result(10, x))  # Ok(2)\nOk(0).flat_map(lambda x: safe_divide_result(10, x))  # Err("cannot divide by zero!") \nErr("some other error").map(lambda x: safe_divide_result(10, x))  # Err("some other error")\n```\n\n`Result` can be convenient with `try`/`except` logic.\n```python3\nfrom koda import Result, Ok, Err\n\ndef divide_by(dividend: int, divisor: int) -> Result[float, ZeroDivisionError]:\n    try:\n        return Ok(dividend / divisor)\n    except ZeroDivisionError as exc:\n        return Err(exc)\n\n\ndivided: Result[float, ZeroDivisionError] = divide_by(10, 0)  # Err(ZeroDivisionError("division by zero"))\n```\n\nAnother way to perform the same computation would be to use `safe_try`:\n```python3\nfrom koda import Result, safe_try\n\n\n# not safe on its own!\ndef divide(dividend: int, divisor: int) -> float:\n    return dividend / divisor\n\n# safe if used with `safe_try`\ndivided_ok: Result[float, Exception] = safe_try(divide, 10, 2)  # Ok(5)\ndivided_err: Result[float, Exception] = safe_try(divide, 10, 0)  # Err(ZeroDivisionError("division by zero"))\n```\n\n### Conversion between `Result`s, `Maybe`s, and `Optional`s\n\n### Result and Maybe\n\nConvert a `Result` to a `Maybe` type.\n\n```python3\nfrom koda import Just, nothing, Ok, Err\n\nassert Ok(5).to_maybe == Just(5)\nassert Err("any error").to_maybe == nothing \n```\n\nConvert a `Maybe` to a `Result` type.\n\n```python3\nfrom koda import Just, nothing, Ok, Err\n\nassert nothing.to_result("value if nothing") == Err("value if nothing")\nassert Just(5).to_result("value if nothing") == Ok(5)\n```\n\n### `Maybe` and `Optional`\n\nConvert an `Optional` value to a `Maybe`.\n\n```python3\nfrom koda import to_maybe, Just, nothing\n\nassert to_maybe(5) == Just(5)\nassert to_maybe("abc") == Just("abc")\nassert to_maybe(False) == Just(False)\n\nassert to_maybe(None) == nothing\n```\n\nConvert a `Maybe` to an `Optional`.\n```python3\nfrom koda import Just, nothing\n\nassert Just(5).to_optional == 5\nassert nothing.to_optional is None\n\n# note that `Maybe[None]` will always return None, \n# so `Maybe.get_or_else` would be preferable in this case\nassert Just(None) is None\n```\n\n### `Result` and `Optional`\n\nConvert an `Optional` value to a `Result`.\n\n```python3\nfrom koda import to_result, Ok, Err \n\nassert to_result(5, "fallback") == Ok(5)\nassert to_result("abc", "fallback") == Ok("abc")\nassert to_result(False, "fallback") == Ok(False)\n\nassert to_result(None, "fallback") == Err("fallback")\n\n```\n\nConvert a `Result` to an `Optional`.\n```python3\nfrom koda import Ok, Err\n\nassert Ok(5).to_optional == 5\nassert Err("some error").to_optional is None\n\n# note that `Result[None, Any]` will always return None, \n# so `Result.get_or_else` would be preferable in this case\nassert Ok(None) is None\n```\n\n## More\n\nThere are many other functions and datatypes included. Some examples:\n\n### compose\nCombine functions by sequencing.\n\n```python3\nfrom koda import compose\nfrom typing import Callable\n\ndef int_to_str(val: int) -> str:\n    return str(val)\n\ndef prepend_str_abc(val: str) -> str:\n    return f"abc{val}"    \n\ncombined_func: Callable[[int], str] = compose(int_to_str, prepend_str_abc)\nassert combined_func(10) == "abc10"\n```\n\n### mapping_get\nTry to get a value from a `Mapping` object, and return an unambiguous result.\n\n```python3\nfrom koda import mapping_get, Just, Maybe, nothing\n\nexample_dict: dict[str, Maybe[int]] = {"a": Just(1), "b": nothing}\n\nassert mapping_get(example_dict, "a") == Just(Just(1))\nassert mapping_get(example_dict, "b") == Just(nothing)\nassert mapping_get(example_dict, "c") == nothing\n```\n\nAs a comparison, note that `dict.get` can return ambiguous results:\n```python\nfrom typing import Optional\n\nexample_dict: dict[str, Optional[int]] = {"a": 1, "b": None}\n\nassert example_dict.get("b") is None\nassert example_dict.get("c") is None\n```\nWe can\'t tell from the resulting value whether the `None` was the \nvalue for a key, or whether the key was not present in the `dict`\n\n### load_once\nCreate a lazy function, which will only call the passed-in function\nthe first time it is called. After it is called, the value is cached.\nThe cached value is returned on each successive call.\n```python3\nfrom random import random\nfrom koda import load_once\n\ncall_random_once = load_once(random)  # has not called random yet\n\nretrieved_val: float = call_random_once()\nassert retrieved_val == call_random_once()\n```\n\n## Intent\n\nKoda is intended to focus on a small set of practical data types and utility functions for Python. It will not \ngrow to encompass every possible functional or typesafe concept. Similarly, the intent of this library is to avoid \nrequiring extra plugins (beyond a type-checker like mypy or pyright) or specific typchecker settings. As such,\nit is unlikely that things like Higher Kinded Types emulation or extended type inference will be implemented in this \nlibrary.\n',
    'author': 'Keith Philpott',
    'author_email': 'None',
    'maintainer': 'None',
    'maintainer_email': 'None',
    'url': 'https://github.com/keithasaurus/koda',
    'packages': packages,
    'package_data': package_data,
    'python_requires': '>=3.8,<4.0',
}


setup(**setup_kwargs)
