microsoftgraph / microsoftgraph/msgraph-sdk-python

Exception: string index out of range when fetching site lists with expand:fields

未关闭
#940 7 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

priority:p1 type:bug
主要语言
Python
星标
630
派生
96
平均合并
15 小时 20 分钟
30 天内合并 PR
3

描述

Describe the bug

I am trying to fetch the list of lists for a given site, with an expand on the fields.
This crashes during deserialisation with a "string index out of range".
The full stack trace is the following

File /usr/local/lib/python3.10/site-packages/msgraph/generated/sites/item/lists/item/items/items_request_builder.py:81, in ItemsRequestBuilder.get(self, request_configuration)
     78     raise Exception("Http core is null") 
     79 from ......models.list_item_collection_response import ListItemCollectionResponse
---> 81 return await self.request_adapter.send_async(request_info, ListItemCollectionResponse, error_mapping)

File /usr/local/lib/python3.10/site-packages/kiota_http/httpx_request_adapter.py:196, in HttpxRequestAdapter.send_async(self, request_info, parsable_factory, error_map)
    194     return None
    195 _deserialized_span = self._start_local_tracing_span("get_object_value", parent_span)
--> 196 value = root_node.get_object_value(parsable_factory)
    197 parent_span.set_attribute(DESERIALIZED_MODEL_NAME_KEY, value.__class__.__name__)
    198 _deserialized_span.end()

File /usr/local/lib/python3.10/site-packages/kiota_serialization_json/json_parse_node.py:222, in JsonParseNode.get_object_value(self, factory)
    220 if on_before := self.on_before_assign_field_values:
    221     on_before(result)
--> 222 self._assign_field_values(result)
    223 if on_after := self.on_after_assign_field_values:
    224     on_after(result)

File /usr/local/lib/python3.10/site-packages/kiota_serialization_json/json_parse_node.py:291, in JsonParseNode._assign_field_values(self, item)
    289         continue
    290     field_deserializer = field_deserializers[field_name]
--> 291     field_deserializer(JsonParseNode(field_value))
    292 elif item_additional_data is not None:
    293     item_additional_data[field_name] = self.try_get_anything(field_value)

File /usr/local/lib/python3.10/site-packages/msgraph/generated/models/list_item_collection_response.py:40, in ListItemCollectionResponse.get_field_deserializers.<locals>.<lambda>(n)
     36 from .base_collection_pagination_count_response import BaseCollectionPaginationCountResponse
     37 from .list_item import ListItem
     39 fields: Dict[str, Callable[[Any], None]] = {
---> 40     "value": lambda n : setattr(self, 'value', n.get_collection_of_object_values(ListItem)),
     41 }
     42 super_fields = super().get_field_deserializers()
     43 fields.update(super_fields)

File /usr/local/lib/python3.10/site-packages/kiota_serialization_json/json_parse_node.py:170, in JsonParseNode.get_collection_of_object_values(self, factory)
    165 """Gets the collection of type U values from the json node
    166 Returns:
    167     List[U]: The collection of model object values of the node
    168 """
    169 if isinstance(self._json_node, list):
--> 170     return list(
    171         map(
    172             lambda x: self._create_new_node(x).get_object_value(factory),  # type: ignore
    173             self._json_node,
    174         )
    175     )
    176 return []

File /usr/local/lib/python3.10/site-packages/kiota_serialization_json/json_parse_node.py:172, in JsonParseNode.get_collection_of_object_values.<locals>.<lambda>(x)
    165 """Gets the collection of type U values from the json node
    166 Returns:
    167     List[U]: The collection of model object values of the node
    168 """
    169 if isinstance(self._json_node, list):
    170     return list(
    171         map(
--> 172             lambda x: self._create_new_node(x).get_object_value(factory),  # type: ignore
    173             self._json_node,
    174         )
    175     )
    176 return []

File /usr/local/lib/python3.10/site-packages/kiota_serialization_json/json_parse_node.py:222, in JsonParseNode.get_object_value(self, factory)
    220 if on_before := self.on_before_assign_field_values:
    221     on_before(result)
--> 222 self._assign_field_values(result)
    223 if on_after := self.on_after_assign_field_values:
    224     on_after(result)

File /usr/local/lib/python3.10/site-packages/kiota_serialization_json/json_parse_node.py:291, in JsonParseNode._assign_field_values(self, item)
    289         continue
    290     field_deserializer = field_deserializers[field_name]
--> 291     field_deserializer(JsonParseNode(field_value))
    292 elif item_additional_data is not None:
    293     item_additional_data[field_name] = self.try_get_anything(field_value)

File /usr/local/lib/python3.10/site-packages/msgraph/generated/models/list_item.py:76, in ListItem.get_field_deserializers.<locals>.<lambda>(n)
     68 from .list_item_version import ListItemVersion
     69 from .sharepoint_ids import SharepointIds
     71 fields: Dict[str, Callable[[Any], None]] = {
     72     "analytics": lambda n : setattr(self, 'analytics', n.get_object_value(ItemAnalytics)),
     73     "contentType": lambda n : setattr(self, 'content_type', n.get_object_value(ContentTypeInfo)),
     74     "documentSetVersions": lambda n : setattr(self, 'document_set_versions', n.get_collection_of_object_values(DocumentSetVersion)),
     75     "driveItem": lambda n : setattr(self, 'drive_item', n.get_object_value(DriveItem)),
---> 76     "fields": lambda n : setattr(self, 'fields', n.get_object_value(FieldValueSet)),
     77     "sharepointIds": lambda n : setattr(self, 'sharepoint_ids', n.get_object_value(SharepointIds)),
     78     "versions": lambda n : setattr(self, 'versions', n.get_collection_of_object_values(ListItemVersion)),
     79 }
     80 super_fields = super().get_field_deserializers()
     81 fields.update(super_fields)

File /usr/local/lib/python3.10/site-packages/kiota_serialization_json/json_parse_node.py:222, in JsonParseNode.get_object_value(self, factory)
    220 if on_before := self.on_before_assign_field_values:
    221     on_before(result)
--> 222 self._assign_field_values(result)
    223 if on_after := self.on_after_assign_field_values:
    224     on_after(result)

File /usr/local/lib/python3.10/site-packages/kiota_serialization_json/json_parse_node.py:293, in JsonParseNode._assign_field_values(self, item)
    291     field_deserializer(JsonParseNode(field_value))
    292 elif item_additional_data is not None:
--> 293     item_additional_data[field_name] = self.try_get_anything(field_value)
    294 else:
    295     warnings.warn(
    296         f"Found additional property {field_name} to \
    297         deserialize but the model doesn't support additional data"
    298     )

File /usr/local/lib/python3.10/site-packages/kiota_serialization_json/json_parse_node.py:316, in JsonParseNode.try_get_anything(self, value)
    313 if self.__is_four_digit_number(value):
    314     return value
--> 316 datetime_obj = pendulum.parse(value)
    317 if isinstance(datetime_obj, pendulum.Duration):
    318     return datetime_obj.as_timedelta()

File /usr/local/lib/python3.10/site-packages/pendulum/parser.py:30, in parse(text, **options)
     26 def parse(text: str, **options: t.Any) -> Date | Time | DateTime | Duration:
     27     # Use the mock now value if it exists
     28     options["now"] = options.get("now")
---> 30     return _parse(text, **options)

File /usr/local/lib/python3.10/site-packages/pendulum/parser.py:43, in _parse(text, **options)
     40 if text == "now":
     41     return pendulum.now()
---> 43 parsed = base_parse(text, **options)
     45 if isinstance(parsed, datetime.datetime):
     46     return pendulum.datetime(
     47         parsed.year,
     48         parsed.month,
   (...)
     54         tz=parsed.tzinfo or options.get("tz", UTC),
     55     )

File /usr/local/lib/python3.10/site-packages/pendulum/parsing/__init__.py:78, in parse(text, **options)
     75 _options: dict[str, Any] = copy.copy(DEFAULT_OPTIONS)
     76 _options.update(options)
---> 78 return _normalize(_parse(text, **_options), **_options)

File /usr/local/lib/python3.10/site-packages/pendulum/parsing/__init__.py:116, in _parse(text, **options)
    113     return parse_iso8601(text)
    115 with contextlib.suppress(ValueError):
--> 116     return _parse_iso8601_interval(text)
    118 with contextlib.suppress(ParserError):
    119     return _parse_common(text, **options)

File /usr/local/lib/python3.10/site-packages/pendulum/parsing/__init__.py:217, in _parse_iso8601_interval(text)
    214 first, last = text.split("/")
    215 start = end = duration = None
--> 217 if first[0] == "P":
    218     # duration/end
    219     duration = parse_iso8601(first)
    220     end = parse_iso8601(last)

IndexError: string index out of range

The field that is being deserialised is 'WorkPhone' with a value of '/'. That is clearly not a date even though it is trying to decode it as a date.

Expected behavior

I expect to retrieve the decoded object

How to reproduce
from azure.identity import ClientSecretCredential
from msgraph import GraphServiceClient
import asyncio
from msgraph.generated.users.item.messages.messages_request_builder import  MessagesRequestBuilder

credentials = ClientSecretCredential(
            tenant_id=SHAREPOINT_TENANT_ID,
            client_id=SHAREPOINT_CLIENT_ID,
            client_secret=SHAREPOINT_SECRET_VALUE
        )
client = GraphServiceClient(credentials, scopes=["https://graph.microsoft.com/.default"])
loop = asyncio.get_event_loop()

site_id = <the_site_id>

query_params = MessagesRequestBuilder.MessagesRequestBuilderGetQueryParameters(expand=['fields'])
configuration = MessagesRequestBuilder.MessagesRequestBuilderGetRequestConfiguration(query_parameters=query_params)
fn = client.sites.by_site_id(site_id)lists.by_list_id("User Information List").items.get(request_configuration=configuration)
a = asyncio.run_coroutine_threadsafe(fn, loop)
a.result()

This obviously triggers the issue only when the data coming from the request contains the mentioned field with the specific value.

SDK Version

1.11.0

Latest version known to work for scenario above?

None

Known Workarounds

No response

Debug output

No response

Configuration

No response

Other information

No response

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 kiota_serialization_json/json_parse_node.py 开始,重点查看 try_get_anything,并使用 expand=['fields'] 和 WorkPhone 值 '/' 重现站点列表请求。追踪该值为何会传到 pendulum.parse;对于此输入,请求返回解码后的对象而不是 IndexError,即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
api
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
35/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。