dropbox / dropbox-sdk-python

The Official Dropbox API V2 SDK for Python
https://www.dropbox.com/developers
MIT License
930 stars 318 forks source link

`files_search_v2` raises an exception when the result match type is `other` #485

Closed YAtOff closed 9 months ago

YAtOff commented 9 months ago

Calling the method files_search_v2 raises an exception when the result match type is other.

I have recorded a session. It shows the method call, HTTP request and response and a stack trace with context:

In [3]: dbx.files_search_v2('image', options=SearchOptions(max_results=5, filename_only=True))
[08:15:16] INFO     Request to files/search_v2                                                                   dropbox_client.py:474
-----------START-----------
POST https://api.dropboxapi.com/2/files/search_v2
User-Agent: OfficialDropboxPythonSDKv2/11.36.2
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Authorization: Bearer ....
Dropbox-API-Path-Root: {".tag": "namespace_id", "namespace_id": "..."}
Content-Type: application/json
Content-Length: 72

{"query": "image", "options": {"max_results": 5, "filename_only": true}}
-----------END------------
HTTP/1.1 200
Cache-Control: no-cache
Content-Disposition: attachment
Content-Security-Policy: sandbox
Content-Type: application/json
Pragma: no-cache
X-Content-Security-Policy: sandbox
X-Content-Type-Options: nosniff
X-Frame-Options: sameorigin
X-Server-Response-Time: 343
X-Webkit-Csp: sandbox
Date: Thu, 02 Nov 2023 12:15:16 GMT
Server: envoy
Content-Encoding: gzip
Vary: Accept-Encoding
X-Dropbox-Response-Origin: far_remote
X-Dropbox-Request-Id: e26f0db3ab6f4fa4bc8f44c56bcb821d
Transfer-Encoding: chunked

b'{"cursor":"ChYKBWltYWdlEgYQBSABaAEiBQjz5PhBEAU=","has_more":true,"matches":[{"match_type":{".tag":"filename"},"metadata":{".tag":"me
tadata","metadata":{".tag":"folder","id":"id:REF2YvO_6MAAAAAAAAAAAQ","name":"images","path_display":"/public/quiz/_static/images","pat
h_lower":"/public/quiz/_static/images"}}},{"match_type":{".tag":"filename"},"metadata":{".tag":"metadata","metadata":{".tag":"folder",
"id":"id:-D0RWZpAO7kAAAAAAAe6rA","name":"images","path_display":"/projects/vw/search/client/images","path_lower":"/projects/vw/search/
client/images"}}},{"match_type":{".tag":"filename"},"metadata":{".tag":"metadata","metadata":{".tag":"file","client_modified":"2018-05
-03T15:11:13Z","content_hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","id":"id:-D0RWZpAO7kAAAAAAAf5Bw","is_
downloadable":true,"name":"ZoomableImage.jsx","path_display":"/projects/vw/newhelp/components/ZoomableImage.jsx","path_lower":"/projec
ts/vw/newhelp/components/zoomableimage.jsx","rev":"101caf083e3273","server_modified":"2018-05-03T15:11:25Z","size":200}}},{"match_type
":{".tag":"filename"},"metadata":{".tag":"metadata","metadata":{".tag":"file","client_modified":"2016-12-02T09:26:05Z","content_hash":
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","id":"id:-D0RWZpAO7kAAAAAAAfFpA","is_downloadable":true,"name":"ima
ge.png","path_display":"/projects/vw/search/client/node_modules/serve-index/public/icons/image.png","path_lower":"/projects/vw/search/
client/node_modules/serve-index/public/icons/image.png","rev":"fc00d083e3273","server_modified":"2016-12-02T09:28:29Z","size":516}}},{
"match_type":{".tag":"other"},"metadata":{".tag":"metadata","metadata":{".tag":"file","client_modified":"2023-10-26T10:48:02Z","conten
t_hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","id":"id:-D0RWZpAO7kAAAAAAAgCFQ","is_downloadable":true,"na
me":"img1.jpg","path_display":"/Work/vwx1/img1.jpg","path_lower":"/work/vwx1/img1.jpg","rev":"6089c4e8323a5083e3273","server_modified"
:"2023-10-26T10:48:05Z","size":236828}}}]}'
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
Cell In[3], line 1
----> 1 dbx.files_search_v2('image', options=SearchOptions(max_results=5, filename_only=True))

File ~/store/Projects/orion/documents/storage/dropboxstorage.py:181, in handle_path_root_error.<locals>.wrapper(client, *args, **kwarg
s)
    179 def wrapper(client, *args, **kwargs):
    180     try:
--> 181         return method(client, *args, **kwargs)
    182     except PathRootError:
    183         DropboxAccountInfo.from_credentials(client._credentials, force_update=True)

File ~/store/Projects/orion/documents/storage/storage.py:24, in invalid_credentials_handler.<locals>.wrapper(client, *args, **kwargs)
     22 def wrapper(client, *args, **kwargs):
     23     try:
---> 24         return method(client, *args, **kwargs)
     25     except AuthError:
     26         client._credentials.revoke().save()

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/dropbox/base.py:3018, in DropboxBase.files_search_v2(self,
query, options, match_field_options, include_highlights)
   2990 """
   2991 Searches for files and folders. Note: :meth:`files_search_v2` along with
   2992 :meth:`files_search_continue_v2` can only be used to retrieve a maximum
   (...)
   3012     :class:`dropbox.files.SearchError`
   3013 """
   3014 arg = files.SearchV2Arg(query,
   3015                         options,
   3016                         match_field_options,
   3017                         include_highlights)
-> 3018 r = self.request(
   3019     files.search_v2,
   3020     'files',
   3021     arg,
   3022     None,
   3023 )
   3024 return r

File ~/store/Projects/orion/documents/storage/dropboxstorage.py:181, in handle_path_root_error.<locals>.wrapper(client, *args, **kwarg
s)
    179 def wrapper(client, *args, **kwargs):
    180     try:
--> 181         return method(client, *args, **kwargs)
    182     except PathRootError:
    183         DropboxAccountInfo.from_credentials(client._credentials, force_update=True)

File ~/store/Projects/orion/documents/storage/storage.py:24, in invalid_credentials_handler.<locals>.wrapper(client, *args, **kwargs)
     22 def wrapper(client, *args, **kwargs):
     23     try:
---> 24         return method(client, *args, **kwargs)
     25     except AuthError:
     26         client._credentials.revoke().save()

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/dropbox/dropbox_client.py:347, in _DropboxTransport.request
(self, route, namespace, request_arg, request_binary, timeout)
    343 else:
    344     raise AssertionError('Expected RouteResult or RouteErrorResult, '
    345                          'but res is %s' % type(res))
--> 347 deserialized_result = stone_serializers.json_compat_obj_decode(
    348     returned_data_type, obj, strict=False)
    350 if isinstance(res, RouteErrorResult):
    351     raise ApiError(res.request_id,
    352                    deserialized_result,
    353                    user_message_text,
    354                    user_message_locale)

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:977, in jso
n_compat_obj_decode(data_type, obj, caller_permissions, alias_validators, strict, old_style, for_msgpack)
    974     return decoder.make_stone_friendly(
    975         data_type, obj, True)
    976 else:
--> 977     return decoder.json_compat_obj_decode_helper(
    978         data_type, obj)

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:558, in Pyt
honPrimitiveToStoneDecoder.json_compat_obj_decode_helper(self, data_type, obj)
    556     return self.decode_struct_tree(data_type, obj)
    557 elif isinstance(data_type, bv.Struct):
--> 558     return self.decode_struct(data_type, obj)
    559 elif isinstance(data_type, bv.Union):
    560     if self.old_style:

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:607, in Pyt
honPrimitiveToStoneDecoder.decode_struct(self, data_type, obj)
    605             raise bv.ValidationError("unknown field '%s'" % key)
    606 ins = data_type.definition()
--> 607 self.decode_struct_fields(ins, all_fields, obj)
    608 # Check that all required fields have been set.
    609 data_type.validate_fields_only_with_permissions(ins, self.caller_permissions)

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:626, in Pyt
honPrimitiveToStoneDecoder.decode_struct_fields(self, ins, fields, obj)
    624 if name in obj:
    625     try:
--> 626         v = self.json_compat_obj_decode_helper(field_data_type, obj[name])
    627         setattr(ins, name, v)
    628     except bv.ValidationError as e:

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:565, in Pyt
honPrimitiveToStoneDecoder.json_compat_obj_decode_helper(self, data_type, obj)
    563         return self.decode_union(data_type, obj)
    564 elif isinstance(data_type, bv.List):
--> 565     return self.decode_list(
    566         data_type, obj)
    567 elif isinstance(data_type, bv.Map):
    568     return self.decode_map(
    569         data_type, obj)

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:842, in Pyt
honPrimitiveToStoneDecoder.decode_list(self, data_type, obj)
    839 if not isinstance(obj, list):
    840     raise bv.ValidationError(
    841         'expected list, got %s' % bv.generic_type_name(obj))
--> 842 return [
    843     self.json_compat_obj_decode_helper(data_type.item_validator, item)
    844     for item in obj]

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:843, in <li
stcomp>(.0)
    839 if not isinstance(obj, list):
    840     raise bv.ValidationError(
    841         'expected list, got %s' % bv.generic_type_name(obj))
    842 return [
--> 843     self.json_compat_obj_decode_helper(data_type.item_validator, item)
    844     for item in obj]

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:558, in Pyt
honPrimitiveToStoneDecoder.json_compat_obj_decode_helper(self, data_type, obj)
    556     return self.decode_struct_tree(data_type, obj)
    557 elif isinstance(data_type, bv.Struct):
--> 558     return self.decode_struct(data_type, obj)
    559 elif isinstance(data_type, bv.Union):
    560     if self.old_style:

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:607, in Pyt
honPrimitiveToStoneDecoder.decode_struct(self, data_type, obj)
    605             raise bv.ValidationError("unknown field '%s'" % key)
    606 ins = data_type.definition()
--> 607 self.decode_struct_fields(ins, all_fields, obj)
    608 # Check that all required fields have been set.
    609 data_type.validate_fields_only_with_permissions(ins, self.caller_permissions)

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:626, in Pyt
honPrimitiveToStoneDecoder.decode_struct_fields(self, ins, fields, obj)
    624 if name in obj:
    625     try:
--> 626         v = self.json_compat_obj_decode_helper(field_data_type, obj[name])
    627         setattr(ins, name, v)
    628     except bv.ValidationError as e:

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:571, in Pyt
honPrimitiveToStoneDecoder.json_compat_obj_decode_helper(self, data_type, obj)
    568     return self.decode_map(
    569         data_type, obj)
    570 elif isinstance(data_type, bv.Nullable):
--> 571     return self.decode_nullable(
    572         data_type, obj)
    573 elif isinstance(data_type, bv.Primitive):
    574     # Set validate to false because validation will be done by the
    575     # containing struct or union when the field is assigned.
    576     return self.make_stone_friendly(data_type, obj, False)

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:866, in Pyt
honPrimitiveToStoneDecoder.decode_nullable(self, data_type, obj)
    861 """
    862 The data_type argument must be a Nullable.
    863 See json_compat_obj_decode() for argument descriptions.
    864 """
    865 if obj is not None:
--> 866     return self.json_compat_obj_decode_helper(data_type.validator, obj)
    867 else:
    868     return None

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:563, in Pyt
honPrimitiveToStoneDecoder.json_compat_obj_decode_helper(self, data_type, obj)
    561         return self.decode_union_old(data_type, obj)
    562     else:
--> 563         return self.decode_union(data_type, obj)
    564 elif isinstance(data_type, bv.List):
    565     return self.decode_list(
    566         data_type, obj)

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:658, in Pyt
honPrimitiveToStoneDecoder.decode_union(self, data_type, obj)
    656         raise bv.ValidationError("unknown tag '%s'" % tag)
    657 elif isinstance(obj, dict):
--> 658     tag, val = self.decode_union_dict(data_type, obj)
    659 else:
    660     raise bv.ValidationError("expected string or object, got %s" %
    661                              bv.generic_type_name(obj))

File ~/.pyenv/versions/3.11.4/envs/orion-3.11/lib/python3.11/site-packages/stone/backends/python_rsrc/stone_serializers.py:678, in Pyt
honPrimitiveToStoneDecoder.decode_union_dict(self, data_type, obj)
    676         raise bv.ValidationError("unknown tag '%s'" % tag)
    677 if tag == data_type.definition._catch_all:
--> 678     raise bv.ValidationError(
    679         "unexpected use of the catch-all tag '%s'" % tag)
    681 val_data_type = data_type.definition._get_val_data_type(tag, self.caller_permissions)
    682 if isinstance(val_data_type, bv.Nullable):

ValidationError: matches.match_type: unexpected use of the catch-all tag 'other'

Versions SDK version: v11.36.2 Python 3.11, Linux

Additional context It used to work. Some changes in the server response may be causing the issue.

greg-db commented 9 months ago

Thanks for the detailed report! We'll look into it and I'll follow up here once I have an update on this.

greg-db commented 9 months ago

This should be fixed now. Please try again and let me know if you're still seeing any issues. Thanks!