Skip to content

Commit eac66b8

Browse files
author
Sylvain MARIE
committed
Names used in include and exclude are now correctly taken into account by autodict and autohash even if the names correspond to property names and therefore the actual attributes names start with an underscore. Fixes #21
1 parent a36bb55 commit eac66b8

4 files changed

Lines changed: 35 additions & 8 deletions

File tree

autoclass/autodict_.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,8 @@ def __iter__(self):
297297
:param self:
298298
:return:
299299
"""
300-
for att_name in (list(vars(self)) + [o for o in super(object_type, self).__iter__()
301-
if o not in vars(self)]):
300+
myattrs = [possibly_replace_with_property_name(self.__class__, att_name) for att_name in vars(self)]
301+
for att_name in myattrs + [o for o in super(object_type, self).__iter__() if o not in vars(self)]:
302302
if is_attr_selected(att_name, include=include, exclude=exclude):
303303
if not only_public_fields \
304304
or (only_public_fields and not att_name.startswith(private_name_prefix)):
@@ -311,7 +311,8 @@ def __iter__(self):
311311
:param self:
312312
:return:
313313
"""
314-
for att_name in vars(self):
314+
for att_name in [possibly_replace_with_property_name(self.__class__, att_name)
315+
for att_name in vars(self)]:
315316
if is_attr_selected(att_name, include=include, exclude=exclude):
316317
if not only_public_fields \
317318
or (only_public_fields and not att_name.startswith(private_name_prefix)):
@@ -337,6 +338,7 @@ def __getitem__(self, key):
337338
:return:
338339
"""
339340
if hasattr(self, key):
341+
key = possibly_replace_with_property_name(self.__class__, key)
340342
if is_attr_selected(key, include=include, exclude=exclude) and \
341343
(not only_public_fields or
342344
(only_public_fields and not key.startswith(private_name_prefix))):
@@ -366,6 +368,7 @@ def __getitem__(self, key):
366368
:return:
367369
"""
368370
if hasattr(self, key):
371+
key = possibly_replace_with_property_name(self.__class__, key)
369372
if is_attr_selected(key, include=include, exclude=exclude) and \
370373
(not only_public_fields or
371374
(only_public_fields and not key.startswith(private_name_prefix))):

autoclass/autohash_.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ def __hash__(self):
177177
to_hash = []
178178

179179
for att_name, att_value in vars(self).items():
180+
att_name = possibly_replace_with_property_name(self.__class__, att_name)
180181
if is_attr_selected(att_name, include=include, exclude=exclude):
181182
if not only_public_fields \
182183
or (only_public_fields and not att_name.startswith(private_name_prefix)):

autoclass/tests/test_autohash.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,19 +84,40 @@ class Dummy2:
8484
assert hash(a) != hash(f)
8585

8686

87-
@pytest.mark.xfail(reason='Currently the test does not work, see https://github.com/smarie/python-autoclass/issues/21')
8887
def test_autohash_exclude():
8988
""" Tests that exclusion works correctly with autohash """
9089

91-
# Currently the test does not work, see https://github.com/smarie/python-autoclass/issues/21
9290
@autoclass(autohash=False)
93-
@autohash(exclude='bar')
94-
class Foo:
91+
@autohash(exclude='bar') # we have to put an underscore because that's the property
92+
class Foo(object):
9593
def __init__(self,
9694
foo, # type: str
9795
bar # type: Dict[str, str]
9896
):
9997
pass
10098

10199
a = Foo('hello', dict())
102-
hash(a) # supposed to work since we exclude the dict (unhashable)
100+
assert hash(a) == hash((a.foo, )) # supposed to work since we exclude the dict (unhashable)
101+
102+
# combined tests (foo is transformed to a property)
103+
@autoclass(include='foo')
104+
class Foo(object):
105+
def __init__(self,
106+
foo, # type: str
107+
bar # type: Dict[str, str]
108+
):
109+
pass
110+
111+
a = Foo('hello', dict())
112+
assert hash(a) == hash((a.foo, )) # supposed to work since we exclude the dict (unhashable)
113+
114+
@autoclass(exclude='bar')
115+
class Foo(object):
116+
def __init__(self,
117+
foo, # type: str
118+
bar # type: Dict[str, str]
119+
):
120+
pass
121+
122+
a = Foo('hello', dict())
123+
assert hash(a) == hash((a.foo,)) # supposed to work since we exclude the dict (unhashable)

docs/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
[![Documentation](https://img.shields.io/badge/doc-latest-blue.svg)](https://smarie.github.io/python-autoclass/) [![PyPI](https://img.shields.io/pypi/v/autoclass.svg)](https://pypi.python.org/pypi/autoclass/) [![Downloads](https://pepy.tech/badge/autoclass)](https://pepy.tech/project/autoclass) [![Downloads per week](https://pepy.tech/badge/autoclass/week)](https://pepy.tech/project/autoclass) [![GitHub stars](https://img.shields.io/github/stars/smarie/python-autoclass.svg)](https://github.com/smarie/python-autoclass/stargazers)
88

9+
!!! warning "`include` and `exclude` have been fixed in `@autodict` and `@autohash`, you do not need to add an underscore anymore when the attribute corresponds to a property. See [#21](https://github.com/smarie/python-autoclass/issues/21)"
10+
911
`autoclass` provides tools to automatically generate python classes code. The objective of this library is to reduce the amount of redundancy by automatically generating parts of the code from the information already available somewhere else (typically, in the constructor signature). It is made of several independent features that can be combined:
1012

1113
* with `@autoargs` you don't have to write `self.xxx = xxx` in your constructor

0 commit comments

Comments
 (0)