如何在python中断言一个字典包含另一个没有assertDictContainsSubset的字典?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21058230/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 21:57:02  来源:igfitidea点击:

How to assert a dict contains another dict without assertDictContainsSubset in python?

pythonpython-2.7python-3.xpython-unittest

提问by JerryCai

I know assertDictContainsSubsetcan do this in python 2.7, but for some reason it's deprecated in python 3.2. So is there any way to assert a dict contains another one without assertDictContainsSubset?

我知道assertDictContainsSubset可以在 python 2.7 中做到这一点,但由于某种原因,它在 python 3.2 中已被弃用。那么有没有办法断言一个 dict 包含另一个没有assertDictContainsSubset

This seems not good:

这似乎不太好:

for item in dic2:
    self.assertIn(item, dic)

any other good way? Thanks

还有什么好办法吗?谢谢

采纳答案by John1024

>>> d1 = dict(a=1, b=2, c=3, d=4)
>>> d2 = dict(a=1, b=2)
>>> set(d2.items()).issubset( set(d1.items()) )
True

And the other way around:

反过来说:

>>> set(d1.items()).issubset( set(d2.items()) )
False

Limitation:the dictionary values have to be hashable.

限制:字典值必须是可散列的。

回答by user1338062

Here is a comparison that works even if you have lists in the dictionaries:

即使您在字典中有列表,以下比较也有效:

superset = {'a': 1, 'b': 2}
subset = {'a': 1}

common = { key: superset[key] for key in set(superset.keys()).intersection(set(subset.keys())) }

self.assertEquals(common, subset)

回答by Risadinha

John1024's solution worked for me. However, in case of a failure it only tells you Falseinstead of showing you which keys are not matching. So, I tried to avoid the deprecated assert method by using other assertion methods that will output helpful failure messages:

John1024 的解决方案对我有用。但是,如果出现故障,它只会告诉您False而不是向您显示哪些键不匹配。因此,我尝试通过使用将输出有用的失败消息的其他断言方法来避免弃用断言方法:

    expected = {}
    response_keys = set(response.data.keys())
    for key in input_dict.keys():
        self.assertIn(key, response_keys)
        expected[key] = response.data[key]
    self.assertDictEqual(input_dict, expected)

回答by JnBrymn

This answers a little broader question than you're asking but I use this in my test harnesses to see if the containerdictionary contains something that looks like the containeddictionary. This checks keys and values. Additionally you can use the keyword 'ANYTHING'to indicate that you don't care how it matches.

这回答了一个比你问的更广泛的问题,但我在我的测试工具中使用它来查看container字典是否包含看起来像contained字典的内容。这将检查键和值。此外,您可以使用关键字'ANYTHING'来表示您不关心它是如何匹配的。

def contains(container, contained):
    '''ensure that `contained` is present somewhere in `container`

    EXAMPLES:

    contains(
        {'a': 3, 'b': 4},
        {'a': 3}
    ) # True

    contains(
        {'a': [3, 4, 5]},
        {'a': 3},
    ) # True

    contains(
        {'a': 4, 'b': {'a':3}},
        {'a': 3}
    ) # True

    contains(
        {'a': 4, 'b': {'a':3, 'c': 5}},
        {'a': 3, 'c': 5}
    ) # True

    # if an `contained` has a list, then every item from that list must be present
    # in the corresponding `container` list
    contains(
        {'a': [{'b':1}, {'b':2}, {'b':3}], 'c':4},
        {'a': [{'b':1},{'b':2}], 'c':4},
    ) # True

    # You can also use the string literal 'ANYTHING' to match anything
        contains(
        {'a': [{'b':3}]},
        {'a': 'ANYTHING'},
    ) # True

    # You can use 'ANYTHING' as a dict key and it indicates to match the corresponding value anywhere
    # below the current point
    contains(
        {'a': [ {'x':1,'b1':{'b2':{'c':'SOMETHING'}}}]},
        {'a': {'ANYTHING': 'SOMETHING', 'x':1}},
    ) # True

    contains(
        {'a': [ {'x':1, 'b':'SOMETHING'}]},
        {'a': {'ANYTHING': 'SOMETHING', 'x':1}},
    ) # True

    contains(
        {'a': [ {'x':1,'b1':{'b2':{'c':'SOMETHING'}}}]},
        {'a': {'ANYTHING': 'SOMETHING', 'x':1}},
    ) # True
    '''
    ANYTHING = 'ANYTHING'
    if contained == ANYTHING:
        return True

    if container == contained:
        return True

    if isinstance(container, list):
        if not isinstance(contained, list):
            contained = [contained]
        true_count = 0
        for contained_item in contained:
            for item in container:
                if contains(item, contained_item):
                    true_count += 1
                    break
        if true_count == len(contained):
            return True

    if isinstance(contained, dict) and isinstance(container, dict):
        contained_keys = set(contained.keys())
        if ANYTHING in contained_keys:
            contained_keys.remove(ANYTHING)
            if not contains(container, contained[ANYTHING]):
                return False

        container_keys = set(container.keys())
        if len(contained_keys - container_keys) == 0:
            # then all the contained keys are in this container ~ recursive check
            if all(
                contains(container[key], contained[key])
                for key in contained_keys
            ):
                return True

    # well, we're here, so I guess we didn't find a match yet
    if isinstance(container, dict):
        for value in container.values():
            if contains(value, contained):
                return True

    return False

回答by Sam Redway

The big problem with the accepted answer is that it does not work if you have non hashable values in your objects values. The second thing is that you get no useful output - the test passes or fails but doesn't tell you which field within the object is different.

接受的答案的一个大问题是,如果您的对象值中有不可散列的值,它就不起作用。第二件事是您没有得到任何有用的输出 - 测试通过或失败,但不会告诉您对象中的哪个字段不同。

As such it is easier to simply create a subset dictionary then test that. This way you can use the TestCase.assertDictEquals()method which will give you very useful formatted output in your test runner showing the diff between the actual and the expected.

因此,简单地创建一个子集字典然后测试它会更容易。通过这种方式,您可以使用该TestCase.assertDictEquals()方法,该方法将在您的测试运行器中为您提供非常有用的格式化输出,显示实际和预期之间的差异。

I think the most pleasing and pythonic way to do this is with a simple dictionary comprehension as such:

我认为最令人愉快和 Pythonic 的方法是使用简单的字典理解:

from unittest import TestCase


actual = {}
expected = {}

subset = {k:v for k, v in actual.items() if k in expected}
TestCase().assertDictEqual(subset, expected)

NOTE obviously if you are running your test in a method that belongs to a child class that inherits from TestCase (as you almost certainly should be) then it is just self.assertDictEqual(subset, expected)

注意显然,如果您在属于继承自 TestCase 的子类的方法中运行测试(您几乎肯定应该这样做),那么它只是 self.assertDictEqual(subset, expected)

回答by kepler

Although I'm using pytest, I found the following idea in a comment. It worked really great for me, so I thought it could be useful here:

虽然我使用的是 pytest,但我在评论中发现了以下想法。它对我来说非常有用,所以我认为它在这里很有用:

assert dict1.items() <= dict2.items()

for Python 3 and

对于 Python 3 和

assert dict1.viewitems() <= dict2.viewitems()

for Python 2.

对于 Python 2。

It works with non-hashable items, but you can't know exactly which item eventually fails.

它适用于不可散列的项目,但您无法确切知道哪个项目最终失败。

回答by augurar

In Python 3 and Python 2.7, you can create a set-like "item view" of a dict without copying any data. This allows you can use comparison operators to test for a subset relationship.

在 Python 3 和 Python 2.7 中,您可以在不复制任何数据的情况下创建一个类似于集合的“项目视图”。这允许您可以使用比较运算符来测试子集关系。

In Python 3, this looks like:

在 Python 3 中,这看起来像:

# Test if d1 is a sub-dict of d2
d1.items() <= d2.items()

# Get items in d1 not found in d2
difference = d1.items() - d2.items()

In Python 2.7 you can use the viewitems()method in place of items()to achieve the same result.

在 Python 2.7 中,您可以使用该viewitems()方法代替items()来实现相同的结果。

In Python 2.6 and below, your best bet is to iterate over the keys in the first dict and check for inclusion in the second.

在 Python 2.6 及以下版本中,最好的办法是迭代第一个字典中的键并检查是否包含在第二个字典中。

# Test if d1 is a subset of d2
all(k in d2 and d2[k] == d1[k] for k in d1)

回答by Bedram Tamang

You can use assertGreaterEqual() method Instead.

您可以改用 assertGreaterEqual() 方法。

users = {'id': 28027, 'email': '[email protected]','created_at': '2005-02-13'}

data = {"email": "[email protected]"}

self.assertGreaterEqual(user.items(), data.items())