Skip to content

fix(multipart): omit nil header string values and handle null objects in write_object_value - #833

Merged
Vincent Biret (baywet) merged 7 commits into
microsoft:mainfrom
hardikkaurani:fix/multipart-header-and-object-serialization
Oct 28, 2026
Merged

Vincent Biret (baywet) merged 7 commits into
microsoft:mainfrom
hardikkaurani:fix/multipart-header-and-object-serialization

Conversation

@hardikkaurani

@hardikkaurani Hardik K (hardikkaurani) commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary of Changes

  1. Omit None string header values: In multipart serialization, write_str_value(key, value) previously emitted bare header names like Content-Type\r\n (without a colon or value) when value is None. Calling write_str_value with a None value now safely returns without writing malformed header lines, matching MIME header formatting specifications.
  2. Handle null objects in write_object_value: When value is None, write_object_value previously raised ValueError: Expected a MultipartBody instance but got <class 'NoneType'>. It now safely returns early without throwing, establishing behavioral consistency across Kiota serialization writers.
  3. Reverted additional_values_to_merge & Boundary Rewriting: Per maintainer feedback (aligning with microsoft/kiota-serialization-multipart-go#125 and microsoft/kiota-java#2220), multi-body merging and boundary rewriting were reverted in write_object_value. Multipart payloads represent distinct MIME documents with isolated boundaries rather than intersection wrappers.

Verification

  • Unit tests in packages/serialization/multipart/tests covering:
    • Header formatting with None string values.
    • Calling write_object_value with None (ensuring no exception is thrown).
    • Calling write_object_value with None primary and additional values (ensuring no exception is thrown).
  • All unit tests passing: 17 passed in packages/serialization/multipart/tests.
  • Static typing and code style verified with mypy (strict), isort, yapf, and pylint (10.00/10).

@hardikkaurani
Hardik K (hardikkaurani) requested a review from a team as a code owner October 27, 2026 08:09
Copilot AI balanced review requested due to automatic review settings October 27, 2026 08:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@hardikkaurani

Hardik K (hardikkaurani) commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor Author

Hi Vincent Biret (@baywet),

This PR brings MultipartSerializationWriter into behavioral alignment with Kiota's other serialization implementations and multipart specifications.

  1. Header formatting: write_str_value(key, value) previously emitted a bare key string (Content-Type\r\n) without a delimiter or value when value was None. It now safely omits empty values, preventing malformed multipart part headers.

  2. Null object safety: write_object_value(key, value) previously raised a ValueError when passed value=None without additional values. It now returns early without throwing.

  3. Intersection wrapper support: Added support for additional_values_to_merge, validating each entry as MultipartBody, writing them sequentially, and properly triggering on_after_object_serialization.

All 18 unit tests in packages/serialization/multipart/tests are passing. Formatting and lint checks (yapf, isort, mypy, and pylint with a score of 10.00/10) have also been verified locally.

Thanks for reviewing!

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Additional bodies are serialized after the main closing boundary, causing MIME parsers to ignore their parts.

1 open issue

Review effort: Balanced

@hardikkaurani
Hardik K (hardikkaurani) force-pushed the fix/multipart-header-and-object-serialization branch from 266d22f to 3870a8d Compare October 27, 2026 14:17
Copilot AI balanced review requested due to automatic review settings October 27, 2026 14:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@hardikkaurani

Copy link
Copy Markdown
Contributor Author

Hi Vincent Biret (@baywet),

I've updated the PR to address the review feedback regarding multipart intersection serialization:

  • Single Boundary Aggregation: MultipartSerializationWriter.write_object_value now serializes all parts from value and additional_values_to_merge under the primary body's boundary, with a single closing boundary delimiter (--<boundary>--) emitted only after all bodies are processed. This ensures standard MIME parsers process all parts rather than treating trailing bodies as ignored epilogue data.
  • Preserved Lifecycle Callbacks: The per-object serialization hooks (on_before_object_serialization, on_start_object_serialization, and on_after_object_serialization) continue to execute sequentially for each individual model object.
  • MIME Parser Verification: Updated the merge test suite to validate that all parts across merged bodies are fully discoverable and extractable using Python's standard email.message_from_bytes MIME parser.
  • Validation: All tests, static type checks (mypy), code formatting (yapf, isort), and linting (pylint 10.00/10) pass cleanly across 4 signed-off commits.

Ready for review!

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Merged serialization validates body state before lifecycle callbacks can initialize it, rejecting otherwise valid callback-initialized bodies.

1 open issue
1 resolved since last review

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 27, 2026 20:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@hardikkaurani

Copy link
Copy Markdown
Contributor Author

Hi Vincent Biret (@baywet),

I've pushed an update addressing the review feedback on serialization lifecycle callback sequencing for merged multipart bodies.

In write_object_value, on_before_object_serialization and on_start_object_serialization are now invoked prior to validating the adapter and parts state, matching the single-body serialization lifecycle order.

Added regression test test_write_object_value_with_additional_values_callback_initialization to cover callback-initialized bodies during merge serialization. All unit tests (19 passed), static typing (mypy), formatting (yapf, isort), and linting (pylint 10.00/10) pass cleanly.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Multipart serialization silently skips invalid falsy additions when the primary body is absent and can emit a stale delimiter when callbacks initialize the boundary.

No open issues 🎉

2 previously missed issues

In code that hasn't changed since last review

Medium severity Validate falsy additional values when primary value is None

packages/​serialization/​multipart/​kiota_serialization_multipart/​multipart_serialization_writer.py:177

When the primary value is None, any() treats non-None falsy additions such as False, 0, or "" as absent and returns before type validation. These inputs therefore succeed silently, whereas the same invalid additions raise ValueError when a primary body is present. Check explicitly for None so every non-None additional value reaches validation.

Medium severity Capture boundary after primary body callbacks

packages/​serialization/​multipart/​kiota_serialization_multipart/​multipart_serialization_writer.py:210

The boundary is captured before the primary body's before/start callbacks run. If a callback initializes body.boundary, merged output still uses the old delimiter, so parsing with the updated boundary fails. Capture the boundary after the primary body's callbacks, then retain it for the remaining bodies.

1 resolved since last review

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 28, 2026 13:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@hardikkaurani

Copy link
Copy Markdown
Contributor Author

Hi Vincent Biret (@baywet),

I've addressed the edge cases highlighted by Copilot's review in f8e24d4:

  • Falsy additional values validation: Updated write_object_value to check not any(v is not None for v in additional_values_to_merge) instead of relying on any()'s truthiness check when the primary value is None. This guarantees that falsy non-None inputs (such as "", 0, or False) are properly validated and raise ValueError consistently with the primary body path.
  • Boundary capture after callbacks: In merged multipart serialization, the boundary delimiter is now captured from the primary body after its on_before_object_serialization and on_start_object_serialization lifecycle callbacks have executed. This prevents emitting stale boundary delimiters if a callback initializes or modifies body.boundary.
  • Unit test coverage: Added unit tests in test_multipart_serialization_writer.py verifying falsy invalid additional values, None handling, and boundary updates during callback lifecycle execution. All tests pass cleanly.

Ready for review when you have a moment.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed to judge whether string-only merge tests provide sufficient confidence in model, binary, and filename handling on the untested multi-body path.

No open issues 🎉

Review effort: Balanced

@github-project-automation github-project-automation Bot moved this to In Progress 🚧 in Kiota Oct 28, 2026
Copilot AI balanced review requested due to automatic review settings October 28, 2026 17:05
@hardikkaurani Hardik K (hardikkaurani) changed the title fix(multipart): omit nil header string values and support additional_values_to_merge fix(multipart): omit nil header string values and handle null objects in write_object_value Oct 28, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@hardikkaurani

Copy link
Copy Markdown
Contributor Author

Hi Vincent Biret (@baywet),

I've updated the PR in d81abd3 to align with the Go and Java multipart implementations:

  • Reverted additional_values_to_merge Handling: Removed the merge logic, boundary rewriting, and associated tests.
  • Strictly Scoped: The PR is now focused strictly on:
    1. Omitting header lines when value is None in write_str_value(), preventing bare headers from being emitted.
    2. Safely returning early when value is None in write_object_value().
  • All unit tests in packages/serialization/multipart (17/17 passed), mypy type checking, isort, yapf, and pylint (10.00/10) pass cleanly.

Apologies for the noise earlier, and thank you for keeping the implementations consistent across the SDKs!

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Multipart serialization ignores additional_values_to_merge, silently dropping additional bodies, accepting invalid additional values, and producing no output when only an additional body is supplied.

1 open issue

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 28, 2026 17:15
@baywet
Vincent Biret (baywet) force-pushed the fix/multipart-header-and-object-serialization branch from d81abd3 to ce098a2 Compare October 28, 2026 17:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@sonarqubecloud

Copy link
Copy Markdown

@baywet
Vincent Biret (baywet) merged commit ba512ab into microsoft:main Oct 28, 2026
69 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress 🚧 to Done ✔️ in Kiota Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done ✔️

Development

Successfully merging this pull request may close these issues.

3 participants