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 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 | |
SomeEmail() | is_email |
equals strings that are email addresses | |
SomeUuid() | is_uuid |
equals strings that are UUIDs |
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"))
SomeEmail
SomeEmail
is a subclass of SomeStr
that only equals a string if it is valid email address
from pysome import SomeEmail, expect
expect("ab.cd@ef.gh").to_be(SomeEmail())
expect("ab.cdef.gh").not_to_be(SomeEmail())
SomeUuid
SomeUuid
is a subclass of SomeStr
that only equals a string if it is valid UUID
from pysome import SomeUuid, expect
expect("7de52743-8a1a-4782-9877-b10bf792172f").to_be(SomeUuid())
expect("not a uuid").not_to_be(SomeUuid())
Same API
:warning: Same should only be used with the
expect(...).to_be(...)
syntax!
Same
Same()
objects can be used to check inside an expect
statement that two values are the same.
Same also inherits from Some()
so you can also use default parameter. A single Same()
will therefore
behave exactly 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 multiple 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")
]
)
name | alias | short description |
---|---|---|
Same() | is_same |
all Same() objects in one expect statement only equal if all do equal |
NotSame() | is_unique |
all NotSame() objects in one expect statement only equal if all are unique |
NotSame
NotSame()
or is_unique
can be used to check inside an expect statement that two values are unique (do not equal)
from pysome import NotSame, expect
expect([1, 2, 3]).to_be([NotSame(), NotSame(), NotSame()])
expect({
"a": "abc",
"b": "abc"
}).not_to_be({
"a": NotSame(str),
"b": NotSame(str)
})
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
Built Distribution
File details
Details for the file pysome-0.1.2.tar.gz
.
File metadata
- Download URL: pysome-0.1.2.tar.gz
- Upload date:
- Size: 11.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
Algorithm | Hash digest | |
---|---|---|
SHA256 | 79f1612170d2ea6035859824fea8b39e3104abe7966958f77aac1dbb9c144918 |
|
MD5 | a61fac3640cea53b3233ee6c076adc89 |
|
BLAKE2b-256 | 3a098153c3dedf9cfeeb4cce37650dd175b07a03fc3917749f3db7bf04614b3b |
File details
Details for the file pysome-0.1.2-py3-none-any.whl
.
File metadata
- Download URL: pysome-0.1.2-py3-none-any.whl
- Upload date:
- Size: 9.4 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
Algorithm | Hash digest | |
---|---|---|
SHA256 | fad33b6ab9d3ee03e7d9cfc3b50272ce96ce2fa3979a216ed171abb167ac83ff |
|
MD5 | d5aae74f724c69b21ad4330d347f0376 |
|
BLAKE2b-256 | 7bad050b5bf635f2c2f14c4537565b76a131783fa166b44d94438ab190576125 |