-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from bartkl/cli
Cli
- Loading branch information
Showing
8 changed files
with
271 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
## Installation | ||
Make sure you have Python (≥ 3.11) and Poetry installed. | ||
|
||
Run `poetry install` to have it set up a virtual environment for you with the necessary dependencies installed and configuration taken care of. | ||
|
||
## Running `cim2linkml` | ||
|
||
#### From within the virtual environment | ||
Activate your virtual environment and you should be able to use the `cim2linkml` script. | ||
|
||
``` | ||
$ poetry shell | ||
$ cim2linkml --help | ||
# ... | ||
``` | ||
|
||
#### Using `poetry run` | ||
You can also run the script inside the virtual environment without activating it. | ||
|
||
``` | ||
$ poetry run cim2linkml --help | ||
# ... | ||
``` | ||
|
||
|
||
### Usage | ||
``` | ||
Usage: cim2linkml [OPTIONS] QEA_FILE | ||
Generates LinkML schemas from the supplied Sparx EA QEA database file. | ||
You can specify which packages in the UML model to generate schemas from | ||
using the `--package` parameter, where you provide the fully qualified | ||
package name (e.g. `TC57CIM.IEC61970.Base.Core') of the package to select | ||
it. | ||
If the specified package is a leaf package, a single schema file will be | ||
generated. | ||
If the provided package is a non-leaf package, by default its subpackages | ||
are included and a schema file per package is created. A single schema file | ||
can also be created by passing `--single-schema'. Finally, it's possible to | ||
ignore all subpackages and create a single schema file just for the | ||
specified package alone. To achieve this, pass `--ignore-subpackages'. | ||
Options: | ||
-p, --package TEXT Fully qualified package name. [default: TC57CIM] | ||
--single-schema If true, a single schema is created, a schema per | ||
package otherwise. | ||
--ignore-subpackages If passed, all subpackages of the provided package | ||
are ignored, i.e. only the package itself is | ||
selected. | ||
-o, --output-dir PATH Directory where schemas will be outputted. [default: | ||
schemas] | ||
--help Show this message and exit. | ||
``` | ||
|
||
### Examples | ||
|
||
#### The entire CIM | ||
|
||
##### Schema per package | ||
If no package is specified, it defaults to TC57CIM, i.e. the entire CIM. For non-leaf | ||
packages like this one, the default behavior is to generate a schema for each subpackage. | ||
|
||
```shell | ||
$ cim2linkml data/cim.qea | ||
``` | ||
|
||
##### Single schema | ||
If generating a single schema file is desired, this can be done as follows: | ||
|
||
```shell | ||
$ cim2linkml data/cim.qea --single-schema | ||
``` | ||
|
||
#### Leaf package | ||
Leaf peackages by definition don't have subpackages and therefore always become a single schema. | ||
|
||
```shell | ||
$ cim2linkml data/cim.qea -p TC57CIM.IEC61970.Base.Wires | ||
``` | ||
|
||
#### Non-leaf package | ||
|
||
##### Including subpackages | ||
By default, when providing a non-leaf package, all subpackages are included and schema files are | ||
created for each package. | ||
|
||
```shell | ||
$ cim2linkml data/cim.qea -p TC57CIM.IEC61970 | ||
``` | ||
|
||
If a single schema file is desired, `--single-schema` can be passed. | ||
|
||
##### Ignoring subpackages | ||
If only selecting the package itself is desired, i.e. not including subpackages, one can pass `--ignore-subpackages`. | ||
Note that in this case, it is always a single schema file (`--single-schema` is implied). | ||
|
||
```shell | ||
$ cim2linkml data/cim.qea -p TC57CIM.IEC61970 --ignore-subpackages | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +0,0 @@ | ||
import cProfile | ||
import sqlite3 | ||
|
||
from cim_to_linkml.generator import LinkMLGenerator | ||
from cim_to_linkml.parser import parse_uml_project | ||
from cim_to_linkml.read import read_uml_project | ||
from cim_to_linkml.writer import init_yaml_serializer, write_schema | ||
|
||
init_yaml_serializer() | ||
|
||
|
||
def main(): | ||
db_file = "data/iec61970cim17v40_iec61968cim13v13b_iec62325cim03v17b_CIM100.1.1.1.qea" | ||
with sqlite3.connect(db_file) as conn: | ||
uml_project = parse_uml_project(*read_uml_project(conn)) | ||
|
||
generator = LinkMLGenerator(uml_project) | ||
for pkg_id in generator.uml_project.packages.by_id: | ||
if pkg_id == 2: | ||
continue # `Model` base package. | ||
|
||
schema = generator.gen_schema_for_package(pkg_id) | ||
write_schema(schema) | ||
|
||
|
||
if __name__ == "__main__": | ||
# cProfile.run("main()", sort="tottime") | ||
main() | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import cProfile | ||
import logging | ||
import os | ||
import sqlite3 | ||
from itertools import chain | ||
from pathlib import Path | ||
|
||
import click | ||
|
||
from cim_to_linkml.generator import LinkMLGenerator | ||
from cim_to_linkml.parser import parse_uml_project | ||
from cim_to_linkml.read import read_uml_project | ||
from cim_to_linkml.writer import init_yaml_serializer, write_schema | ||
|
||
LOG_FORMAT = "[%(asctime)s] [%(levelname)s] %(message)s" | ||
|
||
logger = logging.getLogger(__name__) | ||
logging.basicConfig(format=LOG_FORMAT) | ||
|
||
|
||
init_yaml_serializer() | ||
|
||
|
||
@click.command() | ||
@click.argument("cim_db", type=click.Path(exists=True, path_type=Path), nargs=1, metavar="QEA_FILE") | ||
@click.option( | ||
"--package", | ||
"-p", | ||
type=str, | ||
show_default=True, | ||
default="TC57CIM", | ||
help="Fully qualified package name.", | ||
) | ||
@click.option( | ||
"--single-schema", | ||
is_flag=True, | ||
default=False, | ||
show_default=True, | ||
help="If true, a single schema is created, a schema per package otherwise.", | ||
) | ||
@click.option( | ||
"--ignore-subpackages", | ||
is_flag=True, | ||
default=False, | ||
show_default=True, | ||
help="If passed, all subpackages of the provided package are ignored, i.e. only the package itself is selected.", | ||
) | ||
@click.option( | ||
"--output-dir", | ||
"-o", | ||
default=Path("schemas"), | ||
show_default=True, | ||
type=click.Path(path_type=Path), | ||
help="Directory where schemas will be outputted.", | ||
) | ||
def cli( | ||
cim_db, | ||
package, | ||
single_schema, | ||
ignore_subpackages, | ||
output_dir, | ||
): | ||
""" | ||
Generates LinkML schemas from the supplied Sparx EA QEA database file. | ||
You can specify which packages in the UML model to generate schemas from | ||
using the `--package` parameter, where you provide the fully qualified | ||
package name (e.g. `TC57CIM.IEC61970.Base.Core') of the package to select it. | ||
If the specified package is a leaf package, a single schema file will be | ||
generated. | ||
If the provided package is a non-leaf package, by default its subpackages are | ||
included and a schema file per package is created. A single schema file can also | ||
be created by passing `--single-schema'. | ||
Finally, it's possible to ignore all subpackages and create a single schema file | ||
just for the specified package alone. To achieve this, pass `--ignore-subpackages'. | ||
""" | ||
|
||
with sqlite3.connect(cim_db) as conn: | ||
uml_project = parse_uml_project(*read_uml_project(conn)) | ||
|
||
try: | ||
uml_package = uml_project.packages.by_qualified_name[package] | ||
except KeyError: | ||
click.echo(f"Ignoring unknown package: `{package}'.", err=True) | ||
raise SystemExit(1) | ||
|
||
if uml_project.packages.is_leaf_package(package): | ||
single_schema = True | ||
ignore_subpackages = True | ||
|
||
if ignore_subpackages: | ||
uml_packages = [uml_package] | ||
single_schema = True | ||
else: | ||
uml_packages = [p for qname, p in uml_project.packages.by_qualified_name.items() if qname.startswith(package)] | ||
|
||
generator = LinkMLGenerator(uml_project) | ||
os.makedirs(output_dir, exist_ok=True) | ||
|
||
if single_schema: | ||
uml_classes = list( | ||
chain.from_iterable( | ||
uml_class for p in uml_packages if (uml_class := uml_project.classes.by_package.get(p.id)) | ||
) | ||
) | ||
schema = generator.gen_schema_for_package(uml_package.id, uml_classes) | ||
|
||
schema_path = os.path.join(output_dir, package) + ".yml" | ||
write_schema(schema, schema_path) | ||
else: | ||
for uml_package in uml_packages: | ||
uml_classes = uml_project.classes.by_package.get(uml_package.id, []) | ||
schema = generator.gen_schema_for_package(uml_package.id, uml_classes) | ||
|
||
qname = uml_project.packages.get_qualified_name(uml_package.id) | ||
package_path = qname.split(".") | ||
dir_path = os.path.join(output_dir, os.path.sep.join(package_path[:-1])) | ||
file_name = package_path[-1] + ".yml" | ||
out_file = os.path.join(dir_path, file_name) | ||
os.makedirs(dir_path, exist_ok=True) | ||
write_schema(schema, out_file) | ||
|
||
|
||
if __name__ == "__main__": | ||
# cProfile.run("main()", sort="tottime") | ||
cli.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters