public PyClass(string name, DocComments docComments, RustAttributes attributes) { Name = name; DocComments = docComments; Attributes = attributes; Methods = new List <PyMethod>(); }
public PyMethod(string name, DocComments docComments, RustAttributes attributes, List <PyMethodArg> arguments, string rustReturnType) { Name = name; DocComments = docComments; Attributes = attributes; Arguments = arguments; RustReturnType = rustReturnType; }
static void Write(FileWriter writer, PyiDocGen docGen, IdentifierConverter idConverter, PyClass pyClass, PyMethod method, DocComments docComments, Dictionary <string, EnumType> toEnumType) { if (method.Attributes.Any(AttributeKind.ClassMethod)) { writer.WriteLine("@classmethod"); } if (method.Attributes.Any(AttributeKind.StaticMethod)) { writer.WriteLine("@staticmethod"); } bool isGetter = method.Attributes.Any(AttributeKind.Getter); bool isSetter = method.Attributes.Any(AttributeKind.Setter); if (isGetter) { writer.WriteLine("@property"); } if (isSetter) { writer.WriteLine($"@{method.Name}.setter"); } string sphinxReturnType = string.Empty; if (isGetter || isSetter) { if (docComments.Sections.FirstOrDefault() is not TextDocCommentSection textDocs || textDocs.Lines.Length == 0) { throw new InvalidOperationException(); } if (!ParseUtils.TryParseTypeAndDocs(textDocs.Lines[0], out _, out var typeInfo)) { throw new InvalidOperationException(); } sphinxReturnType = typeInfo.SphinxType; } else { var returns = docComments.Sections.OfType <ReturnsDocCommentSection>().FirstOrDefault(); if (returns is not null) { sphinxReturnType = returns.Returns.SphinxType; } } bool isCtor = method.Attributes.Any(AttributeKind.New); writer.Write("def "); writer.Write(isCtor ? "__init__" : method.Name); writer.Write("("); int argCount = 0; if (isCtor) { writer.Write("self"); argCount++; } var argsDocs = docComments.Sections.OfType <ArgsDocCommentSection>().FirstOrDefault(); int hasThis = method.Arguments.Count != 0 && method.Arguments[0].IsSelf ? 1 : 0; Dictionary <string, string> toDefaultValue; var argsAttr = method.Attributes.Attributes.FirstOrDefault(a => a.Kind == AttributeKind.Args); if (argsAttr is null) { toDefaultValue = new Dictionary <string, string>(StringComparer.Ordinal); } else { toDefaultValue = ParseUtils.GetArgsNameValues(argsAttr.Text).ToDictionary(a => a.name, a => a.value, StringComparer.Ordinal); } for (int i = 0; i < method.Arguments.Count; i++) { if (argsDocs is not null && argsDocs.Args.Length != method.Arguments.Count - hasThis) { throw new InvalidOperationException(); } var methodArg = method.Arguments[i]; if (argCount > 0) { writer.Write(", "); } argCount++; if (methodArg.IsSelf) { writer.Write("self"); } else { writer.Write(methodArg.Name); string docsSphinxType; if (argsDocs is not null) { var docsArg = argsDocs.Args[i - hasThis]; if (docsArg.Name != methodArg.Name) { throw new InvalidOperationException(); } docsSphinxType = docsArg.SphinxType; } else { docsSphinxType = string.Empty; } if (i == 1 && isSetter) { docsSphinxType = sphinxReturnType; } writer.Write(": "); var type = GetType(pyClass, method.Name, methodArg.RustType, docsSphinxType); writer.Write(type); if (toDefaultValue.TryGetValue(methodArg.Name, out var defaultValueStr)) { writer.Write(" = "); if (!TryGetValueStr(idConverter, type, defaultValueStr, toEnumType, out var valueStr)) { throw new InvalidOperationException($"method {pyClass.Name}.{method.Name}(): Couldn't convert default value `{defaultValueStr}` to a Python value"); } writer.Write(valueStr); } } } writer.Write(") -> "); if (method.HasReturnType && !isCtor) { writer.Write(GetReturnType(pyClass, method.Name, method.RustReturnType, sphinxReturnType)); } else { writer.Write("None"); } if (method.DocComments.Sections.Count == 0) { writer.WriteLine(": ..."); } else { writer.WriteLine(":"); using (writer.Indent()) { WriteDocs(writer, docGen.Convert(method.DocComments)); writer.WriteLine("..."); } } }
public List <string> Convert(DocComments docComments) { converted.Clear(); bool addEmptyLine = false; var colDefs = new List <(int start, int length)>(); var tableLines = new List <List <string> >(); var columnLengths = new List <int>(); var sb = new StringBuilder(); foreach (var section in docComments.Sections) { if (addEmptyLine) { converted.Add(string.Empty); } addEmptyLine = true; switch (section) { case TextDocCommentSection text: for (int i = 0; i < text.Lines.Length; i++) { var line = text.Lines[i]; // Convert tables to code blocks. They're not converted to // markdown tables because Jedi doesn't support tables in // tooltips. Instead, we create a text block that will be // rendered with a monospaced font. if (IsTableLine(line)) { GetColumnDefs(colDefs, line); if (colDefs.Count < 2) { throw new InvalidOperationException($"Invalid table, expected at least 2 columns. First line: {line}"); } i++; if (!TryGetNextTableLine(text.Lines, ref i, out var tblLine) || IsTableLine(tblLine)) { throw new InvalidOperationException("Invalid table"); } tableLines.Add(GetColumns(colDefs, tblLine)); if (!TryGetNextTableLine(text.Lines, ref i, out tblLine) || !IsTableLine(tblLine)) { throw new InvalidOperationException("Invalid table"); } while (TryGetNextTableLine(text.Lines, ref i, out tblLine) && !IsTableLine(tblLine)) { tableLines.Add(GetColumns(colDefs, tblLine)); } foreach (var tableCols in tableLines) { for (int j = 0; j < tableCols.Count; j++) { tableCols[j] = FixTableColumn(tableCols[j], j == 0); } } columnLengths.Clear(); for (int j = 0; j < colDefs.Count; j++) { columnLengths.Add(0); } foreach (var tableCols in tableLines) { if (tableCols.Count != columnLengths.Count) { throw new InvalidOperationException(); } for (int j = 0; j < columnLengths.Count; j++) { columnLengths[j] = Math.Max(columnLengths[j], tableCols[j].Length); } } const int colSepLen = 2; for (int j = 0; j < columnLengths.Count - 1; j++) { columnLengths[j] += colSepLen; } converted.Add("```text"); for (int j = 0; j < tableLines.Count; j++) { var tableCols = tableLines[j]; sb.Clear(); for (int k = 0; k < tableCols.Count; k++) { var col = tableCols[k]; sb.Append(FixCodeBlockLine(col)); int colLen = columnLengths[k]; if (col.Length > colLen) { throw new InvalidOperationException(); } if (k + 1 != tableCols.Count) { sb.Append(' ', colLen - col.Length); } } converted.Add(sb.ToString()); if (j == 0) { sb.Clear(); sb.Append('-', columnLengths.Sum() - columnLengths[^ 1] + tableLines[0][^ 1].Length);