-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Content-Disposition fast access in ClientResponse #2455
Conversation
|
I dislike two properties. |
|
|
I like idea of |
|
PR number is ok for the case -- it doesn't cover the whole issue. |
Codecov Report
@@ Coverage Diff @@
## master #2455 +/- ##
==========================================
+ Coverage 97.14% 97.14% +<.01%
==========================================
Files 39 39
Lines 8125 8136 +11
Branches 1419 1420 +1
==========================================
+ Hits 7893 7904 +11
Misses 101 101
Partials 131 131
Continue to review full report at Codecov.
|
be43246 to
6afa66c
Compare
aiohttp/helpers.py
Outdated
| @@ -737,3 +755,10 @@ def content_length(self, *, _CONTENT_LENGTH=hdrs.CONTENT_LENGTH): | |||
|
|
|||
| if content_length: | |||
| return int(content_length) | |||
|
|
|||
| @property | |||
| def content_disposition(self, *, header=hdrs.CONTENT_DISPOSITION): | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the property is in HeadersMixin?
Should web.Request has the property?
I thought it is only for ClientResponse
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed it's response only header.
aiohttp/helpers.py
Outdated
| else: | ||
| value, params = multipart.parse_content_disposition(raw) | ||
| filename = multipart.content_disposition_filename(params) | ||
| self._content_disposition = ContentDisposition(value, params, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Convert params into types.MappingProxyType. The value should be immutable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do in next patchset.
aiohttp/helpers.py
Outdated
| @property | ||
| def content_disposition(self, *, header=hdrs.CONTENT_DISPOSITION): | ||
| """The value of Content-Disposition HTTP header.""" | ||
| if self._content_disposition == False: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is False
aiohttp/helpers.py
Outdated
| @@ -703,6 +708,7 @@ class HeadersMixin: | |||
|
|
|||
| _content_type = None | |||
| _content_dict = None | |||
| _content_disposition = False | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quite strange default. Why False?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
False if header are not parsed/cached yet
None if there was an attempt to parse, but no header found
ContentDisposition if header was found and parsed
aiohttp/helpers.py
Outdated
| @@ -714,6 +720,18 @@ def _parse_content_type(self, raw): | |||
| else: | |||
| self._content_type, self._content_dict = cgi.parse_header(raw) | |||
|
|
|||
| def _parse_content_disposition(self, _CONTENT_DISPOSITION): | |||
| from . import multipart | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why hidden import?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was here due to circular import
6afa66c to
41fd2c3
Compare
aiohttp/client_reqrep.py
Outdated
| @@ -500,6 +505,7 @@ class ClientResponse(HeadersMixin): | |||
| raw_headers = None # Response raw headers, a sequence of pairs | |||
|
|
|||
| _connection = None # current connection | |||
| _content_disposition = False # content disposition cache | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think that's not good choice. None means no value. We tried to parse it, nothing happened. Yes, this will trigger headers lookup for each property access - but that's not a problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
helpers.sentinel is an option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good alternative, but None is fine as well. However, even better would be to use reify here and avoid internal attributes. Headers are immutable in anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for reify
41fd2c3 to
2ede86e
Compare
aiohttp/client_reqrep.py
Outdated
| value, params = multipart.parse_content_disposition(raw) | ||
| params = MappingProxyType(params) | ||
| filename = multipart.content_disposition_filename(params) | ||
| return ContentDisposition(value, params, filename) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Convert params into immutable structure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean? params is already converted to MappingProxyType line 565
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry.
Nevermind
|
|
aiohttp/client_reqrep.py
Outdated
| @@ -527,6 +532,7 @@ def __init__(self, method, url, *, | |||
| self._request_info = request_info | |||
| self._timer = timer if timer is not None else TimerNoop() | |||
| self._auto_decompress = auto_decompress | |||
| self._cache = {} | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like no. All classes with @reify methods have this and AttributeError is raising without this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implicit magic. Worth to add notice about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean the attr is required, not a notice :)
But the notice makes no harm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, ok. Last time I saw reify in acttion, no special attrs were required.
tests/test_client_response.py
Outdated
|
|
||
| assert 'attachment' == response.content_disposition.value | ||
| assert 'bar' == response.content_disposition.parameters["foo"] | ||
| assert 'archive.tar.gz' == response.content_disposition.filename |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth to add two more cases:
content_disposition.parametersis immutable- second access to
content_dispositionreturns the same result ifClientResponse.headerswere modified in-between (I'm surprised to see it's not read-only property).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do
docs/client_reference.rst
Outdated
|
|
||
| .. attribute:: value | ||
|
|
||
| Value of Content-Disposition header itself, e.g. ``attachment``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"attachment" - you want to notice that the value is a string typed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do
docs/client_reference.rst
Outdated
|
|
||
| .. attribute:: parameters | ||
|
|
||
| A :class:`dict` instance contains all parameters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it's not a dict, but MapptingProxy. Difference in mutability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could just replace it with *mapping* for sake of simplicity.
I pretty sure not many python developers know what MappingProxy is :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea.
aiohttp/client_reqrep.py
Outdated
| @@ -33,6 +34,10 @@ | |||
| __all__ = ('ClientRequest', 'ClientResponse', 'RequestInfo') | |||
|
|
|||
|
|
|||
| ContentDisposition = collections.namedtuple( | |||
| 'ContentDisposition', ('value', 'parameters', 'filename')) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think value is not the best choice. The RFC defines it as a type which suites more to what the value it holds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree
aiohttp/client_reqrep.py
Outdated
| raw = self._headers.get(hdrs.CONTENT_DISPOSITION) | ||
| if raw is None: | ||
| return None | ||
| value, params = multipart.parse_content_disposition(raw) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems only two values here are valid for HTTP headers case: inline and attachment. May be worth to raise a warning about invalid type or turn the value in Enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to https://tools.ietf.org/html/rfc6266#section-4.1 any token is valid
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like Enum but how the change affects multidict and existing users.
I suspect parse_content_disposition is internal API but not 100% sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@redixin Yes, but RFC defines more general Content-Disposition definition. Mozilla explicitly splits it into HTTP headers and Multpart headers. The second one utilize token rule completely, but here we are in HTTP response land.
ff12184 to
dec87c0
Compare
Add ContentDisposition class and content_disposition property Partially implements aio-libs#1670
dec87c0 to
9b6a528
Compare
|
Great work! |
|
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. |
Add content_disposition and content_disposition_dict properties
Partially implements #1670
What do these changes do?
Improves ClientResponse ergonomics
Are there changes in behavior for the user?
All changes are documented.
Related issue number
#1670
Checklist
CONTRIBUTORS.txtCHANGESfolder<issue_id>.<type>for example (588.bug)issue_idchange it to the pr id after creating the pr.feature: Signifying a new feature..bugfix: Signifying a bug fix..doc: Signifying a documentation improvement..removal: Signifying a deprecation or removal of public API..misc: A ticket has been closed, but it is not of interest to users.