Skip to content
New issue

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

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

Already on GitHub? # to your account

Only calculate hash once for Marker objects #513

Merged
merged 6 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion voluptuous/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@

# fmt: on

__version__ = '0.14.2'
__version__ = '0.13.1'
__author__ = 'alecthomas'
20 changes: 13 additions & 7 deletions voluptuous/schema_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import typing
from collections.abc import Generator
from contextlib import contextmanager
from functools import wraps
from functools import lru_cache, wraps

from voluptuous import error as er
from voluptuous.error import Error
Expand Down Expand Up @@ -1026,6 +1026,8 @@ class Marker(object):
introspected by any external tool, for example to generate schema documentation.
"""

__slots__ = ('schema', '_schema', 'msg', 'description', '__hash__')

def __init__(
self,
schema_: Schemable,
Expand All @@ -1036,6 +1038,7 @@ def __init__(
self._schema = Schema(schema_)
self.msg = msg
self.description = description
self.__hash__ = lru_cache(maxsize=None)(lambda: hash(schema_))

def __call__(self, v):
try:
Expand All @@ -1056,9 +1059,6 @@ def __lt__(self, other):
return self.schema < other.schema
return self.schema < other

def __hash__(self):
return hash(self.schema)

def __eq__(self, other):
return self.schema == other

Expand Down Expand Up @@ -1244,16 +1244,22 @@ class Remove(Marker):
[1, 2, 3, 5, '7']
"""

def __init__(
self,
schema_: Schemable,
msg: typing.Optional[str] = None,
description: typing.Optional[str] = None,
) -> None:
super().__init__(schema_, msg, description)
self.__hash__ = lru_cache(maxsize=None)(lambda: object.__hash__(self))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? Doesn't Marker.__hash__ cover this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its overriding the hash here to use the base object.__hash__ instead of Marker.__hash__


def __call__(self, schema: Schemable):
super(Remove, self).__call__(schema)
return self.__class__

def __repr__(self):
return "Remove(%r)" % (self.schema,)

def __hash__(self):
return object.__hash__(self)


def message(
default: typing.Optional[str] = None,
Expand Down
1 change: 1 addition & 0 deletions voluptuous/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,7 @@ def test_marker_hashable():
assert definition.get('y') == float
assert Required('x') == Required('x')
assert Required('x') != Required('y')
assert hash(Required('x').schema) == hash(Required('x'))
# Remove markers are not hashable
assert definition.get('j') is None

Expand Down