You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(abstractions): enhance request information sanitization, span naming, and option removal - #828
In RequestInformation (microsoft-kiota-abstractions), this PR addresses several issues regarding URI template parameter sanitization, telemetry span naming, scalar serialization, and option removal:
Empty Collection Sanitization:
_get_sanitized_value previously evaluated elif isinstance(value, list) and all(isinstance(x, Enum) for x in value):. For an empty list [], Python's all([]) evaluates to True, so [] was converted to "" (empty string). When passed to StdUriTemplate.expand("https://example.com{?ids*}", {"ids": ""}), it generated a dangling assignment https://example.com?ids= instead of omitting the query parameter per RFC 6570.
Collection Element Sanitization (UUID, date, time, datetime):
_get_sanitized_value previously only sanitized UUID, date, time, and datetime when passed as single scalar values. When passed in a collection (list, tuple, set), StdUriTemplate.expand crashed with ValueError: Illegal class passed as substitution because non-primitive objects were forwarded unformatted.
Collections are now recursively sanitized element-by-element so objects like UUIDs and datetimes are serialized to strings before URI template expansion. Tuples and sets are also normalized to lists for StdUriTemplate.
Span Naming & URI Template Decoding:
_decode_uri_string previously returned "" when the URI did not contain % (if uri and "%" in uri:). As a result, standard unencoded URLs (the vast majority of templates) caused _create_parent_span_name to return incomplete names like "set_content_from_parsable - " with a trailing hyphen and missing URI.
_decode_uri_string now returns unencoded URIs as-is, and _create_parent_span_name handles null or empty templates cleanly without a trailing delimiter.
Missing bytes and Enum support in set_content_from_scalar:
T in request_information.py explicitly includes bytes: T = TypeVar("T", bool, str, int, float, UUID, datetime, timedelta, date, time, bytes). However, bytes was missing from function_values, raising ValueError: Encountered an unknown type during serialization <class 'bytes'> whenever byte scalars were set.
Added bytes: writer.write_bytes_value and supported Enum scalar serialization via writer.write_enum_value.
Safe Option Removal:
remove_request_options used del self.__request_options[option.get_key()], which raised an unhandled KeyError if an option being removed had not been set or was already removed.
Replaced del with self.__request_options.pop(option.get_key(), None) to ensure idempotent, safe removal, and typed options as Optional[list[RequestOption]] matching add_request_options.
Changes
Updated _get_sanitized_value to handle empty collections, normalize tuples/sets, and recursively sanitize collection elements.
Fixed _decode_uri_string to return unencoded URIs instead of "", and cleaned up _create_parent_span_name.
Added bytes and Enum handling to set_content_from_scalar.
Made remove_request_options idempotent using .pop(..., None) and accepted Optional[list[RequestOption]].
Added comprehensive unit tests in test_request_information.py.
I've updated the PR in commit \81609ff\ to address the review recommendation:
Type Annotations: Updated \set_content_from_scalar()\ parameter annotation and docstring to \Union[T, list[T], Enum], ensuring that static type checkers accept \Enum\ scalar inputs cleanly for typed SDK consumers.
All 175 unit tests in \kiota_abstractions\ and Mypy static type checking pass without issues. Whenever convenient, please take another look. Thank you!
Optional: this test only supplies a tuple, so it never exercises the newly added set normalization despite its name and docstring. Parameterize it with a set too, allowing either query-parameter order because set iteration order is not guaranteed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
In
RequestInformation(microsoft-kiota-abstractions), this PR addresses several issues regarding URI template parameter sanitization, telemetry span naming, scalar serialization, and option removal:Empty Collection Sanitization:
_get_sanitized_valuepreviously evaluatedelif isinstance(value, list) and all(isinstance(x, Enum) for x in value):. For an empty list[], Python'sall([])evaluates toTrue, so[]was converted to""(empty string). When passed toStdUriTemplate.expand("https://example.com{?ids*}", {"ids": ""}), it generated a dangling assignmenthttps://example.com?ids=instead of omitting the query parameter per RFC 6570.[]to preserve RFC 6570 omit-if-empty semantics.Collection Element Sanitization (
UUID,date,time,datetime):_get_sanitized_valuepreviously only sanitizedUUID,date,time, anddatetimewhen passed as single scalar values. When passed in a collection (list,tuple,set),StdUriTemplate.expandcrashed withValueError: Illegal class passed as substitutionbecause non-primitive objects were forwarded unformatted.StdUriTemplate.Span Naming & URI Template Decoding:
_decode_uri_stringpreviously returned""when the URI did not contain%(if uri and "%" in uri:). As a result, standard unencoded URLs (the vast majority of templates) caused_create_parent_span_nameto return incomplete names like"set_content_from_parsable - "with a trailing hyphen and missing URI._decode_uri_stringnow returns unencoded URIs as-is, and_create_parent_span_namehandles null or empty templates cleanly without a trailing delimiter.Missing
bytesandEnumsupport inset_content_from_scalar:Tinrequest_information.pyexplicitly includesbytes:T = TypeVar("T", bool, str, int, float, UUID, datetime, timedelta, date, time, bytes). However,byteswas missing fromfunction_values, raisingValueError: Encountered an unknown type during serialization <class 'bytes'>whenever byte scalars were set.bytes: writer.write_bytes_valueand supportedEnumscalar serialization viawriter.write_enum_value.Safe Option Removal:
remove_request_optionsuseddel self.__request_options[option.get_key()], which raised an unhandledKeyErrorif an option being removed had not been set or was already removed.delwithself.__request_options.pop(option.get_key(), None)to ensure idempotent, safe removal, and typedoptionsasOptional[list[RequestOption]]matchingadd_request_options.Changes
_get_sanitized_valueto handle empty collections, normalize tuples/sets, and recursively sanitize collection elements._decode_uri_stringto return unencoded URIs instead of"", and cleaned up_create_parent_span_name.bytesandEnumhandling toset_content_from_scalar.remove_request_optionsidempotent using.pop(..., None)and acceptedOptional[list[RequestOption]].test_request_information.py.