private static string AppendCopyright(this string input, IDecl declaration) { string package = PyExtensions.GetPackage(declaration); string dcCopyright = @"# Copyright (C) 2013-present The DataCentric Authors. # # Licensed under the Apache License, Version 2.0 (the ""License""); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an ""AS IS"" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. "; if (package == "datacentric") { return(dcCopyright + input); } else { throw new Exception($"Copyright header is not specified for module {package}."); } }
private static string GetTypeHint(TypeDecl decl, ElementDecl element) { string GetParamNamespace(TypeDecl declaration, IDeclKey key) => !PyExtensions.IsPackageEquals(declaration, key) ? PyExtensions.GetAlias(key) + "." : ""; string GetFinalHint(string typeHint) => element.Vector == YesNo.Y ? $"List[{typeHint}]" : typeHint; if (element.Value != null) { string hint = GetValue(element.Value); return(GetFinalHint(hint)); } else if (element.Data != null) { string paramNamespace = GetParamNamespace(decl, element.Data); string hint = $"{paramNamespace}{element.Data.Name}"; return(GetFinalHint(hint)); } else if (element.Key != null) { return(GetFinalHint("str")); } else if (element.Enum != null) { string paramNamespace = GetParamNamespace(decl, element.Enum); string hint = $"{paramNamespace}{element.Enum.Name}"; return(GetFinalHint(hint)); } else { throw new ArgumentException("Can't deduct type"); } }
private static string GetTypeHint(TypeDecl decl, ParamDecl parameter) { if (parameter.Value != null) { string result = GetValue(parameter.Value); return(parameter.Vector == YesNo.Y ? $"List[{result}]" : result); } else if (parameter.Data != null) { string paramNamespace = !PyExtensions.IsPackageEquals(decl, parameter.Data) ? PyExtensions.GetAlias(parameter.Data) + "." : ""; string result = $"{paramNamespace}{parameter.Data.Name}"; return(parameter.Vector == YesNo.Y ? $"List[{result}]" : result); } else if (parameter.Key != null) { return(parameter.Vector == YesNo.Y ? "List[str]" : "str"); } else if (parameter.Enum != null) { string paramNamespace = !PyExtensions.IsPackageEquals(decl, parameter.Enum) ? PyExtensions.GetAlias(parameter.Enum) + "." : ""; string result = $"{paramNamespace}{parameter.Enum.Name}"; return(parameter.Vector == YesNo.Y ? $"List[{result}]" : result); } else { throw new ArgumentException("Can't deduct type"); } }
private static List <FileInfo> GenerateInitFiles(List <IDecl> declarations) { Dictionary <string, List <string> > packageImports = new Dictionary <string, List <string> >(); List <TypeDecl> typeDecls = declarations.OfType <TypeDecl>().ToList(); List <EnumDecl> enumDecls = declarations.OfType <EnumDecl>().ToList(); foreach (var decl in enumDecls) { var package = PyExtensions.GetPackage(decl); if (!packageImports.ContainsKey(package)) { packageImports[package] = new List <string>(); } packageImports[package].Add($"from {decl.Category} import {decl.Name}"); } foreach (var decl in typeDecls) { var package = PyExtensions.GetPackage(decl); if (!packageImports.ContainsKey(package)) { packageImports[package] = new List <string>(); } // Two classes are imported in case of first children of record if (decl.IsRecord && decl.Inherit == null) { packageImports[package].Add($"from {decl.Category} import {decl.Name}, {decl.Name}Key"); } else { packageImports[package].Add($"from {decl.Category} import {decl.Name}"); } } var result = new List <FileInfo>(); foreach (var pair in packageImports) { var init = new FileInfo { FileName = "__init__.py", FolderName = pair.Key, Content = string.Join(StringUtil.Eol, pair.Value) }; result.Add(init); } return(result); }
/// <summary> /// Generate python classes from declaration. /// </summary> public static string Build(TypeDecl decl, List <IDecl> declarations) { var writer = new CodeWriter(); string name = decl.Name; // Determine if we are inside datacentric package // based on module name. This affects the imports // and namespace use. bool insideDc = PyExtensions.GetPackage(decl) == "datacentric"; // If not generating for DataCentric package, use dc. namespace // in front of datacentric types, otherwise use no prefix string dcNamespacePrefix = insideDc ? "" : "dc."; PythonImportsBuilder.WriteImports(decl, declarations, writer); writer.AppendNewLineWithoutIndent(); writer.AppendNewLineWithoutIndent(); // Get base classes for current declaration List <string> bases = new List <string>(); if (decl.Keys.Any()) { bases.Add(dcNamespacePrefix + "Record"); } else if (decl.Inherit != null) { // Full package name and short namespace of the parent class, // or null if there is no parent bool parentClassInDifferentModule = !PyExtensions.IsPackageEquals(decl, decl.Inherit); string parentPackage = PyExtensions.GetPackage(decl.Inherit); string parentClassNamespacePrefix = parentClassInDifferentModule ? PyExtensions.GetAlias(parentPackage) + "." : ""; bases.Add(parentClassNamespacePrefix + decl.Inherit.Name); } else { bases.Add(dcNamespacePrefix + "Data"); } if (decl.Kind == TypeKind.Abstract) { bases.Add("ABC"); } // Python 3.8: // if (decl.Kind == TypeKind.Final) // writer.AppendLine("@final"); writer.AppendLine("@attr.s(slots=True, auto_attribs=True)"); writer.AppendLine($"class {name}({string.Join(", ", bases)}):"); writer.PushIndent(); writer.AppendLines(CommentHelper.PyComment(decl.Comment)); writer.AppendNewLineWithoutIndent(); if (!decl.Elements.Any()) { writer.AppendLine("pass"); } foreach (var element in decl.Elements) { // TODO: Should be replaced with callable with specific format instead of skipping string skipRepresentation = element.Vector == YesNo.Y ? ", repr=False" : ""; writer.AppendLine($"{element.Name.Underscore()}: {GetTypeHint(decl, element)} = attr.ib(default=None, kw_only=True{skipRepresentation}{GetMetaData(element)})"); writer.AppendLines(CommentHelper.PyComment(element.Comment)); if (element != decl.Elements.Last()) { writer.AppendNewLineWithoutIndent(); } } // Add to_key and create_key() methods if (decl.Keys.Any()) { var keyElements = decl.Elements.Where(e => decl.Keys.Contains(e.Name)).ToList(); writer.AppendNewLineWithoutIndent(); writer.AppendLine("def to_key(self) -> str:"); writer.PushIndent(); writer.AppendLine(CommentHelper.PyComment($"Get {decl.Name} key.")); writer.AppendLines($"return '{decl.Name}='{GetToKeyArgs(decl.Name, keyElements, true)}"); writer.PopIndent(); writer.AppendNewLineWithoutIndent(); var namedParams = keyElements.Select(e => $"{e.Name.Underscore()}: {GetTypeHint(decl, e)}").ToList(); var joinedNamedParams = string.Join(", ", namedParams); string start = "def create_key("; // Check if tokens should be separated by new line if (4 + start.Length + joinedNamedParams.Length > 120) { var indent = new string(' ', start.Length); joinedNamedParams = string.Join("," + Environment.NewLine + indent, namedParams); } writer.AppendLine("@classmethod"); writer.AppendLines($"def create_key(cls, *, {joinedNamedParams}) -> str:"); writer.PushIndent(); writer.AppendLine(CommentHelper.PyComment($"Create {decl.Name} key.")); writer.AppendLines($"return '{decl.Name}='{GetToKeyArgs(decl.Name, keyElements, false)}"); writer.PopIndent(); } if (decl.Declare != null) { writer.AppendNewLineWithoutIndent(); WriteMethods(decl, writer); } // Class end writer.PopIndent(); return(writer.ToString()); }
/// <summary> /// Add import statements for given declaration. /// </summary> public static void WriteImports(TypeDecl decl, List <IDecl> declarations, CodeWriter writer) { // Always import attr module writer.AppendLine("import attr"); // Instant is generated as Union[dt.datetime, dc.Instant] thus dt import is required if (decl.Elements.Any(e => e.Value != null && (e.Value.Type == ValueParamType.Instant || e.Value.Type == ValueParamType.NullableInstant))) { writer.AppendLine("import datetime as dt"); } // If type is abstract - ABC import is needed if (decl.Kind == TypeKind.Abstract) { writer.AppendLine("from abc import ABC"); } // Check if ObjectId is used bool hasObjectId = decl.Elements.Any(e => e.Value != null && (e.Value.Type == ValueParamType.TemporalId || e.Value.Type == ValueParamType.NullableTemporalId)); if (hasObjectId) { writer.AppendLine("from bson import ObjectId"); } // Check imports from typing var typingImports = new List <string>(); // Python 3.8 // if (decl.Keys.Any() || decl.Kind == TypeKind.Final) // typingImports.Add("final"); if (decl.Elements.Any(e => e.Vector == YesNo.Y)) { typingImports.Add("List"); } if (typingImports.Any()) { var items = string.Join(", ", typingImports); writer.AppendLine($"from typing import {items}"); } bool insideDc = PyExtensions.GetPackage(decl) == "datacentric"; List <string> packagesToImport = new List <string>(); List <string> individualImports = new List <string>(); // Import parent class package as its namespace, or if inside the same package, // import individual class instead if (decl.Inherit != null) { if (PyExtensions.IsPackageEquals(decl, decl.Inherit)) { IDecl parentDecl = declarations.FindByKey(decl.Inherit); individualImports.Add($"from {parentDecl.Category} import {decl.Inherit.Name}"); } else { packagesToImport.Add(PyExtensions.GetPackage(decl.Inherit)); } } // Import datacentric package as dc, or if inside datacentric, // import individual classes instead else if (decl.IsRecord) { if (insideDc) { individualImports.Add("from datacentric.storage.record import Record"); } else { packagesToImport.Add("datacentric"); } } // First child class of Data else { if (insideDc) { individualImports.Add("from datacentric.storage.data import Data"); } else { packagesToImport.Add("datacentric"); } } foreach (var data in decl.Elements.Where(d => d.Data != null).Select(d => d.Data)) { if (PyExtensions.IsPackageEquals(decl, data)) { IDecl dataDecl = declarations.FindByKey(data); individualImports.Add($"from {dataDecl.Category} import {data.Name}"); } else { packagesToImport.Add(PyExtensions.GetPackage(data)); } } foreach (var enumElement in decl.Elements.Where(d => d.Enum != null).Select(d => d.Enum)) { if (PyExtensions.IsPackageEquals(decl, enumElement)) { IDecl enumDecl = declarations.FindByKey(enumElement); individualImports.Add($"from {enumDecl.Category} import {enumElement.Name}"); } else { packagesToImport.Add(PyExtensions.GetPackage(enumElement)); } } foreach (var package in packagesToImport.Distinct()) { writer.AppendLine($"import {package} as {PyExtensions.GetAlias(package)}"); } foreach (var import in individualImports.Distinct()) { writer.AppendLine(import); } }