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

packages = \
['cerealbox']

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

setup_kwargs = {
    'name': 'cerealbox',
    'version': '0.1.0',
    'description': 'Zero dependency generic serializer and deserializer with DynamoDB JSON support',
    'long_description': '# CerealBox for Python\n\nCerealBox is a Zero Dependency generic Serializer / Deserializer for python dictionaries. It has an extendable\narchitecture that allows custom serializers to be built through config. The module also includes built in\nimplementations of serializing common data types to a JSON compatible dictionary or DynamoDB JSON.\n\n## Getting started\n\n### Install the module\n\nUsing poetry\n\n```\npoetry add cerealbox\n```\n\nor using pip\n\n```\npip install cerealbox\n```\n\n### Using the built-in serializers\n\n* jsonable\n\nThe jsonable serializer converts any input dict or value into JSON serializable output value.\n\n```python\nfrom cerealbox.jsonable import as_jsonable\nfrom decimal import Decimal\nfrom enum import Enum\nfrom datetime import datetime\n\n\nclass Country(Enum):\n    ZA = \'South Africa\'\n    AU = \'Australia\'\n    US = \'United States\'\n\n\nsample_input = {\n    "name": "Jane",\n    "age": 23,\n    "balance": Decimal(\'250.10\'),\n    "country": Country.ZA,\n    "updated_at": datetime(2020, 1, 1)\n}\n\nprint(as_jsonable(sample_input))\n# {\'name\': \'Jane\', \'age\': 23, \'balance\': \'250.10\', \'country\': \'South Africa\', \'updated_at\': \'2020-01-01T00:00:00\'}\n\n# You can also use as_jsonable as the default function to json.dumps \nimport json\n\nprint(json.dumps(sample_input, default=as_jsonable, indent=4))\n# {\n#     "name": "Jane",\n#     "age": 23,\n#     "balance": "250.10",\n#     "country": "South Africa",\n#     "updated_at": "2020-01-01T00:00:00"\n# }\n```\n\nThe default encoders for `as_jsonable` are as follows:\n\n```\n     | Python            | JSONABLE        |\n     +===================+=================+\n     | dict              | dict            |\n     | list, tuple       | list            |\n     | set               | list            |\n     | string            | string          |\n     | int, float        | int, float      |\n     | bool              | bool            |\n     | None              | None            |\n     | Decimal           | string          |\n     | datetime          | string (iso)    |\n     | enum              | string (value)  |\n     | uuid              | string          |\n```\n\n* DynamoDB\n\nThe DynamoDB Serializer/Deserializer is capable of transforming python values into DynamoDB JSON and back. It supports\nmost common data types. Some transformations are not reversible (eg converting a datetime to a string). This limitation\nis due to cerealbox being schemaless, and can be overcome by using a module such as `typed-models` or `pydantic`\n\n```python\nfrom cerealbox.dynamo import from_dynamodb_json, as_dynamodb_json\nfrom decimal import Decimal\nfrom enum import Enum\nfrom datetime import datetime\nfrom pprint import pprint\n\n\nclass Country(Enum):\n    ZA = \'South Africa\'\n    AU = \'Australia\'\n    US = \'United States\'\n\n\nsample_input = {\n    "name": "Jane",\n    "age": 23,\n    "balance": Decimal(\'250.10\'),\n    "country": Country.ZA,\n    "updated_at": datetime(2020, 1, 1)\n}\n\nddb_json = as_dynamodb_json(sample_input)\npprint(ddb_json)\n# {\'M\': {\'age\': {\'N\': \'23\'},\n#        \'balance\': {\'N\': \'250.10\'},\n#        \'country\': {\'S\': \'South Africa\'},\n#        \'name\': {\'S\': \'Jane\'},\n#        \'updated_at\': {\'S\': \'2020-01-01T00:00:00\'}}}\n\n# Reversing the operation\n\npprint(from_dynamodb_json(ddb_json))\n\n# {\'age\': Decimal(\'23\'),\n#  \'balance\': Decimal(\'250.10\'),\n#  \'country\': \'South Africa\',\n#  \'name\': \'Jane\',\n#  \'updated_at\': \'2020-01-01T00:00:00\'}\n```\n\nWhen serializing from a dictionary to DynamoDB JSON, the following mapping is used:\n\n```\n   Python                                  DynamoDB\n   ------                                  --------\n   None                                    {\'NULL\': True}\n   True/False                              {\'BOOL\': True/False}\n   int/Decimal                             {\'N\': str(value)}\n   string                                  {\'S\': string}\n   Binary/bytearray/bytes (py3 only)       {\'B\': bytes}\n   set([int/Decimal])                      {\'NS\': [str(value)]}\n   set([string])                           {\'SS\': [string])\n   set([Binary/bytearray/bytes])           {\'BS\': [bytes]}\n   list                                    {\'L\': list}\n   dict                                    {\'M\': dict}\n   float                                   {\'S\': str(value)}\n   datetime/date/time                      {\'S\': str(value.isoformat())}\n   Enum                                    {\'S\': str(value.value)}\n   UUID                                    {\'S\': str(value)}\n```\n\nWhen serializing from DynamoDB JSON to a Python dict, the following mapping is used:\n\n```\n   DynamoDB                                Python\n   --------                                ------\n   {\'NULL\': True}                          None\n   {\'BOOL\': True/False}                    True/False\n   {\'N\': str(value)}                       Decimal(str(value))\n   {\'S\': string}                           string\n   {\'B\': bytes}                            Binary(bytes)\n   {\'NS\': [str(value)]}                    set([Decimal(str(value))])\n   {\'SS\': [string]}                        set([string])\n   {\'BS\': [bytes]}                         set([bytes])\n   {\'L\': list}                             list\n   {\'M\': dict}                             dict\n```\n\n### Writing your own serializer\n\nA serializer is made up of a dict that maps each datatype to a function that produces its serialized version. There are\n3 special cases for these functions:\n\n1. If the type and the mapped function are the same (eg `{str: str}`), the value is not modified during serialization.\n   This is a performance optimization.\n2. Dealing with the value `None` is a special case, since `type(None)` is `NoneType`. If you would like to handle `None`\n   , import `NoneType` from cerealbox and use it as the type\n3. If a type maps to a function that accepts a parameter named `serialize`, an instance of the serializer is passed\n   along with the function. This allows recursive calls to deal with items inside of dictionaries, lists etc.\n\nExample use case:\n-\n> When serializing a dict, convert all Decimal types to a String with the prefix `$ `. Redact any string that contains the word "classified". Handle nested items inside of a list in a similar manner\n\n```python\nfrom cerealbox import Cereal\nfrom decimal import Decimal\nfrom pprint import pprint\n\ndef redact_strings(value):\n   if \'classified\' in value.lower():\n      return "***classified***"\n   \n   return value\n\ndef serialize_list(value, serialize):\n   return [serialize(item) for item in value]\n\nENCODERS = {\n   str: redact_strings,\n   Decimal: lambda num: f"$ {num}",\n   list: serialize_list,\n   dict: lambda v, serialize: {k_: serialize(v_) for k_, v_ in v.items()}\n}\n\ncustom_serializer = Cereal(encoders=ENCODERS)\n\nsample_input = {\n   "name": "Jane",\n   "assignment": "Eat Cereal. Mission is Classified",\n   "funds": Decimal(\'1024.50\'),\n   "keywords": [Decimal(\'1.5\'), "Hello, World", "I am classified."]\n}\n\npprint(custom_serializer(sample_input))\n# {\'assignment\': \'***classified***\',\n#  \'funds\': \'$ 1024.50\',\n#  \'keywords\': [\'$ 1.5\', \'Hello, World\', \'***classified***\'],\n#  \'name\': \'Jane\'}\n```\n\n### Extending an existing serializer\n\n> Extend jsonable to redact strings containing the word Classified\n\n```python\nfrom cerealbox.jsonable import as_jsonable\n\ndef redact_strings(value):\n   if \'classified\' in value.lower():\n      return "***classified***"\n   \n   return value\n\nas_jsonable.extend_encoders({str: redact_strings})\n\nsample_input = {\n    "name": "Jane",\n    "age": 23,\n    "mission": "[Classified] Divide by zero and see what happens.",\n}\n\nprint(as_jsonable(sample_input))\n# {\'name\': \'Jane\', \'age\': 23, \'mission\': \'***classified***\'}\n```\n\n## Contributing\n\nTo work on the cerealbox codebase, you\'ll want to clone the project locally and install the required dependencies\nvia `poetry <https://poetry.eustace.io>`_.\n\n```bash\ngit clone git@github.com:a2d24/cerealbox.git\n```\n',
    'author': 'Imtiaz Mangerah',
    'author_email': 'Imtiaz_Mangerah@a2d24.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/a2d24/cerealbox',
    'packages': packages,
    'package_data': package_data,
    'python_requires': '>=3.8,<4.0',
}


setup(**setup_kwargs)
