Skip to main content

asymmetric-matchers

CI PyPI codecov

A collection of asymmetric matchers in Python for testing or general uses.

What are asymmetric matchers?

An asymmetric matcher is an object that can be compared equally to a variety of other objects. Practically speaking, it's useful to test if a value satisfies a set of rules, but not an equality comparison.

Popular examples are the asymmetric matchers present in the Jasmine and Jest (JavaScript testing frameworks.)

Example

Say we have a function similar that calls an external API:

def get_user(user_id: str, fields: List[str]) -> User:
    fields = add_default_fields(fields)
    return external_api.get_user({user_id: user_id, fields: fields})

And we want to write a test that asserts the external_api.get_user() was called with the correct arguments:

def test_external_get_user_is_called():
    with mock.patch("external_api.get_user") as ext_mock:
        get_user("abc4321", ["name", "profile_picture"])
        ext_mock.assert_called_once_with("abc4321", ["name", "profile_picture"])

It doesn't work because we don't know what are the default fields added and perhaps the context of this specific test is not concerned on the behavior of the add_default_fields function. So we write more specific assertions:

def test_external_get_user_is_called():
    with mock.patch("external_api.get_user") as ext_mock:
        get_user("abc4321", ["name", "profile_picture"])

        ext_mock.assert_called_once()
        args = ext_mock.call_args[0]
        assert args[0] == "abc4321"
        assert "name" in args[1]
        assert "profile_picture" in args[1]

Great! Now we're testing exactly what we want, but it's not as straight-forward to a future reader what exactly we want to test.

That's where an asymmetric tester is useful. We can rewrite this test as:

from asymmetric_matchers import list_containing


def test_external_get_user_is_called():
    with mock.patch("external_api.get_user") as ext_mock:
        get_user("abc4321", ["name", "profile_picture"])

        ext_mock.assert_called_once_with(
            "abc4321", list_containing(["name", "profile_picture"])
        )

Very nice! Now it's more clear what's our intent with this test to future readers.

It's very useful in situations when we can combine two or more matchers. One example is to test that a dict contains a specific key and its value is a list that contains some elements:

assert "fields" in some_dict
assert "name" in some_dict["fields"]
assert "profile_picture" in some_dict["fields"]

# using asymmetric matchers

assert some_dict == dict_containing(
    {"fields": list_containing(["name", "profile_picture"])}
)

API

  • anything()

    Matcher is equal to any value, except None.

    plugin_mock.assert_called_once_with("app_name", anything(), True)
    

    It's similar to unittest.mock.ANY.

  • string_matching(str_or_pattern)

    Matcher is equal to a string that matches the pattern (using re.search).

    assert generate_id() == string_matching(r"[a-z]{4}[0-9}3")
    
  • list_containing(expected)

    Matcher is equal to a list that contains all items from expected.

    assert fields == list_containing(["name", "profile_pic"])
    
  • dict_containing(expected)

    Matcher is equal to a dict that contains all keys from expected and their values match.

    assert request_dict == dict_containing({"user_id": "abc123"})
    

License

Apache-2.0 License

Metadata

Release files for asymmetric-matchers 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for asymmetric-matchers 0.2.0
File Size Uploaded Provenance Actions
asymmetric_matchers-0.2.0.tar.gz 7.8 kB Without provenance Details for asymmetric_matchers-0.2.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for asymmetric-matchers 0.2.0
File Interpreter ABI Platform Actions
asymmetric_matchers-0.2.0-py3-none-any.whl Python 3 none any Details for asymmetric_matchers-0.2.0-py3-none-any.whl
asymmetric_matchers-0.2.0-py2-none-any.whl Python 2 none any Details for asymmetric_matchers-0.2.0-py2-none-any.whl

Total release size: 23.6 kB

Release files / asymmetric_matchers-0.2.0.tar.gz

Download URL asymmetric_matchers-0.2.0.tar.gz
Size 7.8 kB
Tags Source
SHA-256 checksum
How to use checksums
1104565c31f94a3aa1d44cc5e7e88ade968b1dd5072e017fa96895947f814da8
BLAKE2b-256 checksum
How to use checksums
25a0f9a42a7c99f34866b77fbac4ecbbc8463efe44973c0f061650f6cbe65d8c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.7.1 importlib_metadata/4.8.2 pkginfo/1.8.2 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

Release files / asymmetric_matchers-0.2.0-py3-none-any.whl

Download URL asymmetric_matchers-0.2.0-py3-none-any.whl
Size 7.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4469e13de8ee0d68c057c024260268385edde1cc8f7bfbc96b21a182ff27fc7b
BLAKE2b-256 checksum
How to use checksums
106ccfa42f6560735d1d74af64e9517ab69ea5331f8efc1b39290f67207488b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.7.1 importlib_metadata/4.8.2 pkginfo/1.8.2 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

Release files / asymmetric_matchers-0.2.0-py2-none-any.whl

Download URL asymmetric_matchers-0.2.0-py2-none-any.whl
Size 7.9 kB
Tags Python 2
SHA-256 checksum
How to use checksums
4875fc2f69c321643cd11f4b8eb49a2fa123fbeff28edfafa2e339053a6d6978
BLAKE2b-256 checksum
How to use checksums
cc0c596db878372a3225e052b3912b863fa7f4507ca09cda9dcf1adb31783423
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.7.1 importlib_metadata/4.8.2 pkginfo/1.8.2 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0

Security for asymmetric-matchers 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

3 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page