Skip to content

Commit

Permalink
Request configuration revamp
Browse files Browse the repository at this point in the history
  • Loading branch information
samwelkanda committed Jun 15, 2022
1 parent c5f4e00 commit f6d8a37
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 31 deletions.
77 changes: 71 additions & 6 deletions src/Kiota.Builder/Refiners/PythonRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ public PythonRefiner(GenerationConfiguration configuration) : base(configuration
public override void Refine(CodeNamespace generatedCode)
{
AddDefaultImports(generatedCode, defaultUsingEvaluators);
DisableActionOf(generatedCode,
CodeParameterKind.RequestConfiguration);
ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode, false, "_by_id");
RemoveCancellationParameter(generatedCode);
CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements);
CorrectCoreTypesForBackingStore(generatedCode, "BackingStoreFactorySingleton.__instance.create_backing_store()");
AddPropertiesAndMethodTypesImports(generatedCode, true, true, true);
AddPropertiesAndMethodTypesImportsPython(generatedCode, true, true, true);
AddParsableImplementsForModelClasses(generatedCode, "Parsable");
ReplaceBinaryByNativeType(generatedCode, "bytes",null);
ReplaceReservedNames(generatedCode, new PythonReservedNamesProvider(), x => $"{x}_escaped");
Expand All @@ -28,13 +30,20 @@ public override void Refine(CodeNamespace generatedCode)
string.Empty,
string.Empty);
AddConstructorsForDefaultValues(generatedCode, true);
var defaultConfiguration = new GenerationConfiguration();
ReplaceDefaultSerializationModules(
generatedCode,
"serialization_json.json_serialization_writer_factory.JsonSerializationWriterFactory"
defaultConfiguration.Serializers,
new (StringComparer.OrdinalIgnoreCase) {
"serialization_json.json_serialization_writer_factory.JsonSerializationWriterFactory"
}
);
ReplaceDefaultDeserializationModules(
generatedCode,
"serialization_json.json_parse_node_factory.JsonParseNodeFactory"
defaultConfiguration.Deserializers,
new (StringComparer.OrdinalIgnoreCase) {
"serialization_json.json_parse_node_factory.JsonParseNodeFactory"
}
);
AddSerializationModulesImport(generatedCode,
new[] { $"{AbstractionsPackageName}.api_client_builder.register_default_serializer",
Expand Down Expand Up @@ -81,6 +90,7 @@ public override void Refine(CodeNamespace generatedCode)
$"{AbstractionsPackageName}.store", "BackingStoreFactory", "BackingStoreFactorySingleton"),
new (x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.BackingStore),
$"{AbstractionsPackageName}.store", "BackingStore", "BackedModel", "BackingStoreFactorySingleton" ),
new (x => x is CodeClass && x.Parent is CodeClass, "dataclasses", "dataclass")
};
private static void CorrectImplements(ProprietableBlockDeclaration block) {
block.Implements.Where(x => "IAdditionalDataHolder".Equals(x.Name, StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Name = x.Name[1..]); // skipping the I
Expand All @@ -90,6 +100,12 @@ private static void CorrectPropertyType(CodeProperty currentProperty) {
currentProperty.Type.Name = "RequestAdapter";
else if(currentProperty.IsOfKind(CodePropertyKind.BackingStore))
currentProperty.Type.Name = currentProperty.Type.Name[1..]; // removing the "I"
else if(currentProperty.IsOfKind(CodePropertyKind.Options))
currentProperty.Type.Name = "List[RequestOption]";
else if(currentProperty.IsOfKind(CodePropertyKind.Headers))
currentProperty.Type.Name = "Dict[str, str]";
else if (currentProperty.IsOfKind(CodePropertyKind.QueryParameters))
currentProperty.Type.Name = $"{currentProperty.Parent?.Parent.Name}.{currentProperty.Type.Name.ToFirstCharacterUpperCase()}";
else if(currentProperty.IsOfKind(CodePropertyKind.AdditionalData)) {
currentProperty.Type.Name = "Dict[str, Any]";
currentProperty.DefaultValue = "{}";
Expand All @@ -105,9 +121,6 @@ private static void CorrectMethodType(CodeMethod currentMethod) {
if(currentMethod.IsOfKind(CodeMethodKind.RequestExecutor, CodeMethodKind.RequestGenerator)) {
if(currentMethod.IsOfKind(CodeMethodKind.RequestExecutor))
currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.ResponseHandler) && x.Type.Name.StartsWith("i", StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Type.Name = x.Type.Name[1..]);
currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.Options)).ToList().ForEach(x => x.Type.Name = "List[RequestOption]");
currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.QueryParameter)).ToList().ForEach(x => { x.Type.Name = "GetQueryParameters"; x.Type.ActionOf = false; });
currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.Headers)).ToList().ForEach(x => { x.Type.Name = "Dict[str, str]"; x.Type.ActionOf = false; });
}
else if(currentMethod.IsOfKind(CodeMethodKind.Serializer))
currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.Serializer) && x.Type.Name.StartsWith("i", StringComparison.OrdinalIgnoreCase)).ToList().ForEach(x => x.Type.Name = x.Type.Name[1..]);
Expand Down Expand Up @@ -140,6 +153,58 @@ private static void CorrectMethodType(CodeMethod currentMethod) {
.Union(new CodeTypeBase[] { currentMethod.ReturnType})
.ToArray());
}
private static readonly CodeUsingComparer usingComparerWithDeclarations = new(true);
private static readonly CodeUsingComparer usingComparerWithoutDeclarations = new(false);
private static void AddPropertiesAndMethodTypesImportsPython(CodeElement current, bool includeParentNamespaces, bool includeCurrentNamespace, bool compareOnDeclaration) {
if(current is CodeClass currentClass &&
currentClass.StartBlock is ClassDeclaration currentClassDeclaration) {
var currentClassNamespace = currentClass.GetImmediateParentOfType<CodeNamespace>();
var currentClassChildren = currentClass.GetChildElements(true);
var inheritTypes = currentClassDeclaration.Inherits?.AllTypes ?? Enumerable.Empty<CodeType>();
var propertiesTypes = currentClass
.Properties
.Where(x => !x.IsOfKind(CodePropertyKind.QueryParameters))
.Select(x => x.Type)
.Distinct();
var methods = currentClass.Methods;
var methodsReturnTypes = methods
.Select(x => x.ReturnType)
.Distinct();
var methodsParametersTypes = methods
.SelectMany(x => x.Parameters)
.Where(x => x.IsOfKind(CodeParameterKind.Custom, CodeParameterKind.RequestBody))
.Select(x => x.Type)
.Distinct();
var indexerTypes = currentClassChildren
.OfType<CodeIndexer>()
.Select(x => x.ReturnType)
.Distinct();
var errorTypes = currentClassChildren
.OfType<CodeMethod>()
.Where(x => x.IsOfKind(CodeMethodKind.RequestExecutor))
.SelectMany(x => x.ErrorMappings)
.Select(x => x.Value)
.Distinct();
var usingsToAdd = propertiesTypes
.Union(methodsParametersTypes)
.Union(methodsReturnTypes)
.Union(indexerTypes)
.Union(inheritTypes)
.Union(errorTypes)
.Where(x => x != null)
.SelectMany(x => x?.AllTypes?.Select(y => (type: y, ns: y?.TypeDefinition?.GetImmediateParentOfType<CodeNamespace>())))
.Where(x => x.ns != null && (includeCurrentNamespace || x.ns != currentClassNamespace))
.Where(x => includeParentNamespaces || !currentClassNamespace.IsChildOf(x.ns))
.Select(x => new CodeUsing { Name = x.ns.Name, Declaration = x.type })
.Where(x => x.Declaration?.TypeDefinition != current)
.Distinct(compareOnDeclaration ? usingComparerWithDeclarations : usingComparerWithoutDeclarations)
.ToArray();
if(usingsToAdd.Any())
(currentClass.Parent is CodeClass parentClass ? parentClass : currentClass).AddUsing(usingsToAdd); //lots of languages do not support imports on nested classes
}
CrawlTree(current, (x) => AddPropertiesAndMethodTypesImportsPython(x, includeParentNamespaces, includeCurrentNamespace, compareOnDeclaration));
}

private const string DateTimePackageName = "datetime";
private static readonly Dictionary<string, (string, CodeUsing)> DateTypesReplacements = new (StringComparer.OrdinalIgnoreCase) {
{"DateTimeOffset", ("datetime", new CodeUsing {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Linq;
using Kiota.Builder.Extensions;

Expand All @@ -10,8 +11,10 @@ public CodeClassDeclarationWriter(PythonConventionService conventionService, str
}
public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWriter writer)
{
AddStandardImports(writer);
if(codeElement == null) throw new ArgumentNullException(nameof(codeElement));
if(writer == null) throw new ArgumentNullException(nameof(writer));
var parentNamespace = codeElement.GetImmediateParentOfType<CodeNamespace>();
AddStandardImports(writer);
var externalImportSymbolsAndPaths = codeElement.Usings
.Where(x => x.IsExternal)
.Select(x => (x.Name, string.Empty, x.Declaration?.Name))
Expand Down Expand Up @@ -41,6 +44,9 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit
var inheritSymbol = conventions.GetTypeString(codeElement.Inherits, codeElement);
var abcClass = !codeElement.Implements.Any() ? string.Empty : $"{codeElement.Implements.Select(x => x.Name.ToFirstCharacterUpperCase()).Aggregate((x,y) => x + ", " + y)}";
var derivation = inheritSymbol == null ? abcClass : $"{inheritSymbol.ToFirstCharacterUpperCase()}";
if(codeElement.Parent?.Parent is CodeClass){
writer.WriteLine($"@dataclass");
}
writer.WriteLine($"class {codeElement.Name.ToFirstCharacterUpperCase()}({derivation}):");
writer.IncreaseIndent();
conventions.WriteShortDescription((codeElement.Parent as CodeClass).Description, writer);
Expand Down
5 changes: 4 additions & 1 deletion src/Kiota.Builder/Writers/Python/CodeEnumWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write
writer.WriteLine();
writer.WriteLine($"class {codeElement.Name.ToFirstCharacterUpperCase()}(Enum):");
writer.IncreaseIndent();
codeElement.Options.ToList().ForEach(x => writer.WriteLine($"{x} = '{x}'"));
codeElement.Options.ToList().ForEach(x => {
conventions.WriteInLineDescription(x.Description, writer);
writer.WriteLine($"{x.Name.ToFirstCharacterUpperCase()} = \"{x.SerializationName ?? x.Name}\",");
});
}
}
}
38 changes: 18 additions & 20 deletions src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
var parentClass = codeElement.Parent as CodeClass;
var inherits = parentClass.StartBlock.Inherits != null && !parentClass.IsErrorDefinition;
var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody);
var queryStringParam = codeElement.Parameters.OfKind(CodeParameterKind.QueryParameter);
var headersParam = codeElement.Parameters.OfKind(CodeParameterKind.Headers);
var optionsParam = codeElement.Parameters.OfKind(CodeParameterKind.Options);
var requestParams = new RequestParams(requestBodyParam, queryStringParam, headersParam, optionsParam);
var requestConfigParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration);
var requestParams = new RequestParams(requestBodyParam, requestConfigParam);
if(!codeElement.IsOfKind(CodeMethodKind.Setter))
foreach(var parameter in codeElement.Parameters.Where(x => !x.Optional).OrderBy(x => x.Name)) {
var parameterName = parameter.Name.ToSnakeCase();
Expand Down Expand Up @@ -122,7 +120,7 @@ private static void WriteQueryParametersMapper(CodeMethod codeElement, CodeClass
}
writer.WriteLine($"return {parameterName}");
}
private static void WriteSerializationRegistration(List<string> serializationModules, LanguageWriter writer, string methodName) {
private static void WriteSerializationRegistration(HashSet<string> serializationModules, LanguageWriter writer, string methodName) {
if(serializationModules != null)
foreach(var module in serializationModules)
writer.WriteLine($"{methodName}({module})");
Expand Down Expand Up @@ -216,11 +214,11 @@ private void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams requ
?.Name
?.ToSnakeCase();
writer.WriteLine($"request_info = self.{generatorMethodName}(");
var requestInfoParameters = new CodeParameter[] { requestParams.requestBody, requestParams.queryString, requestParams.headers, requestParams.options }
.Select(x => x?.Name).Where(x => x != null);
var requestInfoParameters = new CodeParameter[] { requestParams.requestBody, requestParams.requestConfiguration }
.Select(x => x?.Name.ToSnakeCase()).Where(x => x != null);
if(requestInfoParameters.Any()) {
writer.IncreaseIndent();
writer.WriteLine(requestInfoParameters.Aggregate((x,y) => $"{x.ToSnakeCase()}, {y.ToSnakeCase()}"));
writer.WriteLine(requestInfoParameters.Aggregate((x,y) => $"{x}, {y}"));
writer.DecreaseIndent();
}
writer.WriteLine(")");
Expand Down Expand Up @@ -261,27 +259,27 @@ private void WriteRequestGeneratorBody(CodeMethod codeElement, RequestParams req
$"{RequestInfoVarName}.url_template = {GetPropertyCall(urlTemplateProperty, "''")}",
$"{RequestInfoVarName}.path_parameters = {GetPropertyCall(urlTemplateParamsProperty, "''")}",
$"{RequestInfoVarName}.http_method = HttpMethod.{codeElement.HttpMethod.ToString().ToUpperInvariant()}");
if(requestParams.headers != null) {
writer.WriteLine($"if {requestParams.headers.Name}:");
if(requestParams.requestConfiguration != null) {
writer.WriteLine($"if {requestParams.requestConfiguration.Name.ToSnakeCase()}:");
writer.IncreaseIndent();
writer.WriteLine($"{RequestInfoVarName}.headers = {requestParams.headers.Name.ToSnakeCase()}");
writer.DecreaseIndent();
}
if(requestParams.queryString != null){
writer.WriteLine($"if {requestParams.queryString.Name}:");
writer.IncreaseIndent();
writer.WriteLine($"{RequestInfoVarName}.set_query_string_parameters_from_raw_object({requestParams.queryString.Name.ToSnakeCase()})");
var headers = requestParams.Headers;
if(headers != null)
writer.WriteLine($"{RequestInfoVarName}.add_request_headers({requestParams.requestConfiguration.Name.ToSnakeCase()}.{headers.Name.ToSnakeCase()})");
var queryString = requestParams.QueryParameters;
if(queryString != null)
writer.WriteLines($"{RequestInfoVarName}.set_query_string_parameters_from_raw_object({requestParams.requestConfiguration.Name.ToSnakeCase()}.{queryString.Name.ToSnakeCase()})");
var options = requestParams.Options;
if(options != null)
writer.WriteLine($"{RequestInfoVarName}.add_request_options({requestParams.requestConfiguration.Name.ToSnakeCase()}.{options.Name.ToSnakeCase()})");
writer.DecreaseIndent();
}
if(requestParams.requestBody != null) {
if(requestParams.requestBody.Type.Name.Equals(localConventions.StreamTypeName, StringComparison.OrdinalIgnoreCase))
writer.WriteLine($"{RequestInfoVarName}.set_stream_content({requestParams.requestBody.Name.ToSnakeCase()})");
else {
writer.WriteLine($"{RequestInfoVarName}.set_content_from_parsable(self.{requestAdapterProperty.Name.ToSnakeCase()}, \"{codeElement.ContentType}\", {requestParams.requestBody.Name})");
writer.WriteLine($"{RequestInfoVarName}.set_content_from_parsable(self.{requestAdapterProperty.Name.ToSnakeCase()}, \"{codeElement.RequestBodyContentType}\", {requestParams.requestBody.Name})");
}
}
if(requestParams.options != null)
writer.WriteLine($"{RequestInfoVarName}.add_request_options({requestParams.options.Name.ToSnakeCase()})");
writer.WriteLine($"return {RequestInfoVarName}");
}
private static string GetPropertyCall(CodeProperty property, string defaultValue) => property == null ? defaultValue : $"self.{property.Name.ToSnakeCase()}";
Expand Down
4 changes: 2 additions & 2 deletions src/Kiota.Builder/Writers/Python/PythonConventionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public PythonConventionService(LanguageWriter languageWriter)
writer = languageWriter;
}
private readonly LanguageWriter writer;
public override string StreamTypeName => "bytes";
public override string StreamTypeName => "bytess";
public override string VoidTypeName => "None";
public override string DocCommentPrefix => "";
public override string ParseNodeInterfaceName => "ParseNode";
Expand Down Expand Up @@ -91,7 +91,7 @@ public override string TranslateType(CodeType type)
"datetime" => "datetime",
"DateTimeOffset" => "timedelta",
"boolean" => "bool",
"Object" or "object" or "float" => type.Name.ToSnakeCase(),
"Object" or "object" or "float" or "bytes" => type.Name,
_ => type.Name.ToFirstCharacterUpperCase().Replace("IParseNode", "ParseNode") ?? "object",
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void Dispose(){
[Fact]
public void WritesEnum() {
const string optionName = "option1";
currentEnum.Options.Add(optionName);
currentEnum.AddOption(new CodeEnumOption { Name = optionName});
writer.Write(currentEnum);
var result = tw.ToString();
Assert.Contains($"(Enum):", result);
Expand Down

0 comments on commit f6d8a37

Please sign in to comment.