Is there a difference between assertEquals and assertSetEqual in the python unittest.TestCase for assertion of sets or frozensets?
And if there is not, why are there assertSetEqual?
also for this situation we can use assertCountEqual and assertSequenceEqual!
.
.
.
self.assertEqual({1, 2, 3}, {1, 2, 3})
self.assertSetEqual({1, 2, 3}, {1, 2, 3})
.
.
.
The type-specific calls give type-specific error messages when they fail. For instance, for a set it will list the elements found in each set but not found in the other.
The docs note that assertEqual will call the type-specific test if both args are of the exact same type and if there is a type-specific test - thus, for two sets assertEqual will call assertSetEqual and therefore show the more helpful error message. However, it doesn't do this if both one arg is a set and the other is a frozenset. This may not come up often, but it's one case in which you might call assertSetEqual directly.
>>> TestCase().assertEqual({1, 2, 3}, frozenset((2, 1)))
Traceback (most recent call last):
...
AssertionError: {1, 2, 3} != frozenset({1, 2})
>>> TestCase().assertSetEqual({1, 2, 3}, frozenset((2, 1)))
Traceback (most recent call last):
...
AssertionError: Items in the first set but not the second:
3
Related
Why do set operations work with arbitrary iterables when using set methods, but not operators? To show what I mean:
>>> {0, 1, 2, 3}.intersection([0, 1])
{0, 1}
>>> {0, 1, 2, 3} & [0, 1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'set' and 'list'
>>>
>>> {0, 1, 2, 3}.union([4, 5])
{0, 1, 2, 3, 4, 5}
>>> {0, 1, 2, 3} | [4, 5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'list'
From the docs:
Note, the non-operator versions of union(), intersection(), difference(), and symmetric_difference(), issubset(), and issuperset() methods will accept any iterable as an argument. In contrast, their operator based counterparts require their arguments to be sets. This precludes error-prone constructions like set('abc') & 'cbs' in favor of the more readable set('abc').intersection('cbs').
It was considered less error-prone this way.
I'm attempting to try a simple command on the command line,
dict(zip(ascii_lowercase, range(4)))
expecting to get
{'a': 0, 'b': 1, 'c': 2, 'd': 3}
but I keep getting the error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'ascii_lowercase' is not defined
What am I missing here?
ascii_lowercase is a value provided by the string module. To use it unqualified, you must have previously imported it via:
from string import ascii_lowercase
Why zip with range when you can enumerate?
from string import ascii_lowercase
print {b:a for a,b in enumerate(ascii_lowercase[:4])}
Output:
{'a': 0, 'b': 1, 'c': 2, 'd': 3}
You can also import the string module, and apply your own function using string.ascii_lowercase:
Test
import string
print(dict(zip(string.ascii_lowercase, range(4))))
Output
{'a': 0, 'b': 1, 'c': 2, 'd': 3}
I would like to create some basic statistics for several lists of data and store them in a dictionary:
>>> from statistics import mean,median
>>> a,b,c=[1,2,3],[4,5,6],[7,8,9]
The following list comprehension works and outputs stats for "a":
>>> [eval("{}({})".format(op,a)) for op in ['mean','median','min','max']]
[2, 2, 1, 3]
Assigning the list's variable name (a) to another object (dta) and evaluating "dta" in a list comprehension also works:
>>> dta="a"
>>> [eval("{}({})".format(op,eval("dta"))) for op in ['mean','median','min','max']]
[2, 2, 1, 3]
But when I try to tie this all together in a dictionary comprehension, it does not work:
>>> {k:[eval("{}({})".format(op,eval("k"))) for op in ['mean','median','min','max']] for k in ['a','b','c']}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <dictcomp>
File "<stdin>", line 1, in <listcomp>
File "<string>", line 1, in <module>
NameError: name 'k' is not defined
My guess is that the eval is processed before the comprehension, which is why 'k' is not yet defined? Any suggestions for how to get this work or a different routine that would accomplish the same output?
Do not quote the k in the inner eval:
{k:[eval("{}({})".format(op,eval(k))) for op in ['mean','median','min','max']] for k in ['a','b','c']}
^
Or drop eval altogether:
[[mean(k), median(k), min(k), max(k)] for k in [a, b, c]]
You can do a simple workaround with the keys to change this to a dictionary comprehension.
Try removing the quotation marks around k in your call to eval in the format function.
I ran the following commands:
> from statistics import mean,median
> a,b,c=[1,2,3],[4,5,6],[7,8,9]
> {k:[eval("{}({})".format(op,eval(k))) for op in ['mean','median','min','max']] for k in ['a','b','c']}
and got the following output:
{'a': [2.0, 2, 1, 3], 'c': [8.0, 8, 7, 9], 'b': [5.0, 5, 4, 6]}
I have a test where I am mocking a filter call on a manager. the assert looks like this:
filter_mock.assert_called_once_with(type_id__in=[3, 4, 5, 6], finance=mock_finance, parent_transaction__date_posted=tran_date_posted)
and the code being tested looks like this:
agregates = Balance.objects.filter(
finance=self.finance,type_id__in=self.balance_types,
parent_transaction__date_posted__lte=self.transaction_date_posted
)
I thought that since these are kwargs, order shouldn't matter, but the test is failing, even though the values for each pair DO match. below is the error I am seeing:
AssertionError: Expected call: filter(type_id__in=[3, 4, 5, 6],
parent_transaction__date_posted=datetime.datetime(2015, 5, 29, 16, 22,
59, 532772), finance=) Actual call:
filter(type_id__in=[3, 4, 5, 6], finance=,
parent_transaction__date_posted__lte=datetime.datetime(2015, 5, 29,
16, 22, 59, 532772))
what the heck is going on? kwarg order should not matter, and even if I do order to match what the test is asserting, the test still fails.
Your keys are not exactly the same. In your assert_called_with, you have the key parent_transaction__date_posted, but in your code you are using the key parent_transaction__date_posted__lte. That is what is causing your test to fail, not the bad sorting. Here is my own test as a proof of concept:
>>> myobject.test(a=1, b=2)
>>> mock_test.assert_called_with(b=2, a=1)
OK
>>> myobject.test(a=1, b__lte=2)
>>> mock_test.assert_called_with(b=2, a=1)
AssertionError: Expected call: test(a=1, b=2)
Actual call: test(a=1, b__lte=2)
You will need to correct either your test or your code so that they match (include __lte or don't depending on your need)
I am trying to get a list of list of tuples : something like [ [(1,0),(2,0),(3,0)],[(1,1),(2,1),(3,1)....]]
I used this statement
set([(a,b)for a in range(3)]for b in range(3))
But it gives me an error
TypeError: unhashable type: 'list'
I have 2 questions for the Python Guru's:
a) When I look at the Python definition of Hashable -
"An object is hashable if it has a hash value which never changes during its lifetime (it needs a hash() method)"
when I used dir function on the expression above
dir([(a,b)for a in range(3)]for b in range(3))
it seems to say the __hash__ is there. So, why do I get the error?
I was able to get [[(0, 0), (1, 0), (2, 0)], [(0, 1), (1, 1), (2, 1)], [(0, 2), (1, 2), (2, 2)]]
by using the list command :
list(list((a,b) for a in range(3)) for bin range(3))
b)list and set both takes Iterable as parameter. How come one works(list) and another doesn't (set)?
You are creating a set via set(...) call, and set needs hashable items. You can't have set of lists. Because list's arent hashable.
[[(a,b) for a in range(3)] for b in range(3)] is a list. It's not a hashable type. The __hash__ you saw in dir(...) isn't a method, it's just None.
A list comprehension returns a list, you don't need to explicitly use list there, just use:
>>> [[(a,b) for a in range(3)] for b in range(3)]
[[(0, 0), (1, 0), (2, 0)], [(0, 1), (1, 1), (2, 1)], [(0, 2), (1, 2), (2, 2)]]
Try those:
>>> a = {1, 2, 3}
>>> b= [1, 2, 3]
>>> type(a)
<class 'set'>
>>> type(b)
<class 'list'>
>>> {1, 2, []}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> print([].__hash__)
None
>>> [[],[],[]] #list of lists
[[], [], []]
>>> {[], [], []} #set of lists
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
TLDR:
- You can't hash a list, a set, nor a dict to put that into sets
- You can hash a tuple to put it into a set.
Example:
>>> {1, 2, [3, 4]}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> {1, 2, (3, 4)}
set([1, 2, (3, 4)])
Note that hashing is somehow recursive and the above holds true for nested items:
>>> {1, 2, 3, (4, [2, 3])}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Dict keys also are hashable, so the above holds for dict keys too.
A list is unhashable because its contents can change over its lifetime. You can update an item contained in the list at any time.
A list doesn't use a hash for indexing, so it isn't restricted to hashable items.
The real reason because set does not work is the fact, that it uses the hash function to distinguish different values. This means that sets only allows hashable objects. Why a list is not hashable is already pointed out.
... and so you should do something like this:
set(tuple ((a,b) for a in range(3)) for b in range(3))
... and if needed convert back to list
You'll find that instances of list do not provide a __hash__ --rather, that attribute of each list is actually None (try print [].__hash__). Thus, list is unhashable.
The reason your code works with list and not set is because set constructs a single set of items without duplicates, whereas a list can contain arbitrary data.