Skip to main content

flexible testing of nested objects

Project description

PySome

PySome brings the expect(...).to_be(...) syntax to python to give developers more flexible Options for testing for the testing of nested objects.

Installation

$ pip install pysome

Usage:

Example

from pysome import Some, SomeList, SomeDict, expect
# some large nested api response you want to test
api_response = {
    "menu": {
        "tags": [
            {"id": 1, "z-index": 12},
            {"id": 2, "name": "ax7"},
            {"id": 5, "name": "ax7", "z-index": 12},
            {"id": 2, "alias": "iivz"},
        ],
        "randomInt": 4562,
        "auth_token": "1lm7QOvTDj",
        "labels": {
            "en": {
                "name": "name",
                "delete": "remove",
                "add": "insert"
            },
            "de": {
                "name": "Name", 
                "delete": "löschen", 
                "add": "hinzufügen"
            }
        }
    }
}

# test only important stuff
expect(api_response).to_be({
    "menu": {
        "tags": SomeList(
            SomeDict(id=Some(int))
        ),
        "randomInt": Some(int),
        "labels": Some(dict),
    }
})

Why use expect(...).to_be(...) syntax

For most of the basic stuff it would not be necessary to use the expect(...).to_be(...) syntax. You could for example safely do something like:

from pysome import Some

assert {"a": 12, "b": "x", "c": {}} == {"a": Some(int), "b": Some(str), "c": Some(dict)}

Out of different reasons it is still advised to use expect(...).to_be(...)

Some API

Some

Some equals all objects under the given conditions defined by its args. It equals if any of the conditions is true. A condition can either be type, Callable or another Some.

from pysome import Some, expect

expect(...).to_be(Some()) # equals always
expect(12).to_be(Some(int)) # equals any int
expect("abc").to_be(Some(int, str)) # equals all str and all int

Some can equal arbitrary objects by given functions:

from pysome import Some, expect

def sums_to_10(x):
    return sum(x) == 10

expect([2, 3, 5]).to_be(Some(sums_to_10)) # 2 + 3 + 5 == 10
expect([5, 5]).to_be(Some(sums_to_10)) # 5 + 5 = =10
expect([1, 2, 3]).not_to_be(Some(sums_to_10)) # 1 + 2 + 3 != 10
expect({
    "a": 12,
    "b": [4, 3, 3] 
}).to_be({
    "a": Some(int), # 12 is an int
    "b": Some(sums_to_10)  # 4 + 3 + 3 == 10
})

but there are some useful pre-implemented subclasses of Some:

name alias arguments
*args = Union[type, Callable, Some]
short description
Some() *args equals all objects with any given type or function
AllOf() *args equals only an object if all given arguments are fulfilled
SomeOrNone() *args same as Some but also equals None
SomeIterable() *args, length = None, is_type = None equals all Iterables under given conditions
SomeList() *args, length = None, is_type = None equals all Lists under given conditions
SomeDict() partial_dict: dict = None, **kwargs equals all dicts that have given subset
SomeIn() is_in container equals all objects that are in the given container
SomeWithLen() has_len length = None, min_length = None, max_length = None equals al objects that fulfill given length conditions
NotSome() is_not *args equals all objects that do not fulfill any of the given conditions
SomeStr() regex=None, pattern=None, endswith=None, startswith=None equals all strings under given conditions

AllOf

AllOf() equals all objects that fulfill all given conditions. So for example an object AllOf(str, int) could only match an object that inherits from int and str

from pysome import AllOf, expect
def less_than_10(x):
    return x < 10

expect(8).to_be(AllOf(less_than_10, int))
expect(8.5).not_to_be(AllOf(less_than_10, int))

this is in contrast to Some() which equals all object tha fulfill only one of the conditions

SomeOrNone

SomeOrNone() is basically the same as Some() but it also equals None. This is very usefull if you want to test a key of dict but you do not care if it exists.

from pysome import SomeOrNone, SomeDict, Some, expect

expect(12).to_be(SomeOrNone(int))
expect(None).to_be(SomeOrNone(int))
expect("abc").not_to_be(SomeOrNone(int))

expect({
 "id": 1, 
 "name": "abc"
}).to_be(
 SomeDict({
  "id": Some(int),
  "name": SomeOrNone(str) # name must be a string or non existent
 })
)

expect({
 "id": 1, 
}).to_be(
 SomeDict({
  "id": Some(int),
  "name": SomeOrNone(str)
 })
)

SomeIterable

SomeIterable() equals all objects that are iterable where every element of the iterable must fulfill the given conditions.

from pysome import SomeIterable, expect

expect([1, 2, 3]).to_be(SomeIterable(int))
expect([1, 2.5, 3]).not_to_be(SomeIterable(int))

# you can also build nested structure
expect([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).to_be(SomeIterable(SomeIterable(int)))

SomeList

SomeList() works exactly the same as SomeIterable with the only difference that the Iterable must be of type list

SomeDict

SomeDict() equals any dict that has all the given keys (as one dict or as kwargs). If you want to test if a dict has exactly the keys use a default dict instead.

from pysome import SomeDict, SomeList, Some, expect

expect([
 {"id": 1, "name": "ab"},
 {"id": 2, "z-index": -1},
 {"id": 3 },
]).to_be(
 SomeList(
  SomeDict(id=Some(int))
 )
)

SomeIn

SomeIn equals all objects that are in its given container.

from pysome import SomeIn, expect

expect("a").to_be(SomeIn({1, 2, "a"}))
expect("b").not_to_be(SomeIn({1, 2, "a"}))

SomeWithLen

SomeWithLen() equals all objects that fulfill the given length condition. You can either give an explicit length or define a range with min_length and max_length

from pysome import SomeWithLen, expect

expect([1, 2, 3]).to_be(SomeWithLen(3))
expect([1, 2, 3]).to_be(SomeWithLen(min_length=1))
expect([1, 2, 3]).not_to_be(SomeWithLen(max_length=2))

NotSome

NotSome is the opposite of Some. It only equals an object if all given conditions are false.

from pysome import NotSome, expect

expect(1).to_be(NotSome(str, float))
expect(1.5).not_to_be(NotSome(str, float))

SomeStr

SomeStr is a more flexible option to the simple Some(str) that gives you more options like regex, simple wildcard patterns, endswith and startswith.

from pysome import SomeStr, expect

expect("pysome").to_be(SomeStr())
expect("pysome").to_be(SomeStr(pattern="p__ome"))
expect("pysome").to_be(SomeStr(startswith="py"))
expect("pysome").to_be(SomeStr(endswith="some"))
expect("a8z").to_be(SomeStr(regex="a[0-9]z"))

Same API

:warning: Same should only be used with the expect(...).to_be(...) syntax!

Same() objects can be used to check inside an expect statement that two values are the same. Same also wraps around Some() so you can also use default parameter. A single Same() will therfore behave exaclt like a Some()

from pysome import Same, expect


expect([1, 1]).to_be([Same(), Same()])
expect([1, 2]).not_to_be([Same(), Same()])

you can also provide names to the same to make multile equal checks

from pysome import Same, expect

expect([1, "a", 1, "a"]).to_be(
 [
  Same(int, name="int_same"),
  Same(str, name="str_same"),
  Same(int, name="int_same"),
  Same(str, name="str_same")
 ]
)

Exceptions:

name description
PySomeException Parent class of all Exceptions that are raised by pysome
MustReturnBool(PySomeException) A function used as a validator in an Some() must always return a bool. Either the object equals or not. This exception is thrown if a function doesnt return a bool value
InvalidArgument(PySomeException) This exception is raised if a given argument to a pysome class is invalid
InvalidFunction(InvalidArgument) A function provided as condition to a Some must except exactly one parameter. If it doest this exception is thrown
SameOutsideExpect() If you try to compare a Same object outside of an expect(...).to_be(...) this error is raise

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

pysome-0.1.0.tar.gz (10.3 kB view details)

Uploaded Source

Built Distribution

pysome-0.1.0-py3-none-any.whl (8.7 kB view details)

Uploaded Python 3

File details

Details for the file pysome-0.1.0.tar.gz.

File metadata

  • Download URL: pysome-0.1.0.tar.gz
  • Upload date:
  • Size: 10.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.22.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.8.10

File hashes

Hashes for pysome-0.1.0.tar.gz
Algorithm Hash digest
SHA256 60fd73295a791f2c9763c627ca42e2b8cf4ff2ec70d4bf80e3c2b34a2f4e3b01
MD5 b0b3991bf432769c73bf171ccc970918
BLAKE2b-256 88b2b558cf41ec133fcb2eedad5d349ba552a9c0701c0d723b1178be078b691f

See more details on using hashes here.

File details

Details for the file pysome-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pysome-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.22.0 requests-toolbelt/0.9.1 tqdm/4.62.0 CPython/3.8.10

File hashes

Hashes for pysome-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5c3ad488f879cb015136046a850b26b66112ce03b92c55394c19b175af814d2b
MD5 aa9f6a10f4a17a614d9b08a313012420
BLAKE2b-256 cdfc491f7cb338997057c14b3f40b3d2f1555cfc2462dd6be7f076c8ff6e0e18

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