Data validation and standardization library wrapping Python dictionaries.
Project description
Do-Py
Do-Py, shorthand for DataObject Python, is a data-validation and standardization library wrapping Python dictionaries.
Project milestones
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.
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.
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
.
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.
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.
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.
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.'
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file do-py-0.4.1.tar.gz
.
File metadata
- Download URL: do-py-0.4.1.tar.gz
- Upload date:
- Size: 27.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.27.1 setuptools/61.3.1 requests-toolbelt/0.9.1 tqdm/4.63.1 CPython/3.9.9
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1afc307e5c50607d8eb4877fbeccab3a8339289eeae649ca1d368029e8529e9d |
|
MD5 | 56462b02ffc77a9361720fd96e4c5614 |
|
BLAKE2b-256 | e382ab7853338419f8bcdf4e994f9856c552f356a9c55239226e4ab693ef518a |
File details
Details for the file do_py-0.4.1-py3-none-any.whl
.
File metadata
- Download URL: do_py-0.4.1-py3-none-any.whl
- Upload date:
- Size: 29.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.27.1 setuptools/61.3.1 requests-toolbelt/0.9.1 tqdm/4.63.1 CPython/3.9.9
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | d554a2d5ecaa63a3fd392a2c87b04cb8f0cf1df9d355973ae97d2a3e79227fd4 |
|
MD5 | f4ff8af5f933859549979e5e39019402 |
|
BLAKE2b-256 | 375e44aec4469865cf7078f5d942c9835ae86915926880a1a0e98e2e7d5af139 |