Skip to content

Commit

Permalink
RSDK-9445: move generated python model out of main (#4776)
Browse files Browse the repository at this point in the history
  • Loading branch information
purplenicole730 authored Feb 18, 2025
1 parent 08fd0e9 commit 810cd06
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 67 deletions.
11 changes: 6 additions & 5 deletions cli/module_generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ func populateAdditionalInfo(newModule *modulegen.ModuleInputs) {

titleCaser := cases.Title(language.Und)
replacer := strings.NewReplacer("_", " ", "-", " ")
snakeReplacer := strings.NewReplacer("-", "_", " ", "_")
spaceReplacer := modulegen.SpaceReplacer
newModule.ModulePascal = spaceReplacer.Replace(titleCaser.String(replacer.Replace(newModule.ModuleName)))
newModule.ModuleCamel = strings.ToLower(string(newModule.ModulePascal[0])) + newModule.ModulePascal[1:]
Expand All @@ -382,7 +383,7 @@ func populateAdditionalInfo(newModule *modulegen.ModuleInputs) {
newModule.ResourceTypePascal = spaceReplacer.Replace(titleCaser.String(replacer.Replace(newModule.ResourceType)))
newModule.ModelPascal = spaceReplacer.Replace(titleCaser.String(replacer.Replace(newModule.ModelName)))
newModule.ModelCamel = strings.ToLower(string(newModule.ModelPascal[0])) + newModule.ModelPascal[1:]
newModule.ModelLowercase = strings.ToLower(newModule.ModelPascal)
newModule.ModelSnake = snakeReplacer.Replace(newModule.ModelName)

modelTriple := fmt.Sprintf("%s:%s:%s", newModule.Namespace, newModule.ModuleName, newModule.ModelName)
newModule.ModelTriple = modelTriple
Expand Down Expand Up @@ -689,14 +690,14 @@ func generatePythonStubs(module modulegen.ModuleInputs) error {
return errors.Wrap(err, "cannot generate python stubs -- generator script encountered an error")
}

mainPath := filepath.Join(module.ModuleName, "src", "main.py")
resourcePath := filepath.Join(module.ModuleName, "src", "models", fmt.Sprintf("%s.py", module.ModelSnake))
//nolint:gosec
mainFile, err := os.Create(mainPath)
resourceFile, err := os.Create(resourcePath)
if err != nil {
return errors.Wrap(err, "cannot generate python stubs -- unable to open file")
}
defer utils.UncheckedErrorFunc(mainFile.Close)
_, err = mainFile.Write(out)
defer utils.UncheckedErrorFunc(resourceFile.Close)
_, err = resourceFile.Write(out)
if err != nil {
return errors.Wrap(err, "cannot generate python stubs -- unable to write to file")
}
Expand Down
47 changes: 47 additions & 0 deletions cli/module_generate/_templates/python/src/models/tmpl-resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from typing import ClassVar, Mapping, Sequence, Self
from viam.proto.app.robot import ComponentConfig
from viam.proto.common import ResourceName
from viam.resource.base import ResourceBase
from viam.resource.easy_resource import EasyResource
from viam.resource.types import Model, ModelFamily
from viam.{{ .ResourceType }}s.{{ .ResourceSubtype }} import {{ .ResourceSubtypePascal }}


class {{ .ModelPascal }}({{ .ResourceSubtypePascal }}, EasyResource):
MODEL: ClassVar[Model] = "{{ .ModelTriple }}"

@classmethod
def new(cls, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]) -> Self:
"""This method creates a new instance of this {{ .ResourceSubtype }}.
The default implementation sets the name from the `config` parameter and then calls `reconfigure`.
Args:
config (ComponentConfig): The configuration for this resource
dependencies (Mapping[ResourceName, ResourceBase]): The dependencies (both implicit and explicit)
Returns:
Self: The resource
"""
return super().new(config, dependencies)

@classmethod
def validate_config(cls, config: ComponentConfig) -> Sequence[str]:
"""This method allows you to validate the configuration object received from the machine,
as well as to return any implicit dependencies based on that `config`.
Args:
config (ComponentConfig): The configuration for this resource
Returns:
Sequence[str]: A list of implicit dependencies
"""
return []

def reconfigure(self, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]):
"""This method allows you to dynamically update your service when it receives a new `config` object.
Args:
config (ComponentConfig): The new configuration
dependencies (Mapping[ResourceName, ResourceBase]): Any dependencies (both implicit and explicit)
"""
return super().reconfigure(config, dependencies)
48 changes: 1 addition & 47 deletions cli/module_generate/_templates/python/src/tmpl-main.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,6 @@
import asyncio
from typing import ClassVar, Mapping, Sequence, Self
from viam.module.module import Module
from viam.proto.app.robot import ComponentConfig
from viam.proto.common import ResourceName
from viam.resource.base import ResourceBase
from viam.resource.easy_resource import EasyResource
from viam.resource.types import Model, ModelFamily
from viam.{{ .ResourceType }}s.{{ .ResourceSubtype }} import {{ .ResourceSubtypePascal }}


class {{ .ModelPascal }}({{ .ResourceSubtypePascal }}, EasyResource):
MODEL: ClassVar[Model] = "{{ .ModelTriple }}"

@classmethod
def new(cls, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]) -> Self:
"""This method creates a new instance of this {{ .ResourceSubtype }}.
The default implementation sets the name from the `config` parameter and then calls `reconfigure`.
Args:
config (ComponentConfig): The configuration for this resource
dependencies (Mapping[ResourceName, ResourceBase]): The dependencies (both implicit and explicit)
Returns:
Self: The resource
"""
return super().new(config, dependencies)

@classmethod
def validate_config(cls, config: ComponentConfig) -> Sequence[str]:
"""This method allows you to validate the configuration object received from the machine,
as well as to return any implicit dependencies based on that `config`.
Args:
config (ComponentConfig): The configuration for this resource
Returns:
Sequence[str]: A list of implicit dependencies
"""
return []

def reconfigure(self, config: ComponentConfig, dependencies: Mapping[ResourceName, ResourceBase]):
"""This method allows you to dynamically update your service when it receives a new `config` object.
Args:
config (ComponentConfig): The new configuration
dependencies (Mapping[ResourceName, ResourceBase]): Any dependencies (both implicit and explicit)
"""
return super().reconfigure(config, dependencies)
from .models.{{ .ModelSnake }} import {{ .ModelPascal }}


if __name__ == '__main__':
Expand Down
2 changes: 1 addition & 1 deletion cli/module_generate/modulegen/inputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ type ModuleInputs struct {
ResourceTypePascal string `json:"-"`
ModelPascal string `json:"-"`
ModelCamel string `json:"-"`
ModelSnake string `json:"-"`
ModelTriple string `json:"-"`
ModelLowercase string `json:"-"`
ModelReadmeLink string `json:"-"`
SDKVersion string `json:"-"`
}
Expand Down
22 changes: 8 additions & 14 deletions cli/module_generate/scripts/generate_stubs.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,17 +171,15 @@ def main(
imports.append("from typing import Optional")
imports.append("from viam.utils import ValueTypes")
elif cstmt.name == "get_geometries":
imports.append("from typing import List, Optional")
imports.append("from typing import Any, Dict, List, Optional")
imports.append("from viam.proto.common import Geometry")

model_name_pascal = "".join(
[word.capitalize() for word in slugify(model_name).split("-")]
)
main_file = '''
import asyncio
resource_file = '''
from typing import ClassVar, Mapping, Sequence
from typing_extensions import Self
from viam.module.module import Module
from viam.proto.app.robot import ComponentConfig
from viam.proto.common import ResourceName
from viam.resource.base import ResourceBase
Expand Down Expand Up @@ -232,11 +230,6 @@ def reconfigure(self, config: ComponentConfig, dependencies: Mapping[ResourceNam
{8}
{9}
if __name__ == '__main__':
asyncio.run(Module.run_from_registry())
'''.format(
"\n".join(list(set(imports))),
resource_type,
Expand All @@ -249,19 +242,20 @@ def reconfigure(self, config: ComponentConfig, dependencies: Mapping[ResourceNam
'\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")
f_name = os.path.join(mod_name, "src", "models", "resource.py")
with open(f_name, "w+") as f:
f.write(main_file)
f.write(resource_file)
try:
f.seek(0)
subprocess.check_call([sys.executable, "-m", "black", f_name, "-q"])
f.seek(0)
main_file = f.read()
resource_file = f.read()
except subprocess.CalledProcessError:
pass
os.remove(f_name)
sorted_main = isort.code(main_file)
return sorted_main
sorted_code = isort.code(resource_file)

return sorted_code


if __name__ == "__main__":
Expand Down

0 comments on commit 810cd06

Please sign in to comment.