feat(request): new method get_param_as_dict#2544
feat(request): new method get_param_as_dict#2544StepanUFL wants to merge 7 commits intofalconry:masterfrom
Conversation
Add a new method get_param_as_dict in order to handle OAS "objects" Closes issue falconry#2542
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2544 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 64 64
Lines 7911 7945 +34
Branches 1086 1096 +10
=========================================
+ Hits 7911 7945 +34 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
CaselIT
left a comment
There was a problem hiding this comment.
thanks for the contribution, I've left a few suggestions
| deep_object: bool = False, | ||
| store: StoreArg = None, | ||
| default: Any | None = None, | ||
| ) -> Any: |
There was a problem hiding this comment.
this is likely dict[str, str | None] | None even if we don't want to do the overload like the other ones
| if deep_object: | ||
| oc: dict[str, Any] = {} | ||
| for key, value in self._params.items(): | ||
| if not key.startswith(f'{name}[') and key.endswith(']'): |
There was a problem hiding this comment.
I guess we could optimize this a bit by caching the format, but it's likely not that important
There was a problem hiding this comment.
Another thing to try would be to benchmark this flow vs using a regex, but I doubt a regex would be faster.
| inner = key[len(name) + 1 : -1] | ||
|
|
||
| if isinstance(value, (list, tuple)): | ||
| oc[inner] = value[0] if value else None |
There was a problem hiding this comment.
not sure if we want to use '' instead of None here. depending on it we may want to update the returned type here https://github.com/falconry/falcon/pull/2544/files#r2411775142
There was a problem hiding this comment.
Q: does this case ever happen (empty list)?
There was a problem hiding this comment.
probably not in actual requests... left check in to be safe but can take out
There was a problem hiding this comment.
from my point of view we could keep this check just to be paranoid, but I would use '' in the else case, so that we can just day that the returned values are strings in all cases
| @@ -0,0 +1,118 @@ | |||
| from __future__ import annotations | |||
There was a problem hiding this comment.
we already have a file for these test, called tests/test_query_params.py. could you move the tests there?
also you can probably check there how those methods are tested
| output = dict(zip(values_list[::2], values_list[1::2])) | ||
|
|
||
| if store is not None and isinstance(output, dict): | ||
| store.update(output) |
There was a problem hiding this comment.
I think we should do like in the other methods
if store is not None:
store[name] = output|
|
||
|
|
||
| def test_deep_object_with_list_values(): | ||
| req = DummyRequestParams({'user[name]': ['Bond'], 'user[id]': ['007']}) |
There was a problem hiding this comment.
also test an with a list of multiple objects
and if we decide that an empty list can indeed happen, also an empty list
Co-authored-by: Federico Caselli <cfederico87@gmail.com>
Co-authored-by: Federico Caselli <cfederico87@gmail.com>
vytas7
left a comment
There was a problem hiding this comment.
Thanks for this PR!
The base structure looks good, although I had a handful of nitpicks wrt the implementation (see inline).
| HTTPBadRequest: A required param is missing from the request, or | ||
| the value could not be parsed from the parameter. | ||
|
|
||
| .. versionadded:: 4.1.0 |
There was a problem hiding this comment.
This needs to be the current development version, Falcon 4.2.0, not 4.1.0 (which is already released).
|
|
||
| else: | ||
| try: | ||
| values_list = self.get_param_as_list(name) |
There was a problem hiding this comment.
Could you add a TODO comment here to also support delimiter from #2538?
| values_list = self.get_param_as_list(name) | ||
| except errors.HTTPBadRequest: | ||
| msg = 'It could not parse the query parameter' | ||
| raise errors.HTTPInvalidParam(msg, name) from None |
There was a problem hiding this comment.
Does raising from None have any special purpose here?
Add a code comment explaining the reasoning if there is any clever trick behind this.
| try: | ||
| values_list = self.get_param_as_list(name) | ||
| except errors.HTTPBadRequest: | ||
| msg = 'It could not parse the query parameter' |
There was a problem hiding this comment.
This "It" here sounds slightly odd, could we try to make it more similar to other error messages?
| if values_list is None: | ||
| if required: | ||
| msg = 'Missing query parameter' | ||
| raise errors.HTTPMissingParam(msg) |
There was a problem hiding this comment.
HTTPMissingParam takes the name of the missing parameter as its first argument, not an error message.
|
|
||
| else: | ||
| if len(values_list) % 2 != 0: | ||
| msg = 'Invalid parameter format, list elements must be even' |
There was a problem hiding this comment.
To be precise list elements cannot be even per se unless they are integer numbers. Suggested rewording: "...the number of list elements must be even".
|
|
||
|
|
||
| # NOTE(StepanUFL): If a better way to make this play well with mypy exists... | ||
| DummyRequestParams.get_param_as_dict = Request.get_param_as_dict # type: ignore[method-assign, assignment] |
There was a problem hiding this comment.
Defining a new fake DummyRequestParams is a somewhat unorthodox way to approach this 🤔.
Maybe we could simulate request, or simply construct a normal req object via create_req() (and create_asgi_req())?
To that end, we also have a util fixture (see tests/conftest.py), which can already construct both WSGI and ASGI requests, see util.create_req(asgi, ...).
|
Hi again @StepanUFL, just checking if you are still considering to finish this PR? |
Add a new method get_param_as_dict in order to handle OAS "objects"
Closes issue #2542
Summary of Changes
A new method req.get_param_as_dict() has added to the Request class in falcon/util/request.py
Related Issues
Closes #2542.
Pull Request Checklist
This is just a reminder about the most common mistakes. Please make sure that you tick all appropriate boxes. Reading our contribution guide at least once will save you a few review cycles!
If an item doesn't apply to your pull request, check it anyway to make it apparent that there's nothing to do.
tox.docs/.docs/.versionadded,versionchanged, ordeprecateddirectives.docs/_newsfragments/, with the file name format{issue_number}.{fragment_type}.rst. (Runtowncrier --draftto ensure it renders correctly.)If you have any questions to any of the points above, just submit and ask! This checklist is here to help you, not to deter you from contributing!
PR template inspired by the attrs project.
Hope this is worthy enough for you all! If there's improvements to be made, let me know