From bc1b4717e9a50792a7d3371501aac4123ee711e2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 30 Jul 2024 12:47:00 -0400 Subject: [PATCH 1/2] fix: missing properties in python when no additional properties Signed-off-by: Vincent Biret --- CHANGELOG.md | 1 + src/Kiota.Builder/Refiners/PythonRefiner.cs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34d4178b3b..d01c7af21e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Fixed a bug where properties would be missing in Python models if they didn't have additional properties. [#5037](https://github.com/microsoft/kiota/issues/5037) - Fixed a bug in dotnet where CS1587 warnings are generated in generated enums with descriptions [#4957](https://github.com/microsoft/kiota/issues/4957) - Fixed a bug where the copilot teams toolkit integration would serialize empty declarative copilots. [#4974](https://github.com/microsoft/kiota/issues/4974) - Fixed a bug for the docker image where the volume path would not match the expected configuration for the description. diff --git a/src/Kiota.Builder/Refiners/PythonRefiner.cs b/src/Kiota.Builder/Refiners/PythonRefiner.cs index 08d804cb3b..31110e4b5d 100644 --- a/src/Kiota.Builder/Refiners/PythonRefiner.cs +++ b/src/Kiota.Builder/Refiners/PythonRefiner.cs @@ -288,6 +288,10 @@ private static void CorrectPropertyType(CodeProperty currentProperty) if (!string.IsNullOrEmpty(currentProperty.DefaultValue)) currentProperty.DefaultValue = "{}"; } + else if (currentProperty.Kind is CodePropertyKind.Custom && currentProperty.Type.IsNullable && string.IsNullOrEmpty(currentProperty.DefaultValue)) + { + currentProperty.DefaultValue = "None"; + } currentProperty.Type.Name = currentProperty.Type.Name.ToFirstCharacterUpperCase(); CorrectCoreTypes(currentProperty.Parent as CodeClass, DateTypesReplacements, currentProperty.Type); } From a4f05cdf00513dcbc60bac7287a21747c24abc48 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 1 Aug 2024 09:53:03 -0400 Subject: [PATCH 2/2] fix: regression for defaulted properties Signed-off-by: Vincent Biret --- .../Writers/Python/CodeMethodWriter.cs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs index 67eee514f2..0b5025485b 100644 --- a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs @@ -22,7 +22,7 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException("the parent of a method should be a class"); var returnType = conventions.GetTypeString(codeElement.ReturnType, codeElement, true, writer); - var isVoid = "None".Equals(returnType, StringComparison.OrdinalIgnoreCase); + var isVoid = NoneKeyword.Equals(returnType, StringComparison.OrdinalIgnoreCase); if (parentClass.IsOfKind(CodeClassKind.Model) && (codeElement.IsOfKind(CodeMethodKind.Setter) || codeElement.IsOfKind(CodeMethodKind.Getter) || codeElement.IsOfKind(CodeMethodKind.Constructor))) { writer.IncreaseIndent(); @@ -215,7 +215,7 @@ private void WriteFactoryMethodBody(CodeMethod codeElement, CodeClass parentClas writer.WriteLine($"{DiscriminatorMappingVarName} = {parseNodeParameter.Name}.get_child_node(\"{parentClass.DiscriminatorInformation.DiscriminatorPropertyName}\").get_str_value()"); writer.DecreaseIndent(); writer.StartBlock($"except AttributeError:"); - writer.WriteLine($"{DiscriminatorMappingVarName} = None"); + writer.WriteLine($"{DiscriminatorMappingVarName} = {NoneKeyword}"); writer.DecreaseIndent(); } if (parentClass.DiscriminatorInformation.ShouldWriteDiscriminatorForInheritedType) @@ -351,7 +351,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho writer.WriteLine($"super().__init__({requestAdapterParameter.Name}, {urlTemplateProperty.DefaultValue ?? ""}, {pathParametersParameter.Name})"); } else - writer.WriteLine($"super().__init__({requestAdapterParameter.Name}, {urlTemplateProperty.DefaultValue ?? ""}, None)"); + writer.WriteLine($"super().__init__({requestAdapterParameter.Name}, {urlTemplateProperty.DefaultValue ?? ""}, {NoneKeyword})"); } else writer.WriteLine("super().__init__()"); @@ -376,7 +376,7 @@ private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMetho private void WriteDirectAccessProperties(CodeClass parentClass, LanguageWriter writer) { foreach (var propWithDefault in parentClass.GetPropertiesOfKind(DirectAccessProperties) - .Where(static x => !string.IsNullOrEmpty(x.DefaultValue)) + .Where(static x => !string.IsNullOrEmpty(x.DefaultValue) && !NoneKeyword.Equals(x.DefaultValue, StringComparison.Ordinal)) .OrderByDescending(static x => x.Kind) .ThenBy(static x => x.Name)) { @@ -403,7 +403,7 @@ private void WriteDirectAccessProperties(CodeClass parentClass, LanguageWriter w private void WriteSetterAccessProperties(CodeClass parentClass, LanguageWriter writer) { foreach (var propWithDefault in parentClass.GetPropertiesOfKind(SetterAccessProperties) - .Where(static x => !string.IsNullOrEmpty(x.DefaultValue)) + .Where(static x => !string.IsNullOrEmpty(x.DefaultValue) && !NoneKeyword.Equals(x.DefaultValue, StringComparison.Ordinal)) // do not apply the default value if the type is composed as the default value may not necessarily which type to use .Where(static x => x.Type is not CodeType propType || propType.TypeDefinition is not CodeClass propertyClass || propertyClass.OriginalComposedType is null) .OrderByDescending(static x => x.Kind) @@ -426,19 +426,20 @@ private void WriteSetterAccessProperties(CodeClass parentClass, LanguageWriter w writer.WriteLine($"self.{setterString}"); } } + private const string NoneKeyword = "None"; private void WriteSetterAccessPropertiesWithoutDefaults(CodeClass parentClass, LanguageWriter writer) { foreach (var propWithoutDefault in parentClass.GetPropertiesOfKind(SetterAccessProperties) - .Where(static x => string.IsNullOrEmpty(x.DefaultValue)) + .Where(static x => string.IsNullOrEmpty(x.DefaultValue) || NoneKeyword.Equals(x.DefaultValue, StringComparison.Ordinal)) .OrderByDescending(static x => x.Kind) .ThenBy(static x => x.Name)) { var returnType = conventions.GetTypeString(propWithoutDefault.Type, propWithoutDefault, true, writer); conventions.WriteInLineDescription(propWithoutDefault, writer); if (parentClass.IsOfKind(CodeClassKind.Model)) - writer.WriteLine($"{propWithoutDefault.Name}: {(propWithoutDefault.Type.IsNullable ? "Optional[" : string.Empty)}{returnType}{(propWithoutDefault.Type.IsNullable ? "]" : string.Empty)} = None"); + writer.WriteLine($"{propWithoutDefault.Name}: {(propWithoutDefault.Type.IsNullable ? "Optional[" : string.Empty)}{returnType}{(propWithoutDefault.Type.IsNullable ? "]" : string.Empty)} = {NoneKeyword}"); else - writer.WriteLine($"self.{conventions.GetAccessModifier(propWithoutDefault.Access)}{propWithoutDefault.NamePrefix}{propWithoutDefault.Name}: {(propWithoutDefault.Type.IsNullable ? "Optional[" : string.Empty)}{returnType}{(propWithoutDefault.Type.IsNullable ? "]" : string.Empty)} = None"); + writer.WriteLine($"self.{conventions.GetAccessModifier(propWithoutDefault.Access)}{propWithoutDefault.NamePrefix}{propWithoutDefault.Name}: {(propWithoutDefault.Type.IsNullable ? "Optional[" : string.Empty)}{returnType}{(propWithoutDefault.Type.IsNullable ? "]" : string.Empty)} = {NoneKeyword}"); } } private static void WriteSetterBody(CodeMethod codeElement, LanguageWriter writer, CodeClass parentClass) @@ -539,7 +540,7 @@ private void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, La private void WriteDeserializerBodyForInheritedModel(bool inherits, CodeMethod codeElement, CodeClass parentClass, LanguageWriter writer) { _codeUsingWriter.WriteInternalImports(parentClass, writer); - writer.StartBlock("fields: Dict[str, Callable[[Any], None]] = {"); + writer.StartBlock($"fields: Dict[str, Callable[[Any], {NoneKeyword}]] = {{"); foreach (var otherProp in parentClass .GetPropertiesOfKind(CodePropertyKind.Custom) .Where(static x => !x.ExistsInBaseType) @@ -579,7 +580,7 @@ private void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams requ var returnTypeWithoutCollectionSymbol = GetReturnTypeWithoutCollectionSymbol(codeElement, returnType); var genericTypeForSendMethod = GetSendRequestMethodName(isVoid, isStream, codeElement.ReturnType.IsCollection, returnTypeWithoutCollectionSymbol); var newFactoryParameter = GetTypeFactory(isVoid, isStream, returnTypeWithoutCollectionSymbol); - var errorMappingVarName = "None"; + var errorMappingVarName = NoneKeyword; if (codeElement.ErrorMappings.Any()) { _codeUsingWriter.WriteInternalErrorMappingImports(parentClass, writer); @@ -660,7 +661,7 @@ private void WriteSerializerBodyForUnionModel(CodeClass parentClass, LanguageWri .ThenBy(static x => x.Name)) { writer.StartBlock($"{(includeElse ? "el" : string.Empty)}if self.{otherProp.Name}:"); - writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type)}(None, self.{otherProp.Name})"); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type)}({NoneKeyword}, self.{otherProp.Name})"); writer.DecreaseIndent(); if (!includeElse) includeElse = true; @@ -677,7 +678,7 @@ private void WriteSerializerBodyForIntersectionModel(CodeClass parentClass, Lang .ThenBy(static x => x.Name)) { writer.StartBlock($"{(includeElse ? "el" : string.Empty)}if self.{otherProp.Name}:"); - writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type)}(None, self.{otherProp.Name})"); + writer.WriteLine($"writer.{GetSerializationMethodName(otherProp.Type)}({NoneKeyword}, self.{otherProp.Name})"); writer.DecreaseIndent(); if (!includeElse) includeElse = true; @@ -695,7 +696,7 @@ private void WriteSerializerBodyForIntersectionModel(CodeClass parentClass, Lang .Select(static x => x.Name) .OrderBy(static x => x, StringComparer.OrdinalIgnoreCase) .Aggregate(static (x, y) => $"self.{x}, self.{y}"); - writer.WriteLine($"writer.{GetSerializationMethodName(complexProperties[0].Type)}(None, {propertiesNames})"); + writer.WriteLine($"writer.{GetSerializationMethodName(complexProperties[0].Type)}({NoneKeyword}, {propertiesNames})"); if (includeElse) { writer.DecreaseIndent(); @@ -706,7 +707,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer, st { var nullablePrefix = code.ReturnType.IsNullable && !isVoid ? "Optional[" : string.Empty; var nullableSuffix = code.ReturnType.IsNullable && !isVoid ? "]" : string.Empty; - var returnRemark = isVoid ? "Returns: None" : $"Returns: {nullablePrefix}{returnType}{nullableSuffix}"; + var returnRemark = isVoid ? $"Returns: {NoneKeyword}" : $"Returns: {nullablePrefix}{returnType}{nullableSuffix}"; conventions.WriteLongDescription(code, writer, code.Parameters @@ -744,7 +745,7 @@ private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string _ => string.Empty }; var nullReturnTypeSuffix = !isVoid && !isConstructor; - var returnTypeSuffix = nullReturnTypeSuffix ? $"{nullablePrefix}{returnType}{nullableSuffix}" : "None"; + var returnTypeSuffix = nullReturnTypeSuffix ? $"{nullablePrefix}{returnType}{nullableSuffix}" : NoneKeyword; if (!string.IsNullOrEmpty(propertyDecorator)) writer.WriteLine($"{propertyDecorator}"); writer.WriteLine($"{asyncPrefix}def {accessModifier}{methodName}({instanceReference}{parameters}) -> {returnTypeSuffix}:");