11from itertools import chain
22from typing import Iterable , List , Tuple , Union
33
4- from .base import BaseType , ImportPathList , MetaData
4+ from .base import BaseType , ImportPathList , MetaData , get_hash_string
55from .typing import metadata_to_typing
66
77
88class SingleType (BaseType ):
9- __slots__ = ["type " ]
9+ __slots__ = ["_type" , "_hash " ]
1010
1111 def __init__ (self , t : MetaData ):
12- self .type = t
12+ self ._type = t
13+ self ._hash = None
14+
15+ @property
16+ def type (self ):
17+ return self ._type
18+
19+ @type .setter
20+ def type (self , t : MetaData ):
21+ self ._type = t
22+ self ._hash = None
1323
1424 def __str__ (self ):
15- return f"{ self . __class__ .__name__ } [{ self .type } ]"
25+ return f"{ type ( self ) .__name__ } [{ self .type } ]"
1626
1727 def __repr__ (self ):
18- return f"<{ self . __class__ .__name__ } [{ self .type } ]>"
28+ return f"<{ type ( self ) .__name__ } [{ self .type } ]>"
1929
2030 def __iter__ (self ) -> Iterable ['MetaData' ]:
2131 yield self .type
2232
2333 def __eq__ (self , other ):
24- return isinstance (other , self . __class__ ) and self .type == other .type
34+ return type (other ) is type ( self ) and self .type == other .type
2535
2636 def replace (self , t : 'MetaData' , ** kwargs ) -> 'SingleType' :
2737 self .type = t
2838 return self
2939
40+ def _to_hash_string (self ) -> str :
41+ return f"{ type (self ).__name__ } /{ get_hash_string (self .type )} "
42+
3043
3144class ComplexType (BaseType ):
32- __slots__ = ["_types" ]
45+ __slots__ = ["_types" , "_sorted" , "_hash" ]
3346
3447 def __init__ (self , * types : MetaData ):
3548 self ._types = list (types )
49+ self ._sorted = None
50+ self ._hash = None
3651
3752 @property
3853 def types (self ):
@@ -42,6 +57,7 @@ def types(self):
4257 def types (self , value ):
4358 self ._types = value
4459 self ._sorted = None
60+ self ._hash = None
4561
4662 @property
4763 def sorted (self ):
@@ -62,17 +78,17 @@ def _sort_key(self, item):
6278
6379 def __str__ (self ):
6480 items = ', ' .join (map (str , self .types ))
65- return f"{ self . __class__ .__name__ } [{ items } ]"
81+ return f"{ type ( self ) .__name__ } [{ items } ]"
6682
6783 def __repr__ (self ):
6884 items = ', ' .join (map (str , self .types ))
69- return f"<{ self . __class__ .__name__ } [{ items } ]>"
85+ return f"<{ type ( self ) .__name__ } [{ items } ]>"
7086
7187 def __iter__ (self ) -> Iterable ['MetaData' ]:
7288 yield from self .types
7389
7490 def __eq__ (self , other ):
75- return isinstance (other , self . __class__ ) and self .sorted == other .sorted
91+ return type (other ) is type ( self ) and self .sorted == other .sorted
7692
7793 def __len__ (self ):
7894 return len (self .types )
@@ -97,6 +113,9 @@ def to_typing_code(self) -> Tuple[ImportPathList, str]:
97113 f"[{ nested } ]"
98114 )
99115
116+ def _to_hash_string (self ) -> str :
117+ return type (self ).__name__ + "/" + "," .join (map (get_hash_string , self .types ))
118+
100119
101120class DOptional (SingleType ):
102121 """
@@ -117,16 +136,22 @@ class DUnion(ComplexType):
117136 """
118137
119138 def __init__ (self , * types : Union [type , BaseType , dict ]):
139+ hashes = set ()
120140 unique_types = []
141+ # Ensure that types in union are unique
121142 for t in types :
122143 if isinstance (t , DUnion ):
123144 # Merging nested DUnions
124145 for t2 in list (t ._extract_nested_types ()):
125- if t2 not in unique_types :
146+ h = get_hash_string (t2 )
147+ if h not in hashes :
126148 unique_types .append (t2 )
127- elif t not in unique_types :
128- # Ensure that types in union are unique
129- unique_types .append (t )
149+ hashes .add (h )
150+ else :
151+ h = get_hash_string (t )
152+ if h not in hashes :
153+ hashes .add (h )
154+ unique_types .append (t )
130155 super ().__init__ (* unique_types )
131156
132157 def _extract_nested_types (self ):
0 commit comments