Skip to main content

A lightweight type/object checking library.

Project description

pytechecker

Tests

Pytechecker is a utility library for type checking objects against sample objects.

Table of Contents

Pytechecker works excellently for checking API payloads. For how it can be used for this, here's an example of how it can be used together with a flask api.

Examples

The gist of it all

Use pip to install pytechecker python3 -m pip install pytechecker.

Then you simply use the check function from the module.

from pytechecker import check

sample = {
    "name": {
        "required": True,
        "allowed_types": [str]
    },
    "age": {
        "required": True,
        "allowed_types": [int]
    }
}

obj = {
    "name": "dcronqvist",
    "age": 21
}

# succ will be True if it passed type checking
# errors will be an array of strings that tell you
# what went wrong during type checking, if succ is False.
succ, errors = check(sample, obj)

A simple example

Let's start by taking a look at a very simple sample object:

{
    "name": {
        "required": True,
        "allowed_types": [str]
    },
    "age": {
        "required": False,
        "allowed_types": [int]
    }
}

Here we have defined a sample object which has one required key name and one optional key age. In the sample object we have also specified that the key name can only be of the type str, and age can only be an int. Let's see which objects that fit this sample.

{
    "name": "Daniel",
    "age": 21
}

Above we have an object which fits the sample object. It's an object which has the required key name and the optional key age, and they both are their respective required types.

{
    "name": "Daniel"
}

Above is an object that still fits the sample object. Since the key age is optional, we can omit it from the object without it causing it to be unfit.

{
    "age": 21
}

The above object does, however, NOT fit the sample object. Upon attempting to match the object against the sample, you'll be met with the following error:

ERROR: Key 'name' is required, but was absent in supplied object.

We can also look at an example like this:

{
    "name": "Daniel",
    "age": 21.4
}

The above object is unfit since one of its keys is of a type that is not allowed for that key. You'll be met with the following error:

ERROR: On key 'age', expected one of ['int'], got float.

So there we have it. That's a very simple example of how it works.

Embedded dicts

We don't want to be limited to dicts of only one level, so thankfully pytechecker can handle virtually infinite levels of dicts in dicts. Let's look at an example.

{
    "tenant": {
        "required": True,
        "allowed_types": [dict],
        "embedded_dict": {
            "name": {
                "required": True,
                "allowed_types": [str]
            },
            "age": {
                "required": True,
                "allowed_types": [int]
            }
        }
    },
    "room": {
        "required": True,
        "allowed_types": [str]
    }
}

Above we have a sample object which has a top level key which is allowed to a dict. We can very easily also specify what this embedded dict must look like for it to fit. Let's look at some objects!

{
    "tenant": {
        "name": "Daniel",
        "age": 21
    },
    "room": "RM-212512"
}

This is an object which fits, like a glove! We have the key tenant which of course is a dict (or object) and then the key room which is a string, like specified! We can also see that all keys inside of tenant are required, so leaving one out would result in something like the following:

ERROR: Key 'tenant.age' is required, but was absent in supplied object.

Pytechecker is very nice and also tells you the entire key from top level and down, and won't just say that age is missing.

Like said, this works for a virtually infinite amount of dicts in dicts - it's done via recursion!

What about lists?

Lists are handled very nicely by pytechecker. It will go through all elements in the list and type check them for you. You can even have list elements that are dicts, and they'll also be handled! Let's look at a simple example with lists to begin with.

{
    "nums": {
        "required": True,
        "allowed_types": [list],
        "list_element": {
            "allowed_types": [int, float]
        }
    }
}

Here we have a sample object with a required key nums which must be a list of numbers.

{
    "nums": [5, 1.2, 9, 12.4]
}

Above here is an object which fits since it has they key nums and all elements are of the correct types.

{
    "nums": [5, 1.2, 9, 12.4, "5"]
}

Having something like the object above would give an error like the following:

ERROR: On key 'nums[4]', expected one of ['int', 'float'], got str.

See that [4]? Pytechecker also tells you which element(s) that are wrong in a list. If we would have multiple wrong elements:

{
    "nums": [5, "1.2", 9, 12.4, "5"]
}

We would get multiple errors like this:

[
    "ERROR: On key 'nums[1]', expected one of ['int', 'float'], got str.", 
    "ERROR: On key 'nums[4]', expected one of ['int', 'float'], got str."
]

Important to note is that all errors that have been shown before this example have also been part of an array, they have just been the only element in that array of errors.

Dicts as list elements

{
    "people": {
        "required": True,
        "allowed_types": [list],
        "list_element": {
            "allowed_types": [dict],
            "embedded_dict": {
                "name": {
                    "required": True,
                    "allowed_types": [str]
                },
                "age": {
                    "required": False,
                    "allowed_types": [int]
                }
            }
        }
    }
}

Right, so here we have a sample object which contains a key people which should contain a list of objects with a required key name and optional key age. Let's look at some objects.

{
    "people": [
        {
            "name": "Daniel",
            "age": 21
        },
        {
            "name": "John",
            "age": 42
        },
        {
            "name": "Betty"
        }
    ]
}

Here is our list of people with their names and optional age. This object fits, so let's look at one that doesn't fit.

{
    "people": [
        {
            "name": "Daniel",
            "age": 21
        },
        {
            "name": "John",
            "age": 42
        },
        {
            "age": 35
        }
    ]
}

The person Betty now doesn't have a name, instead it only has an age. This will result in the following error:

ERROR: Key 'people[2].name' is required, but was absent in supplied object.

Once again, pytechecker tells you which of these objects that is unfit, and also what about that object that is unfit.

Tuples

Tuples are much like lists, and handled a lot like them. However, tuples are specified by type order, so that the supplied object must match type order as well, let's look at an example.

{
    "tuple": {
        "required": True,
        "allowed_types": [tuple],
        "tuple_order": [str, int, int, float]
    }
}

Here we have a sample object which specifies a tuple with the specific order of (str, int, int, float). Let's look at objects!

{
    "tuple": ("Hello there!", 5, 2, 1.1)
}

There we are, an object which fits the tuple description perfectly. If we, however, were to flip around some values to not be in the same type order:

{
    "tuple": ("Hello there!", 5, 1.1, 2)
}

Then we'd be met with the following error:

ERROR: On key 'tuple', expected tuple with order (str,int,int,float), got tuple with order (str,int,float,int).

Dicts and lists in tuples

{
    "tuple": {
        "required": True,
        "allowed_types": [tuple],
        "tuple_order": [list, int, dict],
        "list_element": {
            "allowed_types": [dict],
            "embedded_dict": {
                "name": {
                    "required": True,
                    "allowed_types": [str]
                }
            }
        },
        "embedded_dict": {
            "num": {
                "required": True,
                "allowed_types": [int, float]
            }
        }
    }
}

A sample object which should contain a key tuple, which also should be a tuple. This tuple should, respectively, contain a list of objects, an int and a dict.

{
    "tuple": (
        [
            {
                "name": "Daniel"
            },
            {
                "name": "John"
            }
        ], 
        5, 
        {
            "num": 25
        }
    )
}

The above object fits like a glove!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytechecker-1.0.1.tar.gz (7.0 kB view details)

Uploaded Source

Built Distribution

pytechecker-1.0.1-py3-none-any.whl (6.3 kB view details)

Uploaded Python 3

File details

Details for the file pytechecker-1.0.1.tar.gz.

File metadata

  • Download URL: pytechecker-1.0.1.tar.gz
  • Upload date:
  • Size: 7.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.8.7

File hashes

Hashes for pytechecker-1.0.1.tar.gz
Algorithm Hash digest
SHA256 293528e101f05a1e1d2f8915aedc7a3f5b27808e07c71cec298707d1569896c3
MD5 4efeba01618a3ea12b8f711d522ff294
BLAKE2b-256 4d3d462919a1429f1af2048d8555560558e0030187ffe4f4a25bf56027c6b048

See more details on using hashes here.

File details

Details for the file pytechecker-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: pytechecker-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 6.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.25.1 setuptools/49.2.1 requests-toolbelt/0.9.1 tqdm/4.56.0 CPython/3.8.7

File hashes

Hashes for pytechecker-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bdd602bf032d7814bee9262bf1c10932f182a58f780bb9e037f47f2d17bdac7e
MD5 da8cd5e603a6a837c7f43a0789160ba6
BLAKE2b-256 ceeeda12161aa5f4259d9df8c2bdf7d325279ddb096630e1af49086944dbb678

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page