Skip to content

Commit b1b1090

Browse files
authored
Only calculate hash once for Marker objects (#513)
1 parent 9451b61 commit b1b1090

File tree

2 files changed

+14
-7
lines changed

2 files changed

+14
-7
lines changed

voluptuous/schema_builder.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import typing
1010
from collections.abc import Generator
1111
from contextlib import contextmanager
12-
from functools import wraps
12+
from functools import cache, wraps
1313

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

1029+
__slots__ = ('schema', '_schema', 'msg', 'description', '__hash__')
1030+
10291031
def __init__(
10301032
self,
10311033
schema_: Schemable,
@@ -1036,6 +1038,7 @@ def __init__(
10361038
self._schema = Schema(schema_)
10371039
self.msg = msg
10381040
self.description = description
1041+
self.__hash__ = cache(lambda: hash(schema_)) # type: ignore[method-assign]
10391042

10401043
def __call__(self, v):
10411044
try:
@@ -1056,9 +1059,6 @@ def __lt__(self, other):
10561059
return self.schema < other.schema
10571060
return self.schema < other
10581061

1059-
def __hash__(self):
1060-
return hash(self.schema)
1061-
10621062
def __eq__(self, other):
10631063
return self.schema == other
10641064

@@ -1244,16 +1244,22 @@ class Remove(Marker):
12441244
[1, 2, 3, 5, '7']
12451245
"""
12461246

1247+
def __init__(
1248+
self,
1249+
schema_: Schemable,
1250+
msg: typing.Optional[str] = None,
1251+
description: typing.Optional[str] = None,
1252+
) -> None:
1253+
super().__init__(schema_, msg, description)
1254+
self.__hash__ = cache(lambda: object.__hash__(self)) # type: ignore[method-assign]
1255+
12471256
def __call__(self, schema: Schemable):
12481257
super(Remove, self).__call__(schema)
12491258
return self.__class__
12501259

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

1254-
def __hash__(self):
1255-
return object.__hash__(self)
1256-
12571263

12581264
def message(
12591265
default: typing.Optional[str] = None,

voluptuous/tests/tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,7 @@ def test_marker_hashable():
10721072
assert definition.get('y') == float
10731073
assert Required('x') == Required('x')
10741074
assert Required('x') != Required('y')
1075+
assert hash(Required('x').schema) == hash(Required('x'))
10751076
# Remove markers are not hashable
10761077
assert definition.get('j') is None
10771078

0 commit comments

Comments
 (0)