From 97d10978cef979f825464a7bd8c5789ac2a29e3a Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Fri, 25 Oct 2024 16:05:17 -0400 Subject: [PATCH 01/17] add original changes from PR #4459 --- .github/workflows/test-module-generation.yml | 3 +- cli/module_generate.go | 1 + cli/module_generate/scripts/generate_stubs.py | 152 ++++++++++++------ 3 files changed, 107 insertions(+), 49 deletions(-) diff --git a/.github/workflows/test-module-generation.yml b/.github/workflows/test-module-generation.yml index 8eb18fd07d3..054555288fb 100644 --- a/.github/workflows/test-module-generation.yml +++ b/.github/workflows/test-module-generation.yml @@ -15,6 +15,7 @@ jobs: { subtype: "arm", type: "component" }, { subtype: "audio_input", type: "component" }, { subtype: "base", type: "component" }, + { subtype: "board", type: "component" }, { subtype: "camera", type: "component" }, { subtype: "encoder", type: "component" }, { subtype: "gantry", type: "component" }, @@ -50,7 +51,7 @@ jobs: - name: Run module run: | cd my-module - chmod +x run.sh + ./run.sh /tmp/viam.sock & PID=$! sleep 5 diff --git a/cli/module_generate.go b/cli/module_generate.go index 15f09fcca76..598cc517028 100644 --- a/cli/module_generate.go +++ b/cli/module_generate.go @@ -232,6 +232,7 @@ func promptUser() (*common.ModuleInputs, error) { huh.NewOption("Arm Component", "arm component"), huh.NewOption("Audio Input Component", "audio_input component"), huh.NewOption("Base Component", "base component"), + huh.NewOption("Board Component", "board component"), huh.NewOption("Camera Component", "camera component"), huh.NewOption("Encoder Component", "encoder component"), huh.NewOption("Gantry Component", "gantry component"), diff --git a/cli/module_generate/scripts/generate_stubs.py b/cli/module_generate/scripts/generate_stubs.py index d42511b8353..c1a901bbb91 100644 --- a/cli/module_generate/scripts/generate_stubs.py +++ b/cli/module_generate/scripts/generate_stubs.py @@ -3,15 +3,92 @@ import subprocess import sys from importlib import import_module +from typing import List, Set -def return_attribute(resource_name: str, attr: str) -> ast.Attribute: +def return_attribute(value: str, attr: str) -> ast.Attribute: return ast.Attribute( - value=ast.Name(id=resource_name, ctx=ast.Load()), + value=ast.Name(id=value, ctx=ast.Load()), attr=attr, ctx=ast.Load()) +def update_annotation( + resource_name: str, + annotation: ast.Name | ast.Subscript, + nodes: Set[str], + parent: str +) -> ast.Attribute | ast.Subscript: + if isinstance(annotation, ast.Name) and annotation.id in nodes: + value = parent if parent else resource_name + return return_attribute(value, annotation.id) + elif isinstance(annotation, ast.Subscript): + annotation.slice = update_annotation( + resource_name, + annotation.slice, + nodes, + parent) + return annotation + + +def replace_async_func( + resource_name: str, + func: ast.AsyncFunctionDef, + nodes: Set[str], + parent: str = "" +) -> None: + for arg in func.args.args: + arg.annotation = update_annotation( + resource_name, + arg.annotation, + nodes, + parent) + func.body = [ + ast.Raise( + exc=ast.Call(func=ast.Name(id='NotImplementedError', + ctx=ast.Load()), + args=[], + keywords=[]), + cause=None) + ] + func.decorator_list = [] + if isinstance(func.returns, (ast.Name, ast.Subscript)): + func.returns = update_annotation( + resource_name, func.returns, nodes, parent + ) + + +def return_subclass( + resource_name: str, stmt: ast.ClassDef, parent="" +) -> List[str]: + def parse_subclass(resource_name: str, stmt: ast.ClassDef, parent: str): + nodes = set() + nodes_to_remove = [] + parent = parent if parent else resource_name + stmt.bases = [ast.Name(id=f"{parent}.{stmt.name}", ctx=ast.Load())] + for cstmt in stmt.body: + if isinstance(cstmt, ast.Expr) or ( + isinstance(cstmt, ast.FunctionDef) and cstmt.name == "__init__" + ): + nodes_to_remove.append(cstmt) + elif isinstance(cstmt, ast.AnnAssign): + nodes.add(cstmt.target.id) + nodes_to_remove.append(cstmt) + elif isinstance(cstmt, ast.ClassDef): + parse_subclass(resource_name, cstmt, stmt.bases[0].id) + elif isinstance(cstmt, ast.AsyncFunctionDef): + replace_async_func(resource_name, cstmt, nodes, stmt.bases[0].id) + for node in nodes_to_remove: + stmt.body.remove(node) + if stmt.body == []: + stmt.body = [ast.Pass()] + + parse_subclass(resource_name, stmt, parent) + return '\n'.join( + [' ' + line for line in ast.unparse(stmt).splitlines()] + ) + + def main( resource_type: str, resource_subtype: str, @@ -22,48 +99,37 @@ def main( import isort from slugify import slugify - module_name = f"viam.{resource_type}s.{resource_subtype}.{resource_subtype}" + module_name = ( + f"viam.{resource_type}s.{resource_subtype}.{resource_subtype}" + ) module = import_module(module_name) - if resource_subtype == "input": - resource_name = "Controller" - elif resource_subtype == "slam": - resource_name = "SLAM" - elif resource_subtype == "mlmodel": - resource_name = "MLModel" - else: - resource_name = "".join(word.capitalize() for word in resource_subtype.split("_")) - - imports = [] + resource_name = { + "input": "Controller", "slam": "SLAM", "mlmodel": "MLModel" + }.get(resource_subtype, "".join(word.capitalize() + for word in resource_subtype.split("_"))) + + imports, subclasses, abstract_methods = [], [], [] + nodes = set() modules_to_ignore = [ "abc", "component_base", "service_base", "viam.resource.types", ] - abstract_methods = [] with open(module.__file__, "r") as f: - def update_annotation(annotation): - if isinstance(annotation, ast.Name) and annotation.id in nodes: - return return_attribute(resource_name, annotation.id) - elif isinstance(annotation, ast.Subscript): - annotation.slice = update_annotation(annotation.slice) - return annotation - return annotation - tree = ast.parse(f.read()) - nodes = [] for stmt in tree.body: if isinstance(stmt, ast.Import): for imp in stmt.names: if imp.name in modules_to_ignore: continue - if imp.asname: - imports.append(f"import {imp.name} as {imp.asname}") - else: - imports.append(f"import {imp.name}") - elif isinstance(stmt, ast.ImportFrom): - if stmt.module in modules_to_ignore or stmt.module is None: - continue + imports.append(f"import {imp.name} as {imp.asname}" + if imp.asname else f"import {imp.name}") + elif ( + isinstance(stmt, ast.ImportFrom) + and stmt.module + and stmt.module not in modules_to_ignore + ): i_strings = ", ".join( [ ( @@ -79,26 +145,14 @@ def update_annotation(annotation): elif isinstance(stmt, ast.ClassDef) and stmt.name == resource_name: for cstmt in stmt.body: if isinstance(cstmt, ast.ClassDef): - nodes.append(cstmt.name) + subclasses.append(return_subclass(resource_name, cstmt)) elif isinstance(cstmt, ast.AnnAssign): - nodes.append(cstmt.target.id) + nodes.add(cstmt.target.id) elif isinstance(cstmt, ast.AsyncFunctionDef): - for arg in cstmt.args.args: - arg.annotation = update_annotation(arg.annotation) - - cstmt.body = [ - ast.Raise( - exc=ast.Call( - func=ast.Name(id='NotImplementedError', ctx=ast.Load()), - args=[], - keywords=[]), - cause=None, - ) - ] - cstmt.decorator_list = [] - if isinstance(cstmt.returns, ast.Name) and cstmt.returns.id in nodes: - cstmt.returns = return_attribute(resource_name, cstmt.returns.id) - indented_code = '\n'.join([' ' + line for line in ast.unparse(cstmt).splitlines()]) + replace_async_func(resource_name, cstmt, nodes) + indented_code = '\n'.join( + [' ' + line for line in ast.unparse(cstmt).splitlines()] + ) abstract_methods.append(indented_code) model_name_pascal = "".join( @@ -158,6 +212,7 @@ def reconfigure(self, config: ComponentConfig, dependencies: Mapping[ResourceNam return super().reconfigure(config, dependencies) {8} +{9} if __name__ == '__main__': @@ -172,6 +227,7 @@ def reconfigure(self, config: ComponentConfig, dependencies: Mapping[ResourceNam namespace, mod_name, model_name, + '\n\n'.join([subclass for subclass in subclasses]), '\n\n'.join([f'{method}' for method in abstract_methods]), ) f_name = os.path.join(mod_name, "src", "main.py") From b38f91a1382f5e19450aaffcc6a8248387f21d37 Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Fri, 25 Oct 2024 16:06:36 -0400 Subject: [PATCH 02/17] follow param standards --- cli/module_generate/scripts/generate_stubs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/module_generate/scripts/generate_stubs.py b/cli/module_generate/scripts/generate_stubs.py index c1a901bbb91..276886915eb 100644 --- a/cli/module_generate/scripts/generate_stubs.py +++ b/cli/module_generate/scripts/generate_stubs.py @@ -59,7 +59,7 @@ def replace_async_func( def return_subclass( - resource_name: str, stmt: ast.ClassDef, parent="" + resource_name: str, stmt: ast.ClassDef, parent: str = "" ) -> List[str]: def parse_subclass(resource_name: str, stmt: ast.ClassDef, parent: str): nodes = set() From e087e1f84be94e9d363826b61434f2d88aecddcb Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Fri, 25 Oct 2024 16:14:54 -0400 Subject: [PATCH 03/17] add language flag with default python --- cli/app.go | 6 ++++++ cli/module_generate.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cli/app.go b/cli/app.go index 275e1ab1abf..7e26b626154 100644 --- a/cli/app.go +++ b/cli/app.go @@ -42,6 +42,7 @@ const ( apiKeyCreateFlagName = "name" moduleFlagName = "name" + moduleFlagLanguage = "language" moduleFlagPublicNamespace = "public-namespace" moduleFlagPath = "module" moduleFlagVersion = "version" @@ -1496,6 +1497,11 @@ After creation, use 'viam module update' to push your new module to app.viam.com Name: "generate", Usage: "generate a new modular resource via prompts", Flags: []cli.Flag{ + &cli.StringFlag{ + Name: moduleFlagLanguage, + Usage: "resource type to use in module", + Value: "python", + }, &cli.StringFlag{ Name: moduleFlagResourceType, Usage: "resource type to use in module", diff --git a/cli/module_generate.go b/cli/module_generate.go index 598cc517028..ef730f9809f 100644 --- a/cli/module_generate.go +++ b/cli/module_generate.go @@ -65,7 +65,7 @@ func (c *viamClient) generateModuleAction(cCtx *cli.Context) error { ModuleName: "my-module", IsPublic: false, Namespace: "my-org", - Language: python, + Language: cCtx.String(moduleFlagLanguage), Resource: resourceSubtype + " " + resourceType, ResourceType: resourceType, ResourceSubtype: resourceSubtype, From c1cf5564d5566e08c2e1f701e467d4fc339baeba Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Fri, 25 Oct 2024 18:19:09 -0400 Subject: [PATCH 04/17] add subclasses to resource --- cli/module_generate/scripts/generate_stubs.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cli/module_generate/scripts/generate_stubs.go b/cli/module_generate/scripts/generate_stubs.go index 204dc8eba83..6d34c17efff 100644 --- a/cli/module_generate/scripts/generate_stubs.go +++ b/cli/module_generate/scripts/generate_stubs.go @@ -80,6 +80,13 @@ func setGoModuleTemplate(clientCode string, module common.ModuleInputs) (*common } var functions []string ast.Inspect(node, func(n ast.Node) bool { + if typeSpec, ok := n.(*ast.TypeSpec); ok { + if _, ok := typeSpec.Type.(*ast.StructType); ok { + if strings.Contains(typeSpec.Name.Name, "Client") { + functions = append(functions, formatStruct(typeSpec, module.ModuleCamel+module.ModelPascal)) + } + } + } if funcDecl, ok := n.(*ast.FuncDecl); ok { name, args, returns := parseFunctionSignature(module.ResourceSubtype, module.ResourceSubtypePascal, funcDecl) if name != "" { @@ -130,6 +137,15 @@ func handleMapType(str, resourceSubtype string) string { return fmt.Sprintf("map[%s]%s", keyType, valueType) } +func formatStruct(typeSpec *ast.TypeSpec, client string) string { + var buf bytes.Buffer + err := printer.Fprint(&buf, token.NewFileSet(), typeSpec) + if err != nil { + return fmt.Sprintf("Error formatting type: %v", err) + } + return "type " + strings.ReplaceAll(buf.String(), "*client", "*"+client) + "\n\n" +} + // parseFunctionSignature parses function declarations into the function name, the arguments, and the return types. func parseFunctionSignature(resourceSubtype, resourceSubtypePascal string, funcDecl *ast.FuncDecl) (name, args string, returns []string) { if funcDecl == nil { From 55d00415cd95b68ed740bb18e36a6741be80c675 Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Fri, 25 Oct 2024 18:19:19 -0400 Subject: [PATCH 05/17] change receiver of subclass functions --- cli/module_generate/scripts/generate_stubs.go | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/cli/module_generate/scripts/generate_stubs.go b/cli/module_generate/scripts/generate_stubs.go index 6d34c17efff..421dbe3bbc3 100644 --- a/cli/module_generate/scripts/generate_stubs.go +++ b/cli/module_generate/scripts/generate_stubs.go @@ -88,9 +88,9 @@ func setGoModuleTemplate(clientCode string, module common.ModuleInputs) (*common } } if funcDecl, ok := n.(*ast.FuncDecl); ok { - name, args, returns := parseFunctionSignature(module.ResourceSubtype, module.ResourceSubtypePascal, funcDecl) + name, receiver, args, returns := parseFunctionSignature(module.ResourceSubtype, module.ResourceSubtypePascal, module.ModuleCamel+module.ModelPascal, funcDecl) if name != "" { - functions = append(functions, formatEmptyFunction(module.ModuleCamel+module.ModelPascal, name, args, returns)) + functions = append(functions, formatEmptyFunction(receiver, name, args, returns)) } } return true @@ -147,7 +147,7 @@ func formatStruct(typeSpec *ast.TypeSpec, client string) string { } // parseFunctionSignature parses function declarations into the function name, the arguments, and the return types. -func parseFunctionSignature(resourceSubtype, resourceSubtypePascal string, funcDecl *ast.FuncDecl) (name, args string, returns []string) { +func parseFunctionSignature(resourceSubtype, resourceSubtypePascal string, modelType string, funcDecl *ast.FuncDecl) (name string, receiver string, args string, returns []string) { if funcDecl == nil { return } @@ -161,6 +161,19 @@ func parseFunctionSignature(resourceSubtype, resourceSubtypePascal string, funcD return } + // Receiver + receiver = modelType + if funcDecl.Recv != nil && len(funcDecl.Recv.List) > 0 { + field := funcDecl.Recv.List[0] + if f, ok := field.Type.(*ast.StarExpr); ok { + if ident, ok := f.X.(*ast.Ident); ok { + if ident.Name != "client" { + receiver = ident.Name + } + } + } + } + // Parameters var params []string if funcDecl.Type.Params != nil { @@ -215,7 +228,7 @@ func parseFunctionSignature(resourceSubtype, resourceSubtypePascal string, funcD } } - return funcName, strings.Join(params, ", "), returns + return funcName, receiver, strings.Join(params, ", "), returns } // formatEmptyFunction outputs the new function that removes the function body, adds the panic unimplemented statement, From 6aeddf8b8d0d69ee1ed92451aa65cfd5ac4c1fb4 Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 12:33:13 -0400 Subject: [PATCH 06/17] handle channel types --- cli/module_generate/scripts/generate_stubs.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/module_generate/scripts/generate_stubs.go b/cli/module_generate/scripts/generate_stubs.go index 421dbe3bbc3..d4531d1b3ba 100644 --- a/cli/module_generate/scripts/generate_stubs.go +++ b/cli/module_generate/scripts/generate_stubs.go @@ -183,6 +183,8 @@ func parseFunctionSignature(resourceSubtype, resourceSubtypePascal string, model paramType = fmt.Sprintf("%s.%s", resourceSubtype, paramType) } else if strings.HasPrefix(paramType, "[]") && unicode.IsUpper(rune(paramType[2])) { paramType = fmt.Sprintf("[]%s.%s", resourceSubtype, paramType[2:]) + } else if strings.HasPrefix(paramType, "chan ") && unicode.IsUpper(rune(paramType[5])) { + paramType = fmt.Sprintf("chan %s.%s", resourceSubtype, paramType[5:]) } for _, name := range param.Names { From 83daa22c12386e1f0eb54a1f035dfe83365dda5e Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 12:43:21 -0400 Subject: [PATCH 07/17] finalize --- .github/workflows/test-module-generation.yml | 1 - cli/module_generate/scripts/generate_stubs.go | 14 ++++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-module-generation.yml b/.github/workflows/test-module-generation.yml index 054555288fb..fced9e55b5c 100644 --- a/.github/workflows/test-module-generation.yml +++ b/.github/workflows/test-module-generation.yml @@ -51,7 +51,6 @@ jobs: - name: Run module run: | cd my-module - ./run.sh /tmp/viam.sock & PID=$! sleep 5 diff --git a/cli/module_generate/scripts/generate_stubs.go b/cli/module_generate/scripts/generate_stubs.go index d4531d1b3ba..d098a949002 100644 --- a/cli/module_generate/scripts/generate_stubs.go +++ b/cli/module_generate/scripts/generate_stubs.go @@ -88,7 +88,12 @@ func setGoModuleTemplate(clientCode string, module common.ModuleInputs) (*common } } if funcDecl, ok := n.(*ast.FuncDecl); ok { - name, receiver, args, returns := parseFunctionSignature(module.ResourceSubtype, module.ResourceSubtypePascal, module.ModuleCamel+module.ModelPascal, funcDecl) + name, receiver, args, returns := parseFunctionSignature( + module.ResourceSubtype, + module.ResourceSubtypePascal, + module.ModuleCamel+module.ModelPascal, + funcDecl, + ) if name != "" { functions = append(functions, formatEmptyFunction(receiver, name, args, returns)) } @@ -179,11 +184,12 @@ func parseFunctionSignature(resourceSubtype, resourceSubtypePascal string, model if funcDecl.Type.Params != nil { for _, param := range funcDecl.Type.Params.List { paramType := formatType(param.Type) - if unicode.IsUpper(rune(paramType[0])) { + switch { + case unicode.IsUpper(rune(paramType[0])): paramType = fmt.Sprintf("%s.%s", resourceSubtype, paramType) - } else if strings.HasPrefix(paramType, "[]") && unicode.IsUpper(rune(paramType[2])) { + case strings.HasPrefix(paramType, "[]") && unicode.IsUpper(rune(paramType[2])): paramType = fmt.Sprintf("[]%s.%s", resourceSubtype, paramType[2:]) - } else if strings.HasPrefix(paramType, "chan ") && unicode.IsUpper(rune(paramType[5])) { + case strings.HasPrefix(paramType, "chan ") && unicode.IsUpper(rune(paramType[5])): paramType = fmt.Sprintf("chan %s.%s", resourceSubtype, paramType[5:]) } From 1c2e68a9a7ab90a9d94053ac31aca04e264698c0 Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 12:44:40 -0400 Subject: [PATCH 08/17] make lint --- cli/module_generate/scripts/generate_stubs.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cli/module_generate/scripts/generate_stubs.go b/cli/module_generate/scripts/generate_stubs.go index d098a949002..fbda06e7de1 100644 --- a/cli/module_generate/scripts/generate_stubs.go +++ b/cli/module_generate/scripts/generate_stubs.go @@ -152,7 +152,12 @@ func formatStruct(typeSpec *ast.TypeSpec, client string) string { } // parseFunctionSignature parses function declarations into the function name, the arguments, and the return types. -func parseFunctionSignature(resourceSubtype, resourceSubtypePascal string, modelType string, funcDecl *ast.FuncDecl) (name string, receiver string, args string, returns []string) { +func parseFunctionSignature( + resourceSubtype, + resourceSubtypePascal string, + modelType string, + funcDecl *ast.FuncDecl, +) (name string, receiver string, args string, returns []string) { if funcDecl == nil { return } From 887de49d753383cf33e3bd17b9176a94caaeef5b Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 12:53:33 -0400 Subject: [PATCH 09/17] make lint --- cli/module_generate/scripts/generate_stubs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/module_generate/scripts/generate_stubs.go b/cli/module_generate/scripts/generate_stubs.go index fbda06e7de1..379d29d1b7d 100644 --- a/cli/module_generate/scripts/generate_stubs.go +++ b/cli/module_generate/scripts/generate_stubs.go @@ -157,7 +157,7 @@ func parseFunctionSignature( resourceSubtypePascal string, modelType string, funcDecl *ast.FuncDecl, -) (name string, receiver string, args string, returns []string) { +) (name, receiver, args string, returns []string) { if funcDecl == nil { return } From 9b27c8a044825d746c95e1a87f5068d977c73ac7 Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 13:33:04 -0400 Subject: [PATCH 10/17] test go --- .github/workflows/test-module-generation.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-module-generation.yml b/.github/workflows/test-module-generation.yml index fced9e55b5c..8092ff69872 100644 --- a/.github/workflows/test-module-generation.yml +++ b/.github/workflows/test-module-generation.yml @@ -2,14 +2,18 @@ name: Test Template Generators on: workflow_dispatch: + pull_request: + branches: + - main jobs: generate_and_run_module: - if: github.repository_owner == 'viamrobotics' + # if: github.repository_owner == 'viamrobotics' runs-on: ubuntu-latest strategy: fail-fast: true matrix: + language: ["python", "go"] resource: [ { subtype: "arm", type: "component" }, @@ -46,7 +50,7 @@ jobs: go-version-file: go.mod - name: Run module generator - run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }}" + run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }} --language "${{ matrix.language }}" - name: Run module run: | From 775f0c929c6f61f69d6d33a5c92998052da6db63 Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 13:35:38 -0400 Subject: [PATCH 11/17] remove language tag --- .github/workflows/test-module-generation.yml | 7 +------ cli/app.go | 6 ------ cli/module_generate.go | 1 - 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/.github/workflows/test-module-generation.yml b/.github/workflows/test-module-generation.yml index 8092ff69872..488eefcfdaf 100644 --- a/.github/workflows/test-module-generation.yml +++ b/.github/workflows/test-module-generation.yml @@ -2,18 +2,13 @@ name: Test Template Generators on: workflow_dispatch: - pull_request: - branches: - - main jobs: generate_and_run_module: - # if: github.repository_owner == 'viamrobotics' runs-on: ubuntu-latest strategy: fail-fast: true matrix: - language: ["python", "go"] resource: [ { subtype: "arm", type: "component" }, @@ -50,7 +45,7 @@ jobs: go-version-file: go.mod - name: Run module generator - run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }} --language "${{ matrix.language }}" + run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }} - name: Run module run: | diff --git a/cli/app.go b/cli/app.go index 7e26b626154..275e1ab1abf 100644 --- a/cli/app.go +++ b/cli/app.go @@ -42,7 +42,6 @@ const ( apiKeyCreateFlagName = "name" moduleFlagName = "name" - moduleFlagLanguage = "language" moduleFlagPublicNamespace = "public-namespace" moduleFlagPath = "module" moduleFlagVersion = "version" @@ -1497,11 +1496,6 @@ After creation, use 'viam module update' to push your new module to app.viam.com Name: "generate", Usage: "generate a new modular resource via prompts", Flags: []cli.Flag{ - &cli.StringFlag{ - Name: moduleFlagLanguage, - Usage: "resource type to use in module", - Value: "python", - }, &cli.StringFlag{ Name: moduleFlagResourceType, Usage: "resource type to use in module", diff --git a/cli/module_generate.go b/cli/module_generate.go index ef730f9809f..b1985526ab3 100644 --- a/cli/module_generate.go +++ b/cli/module_generate.go @@ -65,7 +65,6 @@ func (c *viamClient) generateModuleAction(cCtx *cli.Context) error { ModuleName: "my-module", IsPublic: false, Namespace: "my-org", - Language: cCtx.String(moduleFlagLanguage), Resource: resourceSubtype + " " + resourceType, ResourceType: resourceType, ResourceSubtype: resourceSubtype, From 3c7a79679d2888a2d0b12bfc948d3848750b93ed Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 13:36:35 -0400 Subject: [PATCH 12/17] finalize --- .github/workflows/test-module-generation.yml | 1 + cli/module_generate.go | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/test-module-generation.yml b/.github/workflows/test-module-generation.yml index 488eefcfdaf..76529bf2ecb 100644 --- a/.github/workflows/test-module-generation.yml +++ b/.github/workflows/test-module-generation.yml @@ -5,6 +5,7 @@ on: jobs: generate_and_run_module: + if: github.repository_owner == 'viamrobotics' runs-on: ubuntu-latest strategy: fail-fast: true diff --git a/cli/module_generate.go b/cli/module_generate.go index b1985526ab3..598cc517028 100644 --- a/cli/module_generate.go +++ b/cli/module_generate.go @@ -65,6 +65,7 @@ func (c *viamClient) generateModuleAction(cCtx *cli.Context) error { ModuleName: "my-module", IsPublic: false, Namespace: "my-org", + Language: python, Resource: resourceSubtype + " " + resourceType, ResourceType: resourceType, ResourceSubtype: resourceSubtype, From 1774be041c25679fd32070409c1204c1c7b547a0 Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 13:37:12 -0400 Subject: [PATCH 13/17] fix --- .github/workflows/test-module-generation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-module-generation.yml b/.github/workflows/test-module-generation.yml index 76529bf2ecb..fced9e55b5c 100644 --- a/.github/workflows/test-module-generation.yml +++ b/.github/workflows/test-module-generation.yml @@ -46,7 +46,7 @@ jobs: go-version-file: go.mod - name: Run module generator - run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }} + run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }}" - name: Run module run: | From 1889d875479848ae7ddfec5fdc06f62168895cbc Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 13:39:13 -0400 Subject: [PATCH 14/17] test --- .github/workflows/test-module-generation.yml | 8 ++++++-- cli/app.go | 6 ++++++ cli/module_generate.go | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-module-generation.yml b/.github/workflows/test-module-generation.yml index fced9e55b5c..20714ed6ad7 100644 --- a/.github/workflows/test-module-generation.yml +++ b/.github/workflows/test-module-generation.yml @@ -2,14 +2,18 @@ name: Test Template Generators on: workflow_dispatch: + pull_request: + branches: + - main jobs: generate_and_run_module: - if: github.repository_owner == 'viamrobotics' + # if: github.repository_owner == 'viamrobotics' runs-on: ubuntu-latest strategy: fail-fast: true matrix: + language: ["python", "go"] resource: [ { subtype: "arm", type: "component" }, @@ -46,7 +50,7 @@ jobs: go-version-file: go.mod - name: Run module generator - run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }}" + run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }}" --language "${{ matrix.language }}" - name: Run module run: | diff --git a/cli/app.go b/cli/app.go index 275e1ab1abf..7e26b626154 100644 --- a/cli/app.go +++ b/cli/app.go @@ -42,6 +42,7 @@ const ( apiKeyCreateFlagName = "name" moduleFlagName = "name" + moduleFlagLanguage = "language" moduleFlagPublicNamespace = "public-namespace" moduleFlagPath = "module" moduleFlagVersion = "version" @@ -1496,6 +1497,11 @@ After creation, use 'viam module update' to push your new module to app.viam.com Name: "generate", Usage: "generate a new modular resource via prompts", Flags: []cli.Flag{ + &cli.StringFlag{ + Name: moduleFlagLanguage, + Usage: "resource type to use in module", + Value: "python", + }, &cli.StringFlag{ Name: moduleFlagResourceType, Usage: "resource type to use in module", diff --git a/cli/module_generate.go b/cli/module_generate.go index 598cc517028..ef730f9809f 100644 --- a/cli/module_generate.go +++ b/cli/module_generate.go @@ -65,7 +65,7 @@ func (c *viamClient) generateModuleAction(cCtx *cli.Context) error { ModuleName: "my-module", IsPublic: false, Namespace: "my-org", - Language: python, + Language: cCtx.String(moduleFlagLanguage), Resource: resourceSubtype + " " + resourceType, ResourceType: resourceType, ResourceSubtype: resourceSubtype, From 751e9555a36244d24d12677753cc49e414e3c7ca Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Mon, 28 Oct 2024 13:42:34 -0400 Subject: [PATCH 15/17] undo test --- .github/workflows/test-module-generation.yml | 8 ++------ cli/app.go | 6 ------ cli/module_generate.go | 2 +- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test-module-generation.yml b/.github/workflows/test-module-generation.yml index 20714ed6ad7..fced9e55b5c 100644 --- a/.github/workflows/test-module-generation.yml +++ b/.github/workflows/test-module-generation.yml @@ -2,18 +2,14 @@ name: Test Template Generators on: workflow_dispatch: - pull_request: - branches: - - main jobs: generate_and_run_module: - # if: github.repository_owner == 'viamrobotics' + if: github.repository_owner == 'viamrobotics' runs-on: ubuntu-latest strategy: fail-fast: true matrix: - language: ["python", "go"] resource: [ { subtype: "arm", type: "component" }, @@ -50,7 +46,7 @@ jobs: go-version-file: go.mod - name: Run module generator - run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }}" --language "${{ matrix.language }}" + run: go run ./cli/viam --debug module generate --resource-subtype "${{ matrix.resource.subtype }}" --resource-type "${{ matrix.resource.type }}" - name: Run module run: | diff --git a/cli/app.go b/cli/app.go index 7e26b626154..275e1ab1abf 100644 --- a/cli/app.go +++ b/cli/app.go @@ -42,7 +42,6 @@ const ( apiKeyCreateFlagName = "name" moduleFlagName = "name" - moduleFlagLanguage = "language" moduleFlagPublicNamespace = "public-namespace" moduleFlagPath = "module" moduleFlagVersion = "version" @@ -1497,11 +1496,6 @@ After creation, use 'viam module update' to push your new module to app.viam.com Name: "generate", Usage: "generate a new modular resource via prompts", Flags: []cli.Flag{ - &cli.StringFlag{ - Name: moduleFlagLanguage, - Usage: "resource type to use in module", - Value: "python", - }, &cli.StringFlag{ Name: moduleFlagResourceType, Usage: "resource type to use in module", diff --git a/cli/module_generate.go b/cli/module_generate.go index ef730f9809f..598cc517028 100644 --- a/cli/module_generate.go +++ b/cli/module_generate.go @@ -65,7 +65,7 @@ func (c *viamClient) generateModuleAction(cCtx *cli.Context) error { ModuleName: "my-module", IsPublic: false, Namespace: "my-org", - Language: cCtx.String(moduleFlagLanguage), + Language: python, Resource: resourceSubtype + " " + resourceType, ResourceType: resourceType, ResourceSubtype: resourceSubtype, From dc74480c818df47fa478469dd9c36a5ce82f60c0 Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Tue, 29 Oct 2024 11:44:24 -0400 Subject: [PATCH 16/17] readability renames --- cli/module_generate/scripts/generate_stubs.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/module_generate/scripts/generate_stubs.go b/cli/module_generate/scripts/generate_stubs.go index 379d29d1b7d..b62fa38f251 100644 --- a/cli/module_generate/scripts/generate_stubs.go +++ b/cli/module_generate/scripts/generate_stubs.go @@ -142,13 +142,13 @@ func handleMapType(str, resourceSubtype string) string { return fmt.Sprintf("map[%s]%s", keyType, valueType) } -func formatStruct(typeSpec *ast.TypeSpec, client string) string { +func formatStruct(typeSpec *ast.TypeSpec, modelType string) string { var buf bytes.Buffer err := printer.Fprint(&buf, token.NewFileSet(), typeSpec) if err != nil { return fmt.Sprintf("Error formatting type: %v", err) } - return "type " + strings.ReplaceAll(buf.String(), "*client", "*"+client) + "\n\n" + return "type " + strings.ReplaceAll(buf.String(), "*client", "*"+modelType) + "\n\n" } // parseFunctionSignature parses function declarations into the function name, the arguments, and the return types. @@ -175,8 +175,8 @@ func parseFunctionSignature( receiver = modelType if funcDecl.Recv != nil && len(funcDecl.Recv.List) > 0 { field := funcDecl.Recv.List[0] - if f, ok := field.Type.(*ast.StarExpr); ok { - if ident, ok := f.X.(*ast.Ident); ok { + if starExpr, ok := field.Type.(*ast.StarExpr); ok { + if ident, ok := starExpr.X.(*ast.Ident); ok { if ident.Name != "client" { receiver = ident.Name } From 207d3e678c59ef946f4ae7779f626da3ad74e0a0 Mon Sep 17 00:00:00 2001 From: purplenicole730 Date: Thu, 31 Oct 2024 10:10:18 -0400 Subject: [PATCH 17/17] add clarifying comments --- cli/module_generate/scripts/generate_stubs.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cli/module_generate/scripts/generate_stubs.go b/cli/module_generate/scripts/generate_stubs.go index b62fa38f251..2678e05769b 100644 --- a/cli/module_generate/scripts/generate_stubs.go +++ b/cli/module_generate/scripts/generate_stubs.go @@ -189,9 +189,13 @@ func parseFunctionSignature( if funcDecl.Type.Params != nil { for _, param := range funcDecl.Type.Params.List { paramType := formatType(param.Type) + + // Check if `paramType` is a type that is capitalized. + // If so, attribute the type to . switch { case unicode.IsUpper(rune(paramType[0])): paramType = fmt.Sprintf("%s.%s", resourceSubtype, paramType) + // IF `paramType` has a prefix, check if type is capitalized after prefix. case strings.HasPrefix(paramType, "[]") && unicode.IsUpper(rune(paramType[2])): paramType = fmt.Sprintf("[]%s.%s", resourceSubtype, paramType[2:]) case strings.HasPrefix(paramType, "chan ") && unicode.IsUpper(rune(paramType[5])):