datacast

Simple way to cast your data.


Keywords
config, env, data, cast
License
MIT
Install
pip install datacast==0.3.5

Documentation

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


Latest version released on PyPI Minimal Python version Test coverage Package license


Basic Usage

Install with pip:

pip install datacast

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

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.

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.

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.

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.