From 8e10e4a15c9027aeacd06cbec9e2d1810af5f2d0 Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Wed, 24 Jan 2024 21:22:57 +0300 Subject: [PATCH 1/7] adds deprecation support Python --- src/Kiota.Builder/Refiners/PythonRefiner.cs | 1 + .../Python/CodeClassDeclarationWriter.cs | 1 + .../Writers/Python/CodeEnumWriter.cs | 1 + .../Writers/Python/CodeMethodWriter.cs | 1 + .../Writers/Python/PythonConventionService.cs | 21 ++++++++++++++++++- 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/PythonRefiner.cs b/src/Kiota.Builder/Refiners/PythonRefiner.cs index 6a9527bb97..56c4f5c876 100644 --- a/src/Kiota.Builder/Refiners/PythonRefiner.cs +++ b/src/Kiota.Builder/Refiners/PythonRefiner.cs @@ -140,6 +140,7 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance private const string AbstractionsPackageName = "kiota_abstractions"; private static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { new (static x => x is CodeClass, "__future__", "annotations"), + new (static x => x is CodeClass, "warnings", "warn"), new (static x => x is CodeClass, "typing", "Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union"), new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), $"{AbstractionsPackageName}.request_adapter", "RequestAdapter"), diff --git a/src/Kiota.Builder/Writers/Python/CodeClassDeclarationWriter.cs b/src/Kiota.Builder/Writers/Python/CodeClassDeclarationWriter.cs index 9d40d35699..adef1bf4a9 100644 --- a/src/Kiota.Builder/Writers/Python/CodeClassDeclarationWriter.cs +++ b/src/Kiota.Builder/Writers/Python/CodeClassDeclarationWriter.cs @@ -51,6 +51,7 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit _codeUsingWriter.WriteConditionalInternalImports(codeElement, writer, parentNamespace); } conventions.WriteLongDescription(parent.Documentation, writer); + conventions.WriteDeprecationWarning(parent, writer); } } } diff --git a/src/Kiota.Builder/Writers/Python/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Python/CodeEnumWriter.cs index c69c73d209..89eea849dd 100644 --- a/src/Kiota.Builder/Writers/Python/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Python/CodeEnumWriter.cs @@ -14,6 +14,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.WriteLine("from enum import Enum"); writer.WriteLine(); writer.WriteLine($"class {codeElement.Name}(str, Enum):"); + conventions.WriteDeprecationWarning(codeElement, writer); writer.IncreaseIndent(); if (!codeElement.Options.Any()) { diff --git a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs index 295f2cb640..0183c12f31 100644 --- a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs @@ -713,6 +713,7 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer, st .OrderBy(static x => x.Name, StringComparer.OrdinalIgnoreCase) .Select(x => $"param {x.Name}: {PythonConventionService.RemoveInvalidDescriptionCharacters(x.Documentation.Description)}") .Union(new[] { returnRemark })); + conventions.WriteDeprecationWarning(code, writer); } private static readonly PythonCodeParameterOrderComparer parameterOrderComparer = new(); private void WriteMethodPrototype(CodeMethod code, LanguageWriter writer, string returnType, bool isVoid) diff --git a/src/Kiota.Builder/Writers/Python/PythonConventionService.cs b/src/Kiota.Builder/Writers/Python/PythonConventionService.cs index bb2ace2a76..caa6829fd6 100644 --- a/src/Kiota.Builder/Writers/Python/PythonConventionService.cs +++ b/src/Kiota.Builder/Writers/Python/PythonConventionService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Kiota.Builder.CodeDOM; @@ -53,7 +54,9 @@ public override string GetParameterSignature(CodeParameter parameter, CodeElemen ArgumentNullException.ThrowIfNull(parameter); ArgumentNullException.ThrowIfNull(targetElement); var defaultValueSuffix = string.IsNullOrEmpty(parameter.DefaultValue) ? string.Empty : $" = {parameter.DefaultValue}"; - return $"{parameter.Name}: {(parameter.Type.IsNullable ? "Optional[" : string.Empty)}{GetTypeString(parameter.Type, targetElement, true, writer)}{(parameter.Type.IsNullable ? "] = None" : string.Empty)}{defaultValueSuffix}"; + var deprecationInfo = GetDeprecationInformation(parameter); + var deprecationSuffix = string.IsNullOrEmpty(deprecationInfo) ? string.Empty : $"# {deprecationInfo}"; + return $"{parameter.Name}: {(parameter.Type.IsNullable ? "Optional[" : string.Empty)}{GetTypeString(parameter.Type, targetElement, true, writer)}{(parameter.Type.IsNullable ? "] = None" : string.Empty)}{defaultValueSuffix}{deprecationSuffix}"; } private static string GetTypeAlias(CodeType targetType, CodeElement targetElement) { @@ -190,4 +193,20 @@ public void WriteInLineDescription(string description, LanguageWriter writer) writer.WriteLine($"{InLineCommentPrefix}{RemoveInvalidDescriptionCharacters(description)}"); } } + + private static string GetDeprecationInformation(IDeprecableElement element) + { + if (element.Deprecation is null || !element.Deprecation.IsDeprecated) return string.Empty; + + var versionComment = string.IsNullOrEmpty(element.Deprecation.Version) ? string.Empty : $" as of {element.Deprecation.Version}"; + var dateComment = element.Deprecation.Date is null ? string.Empty : $" on {element.Deprecation.Date.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; + var removalComment = element.Deprecation.RemovalDate is null ? string.Empty : $" and will be removed {element.Deprecation.RemovalDate.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}"; + return $"{element.Deprecation.Description}{versionComment}{dateComment}{removalComment}"; + } + internal void WriteDeprecationWarning(IDeprecableElement element, LanguageWriter writer) + { + var deprecationMessage = GetDeprecationInformation(element); + if (!string.IsNullOrEmpty(deprecationMessage)) + writer.WriteLine($"warn(\"{deprecationMessage}\", DeprecationWarning)"); + } } From ee64a9bc2b1045771e163d5e56c709e9ca7d47c3 Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Wed, 24 Jan 2024 21:23:20 +0300 Subject: [PATCH 2/7] adds deprecation tests Python --- .../Python/CodeClassDeclarationWriterTests.cs | 15 +++++++++++++++ .../Writers/Python/CodeMethodWriterTests.cs | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs index 78be35d001..883448dd58 100644 --- a/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs @@ -234,4 +234,19 @@ public void WritesInternalImportsNoTypeDef() var result = tw.ToString(); Assert.DoesNotContain("from . import message", result); } + [Fact] + public void WritesModelClassDeprecationInformation() + { + parentClass.Kind = CodeClassKind.Model; + parentClass.Deprecation = new("This class is deprecated", DateTimeOffset.Parse("2024-01-01T00:00:00Z"), DateTimeOffset.Parse("2024-01-01T00:00:00Z"), "v2.0"); + codeElementWriter.WriteCodeElement(parentClass.StartBlock, writer); + var result = tw.ToString(); + Assert.Contains("@dataclass", result); + Assert.Contains("class ParentClass()", result); + Assert.Contains("warn(", result); + Assert.Contains("This class is deprecated", result); + Assert.Contains("2024-01-01", result); + Assert.Contains("2024-01-01", result); + Assert.Contains("v2.0", result); + } } diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs index 3181cb15b8..e455d0b1b2 100644 --- a/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs @@ -2175,4 +2175,17 @@ public void DoesntWriteReadOnlyPropertiesInSerializerBody() Assert.DoesNotContain("ReadOnlyProperty", result); AssertExtensions.CurlyBracesAreClosed(result); } + [Fact] + public void WritesDeprecationInformation() + { + setup(); + method.Deprecation = new("This method is deprecated", DateTimeOffset.Parse("2020-01-01T00:00:00Z"), DateTimeOffset.Parse("2021-01-01T00:00:00Z"), "v2.0"); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("This method is deprecated", result); + Assert.Contains("2020-01-01", result); + Assert.Contains("2021-01-01", result); + Assert.Contains("v2.0", result); + Assert.Contains("warn(", result); + } } From e486c876ed35937acc1d31c5cbd169fc3cda2512 Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Wed, 24 Jan 2024 21:24:06 +0300 Subject: [PATCH 3/7] adds changelog entry for python deprecation support --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd9ae1f14e..1e4e641b8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added Japanese translations to vscode extension. +- Added support for deprecation annotations in Python. [#2798](https://github.com/microsoft/kiota/issues/2798) ### Changed From ddb91a6d26afc7046dfaf69674b5681393d720fa Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Thu, 25 Jan 2024 13:08:42 +0300 Subject: [PATCH 4/7] Use conditional imports --- src/Kiota.Builder/Refiners/PythonRefiner.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Kiota.Builder/Refiners/PythonRefiner.cs b/src/Kiota.Builder/Refiners/PythonRefiner.cs index 56c4f5c876..cc5b593ff5 100644 --- a/src/Kiota.Builder/Refiners/PythonRefiner.cs +++ b/src/Kiota.Builder/Refiners/PythonRefiner.cs @@ -140,7 +140,6 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance private const string AbstractionsPackageName = "kiota_abstractions"; private static readonly AdditionalUsingEvaluator[] defaultUsingEvaluators = { new (static x => x is CodeClass, "__future__", "annotations"), - new (static x => x is CodeClass, "warnings", "warn"), new (static x => x is CodeClass, "typing", "Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union"), new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.RequestAdapter), $"{AbstractionsPackageName}.request_adapter", "RequestAdapter"), @@ -170,6 +169,8 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance new (static x => x is CodeClass @class && (@class.IsOfKind(CodeClassKind.Model) || x.Parent is CodeClass), "dataclasses", "dataclass, field"), new (static x => x is CodeClass { OriginalComposedType: CodeIntersectionType intersectionType } && intersectionType.Types.Any(static y => !y.IsExternal) && intersectionType.DiscriminatorInformation.HasBasicDiscriminatorInformation, $"{AbstractionsPackageName}.serialization", "ParseNodeHelper"), + new (static x => x is IDeprecableElement element && element.Deprecation is not null && element.Deprecation.IsDeprecated, + "warnings", "warn"), }; private static void CorrectCommonNames(CodeElement currentElement) From d30ebacf0598c7eb14316783a73ad40d33d117ea Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Thu, 25 Jan 2024 13:09:16 +0300 Subject: [PATCH 5/7] Fix formatting --- .../Writers/Python/CodeClassDeclarationWriterTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs index 883448dd58..c8e7c03bf0 100644 --- a/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs @@ -241,9 +241,10 @@ public void WritesModelClassDeprecationInformation() parentClass.Deprecation = new("This class is deprecated", DateTimeOffset.Parse("2024-01-01T00:00:00Z"), DateTimeOffset.Parse("2024-01-01T00:00:00Z"), "v2.0"); codeElementWriter.WriteCodeElement(parentClass.StartBlock, writer); var result = tw.ToString(); + Assert.Contains("from warnings import warn") Assert.Contains("@dataclass", result); Assert.Contains("class ParentClass()", result); - Assert.Contains("warn(", result); + Assert.Contains("warn(", result); Assert.Contains("This class is deprecated", result); Assert.Contains("2024-01-01", result); Assert.Contains("2024-01-01", result); From 05d5a6de9dd01daa608b3d3407ead2dc2652eeff Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Thu, 25 Jan 2024 13:11:24 +0300 Subject: [PATCH 6/7] Fix formatting --- .../Writers/Python/CodeClassDeclarationWriterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs index c8e7c03bf0..0401595232 100644 --- a/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs @@ -241,7 +241,7 @@ public void WritesModelClassDeprecationInformation() parentClass.Deprecation = new("This class is deprecated", DateTimeOffset.Parse("2024-01-01T00:00:00Z"), DateTimeOffset.Parse("2024-01-01T00:00:00Z"), "v2.0"); codeElementWriter.WriteCodeElement(parentClass.StartBlock, writer); var result = tw.ToString(); - Assert.Contains("from warnings import warn") + Assert.Contains("from warnings import warn"); Assert.Contains("@dataclass", result); Assert.Contains("class ParentClass()", result); Assert.Contains("warn(", result); From 0a0b9cc7e6c89986bf55b615a04cc91dc09841a6 Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Thu, 25 Jan 2024 13:13:47 +0300 Subject: [PATCH 7/7] Fix failing test --- .../Writers/Python/CodeClassDeclarationWriterTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs index 0401595232..74f36a2bd1 100644 --- a/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Python/CodeClassDeclarationWriterTests.cs @@ -241,7 +241,6 @@ public void WritesModelClassDeprecationInformation() parentClass.Deprecation = new("This class is deprecated", DateTimeOffset.Parse("2024-01-01T00:00:00Z"), DateTimeOffset.Parse("2024-01-01T00:00:00Z"), "v2.0"); codeElementWriter.WriteCodeElement(parentClass.StartBlock, writer); var result = tw.ToString(); - Assert.Contains("from warnings import warn"); Assert.Contains("@dataclass", result); Assert.Contains("class ParentClass()", result); Assert.Contains("warn(", result);