@@ -313,9 +313,6 @@ def generic_repr(self):
313313 cls .__str__ = generic_str
314314 cls .__repr__ = generic_repr
315315
316- if not hasattr (cls , "__hash__" ):
317- raise AssertionError (f"not hashable: { cls } " )
318-
319316 # }}}
320317
321318 # {{{ Python set-like behavior
@@ -908,6 +905,12 @@ def val_to_python(self):
908905 # note: automatic upcasts for method arguments are provided through
909906 # 'implicitly_convertible' on the C++ side of the wrapper.
910907
908+ def make_upcasting_hash (special_method , upcast_method ):
909+ def wrapper (basic_instance ):
910+ return hash ((type (basic_instance ), upcast_method (basic_instance )))
911+
912+ return wrapper
913+
911914 def make_new_upcast_wrapper (method , upcast ):
912915 # This function provides a scope in which method and upcast
913916 # are not changed from one iteration of the enclosing for
@@ -916,7 +919,6 @@ def make_new_upcast_wrapper(method, upcast):
916919 def wrapper (basic_instance , * args , ** kwargs ):
917920 special_instance = upcast (basic_instance )
918921 return method (special_instance , * args , ** kwargs )
919-
920922 return wrapper
921923
922924 def make_existing_upcast_wrapper (basic_method , special_method , upcast ):
@@ -938,6 +940,15 @@ def wrapper(basic_instance, *args, **kwargs):
938940 def add_upcasts (basic_class , special_class , upcast_method ):
939941 from functools import update_wrapper
940942
943+ # {{{ implicitly upcast __hash__
944+
945+ if (getattr (basic_class , "__hash__" , None ) is None
946+ and getattr (special_class , "__hash__" , None ) is not None ):
947+ wrapper = make_upcasting_hash (special_class .__hash__ , upcast_method )
948+ basic_class .__hash__ = update_wrapper (wrapper , basic_class .__hash__ )
949+
950+ # }}}
951+
941952 def my_ismethod (class_ , method_name ):
942953 if method_name .startswith ("_" ):
943954 return False
0 commit comments