Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python/code reduction #2817

Merged
merged 11 commits into from
Jun 27, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Deprecated Visual Studio OpenAPI reference packages.
- Fixes a bug where a stackoverflow exception occurs when inlined schemas have self-references [2656](https://github.com/microsoft/kiota/issues/2656)
- Fixes nil safety while type casting values in collections in Go
- Moved common RequestBuilder ((request_adapter, url_template and path_parameters)) and RequestConfiguration(headers, options) properties to respective base classes in Python.[2440](https://github.com/microsoft/kiota/issues/2440)

## [1.3.0] - 2023-06-09

Expand Down
7 changes: 3 additions & 4 deletions it/exec-cmd.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,9 @@ elseif ($language -eq "php") {
elseif ($language -eq "python") {
Invoke-Call -ScriptBlock {
python -m pip install --upgrade pip
pip install pipenv
pipenv install --dev --skip-lock
pipenv run pylint integration_test --disable=W --rcfile=.pylintrc
pipenv run mypy integration_test
pip install -r requirements-dev.txt
pylint integration_test --disable=W --rcfile=.pylintrc
mypy integration_test
} -ErrorAction Stop
}
Pop-Location
Expand Down
23 changes: 0 additions & 23 deletions it/python/Pipfile

This file was deleted.

136 changes: 136 additions & 0 deletions it/python/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
-i https://pypi.org/simple

astroid==2.15.5 ; python_full_version >= '3.7.2'

certifi==2023.5.7 ; python_version >= '3.6'

charset-normalizer==3.1.0 ; python_full_version >= '3.7.0'

colorama==0.4.6 ; sys_platform == 'win32'

dill==0.3.6 ; python_version < '3.11'

docutils==0.20.1 ; python_version >= '3.7'

exceptiongroup==1.1.1 ; python_version < '3.11'

flit==3.9.0

flit-core==3.9.0 ; python_version >= '3.6'

idna==3.4

importlib-metadata==6.7.0 ; python_version >= '3.7'

iniconfig==2.0.0 ; python_version >= '3.7'

isort==5.12.0

lazy-object-proxy==1.9.0 ; python_version >= '3.7'

mccabe==0.7.0 ; python_version >= '3.6'

mypy==1.4.1

mypy-extensions==1.0.0 ; python_version >= '3.5'

packaging==23.1 ; python_version >= '3.7'

platformdirs==3.8.0 ; python_version >= '3.7'

pluggy==1.2.0 ; python_version >= '3.7'

pylint==2.17.4

pytest==7.4.0

pytest-asyncio==0.21.0

requests==2.31.0 ; python_version >= '3.7'

toml==0.10.2

tomli==2.0.1 ; python_version < '3.11'

tomli-w==1.0.0 ; python_version >= '3.7'

tomlkit==0.11.8 ; python_version >= '3.7'

typing-extensions==4.6.3 ; python_version >= '3.7'

urllib3==2.0.3 ; python_version >= '3.7'

wrapt==1.15.0 ; python_version < '3.11'

yapf==0.40.1

zipp==3.15.0 ; python_version >= '3.7'

aiohttp==3.8.4 ; python_version >= '3.6'

aiosignal==1.3.1 ; python_version >= '3.7'

anyio==3.7.0 ; python_version >= '3.7'

async-timeout==4.0.2 ; python_version >= '3.6'

attrs==23.1.0 ; python_version >= '3.7'

azure-core==1.27.1 ; python_version >= '3.7'

azure-identity==1.13.0

cffi==1.15.1

cryptography==41.0.1 ; python_version >= '3.7'

frozenlist==1.3.3 ; python_version >= '3.7'

h11==0.14.0 ; python_version >= '3.7'

h2==4.1.0

hpack==4.0.0 ; python_full_version >= '3.6.1'

httpcore==0.16.3 ; python_version >= '3.7'

httpx[http2]==0.23.3

hyperframe==6.0.1 ; python_full_version >= '3.6.1'

microsoft-kiota-abstractions==0.5.5

microsoft-kiota-authentication-azure==0.2.0

microsoft-kiota-http==0.4.4

microsoft-kiota-serialization-json==0.3.6

microsoft-kiota-serialization-text==0.2.1

msal==1.22.0

msal-extensions==1.0.0

multidict==6.0.4 ; python_version >= '3.7'

portalocker==2.7.0 ; python_version >= '3.5' and platform_system == 'Windows'

pycparser==2.21

pyjwt[crypto]==2.7.0 ; python_version >= '3.7'

python-dateutil==2.8.2 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'

pywin32==306 ; platform_system == 'Windows'

rfc3986[idna2008]==1.5.0

six==1.16.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'

sniffio==1.3.0 ; python_version >= '3.7'

uritemplate==4.1.1 ; python_version >= '3.6'

yarl==1.9.2 ; python_version >= '3.7'

20 changes: 20 additions & 0 deletions src/Kiota.Builder/Refiners/PythonRefiner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
AddDefaultImports(generatedCode, defaultUsingEvaluators);
DisableActionOf(generatedCode,
CodeParameterKind.RequestConfiguration);
MoveRequestBuilderPropertiesToBaseType(generatedCode,
new CodeUsing
{
Name = "BaseRequestBuilder",
Declaration = new CodeType
{
Name = $"{AbstractionsPackageName}.base_request_builder",
IsExternal = true
}
}, AccessModifier.Public);
cancellationToken.ThrowIfCancellationRequested();
ReplaceIndexersByMethodsWithParameter(generatedCode,
false,
Expand All @@ -42,6 +52,16 @@ public override Task Refine(CodeNamespace generatedCode, CancellationToken cance
new PythonExceptionsReservedNamesProvider(),
static x => $"{x}_"
);
RemoveRequestConfigurationClassesCommonProperties(generatedCode,
new CodeUsing
{
Name = "BaseRequestConfiguration",
Declaration = new CodeType
{
Name = $"{AbstractionsPackageName}.base_request_configuration",
IsExternal = true
}
});
cancellationToken.ThrowIfCancellationRequested();
MoveClassesWithNamespaceNamesUnderNamespace(generatedCode);
ReplacePropertyNames(generatedCode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class PythonReservedNamesProvider : IReservedNamesProvider
"while",
"yield",
"property",
"BaseRequestBuilder",
});
public HashSet<string> ReservedNames => _reservedNames.Value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public override void WriteCodeElement(ClassDeclaration codeElement, LanguageWrit
ArgumentNullException.ThrowIfNull(codeElement);
ArgumentNullException.ThrowIfNull(writer);
var parentNamespace = codeElement.GetImmediateParentOfType<CodeNamespace>();
if (codeElement.Parent?.Parent is not CodeClass) //Imports for inner classes will be written locally
_codeUsingWriter.WriteExternalImports(codeElement, writer); // external imports before internal imports
if (codeElement.Parent?.Parent is not CodeClass) //Internal imports for inner classes will be written locally
{
_codeUsingWriter.WriteExternalImports(codeElement, writer); // external imports before internal imports
_codeUsingWriter.WriteConditionalInternalImports(codeElement, writer, parentNamespace);
}

Expand Down
64 changes: 36 additions & 28 deletions src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
var requestBodyParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestBody);
var requestConfigParam = codeElement.Parameters.OfKind(CodeParameterKind.RequestConfiguration);
var requestParams = new RequestParams(requestBodyParam, requestConfigParam);
if (!codeElement.IsOfKind(CodeMethodKind.Setter))
if (!codeElement.IsOfKind(CodeMethodKind.Setter) &&
!(codeElement.IsOfKind(CodeMethodKind.Constructor) && parentClass.IsOfKind(CodeClassKind.RequestBuilder)))
foreach (var parameter in codeElement.Parameters.Where(static x => !x.Optional).OrderBy(static x => x.Name))
{
var parameterName = parameter.Name.ToSnakeCase();
Expand Down Expand Up @@ -314,31 +315,40 @@ private CodePropertyKind[] SetterAccessProperties
private void WriteConstructorBody(CodeClass parentClass, CodeMethod currentMethod, LanguageWriter writer, bool inherits)
{
if (inherits && !parentClass.IsOfKind(CodeClassKind.Model))
writer.WriteLine("super().__init__()");
{
if (parentClass.IsOfKind(CodeClassKind.RequestBuilder) &&
currentMethod.Parameters.OfKind(CodeParameterKind.RequestAdapter) is CodeParameter requestAdapterParameter &&
parentClass.Properties.OfKind(CodePropertyKind.UrlTemplate) is CodeProperty urlTemplateProperty)
{
if (currentMethod.Parameters.OfKind(CodeParameterKind.PathParameters) is CodeParameter pathParametersParameter)
writer.WriteLine($"super().__init__({requestAdapterParameter.Name.ToSnakeCase()}, {urlTemplateProperty.DefaultValue ?? ""}, {pathParametersParameter.Name.ToSnakeCase()})");
else
writer.WriteLine($"super().__init__({requestAdapterParameter.Name.ToSnakeCase()}, {urlTemplateProperty.DefaultValue ?? ""}, None)");
}
else
writer.WriteLine("super().__init__()");
}
if (parentClass.IsOfKind(CodeClassKind.Model))
{
writer.DecreaseIndent();
}
WriteDirectAccessProperties(parentClass, writer);
WriteSetterAccessProperties(parentClass, writer);
WriteSetterAccessPropertiesWithoutDefaults(parentClass, writer);

if (parentClass.IsOfKind(CodeClassKind.RequestBuilder))
{
if (currentMethod.IsOfKind(CodeMethodKind.Constructor))
{
if (currentMethod.Parameters.OfKind(CodeParameterKind.PathParameters) is CodeParameter pathParametersParam)
conventions.AddParametersAssignment(writer,
pathParametersParam.Type.AllTypes.OfType<CodeType>().FirstOrDefault(),
pathParametersParam.Name.ToFirstCharacterLowerCase(),
currentMethod.Parameters
.Where(x => x.IsOfKind(CodeParameterKind.Path))
.Select(x => (x.Type, x.SerializationName, x.Name.ToFirstCharacterLowerCase()))
.ToArray());
AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.PathParameters, CodePropertyKind.PathParameters, writer, conventions.TempDictionaryVarName);
}
AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.RequestAdapter, CodePropertyKind.RequestAdapter, writer);
if (!(parentClass.IsOfKind(CodeClassKind.RequestBuilder) && currentMethod.IsOfKind(CodeMethodKind.Constructor, CodeMethodKind.ClientConstructor)))
{
WriteDirectAccessProperties(parentClass, writer);
WriteSetterAccessProperties(parentClass, writer);
WriteSetterAccessPropertiesWithoutDefaults(parentClass, writer);
if (currentMethod.Parameters.OfKind(CodeParameterKind.PathParameters) is CodeParameter pathParametersParam)
conventions.AddParametersAssignment(writer,
pathParametersParam.Type.AllTypes.OfType<CodeType>().FirstOrDefault(),
pathParametersParam.Name.ToFirstCharacterLowerCase(),
currentMethod.Parameters
.Where(x => x.IsOfKind(CodeParameterKind.Path))
.Select(x => (x.Type, x.SerializationName, x.Name.ToFirstCharacterLowerCase()))
.ToArray());
AssignPropertyFromParameter(parentClass, currentMethod, CodeParameterKind.PathParameters, CodePropertyKind.PathParameters, writer, conventions.TempDictionaryVarName);
}

if (parentClass.IsOfKind(CodeClassKind.Model))
{
writer.IncreaseIndent();
Expand Down Expand Up @@ -686,8 +696,8 @@ private void WriteMethodDocumentation(CodeMethod code, LanguageWriter writer, st
{
writer.StartBlock("Args:");

foreach (var paramWithDescription in parametersWithDescription.OrderBy(x => x.Name))
writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Name}: {PythonConventionService.RemoveInvalidDescriptionCharacters(paramWithDescription.Documentation.Description)}");
foreach (var paramWithDescription in parametersWithDescription.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase))
writer.WriteLine($"{conventions.DocCommentPrefix}{paramWithDescription.Name.ToSnakeCase()}: {PythonConventionService.RemoveInvalidDescriptionCharacters(paramWithDescription.Documentation.Description)}");
writer.DecreaseIndent();
}
if (!isVoid)
Expand Down Expand Up @@ -804,15 +814,13 @@ private static void UpdateRequestInformationFromRequestConfiguration(RequestPara
if (requestParams.requestConfiguration != null)
{
writer.StartBlock($"if {requestParams.requestConfiguration.Name.ToSnakeCase()}:");
var headers = requestParams.Headers;
if (headers != null)
writer.WriteLine($"{RequestInfoVarName}.add_request_headers({requestParams.requestConfiguration.Name.ToSnakeCase()}.{headers.Name.ToSnakeCase()})");
var headers = requestParams.Headers?.Name.ToSnakeCase() ?? "headers";
writer.WriteLine($"{RequestInfoVarName}.add_request_headers({requestParams.requestConfiguration.Name.ToSnakeCase()}.{headers})");
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()})");
var options = requestParams.Options?.Name.ToSnakeCase() ?? "options";
writer.WriteLine($"{RequestInfoVarName}.add_request_options({requestParams.requestConfiguration.Name.ToSnakeCase()}.{options})");
writer.DecreaseIndent();
}
}
Expand Down
1 change: 1 addition & 0 deletions src/Kiota.Builder/Writers/Python/CodePropertyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public override void WriteCodeElement(CodeProperty codeElement, LanguageWriter w
{
ArgumentNullException.ThrowIfNull(codeElement);
ArgumentNullException.ThrowIfNull(writer);
if (codeElement.ExistsInExternalBaseType) return;
var returnType = conventions.GetTypeString(codeElement.Type, codeElement, true, writer);
if (codeElement.Parent is not CodeClass parentClass) throw new InvalidOperationException("The parent of a property should be a class");
/* Only write specific properties as class attributes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,7 @@ public void WritesMethodAsyncDescription()
Assert.Contains("\"\"\"", result);
Assert.Contains(MethodDescription, result);
Assert.Contains("Args:", result);
Assert.Contains(ParamName, result);
Assert.Contains("param_name", result);
Assert.Contains(ParamDescription, result);
Assert.Contains("Returns:", result);
Assert.Contains("await", result);
Expand Down Expand Up @@ -927,7 +927,7 @@ public void WritesMethodSyncDescription()
Assert.Contains("\"\"\"", result);
Assert.Contains(MethodDescription, result);
Assert.Contains("Args:", result);
Assert.Contains(ParamName, result);
Assert.Contains("param_name", result);
Assert.Contains(ParamDescription, result);
Assert.DoesNotContain("await", result);
}
Expand Down Expand Up @@ -1431,10 +1431,10 @@ public void WritesConstructor()
});
writer.Write(method);
var result = tw.ToString();
Assert.DoesNotContain("super().__init__()", result);
Assert.Contains("This property has a description", result);
Assert.Contains($"self.{propName}: Optional[str] = {defaultValue}", result);
Assert.Contains("get_path_parameters(", result);
Assert.DoesNotContain("super().__init__(self)", result);
Assert.DoesNotContain("This property has a description", result);
Assert.DoesNotContain($"self.{propName}: Optional[str] = {defaultValue}", result);
Assert.DoesNotContain("get_path_parameters(", result);
}
[Fact]
public void DoesntWriteConstructorForModelClasses()
Expand Down Expand Up @@ -1560,9 +1560,9 @@ public void WritesConstructorWithInheritance()
writer.Write(method);
var result = tw.ToString();
Assert.Contains("super().__init__()", result);
Assert.Contains("has a description", result);
Assert.Contains($"self.{prop2Name}: Optional[str] = {defaultValue}", result);
Assert.Contains($"self.{propName}: Optional[str] = None", result);
Assert.DoesNotContain("has a description", result);
Assert.DoesNotContain($"self.{prop2Name}: Optional[str] = {defaultValue}", result);
Assert.DoesNotContain($"self.{propName}: Optional[str] = None", result);
}
[Fact]
public void WritesApiConstructor()
Expand Down