Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit845d2c4

Browse files
author
James Riley McHugh
committed
Added protections to AttributeErrors raised within properties
Signed-off-by: James Riley McHugh <mchugh_james@bah.com>
1 parente9f3fd2 commit845d2c4

File tree

2 files changed

+40
-16
lines changed

2 files changed

+40
-16
lines changed

‎rest_framework/request.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ def wrap_attributeerrors():
7878
raiseexc.with_traceback(info[2])
7979

8080

81+
defsafe_property(func):
82+
"""Property decorator to ensure AttributeErrors raised in properties are properly handled"""
83+
84+
@property
85+
defnew_func(self):
86+
withwrap_attributeerrors():
87+
returnfunc(self)
88+
89+
returnnew_func
90+
91+
8192
classEmpty:
8293
"""
8394
Placeholder for unset attributes.
@@ -193,12 +204,12 @@ def __class_getitem__(cls, *args, **kwargs):
193204
def_default_negotiator(self):
194205
returnapi_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS()
195206

196-
@property
207+
@safe_property
197208
defcontent_type(self):
198209
meta=self._request.META
199210
returnmeta.get('CONTENT_TYPE',meta.get('HTTP_CONTENT_TYPE',''))
200211

201-
@property
212+
@safe_property
202213
defstream(self):
203214
"""
204215
Returns an object that may be used to stream the request content.
@@ -207,28 +218,27 @@ def stream(self):
207218
self._load_stream()
208219
returnself._stream
209220

210-
@property
221+
@safe_property
211222
defquery_params(self):
212223
"""
213224
More semantically correct name for request.GET.
214225
"""
215226
returnself._request.GET
216227

217-
@property
228+
@safe_property
218229
defdata(self):
219230
ifnot_hasattr(self,'_full_data'):
220231
self._load_data_and_files()
221232
returnself._full_data
222233

223-
@property
234+
@safe_property
224235
defuser(self):
225236
"""
226237
Returns the user associated with the current request, as authenticated
227238
by the authentication classes provided to the request.
228239
"""
229240
ifnothasattr(self,'_user'):
230-
withwrap_attributeerrors():
231-
self._authenticate()
241+
self._authenticate()
232242
returnself._user
233243

234244
@user.setter
@@ -244,15 +254,14 @@ def user(self, value):
244254
self._user=value
245255
self._request.user=value
246256

247-
@property
257+
@safe_property
248258
defauth(self):
249259
"""
250260
Returns any non-user authentication information associated with the
251261
request, such as an authentication token.
252262
"""
253263
ifnothasattr(self,'_auth'):
254-
withwrap_attributeerrors():
255-
self._authenticate()
264+
self._authenticate()
256265
returnself._auth
257266

258267
@auth.setter
@@ -264,15 +273,14 @@ def auth(self, value):
264273
self._auth=value
265274
self._request.auth=value
266275

267-
@property
276+
@safe_property
268277
defsuccessful_authenticator(self):
269278
"""
270279
Return the instance of the authentication instance class that was used
271280
to authenticate the request, or `None`.
272281
"""
273282
ifnothasattr(self,'_authenticator'):
274-
withwrap_attributeerrors():
275-
self._authenticate()
283+
self._authenticate()
276284
returnself._authenticator
277285

278286
def_load_data_and_files(self):
@@ -420,9 +428,9 @@ def __getattr__(self, attr):
420428
_request=self.__getattribute__("_request")
421429
returngetattr(_request,attr)
422430
exceptAttributeError:
423-
returnself.__getattribute__(attr)
431+
raiseAttributeError(f"'{self.__class__.__name__}' object has no attribute '{attr}'")
424432

425-
@property
433+
@safe_property
426434
defPOST(self):
427435
# Ensure that request.POST uses our request parsing.
428436
ifnot_hasattr(self,'_data'):
@@ -431,7 +439,7 @@ def POST(self):
431439
returnself._data
432440
returnQueryDict('',encoding=self._request._encoding)
433441

434-
@property
442+
@safe_property
435443
defFILES(self):
436444
# Leave this one alone for backwards compat with Django's request.FILES
437445
# Different from the other two cases, which are not valid property

‎tests/test_request.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,22 @@ def test_duplicate_request_form_data_access(self):
347347
assertrequest.content_type.startswith('multipart/form-data')
348348
assertresponse.data== {'a': ['b']}
349349

350+
deftest_parser_attribute_error(self):
351+
"""Ensure attribute errors raised when parsing are properly re-raised"""
352+
expected_message="Internal error"
353+
354+
classBrokenParser:
355+
media_type="application/json"
356+
357+
defparse(self,*args,**kwargs):
358+
raiseAttributeError(expected_message)
359+
360+
http_request=factory.post('/',data={},format="json")
361+
request=Request(http_request,parsers=[BrokenParser()])
362+
363+
withself.assertRaisesMessage(WrappedAttributeError,expected_message):
364+
request.data
365+
350366

351367
classTestDeepcopy(TestCase):
352368

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp