Skip to content

Commit

Permalink
PEP8 compliant stubs (#19)
Browse files Browse the repository at this point in the history
* feat: PEP8 style stubs generation

* Pin pythonnet version

* Don't upper case PEP8 version of readonly fields

* Upper case static readonly fields as constants

* Bump pythonnet version to 2.0.31

* Ignore python keyword snake-case names
  • Loading branch information
jhonabreul authored Apr 12, 2024
1 parent 2887a0a commit 1e57691
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 15 deletions.
4 changes: 4 additions & 0 deletions QuantConnectStubsGenerator/Model/Property.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ namespace QuantConnectStubsGenerator.Model
public class Property
{
public string Name { get; }

public PythonType Type { get; set; }

public bool Static { get; set; }

public bool Abstract { get; set; }

public bool Constant { get; set; }

public string Value { get; set; }

public string Summary { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions QuantConnectStubsGenerator/Parser/PropertyParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public override void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node
: _currentClass.Properties.Count.ToString(),
Static = true,
Abstract = _currentClass.Interface || HasModifier(node, "abstract"),
Constant = true,
DeprecationReason = GetDeprecationReason(node)
};

Expand Down Expand Up @@ -169,6 +170,7 @@ private void VisitField(BaseFieldDeclarationSyntax node, PythonType type)
Type = type,
Static = _currentClass.Static || HasModifier(node, "static") || HasModifier(node, "const"),
Abstract = _currentClass.Interface || HasModifier(node, "abstract"),
Constant = HasModifier(node, "const") || (HasModifier(node, "static") && HasModifier(node, "readonly")),
DeprecationReason = GetDeprecationReason(node)
};

Expand Down
31 changes: 16 additions & 15 deletions QuantConnectStubsGenerator/QuantConnectStubsGenerator.csproj
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.12" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
<PackageReference Include="QuikGraph" Version="2.3.0" />
</ItemGroup>
<ItemGroup>
<None Update="log4net.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="2.0.12" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
<PackageReference Include="QuikGraph" Version="2.3.0" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.31" />
</ItemGroup>
<ItemGroup>
<None Update="log4net.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
41 changes: 41 additions & 0 deletions QuantConnectStubsGenerator/Renderer/MethodRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ public MethodRenderer(StreamWriter writer, int indentationLevel) : base(writer,

public override void Render(Method method)
{
method = GetSnakeCasedMethod(method);
if (method == null)
{
return;
}

if (method.Static)
{
WriteLine("@staticmethod");
Expand Down Expand Up @@ -82,5 +88,40 @@ private string ParameterToString(Parameter parameter)

return str;
}

private static Method GetSnakeCasedMethod(Method method)
{
var snakeCasedMethodName = method.Name.ToSnakeCase();
if (snakeCasedMethodName.IsPythonReservedWord())
{
return null;
}

var snakeCasedMethod = new Method(snakeCasedMethodName, method.ReturnType)
{
Static = method.Static,
Overload = method.Overload,
Summary = method.Summary,
File = method.File,
DeprecationReason = method.DeprecationReason
};

foreach (var parameter in method.Parameters)
{
var snakeCasedParameterName = parameter.Name.ToSnakeCase();
if (snakeCasedParameterName.IsPythonReservedWord())
{
return null;
}

snakeCasedMethod.Parameters.Add(new Parameter(snakeCasedParameterName, parameter.Type)
{
VarArgs = parameter.VarArgs,
Value = parameter.Value
});
}

return snakeCasedMethod;
}
}
}
26 changes: 26 additions & 0 deletions QuantConnectStubsGenerator/Renderer/PropertyRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ public PropertyRenderer(StreamWriter writer, int indentationLevel) : base(writer

public override void Render(Property property)
{
property = GetSnakeCasedProperty(property);
if (property == null)
{
return;
}

if (property.Static)
{
RenderAttribute(property);
Expand All @@ -22,6 +28,26 @@ public override void Render(Property property)
}
}

private static Property GetSnakeCasedProperty(Property property)
{
var name = property.Name.ToSnakeCase(property.Constant);
if (name.IsPythonReservedWord())
{
return null;
}

return new Property(name)
{
Type = property.Type,
Static = property.Static,
Abstract = property.Abstract,
Constant = property.Constant,
Value = property.Value,
Summary = property.Summary,
DeprecationReason = property.DeprecationReason
};
}

private void RenderAttribute(Property property)
{
// Some attributes have names in C# that are illegal in Python
Expand Down
19 changes: 19 additions & 0 deletions QuantConnectStubsGenerator/Utility/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
using System.Collections.Generic;
using System.Linq;

namespace QuantConnectStubsGenerator.Utility
{
public static class StringExtensions
{
private static readonly HashSet<string> _reservedPythonWord = new HashSet<string>()
{
"and", "as", "assert", "break", "class", "continue", "def", "del", "elif", "else", "except",
"False", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "None",
"nonlocal", "not", "or", "pass", "raise", "return", "True", "try", "while", "with", "yield"
};

public static string Indent(this string str, int level = 1)
{
var indentation = new string(' ', level * 4);
Expand All @@ -14,5 +22,16 @@ public static string Indent(this string str, int level = 1)

return string.Join("\n", lines);
}

public static string ToSnakeCase(this string text, bool constant = false)
{
var result = Python.Runtime.Util.ToSnakeCase(text);
return constant ? result.ToUpperInvariant() : result;
}

public static bool IsPythonReservedWord(this string word)
{
return _reservedPythonWord.Contains(word);
}
}
}

0 comments on commit 1e57691

Please sign in to comment.