Populate Python API error messages during deserialization - #8010
Populate Python API error messages during deserialization#8010AayushP123 wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
🟡 Not ready to approve
The generated assignment self.message = self.<primary> can propagate None into the exception message; it should coerce None to '' (and update the regression test accordingly) to match existing Python error-message semantics and TypeScript’s ?? "".
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR updates the Python code generator so that when a model is an error type and one of its deserialized properties is marked with x-ms-primary-error-message, the generated deserialization logic also populates the inherited APIError.message field—matching behavior already seen in other languages and fixing #7542.
Changes:
- Emit a named per-field deserializer function for primary error message properties in Python model
get_field_deserializers. - In that named deserializer, assign the parsed value to both the generated property and
APIError.message. - Add a focused Python writer regression test and a changelog entry documenting the fix.
File summaries
| File | Description |
|---|---|
| src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs | Generates a named deserializer for primary error message properties and wires it into the deserializer map, while setting self.message. |
| tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs | Adds a regression test asserting the new named deserializer and the self.message assignment are emitted. |
| CHANGELOG.md | Documents the Python client behavior change for APIError.message population. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 2
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| writer.StartBlock($"def deserialize_{primaryErrorMessageProperty.Name}(n: ParseNode) -> None:"); | ||
| writer.WriteLine($"self.{primaryErrorMessageProperty.Name} = n.{GetDeserializationMethodName(primaryErrorMessageProperty.Type, codeElement, parentClass)}"); | ||
| writer.WriteLine($"self.message = self.{primaryErrorMessageProperty.Name}"); | ||
| writer.CloseBlock(string.Empty); |
| Assert.Contains("def deserialize_detail(n: ParseNode) -> None:", result); | ||
| Assert.Contains("self.detail = n.get_str_value()", result); | ||
| Assert.Contains("self.message = self.detail", result); | ||
| Assert.Contains("\"detail\": deserialize_detail,", result); |
cea6f33 to
78bad7b
Compare
78bad7b to
9efa75f
Compare
There was a problem hiding this comment.
🟡 Not ready to approve
The new Python writer logic has a correctness issue in how it coerces/assigns APIError.message and also needs escaping when emitting schema-derived property names into single-quoted literals.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (2)
src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs:582
APIError.messageis assigned using truthiness (or ''), which can silently drop valid falsy values (e.g.,0) and can also assign non-string types if the schema mistakenly marks a non-string property asx-ms-primary-error-message. Using an explicitNonecheck andstr(...)keeps the message consistently a string while still coercingNoneto an empty string.
writer.StartBlock($"def deserialize_{primaryErrorMessageProperty.Name}(n: ParseNode) -> None:");
writer.WriteLine($"self.{primaryErrorMessageProperty.Name} = n.{GetDeserializationMethodName(primaryErrorMessageProperty.Type, codeElement, parentClass)}");
writer.WriteLine($"self.message = self.{primaryErrorMessageProperty.Name} or ''");
src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs:592
- The property name is written into a single-quoted Python string literal for
setattr(...)without escaping. Even thoughCodeProperty.Nameis schema-derived via conventions, escaping at the emission site avoids literal injection/broken output if a name ever contains', backslashes, or control characters.
var deserializer = parentClass.IsErrorDefinition && otherProp.IsPrimaryErrorMessage ?
$"deserialize_{otherProp.Name}" :
$"lambda n : setattr(self, '{otherProp.Name}', n.{GetDeserializationMethodName(otherProp.Type, codeElement, parentClass)})";
writer.WriteLine($"\"{otherProp.WireName.SanitizeDoubleQuote()}\": {deserializer},");
- Files reviewed: 3/3 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
9efa75f to
83a6536
Compare
There was a problem hiding this comment.
🟡 Not ready to approve
The Python writer currently interpolates schema-derived property names into Python identifier/attribute contexts for the named deserializer path without robust hardening, which can produce invalid code and presents a generated-source injection risk.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (1)
tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs:915
- The new primary-error-message deserializer test only covers a simple identifier name (
detail). Since the writer now emits a named deserializer, it would be good to add a regression assertion using a hostile/irregular property name (e.g., containing'and\n) to ensure the named-deserializer path is also safe/escaped (similar to the existingEscapesPropertyNamesInDeserializerBodycoverage for the lambda path).
public void WritesPrimaryErrorMessageDeserializer()
{
setup();
parentClass.IsErrorDefinition = true;
parentClass.AddProperty(new CodeProperty
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| foreach (var primaryErrorMessageProperty in customProperties.Where(static x => x.IsPrimaryErrorMessage)) | ||
| { | ||
| writer.StartBlock($"def deserialize_{primaryErrorMessageProperty.Name}(n: ParseNode) -> None:"); | ||
| writer.WriteLine($"self.{primaryErrorMessageProperty.Name} = n.{GetDeserializationMethodName(primaryErrorMessageProperty.Type, codeElement, parentClass)}"); | ||
| writer.WriteLine($"self.message = '' if self.{primaryErrorMessageProperty.Name} is None else str(self.{primaryErrorMessageProperty.Name})"); |
Summary
Fixes #7542.
Populates the inherited Python
APIError.messagefield when a generated error property is marked withx-ms-primary-error-message. The property itself was already deserialized, but the exception message remained unset.Changes
APIError.messagewith an explicitNonecheck and string coercion.setattr.Testing
ProblemDetailsmodel and verified the output withpython3 -m compileall.dotnet format whitespace kiota.slnx --no-restore --verify-no-changes --include src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs