Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AttributeDict objects not always hashable #2572

Closed
rikublock opened this issue Jul 14, 2022 · 1 comment
Closed

AttributeDict objects not always hashable #2572

rikublock opened this issue Jul 14, 2022 · 1 comment

Comments

@rikublock
Copy link

  • Version: 5.29.2
  • Python: 3.8.10
  • OS: Linux

What was wrong?

Depending on the items, AttributeDict might not always be hashable.

For example, log entries returned by eth_getLogs() can contain list objects (in this case 'topics'), which are not hashable.

AttributeDict({
	'address': '0x2C846CF666f2D427ec86ca4BADe204fFD5CbC421', 
	'topics': [HexBytes('0xdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496'), HexBytes('0x000000000000000000000000e54ca86531e17ef3616d22ca28b0d458b6c89106'), HexBytes('0x000000000000000000000000d2f59be407080abfd97a00a7071d67f93b526733')], 
	'data': '0x000000000000000000000000000000000000000000000000000000000018921600000000000000000000000000000000000000000000000033bd1424be462f14', 
	'blockNumber': 16955438, 
	'transactionHash': HexBytes('0x932a26038bcf3d22bd981543b7ed6aae653a8a565a2a78bd644162c7e1bff6e4'), 
	'transactionIndex': 2, 
	'blockHash': HexBytes('0xd5b1c3a7704a26b1b7b47b12d1a929ecba82bb0cbf9b97f41d227ff104612f7b'), 
	'logIndex': 16, 
	'removed': False
 })

How can it be fixed?

a) Adjust the __hash__ function. Recursively look for mutable types like lists, etc. and temporary replace them before hashing.
This would likely also require changing __eq__ as two object can now have the same hash without being "equal".

source

def __hash__(self) -> int:
    return hash(tuple(sorted(self.items())))

b) Recursively replace mutable types (e.g. list -> tuple) when creating the AttributeDict object.

source

def __init__(
    self, dictionary: Dict[TKey, TValue], *args: Any, **kwargs: Any
) -> None:
    # type ignored on 46/50 b/c dict() expects str index type not TKey
    self.__dict__ = dict(dictionary)  # type: ignore
    self.__dict__.update(dict(*args, **kwargs))

c) Handle it earlier, for instance when parsing response results.

d) Add a more restrictive TValue type (e.g. allow only hashable values). That seems a much larger change though as it likely affects many parts/sections of the code base.

The AttributeDict type is supposed to be immutable, this would suggest going with something like b).

I can prepare a PR, just need some directions on how you would like to have it solved.

@pacrob
Copy link
Contributor

pacrob commented Sep 5, 2023

It looks like the hashability was addressed in #2939, but you have a good point on the __eq__ method. I'll look into it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants