Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use attrs library for data classes #2690

Merged
merged 9 commits into from
Jan 26, 2018
Merged

Use attrs library for data classes #2690

merged 9 commits into from
Jan 26, 2018

Conversation

asvetlov
Copy link
Member

No description provided.

@codecov-io
Copy link

codecov-io commented Jan 25, 2018

Codecov Report

Merging #2690 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2690      +/-   ##
==========================================
+ Coverage   98.01%   98.01%   +<.01%     
==========================================
  Files          39       39              
  Lines        7245     7270      +25     
  Branches     1258     1264       +6     
==========================================
+ Hits         7101     7126      +25     
  Misses         44       44              
  Partials      100      100
Impacted Files Coverage Δ
aiohttp/web_request.py 99.68% <100%> (ø) ⬆️
aiohttp/helpers.py 97.98% <100%> (+0.04%) ⬆️
aiohttp/web_urldispatcher.py 99.51% <100%> (ø) ⬆️
aiohttp/client_reqrep.py 97.39% <100%> (+0.02%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 93bad20...1e44acf. Read the comment docs.

@@ -39,12 +39,18 @@
__all__ = ('ClientRequest', 'ClientResponse', 'RequestInfo', 'Fingerprint')


ContentDisposition = collections.namedtuple(
'ContentDisposition', ('type', 'parameters', 'filename'))
@attr.s(frozen=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have my doubts about the usage of frozen=True taking into account that immutability depends on the type of fields that you have in the data class. In the worst case scenario having a mutable attribute, the hash will fail and you won't prevent modify these attributes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't follow your point.

ConetentDisposition was immutable named tuple, I've just converted the class into immutable attrs representation. All type, parameters and filename attributes are immutable too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... class Foo:
...     a = attr.ib(type=MappingProxyType)
...
>>> d = {}
>>> m = MappingProxyType(d)
>>> f = Foo(m)
>>> hash(f)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<attrs generated hash a57df858a086a8e0acf97d938d787d39b6f33d51>", line 4, in __hash__
TypeError: unhashable type: 'mappingproxy'```

type = attr.ib(type=str)
subtype = attr.ib(type=str)
suffix = attr.ib(type=str)
parameters = attr.ib(type=MultiDict)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MultiDict is mutable frozen=True is IMHO inconsistent in that case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, but afaik that mimics old behavior. May be worth to replace with frozen/proxy version?

Copy link
Member

@kxepal kxepal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few more notes, but nice improvement!

FileField = collections.namedtuple(
'Field', 'name filename file content_type headers')

@attr.s(frozen=True, slots=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rest namedtuple replaces comes without slots. Is that intentional?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually not . I forgot adding new param and was experimenting with different usage.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use slots in attrs, they are not bring new value but slightly slower.

type = attr.ib(type=str)
subtype = attr.ib(type=str)
suffix = attr.ib(type=str)
parameters = attr.ib(type=MultiDict)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, but afaik that mimics old behavior. May be worth to replace with frozen/proxy version?

@kxepal
Copy link
Member

kxepal commented Jan 26, 2018

Btw, what do you think about dataclasses? Would we migrate to them eventually or will stay with attrs?

@asvetlov
Copy link
Member Author

I want keeping frozen classes at least by default. It's safer.

@webknjaz
Copy link
Member

By the way, attrs has a built-in @dataclass decorator

@asvetlov
Copy link
Member Author

@kxepal we can return to discussion about switching to native python dataclasses after dropping Python 3.6 support. In several years.

@asvetlov
Copy link
Member Author

@webknjaz I know about dataclass support embedded into attrs, but we cannot use it until dropping Python 3.5 support.

@kxepal
Copy link
Member

kxepal commented Jan 26, 2018

@asvetlov
I mean...dataclasses are currently provided as standalone package, aren't they? We could just use them as optional dependency for <3.7.

@asvetlov
Copy link
Member Author

https://pypi.python.org/pypi/dataclasses requires Python 3.6, we are limited to 3.5.3

@kxepal
Copy link
Member

kxepal commented Jan 26, 2018

Yeah. Ok, I got your point. Thanks!

@webknjaz
Copy link
Member

What if there was a backport?

@asvetlov
Copy link
Member Author

@webknjaz don't follow

@pfreixes
Copy link
Contributor

@asvetlov I don't see the point of usage by default frozen because its safer. The old namedtuples didn't give you that behavior. Start using the frozen=True means that you would give this feature for just for those params that are immutable. So, safer means that some attributes will be protected and others no? What I'm missing?

@asvetlov
Copy link
Member Author

frozen prevents inplace modification:

In [1]: import attr

In [2]: @attr.s
   ...: class A:
   ...:     a = attr.ib()
   ...:     

In [3]: a = A(1)

In [4]: a.a
Out[4]: 1

In [5]: a.a = 2

In [6]: a.a
Out[6]: 2

In [7]: @attr.s(frozen=True)
   ...: class B:
   ...:     b = attr.ib()
   ...:     

In [8]: b = B(1)

In [9]: b.b
Out[9]: 1

In [10]: b.b = 2
---------------------------------------------------------------------------
FrozenInstanceError                       Traceback (most recent call last)
<ipython-input-10-dc6c31b33bcf> in <module>()
----> 1 b.b = 2

~/.virtualenvs/aiohttp/lib/python3.6/site-packages/attr/_make.py in _frozen_setattrs(self, name, value)
    349     Attached to frozen classes as __setattr__.
    350     """
--> 351     raise FrozenInstanceError()
    352 
    353 

FrozenInstanceError: 

@webknjaz
Copy link
Member

@asvetlov I mean, shouldn't it be possible to backport dataclasses implementation to support 3.5?

@asvetlov
Copy link
Member Author

@webknjaz no, PEP 526 was implemented in Python 3.6 only.
Dataclasses require this feature.

@pfreixes
Copy link
Contributor

pfreixes commented Jan 26, 2018 via email

@webknjaz
Copy link
Member

Fair enough

@asvetlov
Copy link
Member Author

@pfreixes I understand that frozen is not recursive property and all consequence pitfalls.
But frozen classes are better than non-frozen, at least in namedtuple replacement context.

@pfreixes
Copy link
Contributor

Well, at least the whole replacement is safer for all variables, and must be the developer who has the last call to expose a variable mutable or not mutanle. A triki situatuion.

Anyway, lets move forward. LGTM

@asvetlov asvetlov merged commit 50b81c5 into master Jan 26, 2018
@asvetlov asvetlov deleted the attrs branch January 27, 2018 23:23
@asvetlov
Copy link
Member Author

slots=True should be mandatory also -- without the flag attrs doesn't prevent setting a custom attribute, which is not desired behavior usually.

@lock
Copy link

lock bot commented Oct 28, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a [new issue] for related bugs.
If you feel like there's important points made in this discussion, please include those exceprts into that [new issue].
[new issue]: https://github.com/aio-libs/aiohttp/issues/new

@lock lock bot added the outdated label Oct 28, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Oct 28, 2019
@psf-chronographer psf-chronographer bot added the bot:chronographer:provided There is a change note present in this PR label Oct 28, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bot:chronographer:provided There is a change note present in this PR outdated
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants