datacast 0.3.5
Simple way to cast your data.
License: MIT
Requires Python: >=3.3
Keywords: config,env,data,cast

**Datacast** is a Python package that validates and converts your data.

--------------------------------------------

|pypi| |python_version| |coverage| |license|

--------------------------------------------

Basic Usage
-----------

Install with pip:

.. code:: bash

    pip install datacast


Define schema (can be any class with annotations) and use ``cast`` function.

.. code:: python

    from datacast import cast

    class SimpleSchema:
        one: int
        two: str
        three: (lambda x: x ** 2)
        zero: (int, bool)
        four: float = 0.4
        five: None = 'five'

    cast({'one': 1, 'two': 2, 'three': 3, 'zero': '0', 'five': 5}, SimpleSchema)
    # {'one': 1, 'two': '2', 'three': 9, 'zero': False, 'four': 0.4, 'five': 5}

Rules are simple:

-  Params without annotations will be ignored.
-  Annotation is a *caster*, which will be called with the provided value,
   eg. ``bool(0)``.
-  *Caster* is **any** callable. Functions, lambdas, classes etc.
-  It also can be list or tuple (or another iterable).
   Then it acts like a chain of *casters*, eg. ``int('0') -> bool(0) -> False``.
-  If there is no default value - param is required and
   will raise ``RequiredFieldError`` if not provided.
-  ``None`` in annotation means no casting.


Config
------
You can use ``Config`` class which acts like a schema AND stores result data.

.. code:: python

    from datacast import Config

    class SimpleConfig(Config):
        spam: bool
        ham: None
        rabbit: float = None

    config = SimpleConfig({'spam': 0, 'ham': 1})
    assert config.spam == False
    assert config.ham == 1
    assert config.rabbit == None
    assert config._asdict() == {'spam': False, 'ham': 1, 'rabbit': None}

Also there is ``EnvironConfig`` which loads input data from environment,
casts strings to appropriate types and ignores extra vars.

.. code:: python

    from datacast import EnvironConfig

    class SimpleEnvironConfig(EnvironConfig):
        SPAM: bool
        HAM: int
        RABBIT: str
        NONE_VAL: None

    os.environ['SPAM'] = '0'
    os.environ['HAM'] = '1'
    os.environ['RABBIT'] = '2'
    os.environ['NONE_VAL'] = 'null'
    config = SimpleEnvironConfig()
    assert config.SPAM == False
    assert config.HAM == 1
    assert config.RABBIT == '2'
    assert config.NONE_VAL == None

:Valid ``None`` strings: ``'none', 'null', 'nil'``
:Valid ``True`` strings: ``'true', 't', 'yes', 'y', 'on', '1'``
:Valid ``False`` strings: ``'false', 'f', 'no', 'n', 'off', '0', ''``

Case doesn't matter.


Settings
--------

You can specify various settings and apply them in a bunch of different ways.

.. code:: python

    from datacast import apply_settings, Settings

    @apply_settings(
        on_missing='store',
        missing_value=False
    )
    class SimpleSchema:
        ...

    # OR

    class SimpleSettings(Settings):
        on_missing = 'store'
        missing_value = False

    @apply_settings(SimpleSettings)
    class SimpleSchema:
        ...

    # OR pass it to the cast function or Config creation

    cast(input_data, SimpleSchema, settings=SimpleSettings)
    cast(input_data, SimpleSchema, on_missing='store', missing_value=False)
    Config(input_data, settings=SimpleSettings)
    Config(input_data, on_missing='store', missing_value=False)

    # OR use class attribute

    class SimpleSchema:
        __settings__ = SimpleSettings
        # OR
        __settings__ = {'on_missing': 'store', 'missing_value': False}
        ...


**List of settings**

===============  ============  ===============================================
Name             Default       Description
===============  ============  ===============================================
on_extra         ``'ignore'``  What to do with values that absent from schema.
on_invalid       ``'raise'``   What to do when casting has failed.
on_missing       ``'raise'``   What to do when value is missing but required.
missing_value    ``None``      What to store when value is missing.
store_callables  ``False``     If ``False`` - execute callable value on store.
result_class     ``dict``      Class which stores result data.
precasters       ``()``        Prepend additional casters.
postcasters      ``()``        Append additional casters.
cast_defaults    ``False``     Cast default values with full casters chain.
raise_original   ``False``     Raise original exception instead of CastError.
===============  ============  ===============================================

**Options for 'on_extra', 'on_invalid' and 'on_missing'**

:ignore: Value will be ignored and not be stored in the result.
:store: Value will be stored in the result as is. In case of ``on_missing`` it
        will store ``missing_value``.
:raise: Corresponding exception will be raised.
:cast: Value will be casted with precasters, postcasters and then stored.
       Works only with ``on_extra``!

With ``precasters`` and ``postcasters`` you will transform every caster in
schema into a chain, which starts and/or ends with those casters.


.. |pypi| image:: https://img.shields.io/pypi/v/datacast.svg?style=flat-square&label=version
    :target: https://pypi.org/project/datacast
    :alt: Latest version released on PyPI

.. |python_version| image:: https://img.shields.io/badge/python-%3E%3D3.3-blue.svg?style=flat-square
    :alt: Minimal Python version

.. |coverage| image:: https://img.shields.io/badge/coverage-86%25-yellowgreen.svg?style=flat-square
    :alt: Test coverage

.. |license| image:: https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square
    :target: https://raw.githubusercontent.com/fatemonk/datacast/master/LICENSE
    :alt: Package license