do-py


Namedo-py JSON
Version 0.4.1 PyPI version JSON
download
home_pagehttps://github.com/do-py-together/do-py
SummaryData validation and standardization library wrapping Python dictionaries.
upload_time2023-05-20 14:13:26
maintainer
docs_urlNone
authorTim Davis
requires_python
license
keywords development oo
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Do-Py
Do-Py, shorthand for DataObject Python, is a data-validation and standardization library wrapping Python dictionaries.

![release](https://img.shields.io/github/package-json/v/do-py-together/do-py?label=release&logo=release&style=flat-square)
![build](https://img.shields.io/github/workflow/status/do-py-together/do-py/test?style=flat-square)
![coverage](https://img.shields.io/codecov/c/github/do-py-together/do-py?style=flat-square)
![dependencies](https://img.shields.io/librariesio/release/pypi/do-py?style=flat-square)

##### Project milestones

![Beta ready](https://img.shields.io/github/milestones/progress/do-py-together/do-py/1?label=Issues%20until%20Beta&style=flat-square)
![Stable ready](https://img.shields.io/github/milestones/progress/do-py-together/do-py/2?label=Issues%20until%20Stable&style=flat-square)

## Quick-Start

### Make a basic DataObject.
We will make a class and call it `MyFavoriteStuff`. We
will inherit the DataObject class to gain all its wonderful features.
Here you can see we must define the '_restrictions' attribute.
```python
from do_py import DataObject, R


class MyFavoriteStuff(DataObject):
    """
    A DataObject that contains all of my favorite items.
    :restriction favorite_number: The number I favor the most. Strings not allowed.
    :restriction favorite_candy: My favorite candy, this is restricted by value.
    :restriction favorite_movie: My favorite movie. This is optional because a `None` IS allowed!
    """
    # There are two kinds of restrictions, type and value.
    _restrictions = {
        # Type restrictions restrict the type a value can have: int, str, bool, or other DataObjects's
        'favorite_number': R.INT,
        # Value restrictions restrict the value to a specific value in a list.
        'favorite_candy': R('Jolly Ranchers', 'Nerds'),
        # This is a type restriction that allows `None` as a value.
        'favorite_movie': R.NULL_STR
        }


# Instantiate your new DataObject.
instance = MyFavoriteStuff({
    'favorite_number': 1985,
    'favorite_candy': 'Jolly Ranchers',
    'favorite_movie': 'Jolly Green Giant'
    })

print(instance)
# output: MyFavoriteStuff{"favorite_candy": "Jolly Ranchers", "favorite_number": 1985, "favorite_movie": "Jolly Green Giant"}

# You can access values using dot notation or like a `dict`.
print(instance.favorite_number == instance['favorite_number'])
# output: True

print(instance.favorite_number)
print(instance.favorite_candy)
print(instance.favorite_movie)
# output: 1985
# output: Jolly Ranchers
# output: Jolly Green Giant

# Editing the values can also be done very easily.
instance.favorite_number = 2013
print(instance.favorite_number)
# output: 2013
```


### Using restrictions.

Restrictions are written using `do_py.R`. `R` allows developers to define custom value restrictions as well as type
restrictions using the special shortcuts. Here are a few examples of how you can write value restrictions and type
restrictions using the type short-cuts.
```python
from do_py import DataObject, R


class TypeShorCuts(DataObject):
    """
    All of the restrictions written for this DataObject us R's type shortcuts.
    """
    _restrictions = {
        # integer
        'int': R.INT,
        'nullable_int': R.NULL_INT,
        # string
        'str': R.STR,
        'nullable_str': R.NULL_STR,
        # bool
        'bool': R.BOOL,
        # date and datetime
        'date': R.DATE,
        'nullable_date': R.NULL_DATE,
        'datetime': R.DATETIME,
        'nullable_datetime': R.NULL_DATETIME,
        # other (these are rarely used(aqw
        'set': R.SET,
        'list': R.LIST,
        }


class ValueRestrictions(DataObject):
    """
    All of the restrictions for this class are value restrictions.
    """
    _restrictions = {
        # number values
        'integers': R(1, 2, 3),
        'integers and None': R(1, 2, 3, None),
        # string values
        'strings': R('hello', 'hi', 'sup'),
        'nullable_strings': R('hello', 'hi', 'sup', None),
        }
```


### Give the DataObject default values.
DataObjects are able to define the default value for their restrictions. If a developer is not sure
if a value will be available, defaults are a very useful utility. We have updated the original example to have
a default value for it's restriction `favorite_candy.`

In order to use the default value when instantiating a DataObject, we must instantiate it in non-strict mode.

Strict instantiation is used by default. In strict instantiation, the data passed in must contain all the
keys defined in the DataObject's `_restrictions`.

With non-strict initialization, it is acceptable to have some keys missing per DO _restrictions. For all missing keys,
the default restriction value is used. This section provides an example of using a DataObject in non-strict mode
so that we can use the default values for `favorite_candy`.
```python
from do_py import DataObject, R


class MyFavoriteStuff(DataObject):
    """
    :restriction favorite_number: The default value is 1.
    :restriction favorite_candy: The default value is is "Unknown".
    :restriction favorite_movie: When nullable, the default value is `None`.
    """
    _restrictions = {
        'favorite_number': R.INT.with_default(1),
        'favorite_candy': R('Jolly Ranchers', 'Nerds', 'Unknown', default='Unknown'),
        'favorite_movie': R.NULL_STR
        }


# In order to use the default value when instantiating a DataObject, we must instantiate it in non-strict mode.
# Any values that are not provided will use defaults.
instance = MyFavoriteStuff({}, strict=False)

print(instance)
# output: MyFavoriteStuff{"favorite_candy": "Unknown", "favorite_number": 1, "favorite_movie": null}
```


### Nest a DataObject in another DataObject.
```python
from do_py import DataObject, R


class Contact(DataObject):
    _restrictions = {
        'phone_number'
        }


class Author(DataObject):
    """
    A DataObject that contains all of my favorite items.
    :restriction id:
    :restriction favorite_candy: My favorite candy, this is restricted by value.
    :restriction favorite_movie: My favorite movie. This is optional because a `None` IS allowed!
    """
    _restrictions = {
        'id': R.INT,
        'name': R.STR,
        'contact': Contact
        }


class VideoGame(DataObject):
    """
    A DataObject that contains all of my favorite items.
    :restriction id:
    :restriction favorite_candy: My favorite candy, this is restricted by value.
    :restriction favorite_movie: My favorite movie. This is optional because a `None` IS allowed!
    """
    _restrictions = {
        'id': R.INT,
        'name': R.NULL_STR,
        'author': Author
        }


# Data objects must be instantiated at their **init** with a dictionary and
#   strict(True(default) or False)
instance = VideoGame({
    'favorite_number': 1985,
    'favorite_candy': 'Jolly Ranchers',
    'favorite_movie': 'Jolly Green Giant'
    })

print(instance)
```


### Nest a list of DataObjects in another DataObject.
```python
from do_py import DataObject, R
from do_py.common.managed_list import ManagedList


class Book(DataObject):
    """
    There are multiple books in the library!
    :restriction name: Name of the book.
    :restriction author: The author of the book.
    """
    _restrictions = {
        'name': R.STR,
        'author': R.STR,
        }


class Library(DataObject):
    """
    This DataObject represents a library which contains multiple books.
    :restriction city: The city the library is located in.
    :restriction books: A list of instances of the DataObject "Book".
    """
    _restrictions = {
        'city': R.STR,
        'books': ManagedList(Book)
        }
```



## What is a DataObject?

A DataObject allows us to create Python classes that have strictly defined fields called "restrictions". Restrictions
are defined for a DataObject using the `_restriction` attribute. See the Quick-start section.

There are two kinds of restrictions, type and value:
* Value restrictions restrict the value to a specific value in a list.
* Type restrictions restrict the type a value can have: int, str, bool, or other DataObjects.

## Advanced Uses

### Advanced DataObject validations.

Certain use-cases require more complex validations or restrictions that cannot be supported without code execution.
The parent class `Validator` allows us to execute code at instantiation and any time a key is updated. A child of
`Validator` is required to define a `_validate` instance method.
```python
from do_py import R
from do_py.data_object.validator import Validator


class Validated(Validator):
    """
    This DataObject validates that we only have one of key or id, but not both. Since this can't be accomplished only
    using restrictions, we are inheriting from `Validator` so we can attach extra validations.
    """
    _restrictions = {
        'key': R.NULL_STR,
        'id': R.NULL_INT
        }

    def _validate(self):
        """
        Validate that we have exactly one of key or id.

        This function runs at instantiation and any time the instance is updated.
        """
        assert any([self.key, self.id]) and not all([self.key, self.id]), \
            'We need exactly one of id or key to not be None.'
```



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/do-py-together/do-py",
    "name": "do-py",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "development,OO",
    "author": "Tim Davis",
    "author_email": "timdavis.3991@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/e3/82/ab7853338419f8bcdf4e994f9856c552f356a9c55239226e4ab693ef518a/do-py-0.4.1.tar.gz",
    "platform": null,
    "description": "# Do-Py\nDo-Py, shorthand for DataObject Python, is a data-validation and standardization library wrapping Python dictionaries.\n\n![release](https://img.shields.io/github/package-json/v/do-py-together/do-py?label=release&logo=release&style=flat-square)\n![build](https://img.shields.io/github/workflow/status/do-py-together/do-py/test?style=flat-square)\n![coverage](https://img.shields.io/codecov/c/github/do-py-together/do-py?style=flat-square)\n![dependencies](https://img.shields.io/librariesio/release/pypi/do-py?style=flat-square)\n\n##### Project milestones\n\n![Beta ready](https://img.shields.io/github/milestones/progress/do-py-together/do-py/1?label=Issues%20until%20Beta&style=flat-square)\n![Stable ready](https://img.shields.io/github/milestones/progress/do-py-together/do-py/2?label=Issues%20until%20Stable&style=flat-square)\n\n## Quick-Start\n\n### Make a basic DataObject.\nWe will make a class and call it `MyFavoriteStuff`. We\nwill inherit the DataObject class to gain all its wonderful features.\nHere you can see we must define the '_restrictions' attribute.\n```python\nfrom do_py import DataObject, R\n\n\nclass MyFavoriteStuff(DataObject):\n    \"\"\"\n    A DataObject that contains all of my favorite items.\n    :restriction favorite_number: The number I favor the most. Strings not allowed.\n    :restriction favorite_candy: My favorite candy, this is restricted by value.\n    :restriction favorite_movie: My favorite movie. This is optional because a `None` IS allowed!\n    \"\"\"\n    # There are two kinds of restrictions, type and value.\n    _restrictions = {\n        # Type restrictions restrict the type a value can have: int, str, bool, or other DataObjects's\n        'favorite_number': R.INT,\n        # Value restrictions restrict the value to a specific value in a list.\n        'favorite_candy': R('Jolly Ranchers', 'Nerds'),\n        # This is a type restriction that allows `None` as a value.\n        'favorite_movie': R.NULL_STR\n        }\n\n\n# Instantiate your new DataObject.\ninstance = MyFavoriteStuff({\n    'favorite_number': 1985,\n    'favorite_candy': 'Jolly Ranchers',\n    'favorite_movie': 'Jolly Green Giant'\n    })\n\nprint(instance)\n# output: MyFavoriteStuff{\"favorite_candy\": \"Jolly Ranchers\", \"favorite_number\": 1985, \"favorite_movie\": \"Jolly Green Giant\"}\n\n# You can access values using dot notation or like a `dict`.\nprint(instance.favorite_number == instance['favorite_number'])\n# output: True\n\nprint(instance.favorite_number)\nprint(instance.favorite_candy)\nprint(instance.favorite_movie)\n# output: 1985\n# output: Jolly Ranchers\n# output: Jolly Green Giant\n\n# Editing the values can also be done very easily.\ninstance.favorite_number = 2013\nprint(instance.favorite_number)\n# output: 2013\n```\n\n\n### Using restrictions.\n\nRestrictions are written using `do_py.R`. `R` allows developers to define custom value restrictions as well as type\nrestrictions using the special shortcuts. Here are a few examples of how you can write value restrictions and type\nrestrictions using the type short-cuts.\n```python\nfrom do_py import DataObject, R\n\n\nclass TypeShorCuts(DataObject):\n    \"\"\"\n    All of the restrictions written for this DataObject us R's type shortcuts.\n    \"\"\"\n    _restrictions = {\n        # integer\n        'int': R.INT,\n        'nullable_int': R.NULL_INT,\n        # string\n        'str': R.STR,\n        'nullable_str': R.NULL_STR,\n        # bool\n        'bool': R.BOOL,\n        # date and datetime\n        'date': R.DATE,\n        'nullable_date': R.NULL_DATE,\n        'datetime': R.DATETIME,\n        'nullable_datetime': R.NULL_DATETIME,\n        # other (these are rarely used(aqw\n        'set': R.SET,\n        'list': R.LIST,\n        }\n\n\nclass ValueRestrictions(DataObject):\n    \"\"\"\n    All of the restrictions for this class are value restrictions.\n    \"\"\"\n    _restrictions = {\n        # number values\n        'integers': R(1, 2, 3),\n        'integers and None': R(1, 2, 3, None),\n        # string values\n        'strings': R('hello', 'hi', 'sup'),\n        'nullable_strings': R('hello', 'hi', 'sup', None),\n        }\n```\n\n\n### Give the DataObject default values.\nDataObjects are able to define the default value for their restrictions. If a developer is not sure\nif a value will be available, defaults are a very useful utility. We have updated the original example to have\na default value for it's restriction `favorite_candy.`\n\nIn order to use the default value when instantiating a DataObject, we must instantiate it in non-strict mode.\n\nStrict instantiation is used by default. In strict instantiation, the data passed in must contain all the\nkeys defined in the DataObject's `_restrictions`.\n\nWith non-strict initialization, it is acceptable to have some keys missing per DO _restrictions. For all missing keys,\nthe default restriction value is used. This section provides an example of using a DataObject in non-strict mode\nso that we can use the default values for `favorite_candy`.\n```python\nfrom do_py import DataObject, R\n\n\nclass MyFavoriteStuff(DataObject):\n    \"\"\"\n    :restriction favorite_number: The default value is 1.\n    :restriction favorite_candy: The default value is is \"Unknown\".\n    :restriction favorite_movie: When nullable, the default value is `None`.\n    \"\"\"\n    _restrictions = {\n        'favorite_number': R.INT.with_default(1),\n        'favorite_candy': R('Jolly Ranchers', 'Nerds', 'Unknown', default='Unknown'),\n        'favorite_movie': R.NULL_STR\n        }\n\n\n# In order to use the default value when instantiating a DataObject, we must instantiate it in non-strict mode.\n# Any values that are not provided will use defaults.\ninstance = MyFavoriteStuff({}, strict=False)\n\nprint(instance)\n# output: MyFavoriteStuff{\"favorite_candy\": \"Unknown\", \"favorite_number\": 1, \"favorite_movie\": null}\n```\n\n\n### Nest a DataObject in another DataObject.\n```python\nfrom do_py import DataObject, R\n\n\nclass Contact(DataObject):\n    _restrictions = {\n        'phone_number'\n        }\n\n\nclass Author(DataObject):\n    \"\"\"\n    A DataObject that contains all of my favorite items.\n    :restriction id:\n    :restriction favorite_candy: My favorite candy, this is restricted by value.\n    :restriction favorite_movie: My favorite movie. This is optional because a `None` IS allowed!\n    \"\"\"\n    _restrictions = {\n        'id': R.INT,\n        'name': R.STR,\n        'contact': Contact\n        }\n\n\nclass VideoGame(DataObject):\n    \"\"\"\n    A DataObject that contains all of my favorite items.\n    :restriction id:\n    :restriction favorite_candy: My favorite candy, this is restricted by value.\n    :restriction favorite_movie: My favorite movie. This is optional because a `None` IS allowed!\n    \"\"\"\n    _restrictions = {\n        'id': R.INT,\n        'name': R.NULL_STR,\n        'author': Author\n        }\n\n\n# Data objects must be instantiated at their **init** with a dictionary and\n#   strict(True(default) or False)\ninstance = VideoGame({\n    'favorite_number': 1985,\n    'favorite_candy': 'Jolly Ranchers',\n    'favorite_movie': 'Jolly Green Giant'\n    })\n\nprint(instance)\n```\n\n\n### Nest a list of DataObjects in another DataObject.\n```python\nfrom do_py import DataObject, R\nfrom do_py.common.managed_list import ManagedList\n\n\nclass Book(DataObject):\n    \"\"\"\n    There are multiple books in the library!\n    :restriction name: Name of the book.\n    :restriction author: The author of the book.\n    \"\"\"\n    _restrictions = {\n        'name': R.STR,\n        'author': R.STR,\n        }\n\n\nclass Library(DataObject):\n    \"\"\"\n    This DataObject represents a library which contains multiple books.\n    :restriction city: The city the library is located in.\n    :restriction books: A list of instances of the DataObject \"Book\".\n    \"\"\"\n    _restrictions = {\n        'city': R.STR,\n        'books': ManagedList(Book)\n        }\n```\n\n\n\n## What is a DataObject?\n\nA DataObject allows us to create Python classes that have strictly defined fields called \"restrictions\". Restrictions\nare defined for a DataObject using the `_restriction` attribute. See the Quick-start section.\n\nThere are two kinds of restrictions, type and value:\n* Value restrictions restrict the value to a specific value in a list.\n* Type restrictions restrict the type a value can have: int, str, bool, or other DataObjects.\n\n## Advanced Uses\n\n### Advanced DataObject validations.\n\nCertain use-cases require more complex validations or restrictions that cannot be supported without code execution.\nThe parent class `Validator` allows us to execute code at instantiation and any time a key is updated. A child of\n`Validator` is required to define a `_validate` instance method.\n```python\nfrom do_py import R\nfrom do_py.data_object.validator import Validator\n\n\nclass Validated(Validator):\n    \"\"\"\n    This DataObject validates that we only have one of key or id, but not both. Since this can't be accomplished only\n    using restrictions, we are inheriting from `Validator` so we can attach extra validations.\n    \"\"\"\n    _restrictions = {\n        'key': R.NULL_STR,\n        'id': R.NULL_INT\n        }\n\n    def _validate(self):\n        \"\"\"\n        Validate that we have exactly one of key or id.\n\n        This function runs at instantiation and any time the instance is updated.\n        \"\"\"\n        assert any([self.key, self.id]) and not all([self.key, self.id]), \\\n            'We need exactly one of id or key to not be None.'\n```\n\n\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Data validation and standardization library wrapping Python dictionaries.",
    "version": "0.4.1",
    "project_urls": {
        "Homepage": "https://github.com/do-py-together/do-py"
    },
    "split_keywords": [
        "development",
        "oo"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "375e44aec4469865cf7078f5d942c9835ae86915926880a1a0e98e2e7d5af139",
                "md5": "f4ff8af5f933859549979e5e39019402",
                "sha256": "d554a2d5ecaa63a3fd392a2c87b04cb8f0cf1df9d355973ae97d2a3e79227fd4"
            },
            "downloads": -1,
            "filename": "do_py-0.4.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f4ff8af5f933859549979e5e39019402",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 29461,
            "upload_time": "2023-05-20T14:13:23",
            "upload_time_iso_8601": "2023-05-20T14:13:23.568946Z",
            "url": "https://files.pythonhosted.org/packages/37/5e/44aec4469865cf7078f5d942c9835ae86915926880a1a0e98e2e7d5af139/do_py-0.4.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e382ab7853338419f8bcdf4e994f9856c552f356a9c55239226e4ab693ef518a",
                "md5": "56462b02ffc77a9361720fd96e4c5614",
                "sha256": "1afc307e5c50607d8eb4877fbeccab3a8339289eeae649ca1d368029e8529e9d"
            },
            "downloads": -1,
            "filename": "do-py-0.4.1.tar.gz",
            "has_sig": false,
            "md5_digest": "56462b02ffc77a9361720fd96e4c5614",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 27081,
            "upload_time": "2023-05-20T14:13:26",
            "upload_time_iso_8601": "2023-05-20T14:13:26.038860Z",
            "url": "https://files.pythonhosted.org/packages/e3/82/ab7853338419f8bcdf4e994f9856c552f356a9c55239226e4ab693ef518a/do-py-0.4.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-05-20 14:13:26",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "do-py-together",
    "github_project": "do-py",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "do-py"
}
        
Elapsed time: 0.06641s