2121
2222from autoclass .autoprops_ import DuplicateOverrideError
2323from autoclass .utils import is_attr_selected , method_already_there , possibly_replace_with_property_name , \
24- check_known_decorators , AUTO , read_fields
24+ check_known_decorators , AUTO , read_fields , iterate_on_vars
2525
2626from decopatch import class_decorator , DECORATED
2727
@@ -34,6 +34,7 @@ def autodict(include=None, # type: Union[str, Tuple[str]]
3434 exclude = None , # type: Union[str, Tuple[str]]
3535 only_known_fields = True , # type: bool
3636 only_public_fields = True , # type: bool
37+ legacy_str_repr = False , # type: bool
3738 only_constructor_args = AUTO , # type: bool
3839 cls = DECORATED
3940 ):
@@ -57,17 +58,21 @@ def autodict(include=None, # type: Union[str, Tuple[str]]
5758 :param only_public_fields: this parameter is only used when only_constructor_args is set to False. If
5859 only_public_fields is set to False, all fields are visible. Otherwise (default), class-private fields will be
5960 hidden
61+ :param legacy_str_repr: turn this to `True` to get the legacy string representation `{%r: %r, ...}` instead of
62+ the new default one `(%s=%r, ...)`
6063 :return:
6164 """
6265 return autodict_decorate (cls , include = include , exclude = exclude , only_constructor_args = only_constructor_args ,
63- only_public_fields = only_public_fields , only_known_fields = only_known_fields )
66+ only_public_fields = only_public_fields , only_known_fields = only_known_fields ,
67+ legacy_str_repr = legacy_str_repr )
6468
6569
6670def autodict_decorate (cls , # type: Type[T]
6771 include = None , # type: Union[str, Tuple[str]]
6872 exclude = None , # type: Union[str, Tuple[str]]
6973 only_known_fields = True , # type: bool
7074 only_public_fields = True , # type: bool
75+ legacy_str_repr = False , # type: bool
7176 only_constructor_args = AUTO , # type: bool
7277 ):
7378 # type: (...) -> Type[T]
@@ -85,6 +90,8 @@ def autodict_decorate(cls, # type: Type[T]
8590 :param only_public_fields: this parameter is only used when only_constructor_args is set to False. If
8691 only_public_fields is set to False, all fields are visible. Otherwise (default), class-private fields will be
8792 hidden
93+ :param legacy_str_repr: turn this to `True` to get the legacy string representation `{%r: %r, ...}` instead of
94+ the new default one `(%s=%r, ...)`
8895 :return:
8996 """
9097 if only_constructor_args is not AUTO :
@@ -104,10 +111,11 @@ def autodict_decorate(cls, # type: Type[T]
104111 selected_names , source = read_fields (cls , include = include , exclude = exclude , caller = "@autodict" )
105112
106113 # add autohash with explicit list
107- execute_autodict_on_class (cls , selected_names = selected_names )
114+ execute_autodict_on_class (cls , selected_names = selected_names , legacy_str_repr = legacy_str_repr )
108115 else :
109116 # no explicit list
110- execute_autodict_on_class (cls , include = include , exclude = exclude , public_fields_only = only_public_fields )
117+ execute_autodict_on_class (cls , include = include , exclude = exclude , public_fields_only = only_public_fields ,
118+ legacy_str_repr = legacy_str_repr )
111119
112120 return cls
113121
@@ -117,6 +125,7 @@ def execute_autodict_on_class(cls, # type: Type[T]
117125 include = None , # type: Union[str, Tuple[str]]
118126 exclude = None , # type: Union[str, Tuple[str]]
119127 public_fields_only = True , # type: bool
128+ legacy_str_repr = False , # type: bool
120129 ):
121130 """
122131 This method makes objects of the class behave like a read-only `dict`. It does several things:
@@ -140,6 +149,8 @@ def execute_autodict_on_class(cls, # type: Type[T]
140149 :param public_fields_only: this parameter is only used when `selected_names` is not provided. If
141150 public_fields_only is set to False, all fields are visible. Otherwise (default), class-private fields will be
142151 hidden from the exposed dict view.
152+ :param legacy_str_repr: turn this to `True` to get the legacy string representation `{%r: %r, ...}` instead of
153+ the new default one `(%s=%r, ...)`
143154 :return:
144155 """
145156 # check if the class is already a dict-like
@@ -305,6 +316,7 @@ def __eq__(self, other):
305316 cls .__eq__ = __eq__
306317
307318 # 5. override str and repr method if not already implemented
319+ _1 , _2 = "()" if legacy_str_repr else ("" , "" )
308320 if not method_already_there (cls , '__str__' , this_class_only = True ):
309321
310322 def __str__ (self ):
@@ -315,7 +327,7 @@ def __str__(self):
315327 :return:
316328 """
317329 # python 2 compatibility: use self.__class__ not type()
318- return self .__class__ .__name__ + '(' + print_ordered_dict (self ) + ')'
330+ return "%s%s%s%s" % ( self .__class__ .__name__ , _1 , print_ordered_dict (self , eq_mode = not legacy_str_repr ), _2 )
319331
320332 cls .__str__ = __str__
321333
@@ -328,27 +340,33 @@ def __repr__(self):
328340 :return:
329341 """
330342 # python 2 compatibility: use self.__class__ not type()
331- return self .__class__ .__name__ + '(' + print_ordered_dict (self ) + ')'
343+ return "%s%s%s%s" % ( self .__class__ .__name__ , _1 , print_ordered_dict (self , eq_mode = not legacy_str_repr ), _2 )
332344
333345 cls .__repr__ = __repr__
334346
335347 return
336348
337349
338- def print_ordered_dict (odict # type: Mapping
350+ def print_ordered_dict (odict , # type: Mapping
351+ eq_mode = False # type: bool
339352 ):
340353 # type: (...) -> str
341354 """
342355 Utility method to get a string representation for an ordered mapping.
343356
344357 :param odict: an ordered mapping
358+ :param eq_mode: if `False` (default) the representation will be {%r: %r} whereas otherwise it will be
359+ `(%s=%r)`
345360 :return:
346361 """
347362 # This destroys the order
348363 # return str(dict(obj))
349364
350365 # This follows the order from __iter__
351- return '{%s}' % ', ' .join ('%r: %r' % (k , v ) for k , v in odict .items ())
366+ if eq_mode :
367+ return '(%s)' % ', ' .join ('%s=%r' % (k , v ) for k , v in odict .items ())
368+ else :
369+ return '{%s}' % ', ' .join ('%r: %r' % (k , v ) for k , v in odict .items ())
352370
353371
354372def autodict_override_decorate (func # type: Callable
@@ -501,7 +519,7 @@ def __iter__(self):
501519 """
502520 Generated by @autodict. Relies on vars(self) to return the iterable of dict keys.
503521 """
504- return iter (vars (self ))
522+ return iter (iterate_on_vars (self ))
505523
506524 def __getitem__ (self , key ):
507525 """
@@ -530,8 +548,8 @@ def __iter__(self):
530548 Implements the __iter__ method from collections.Iterable by relying on vars(self)
531549 PLUS the super dictionary
532550 """
533- return chain (vars (self ),
534- (o for o in super (cls , self ).__iter__ () if o not in vars (self )))
551+ return chain (iterate_on_vars (self ),
552+ (o for o in super (cls , self ).__iter__ () if o not in iterate_on_vars (self )))
535553
536554 def __getitem__ (self , key ):
537555 """
@@ -572,10 +590,7 @@ def __iter__(self):
572590 """
573591 Generated by @autodict. Relying on a filtered vars(self) for the keys iterable
574592 """
575- for att_name in vars (self ):
576- # replace private names with property names if needed, so that the filter can apply correctly
577- att_name = possibly_replace_with_property_name (self .__class__ , att_name )
578-
593+ for att_name in iterate_on_vars (self ):
579594 # filter based on the name (include/exclude + private/public)
580595 if is_attr_selected (att_name , include = include , exclude = exclude ) and \
581596 (not public_fields_only or not att_name .startswith (private_name_prefix )):
@@ -629,11 +644,8 @@ def __iter__(self):
629644 :param self:
630645 :return:
631646 """
632- myattrs = (possibly_replace_with_property_name (self .__class__ , att_name ) for att_name in vars (self ))
633- for att_name in chain (myattrs , (o for o in super (cls , self ).__iter__ () if o not in vars (self ))):
634- # replace private names with property names if needed, so that the filter can apply correctly
635- att_name = possibly_replace_with_property_name (self .__class__ , att_name )
636-
647+ myattrs = tuple (att_name for att_name in iterate_on_vars (self ))
648+ for att_name in chain (myattrs , (o for o in super (cls , self ).__iter__ () if o not in myattrs )):
637649 # filter based on the name (include/exclude + private/public)
638650 if is_attr_selected (att_name , include = include , exclude = exclude ) and \
639651 (not public_fields_only or not att_name .startswith (private_name_prefix )):
0 commit comments