1414
1515from os .path import exists , join
1616from pathlib import Path
17+ from typing import Any
1718
1819from scripts .download_samm_cli import download_samm_cli
1920
@@ -37,6 +38,14 @@ def _get_client_path():
3738
3839 return cli_path
3940
41+ @staticmethod
42+ def _format_argument (key : str , value : Any ) -> str :
43+ """Helper method to format command line arguments."""
44+ if len (key ) == 1 :
45+ return f"-{ key } ={ value } "
46+ key_formatted = key .replace ("_" , "-" )
47+ return f"--{ key_formatted } ={ value } "
48+
4049 def _validate_client (self ):
4150 """Validate SAMM CLI.
4251
@@ -45,22 +54,20 @@ def _validate_client(self):
4554 if not exists (self ._samm ):
4655 download_samm_cli ()
4756
48- def _call_function (self , function_name , path_to_model , * args , ** kwargs ):
57+ def _call_function (self , function_name , path_to_model , * args , command_type = "aspect" , ** kwargs ):
4958 """Run a SAMM CLI function as a subprocess."""
50- call_args = [self ._samm , "aspect" , path_to_model ] + function_name .split ()
59+ call_args = [self ._samm , command_type , path_to_model ] + function_name .split ()
5160
5261 if args :
5362 call_args .extend ([f"-{ param } " for param in args ])
5463
5564 if kwargs :
5665 for key , value in kwargs .items ():
57- if len (key ) == 1 :
58- arg = f"-{ key } ={ value } "
66+ if isinstance (value , (list , tuple )):
67+ for item in value :
68+ call_args .append (self ._format_argument (key , item ))
5969 else :
60- key = key .replace ("_" , "-" )
61- arg = f"--{ key } ={ value } "
62-
63- call_args .append (arg )
70+ call_args .append (self ._format_argument (key , value ))
6471
6572 if platform .system () == "Darwin" : # macOS
6673 call_args = shlex .join (call_args )
@@ -76,6 +83,36 @@ def validate(self, path_to_model, *args, **kwargs):
7683 """
7784 self ._call_function ("validate" , path_to_model , * args , ** kwargs )
7885
86+ def prettyprint (self , path_to_model , * args , ** kwargs ):
87+ """Pretty-print Aspect Model.
88+
89+ Formats the Aspect Model file with proper indentation and structure.
90+
91+ param path_to_model: local path to the aspect model file (*.ttl)
92+ possible arguments:
93+ - output, o: the output will be saved to the given file
94+ - overwrite, w: overwrite the input file (use as flag without value)
95+ - custom-resolver: use an external resolver for the resolution of the model elements
96+ """
97+ self ._call_function ("prettyprint" , path_to_model , * args , ** kwargs )
98+
99+ def usage (self , path_to_model , * args , ** kwargs ):
100+ """Shows where model elements are used in an Aspect.
101+
102+ param path_to_model: local path to the aspect model file (*.ttl) or an element URN
103+ possible arguments:
104+ - models_root: when model is a URN, at least one models root must be specified
105+ - custom_resolver: use an external resolver for the resolution of the model elements
106+
107+ Examples:
108+ # Show usage for an Aspect Model file
109+ samm_cli.usage("AspectModelFile.ttl")
110+
111+ # Show usage for an element URN with models root
112+ samm_cli.usage("urn:samm:org.eclipse.example:1.0.0#MyElement", models_root="/path/to/models")
113+ """
114+ self ._call_function ("usage" , path_to_model , * args , ** kwargs )
115+
79116 def to_openapi (self , path_to_model , * args , ** kwargs ):
80117 """Generate OpenAPI specification for an Aspect Model.
81118
@@ -157,3 +194,283 @@ def to_svg(self, path_to_model, *args, **kwargs):
157194 - custom-resolver: use an external resolver for the resolution of the model elements
158195 """
159196 self ._call_function ("to svg" , path_to_model , * args , ** kwargs )
197+
198+ def to_java (self , path_to_model , * args , ** kwargs ):
199+ """Generate Java classes from an Aspect Model.
200+
201+ param path_to_model: local path to the aspect model file (*.ttl)
202+ possible arguments:
203+ - output_directory, d: output directory to write files to (default: current directory)
204+ - package_name, pn: package to use for generated Java classes
205+ - no_jackson, nj: disable Jackson annotation generation in generated Java classes
206+ (use as flag without value)
207+ - no_jackson_jsonformat_shape, njjs: disable JsonFormat.
208+ Shape annotation generation in generated Java classes (use as flag without value)
209+ - json_type_info, jti: if Jackson annotations are enabled, determines the value of JsonTypeInfo.Id
210+ (default: DEDUCTION)
211+ - template_library_file, tlf: the path and name of the Velocity template file containing the macro library
212+ - execute_library_macros, elm: execute the macros provided in the Velocity macro library
213+ (use as flag without value)
214+ - static, s: generate Java domain classes for a Static Meta Model (use as flag without value)
215+ - custom_resolver: use an external resolver for the resolution of the model elements
216+ - name_prefix, namePrefix: name prefix for generated Aspect, Entity Java classes
217+ - name_postfix, namePostfix: name postfix for generated Aspect, Entity Java classes
218+ """
219+ self ._call_function ("to java" , path_to_model , * args , ** kwargs )
220+
221+ def to_asyncapi (self , path_to_model , * args , ** kwargs ):
222+ """Generate AsyncAPI specification for an Aspect Model.
223+
224+ param path_to_model: local path to the aspect model file (*.ttl)
225+ possible arguments:
226+ - output, o: output file path (default: stdout)
227+ - channel_address, ca: sets the channel address (i.e., for MQTT, the topic's name)
228+ - application_id, ai: sets the application id, e.g. an identifying URL
229+ - semantic_version, sv: use the full semantic version from the Aspect Model
230+ as the version for the Aspect API (use as flag without value)
231+ - language, l: the language from the model for which an AsyncAPI specification should be generated
232+ (default: en)
233+ - separate_files, sf: create separate files for each schema (use as flag without value)
234+ - custom_resolver: use an external resolver for the resolution of the model elements
235+ """
236+ self ._call_function ("to asyncapi" , path_to_model , * args , ** kwargs )
237+
238+ def to_jsonld (self , path_to_model , * args , ** kwargs ):
239+ """Generate JSON-LD representation of an Aspect Model.
240+
241+ param path_to_model: local path to the aspect model file (*.ttl)
242+ possible arguments:
243+ - output, o: output file path (default: stdout)
244+ - custom_resolver: use an external resolver for the resolution of the model elements
245+ """
246+ self ._call_function ("to jsonld" , path_to_model , * args , ** kwargs )
247+
248+ def to_sql (self , path_to_model , * args , ** kwargs ):
249+ """Generate SQL script that sets up a table for data for this Aspect.
250+
251+ param path_to_model: local path to the aspect model file (*.ttl)
252+ possible arguments:
253+ - output, o: output file path (default: stdout)
254+ - language, l: the language from the model to use for generated comments
255+ - dialect, d: the SQL dialect to generate for (default: databricks)
256+ - mapping_strategy, s: the mapping strategy to use (default: denormalized)
257+ - include_table_comment, tc: include table comment in the generated SQL script (default: true)
258+ - include_column_comments, cc: include column comments in the generated SQL script (default: true)
259+ - table_command_prefix, tcp: the prefix to use for Databricks table creation commands
260+ (default: CREATE TABLE IF NOT EXISTS)
261+ - decimal_precision, dp: the precision to use for Databricks decimal columns (default: 10)
262+ - custom_column, col: additional custom column definition, e.g. for databricks following the pattern
263+ column_name DATATYPE [NOT NULL] [COMMENT 'custom'].
264+ Note: For multiple custom columns, see the special handling in examples.
265+ - custom_resolver: use an external resolver for the resolution of the model elements
266+
267+ Examples:
268+ # Generate SQL script to stdout with defaults
269+ samm_cli.to_sql("AspectModel.ttl")
270+
271+ # Generate SQL script to file with specific dialect
272+ samm_cli.to_sql("AspectModel.ttl", output="schema.sql", dialect="databricks")
273+ # or using short forms
274+ samm_cli.to_sql("AspectModel.ttl", o="schema.sql", d="databricks")
275+
276+ # Generate with custom settings
277+ samm_cli.to_sql("AspectModel.ttl",
278+ output="schema.sql",
279+ language="de",
280+ mapping_strategy="denormalized",
281+ include_table_comment="false",
282+ decimal_precision="15")
283+
284+ # Generate with custom column
285+ samm_cli.to_sql("AspectModel.ttl", custom_column="column_name STRING NOT NULL COMMENT 'custom'")
286+
287+ # For multiple custom columns, you may need to modify the _call_function method
288+ # or call the CLI directly. Current implementation supports single custom column.
289+ samm_cli.to_sql("AspectModel.ttl", custom_column=("column1 STRING", "column2 INT"))
290+ """
291+ self ._call_function ("to sql" , path_to_model , * args , ** kwargs )
292+
293+ def to_aas (self , path_to_model , * args , ** kwargs ):
294+ """Generate an Asset Administration Shell (AAS) submodel template from an Aspect Model.
295+
296+ param path_to_model: local path to the aspect model file (*.ttl)
297+ possible arguments:
298+ - output, o: output file path (default: stdout)
299+ - format, f: output file format (XML, JSON, or AASX, default: XML)
300+ - aspect_data, a: path to a JSON file containing aspect data corresponding to the Aspect Model
301+ - custom_resolver: use an external resolver for the resolution of the model elements
302+ """
303+ self ._call_function ("to aas" , path_to_model , * args , ** kwargs )
304+
305+ def edit_move (self , path_to_model , element , namespace = None , * args , ** kwargs ):
306+ """Move a model element definition from its current place to another existing or
307+ new file in the same or another namespace.
308+
309+ param path_to_model: local path to the aspect model file (*.ttl)
310+ param element: the model element to move (e.g., MyAspect otherFile.ttl)
311+ param namespace: optional namespace URN (e.g., urn:samm:org.eclipse.example.myns:1.0.0)
312+ possible arguments:
313+ - dry_run: don't write changes to the file system, but print a report of changes that would be performed
314+ (use as flag)
315+ - details: when used with --dry-run, include details about model content changes in the report
316+ (use as flag)
317+ - copy_file_header: when a model element is moved to a new file,
318+ copy the file header from the source file to the new file (use as flag)
319+ - force: when a new file is to be created, but it already exists in the file system,
320+ the operation will be cancelled, unless --force is used (use as flag)
321+
322+ Examples:
323+ # Move element to another file
324+ samm_cli.edit_move("AspectModel.ttl", "MyAspect otherFile.ttl")
325+
326+ # Move element to another namespace
327+ samm_cli.edit_move("AspectModel.ttl", "MyAspect someFileInOtherNamespace.ttl",
328+ "urn:samm:org.eclipse.example.myns:1.0.0")
329+
330+ # Dry run with details
331+ samm_cli.edit_move("AspectModel.ttl", "MyAspect otherFile.ttl", None, "dry-run", "details")
332+
333+ # Move with copy file header and force
334+ samm_cli.edit_move("AspectModel.ttl", "MyAspect newFile.ttl", None, "copy-file-header", "force")
335+ """
336+ # Build the function name with positional arguments
337+ function_name = f"edit move { element } "
338+ if namespace :
339+ function_name += f" { namespace } "
340+
341+ self ._call_function (function_name , path_to_model , * args , ** kwargs )
342+
343+ def edit_newversion (self , path_to_model , version_type = None , * args , ** kwargs ):
344+ """Create a new version of an existing file or a complete namespace.
345+
346+ param path_to_model: local path to the aspect model file (*.ttl) or a namespace URN
347+ param version_type: version update type - "major", "minor", or "micro" (optional, pass as flag)
348+ possible arguments:
349+ - major: update the major version (use as flag)
350+ - minor: update the minor version (use as flag)
351+ - micro: update the micro version (use as flag)
352+ - dry_run: don't write changes to the file system,
353+ but print a report of changes that would be performed (use as flag)
354+ - details: when used with --dry-run, include details about model content changes in the report (use as flag)
355+ - force: when a new file is to be created, but it already exists in the file system,
356+ the operation will be cancelled, unless --force is used (use as flag)
357+ - models_root: when model is a URN, at least one models root must be specified
358+
359+ Examples:
360+ # Update major version
361+ samm_cli.edit_newversion("AspectModel.ttl", "major")
362+
363+ # Update minor version
364+ samm_cli.edit_newversion("AspectModel.ttl", "minor")
365+
366+ # Update micro version
367+ samm_cli.edit_newversion("AspectModel.ttl", "micro")
368+
369+ # Dry run with details for major version update
370+ samm_cli.edit_newversion("AspectModel.ttl", "major", "dry-run", "details")
371+
372+ # Force update with specific version type
373+ samm_cli.edit_newversion("AspectModel.ttl", "minor", "force")
374+
375+ # Update namespace with models root
376+ samm_cli.edit_newversion("urn:samm:org.eclipse.example:1.0.0", "major", models_root="/path/to/models")
377+ """
378+ # Add version type to args if specified
379+ args_list = list (args )
380+ if version_type and version_type in ("major" , "minor" , "micro" ):
381+ args_list .insert (0 , version_type )
382+
383+ self ._call_function ("edit newversion" , path_to_model , * args_list , ** kwargs )
384+
385+ def aas_to_aspect (self , aas_file , * args , ** kwargs ):
386+ """Translate Asset Administration Shell (AAS) Submodel Templates to Aspect Models.
387+
388+ param aas_file: path to the AAS file (*.aasx, *.xml, *.json)
389+ possible arguments:
390+ - output_directory, d: output directory to write files to (default: current directory)
391+ - submodel_template, s: selected submodel template for generating;
392+ run aas_list() to list available templates.
393+ Note: For multiple templates, pass as a list.
394+
395+ Examples:
396+ # Convert all submodel templates to Aspect Models
397+ samm_cli.aas_to_aspect("AssetAdminShell.aasx")
398+
399+ # Convert with specific output directory
400+ samm_cli.aas_to_aspect("AssetAdminShell.aasx",
401+ output_directory="./output")
402+ # or using short form
403+ samm_cli.aas_to_aspect("AssetAdminShell.aasx", d="./output")
404+
405+ # Convert specific submodel templates
406+ samm_cli.aas_to_aspect("AssetAdminShell.aasx",
407+ submodel_template=["1", "2"])
408+ # or using short form
409+ samm_cli.aas_to_aspect("AssetAdminShell.aasx", s=["1", "2"])
410+ """
411+ self ._call_function ("to aspect" , aas_file , * args , command_type = "aas" , ** kwargs )
412+
413+ def aas_list (self , aas_file , * args , ** kwargs ):
414+ """Retrieve a list of submodel templates contained within the provided Asset Administration Shell (AAS) file.
415+
416+ param aas_file: path to the AAS file (*.aasx, *.xml, *.json)
417+
418+ Examples:
419+ # List all submodel templates in an AAS file
420+ samm_cli.aas_list("AssetAdminShell.aasx")
421+ """
422+ self ._call_function ("list" , aas_file , * args , command_type = "aas" , ** kwargs )
423+
424+ def package_import (self , namespace_package , * args , ** kwargs ):
425+ """Imports a Namespace Package (file or URL) into a given models' directory.
426+
427+ param namespace_package: path to the namespace package file (.zip) or URL
428+ possible arguments:
429+ - models_root: target models directory (required)
430+ - dry_run: don't write changes to the file system, but print a report of changes that would be performed
431+ (use as flag)
432+ - details: when used with --dry-run, include details about model content changes in the report (use as flag)
433+ - force: when a new file is to be created, but it already exists in the file system,
434+ the operation will be cancelled, unless --force is used (use as flag)
435+
436+ Examples:
437+ # Import a package into models directory
438+ samm_cli.package_import("MyPackage.zip", models_root="c:\\ models")
439+
440+ # Import from URL
441+ samm_cli.package_import("https://example.com/package.zip", models_root="/path/to/models")
442+
443+ # Dry run with details
444+ samm_cli.package_import("MyPackage.zip", "dry-run", "details", models_root="c:\\ models")
445+
446+ # Force import
447+ samm_cli.package_import("MyPackage.zip", "force", models_root="c:\\ models")
448+ """
449+ self ._call_function ("import" , namespace_package , * args , command_type = "package" , ** kwargs )
450+
451+ def package_export (self , model_or_urn , * args , ** kwargs ):
452+ """Exports an Aspect Model with its dependencies or a complete namespace to a Namespace Package (.zip).
453+
454+ param model_or_urn: path to aspect model file (*.ttl) or namespace URN
455+ possible arguments:
456+ - output, o: output file path (default: stdout); as ZIP is a binary format,
457+ it is strongly recommended to output the result to a file
458+ - models_root: when exporting a namespace URN, models root must be specified
459+
460+ Examples:
461+ # Export an Aspect Model with dependencies
462+ samm_cli.package_export("AspectModel.ttl", output="package.zip")
463+ # or using short form
464+ samm_cli.package_export("AspectModel.ttl", o="package.zip")
465+
466+ # Export a complete namespace
467+ samm_cli.package_export(
468+ "urn:samm:org.eclipse.example.myns:1.0.0",
469+ output="package.zip",
470+ models_root="/path/to/models",
471+ )
472+
473+ # Export to specific location
474+ samm_cli.package_export("AspectModel.ttl", output="c:\\ exports\\ my-package.zip")
475+ """
476+ self ._call_function ("export" , model_or_urn , * args , command_type = "package" , ** kwargs )
0 commit comments