import sys
import typing
import argparse
from turbo_turtle import __version__
from turbo_turtle import _settings
from turbo_turtle import _docs
from turbo_turtle import _utilities
from turbo_turtle import _fetch
from turbo_turtle import geometry_xyplot
from turbo_turtle._abaqus_python.turbo_turtle_abaqus import parsers
def _print_abaqus_path_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(add_help=False)
# This parser has no arguments. Current implementation acts like a flag
return parser
[docs]
def _print_abaqus_path_location() -> None:
"""Print the absolute path to the Turbo Turtle Abaqus Python package directory
Exits with a non-zero exit code if the settings variable ``_abaqus_python_parent_abspath`` does not exist.
"""
if not _settings._abaqus_python_parent_abspath.exists():
sys.exit("Could not find a documented path to the Abaqus Python package directory")
else:
print(_settings._abaqus_python_parent_abspath)
[docs]
def add_abaqus_and_cubit(parsers: typing.List[argparse.ArgumentParser]) -> None:
"""Add the Abaqus and Cubit command arguments to each parser in the parsers list
:param list parsers: List of parsers to run ``add_argument`` for the command options
"""
for parser in parsers:
parser.add_argument(
"--abaqus-command",
nargs="+",
default=_settings._default_abaqus_options,
help="Abaqus executable options (default: %(default)s)",
)
parser.add_argument(
"--cubit-command",
nargs="+",
default=_settings._default_cubit_options,
help="Cubit executable options (default: %(default)s)",
)
parser.add_argument(
"--backend",
choices=_settings._backend_choices,
default=_settings._default_backend,
help="Back end software (default: %(default)s)",
)
[docs]
def append_cubit_help(text: str, append: str = "with Abaqus, Cubit, or Gmsh (work-in-progress)") -> str:
"""Append common short help with optional Cubit text
:param str text: original text
:param str append: new text
:returns: appended text
:rtype: str
"""
return f"{text} {append}"
[docs]
def append_cubit_description(
text: str,
# fmt: off
append: str = "Defaults to Abaqus, but can optionally run Cubit (Gmsh implementation is a work-in-progress). "
"Cubit and Gmsh backends replace hyphens with underscores in part name(s) for ACIS "
"compatibility. Cubit backend ignores model/assembly name arguments.",
# fmt: on
) -> str:
"""Append common long description with optional Cubit text
:param str text: original text
:param str append: new text
:returns: appended text
:rtype: str
"""
return f"{text} {append}"
[docs]
def get_parser() -> argparse.ArgumentParser:
"""Get parser object for command line options
:return: parser
:rtype: ArgumentParser
"""
main_description = (
"A collection of solid body modeling tools for 2D sketched, 2D axisymmetric, and 3D revolved models. "
"Implemented for Abaqus, Cubit, and Gmsh (work-in-progress) as backend modeling and meshing software. "
"Most of the interface options and descriptions use Abaqus modeling concepts and language. "
"Turbo-Turtle makes a best effort to maintain common behaviors and features across each third-party "
"software's modeling concepts."
)
main_parser = argparse.ArgumentParser(
description=main_description,
prog=_settings._project_name_short,
)
main_parser.add_argument(
"-V",
"--version",
action="version",
version=f"{_settings._project_name_short} {__version__}",
)
subparsers = main_parser.add_subparsers(
title="subcommands",
metavar="{subcommand}",
dest="subcommand",
)
subparsers.add_parser(
"docs",
help=f"Open the {_settings._project_name_short} HTML documentation",
# fmt: off
description=f"Open the packaged {_settings._project_name_short} HTML documentation in the "
"system default web browser",
# fmt: on
parents=[_docs.get_parser()],
)
subparsers.add_parser(
"fetch",
help=f"Fetch and copy {_settings._project_name} modsim template files and directories",
# fmt: off
description=f"Fetch and copy {_settings._project_name} modsim template files and directories. If no ``FILE`` "
"is specified, all available files will be created. Directories are recursively copied. "
"``pathlib.Path`` recursive pattern matching is possible. The source path is truncated to use the "
"shortest common file prefix, e.g. requesting two files ``common/source/file.1`` and "
"``common/source/file.2`` will create " "``/destination/file.1`` and ``/destination/file.2``, "
"respectively.",
# fmt: on
parents=[_fetch.get_parser()],
)
subparsers.add_parser(
"print-abaqus-path",
help="Print the absolute path to Turbo-Turtle's Abaqus Python compatible package.",
# fmt: off
description="***NOTE: this is an alpha feature for early adopters and developer testing of possible GUI "
"support*** Print the absolute path to Turbo-Turtle's Abaqus Python compatible package. "
"If this directory is on your PYTHONPATH, you can directly import Turbo Turtle Abaqus Python "
"packages in your own scrips (i.e. import turbo_turtle_abaqus.partition)",
# fmt: on
parents=[_print_abaqus_path_parser()],
)
geometry_parser = parsers.geometry_parser(add_help=False, cubit=True)
cylinder_parser = parsers.cylinder_parser(add_help=False, cubit=True)
sphere_parser = parsers.sphere_parser(add_help=False, cubit=True)
partition_parser = parsers.partition_parser(add_help=False, cubit=True)
sets_parser = parsers.sets_parser(add_help=False, cubit=True)
mesh_parser = parsers.mesh_parser(add_help=False, cubit=True)
image_parser = parsers.image_parser(add_help=False, cubit=True)
merge_parser = parsers.merge_parser(add_help=False, cubit=True)
export_parser = parsers.export_parser(add_help=False, cubit=True)
add_abaqus_and_cubit(
[
geometry_parser,
cylinder_parser,
sphere_parser,
partition_parser,
sets_parser,
mesh_parser,
image_parser,
merge_parser,
export_parser,
]
)
subparsers.add_parser(
"geometry",
help=append_cubit_help(parsers.geometry_cli_help),
description=append_cubit_description(parsers.geometry_cli_description),
parents=[geometry_parser],
)
subparsers.add_parser(
"geometry-xyplot",
help="Plot the lines-and-splines as parsed by the geometry subcommand.",
# fmt: off
description="Plot the lines-and-splines as parsed by the geometry subcommand. "
"Lines are shown as solid lines with circle markers at the vertices. "
"Splines are show as dashed lines with plus sign markers at the vertices. "
"If there is more than one part, each part is shown in a unique color.",
# fmt: on
parents=[geometry_parser, geometry_xyplot._get_parser()],
)
subparsers.add_parser(
"cylinder",
help=append_cubit_help(parsers.cylinder_cli_help),
description=append_cubit_description(parsers.cylinder_cli_description),
parents=[cylinder_parser],
)
subparsers.add_parser(
"sphere",
help=append_cubit_help(parsers.sphere_cli_help),
description=append_cubit_description(parsers.sphere_cli_description),
parents=[sphere_parser],
)
subparsers.add_parser(
"partition",
help=append_cubit_help(parsers.partition_cli_help),
description=append_cubit_description(parsers.partition_cli_description),
parents=[partition_parser],
)
subparsers.add_parser(
"sets",
help=append_cubit_help(parsers.sets_cli_help),
description=append_cubit_description(parsers.sets_cli_description),
parents=[sets_parser],
)
subparsers.add_parser(
"mesh",
help=append_cubit_help(parsers.mesh_cli_help),
description=append_cubit_description(parsers.mesh_cli_description),
parents=[mesh_parser],
)
merge_parser = subparsers.add_parser(
"merge",
help=append_cubit_help(parsers.merge_cli_help),
description=append_cubit_description(parsers.merge_cli_description),
parents=[merge_parser],
)
subparsers.add_parser(
"export",
help=append_cubit_help(parsers.export_cli_help),
description=append_cubit_description(parsers.export_cli_description),
parents=[export_parser],
)
subparsers.add_parser(
"image",
help=append_cubit_help(parsers.image_cli_help),
description=append_cubit_description(parsers.image_cli_description),
parents=[image_parser],
)
return main_parser
def main() -> None:
parser = get_parser()
subcommand_list = parser._subparsers._group_actions[0].choices.keys()
args = parser.parse_args()
try:
if args.subcommand not in subcommand_list:
parser.print_help()
elif args.subcommand == "docs":
_docs.main(_settings._installed_docs_index, print_local_path=args.print_local_path)
elif args.subcommand == "fetch":
root_directory = _settings._tutorials_directory.parent
relative_paths = _settings._fetch_subdirectories
_fetch.main(
args.subcommand,
root_directory,
relative_paths,
args.destination,
requested_paths=args.FILE,
overwrite=args.overwrite,
dry_run=args.dry_run,
print_available=args.print_available,
)
elif args.subcommand == "print-abaqus-path":
_print_abaqus_path_location()
elif args.subcommand == "geometry-xyplot":
geometry_xyplot._main(
args.input_file,
args.output_file,
part_name=args.part_name,
unit_conversion=args.unit_conversion,
euclidean_distance=args.euclidean_distance,
delimiter=args.delimiter,
header_lines=args.header_lines,
y_offset=args.y_offset,
rtol=args.rtol,
atol=args.atol,
no_markers=args.no_markers,
annotate=args.annotate,
scale=args.scale,
)
else:
_wrappers, command = _utilities.set_wrappers_and_command(args)
wrapper_command = getattr(_wrappers, args.subcommand)
wrapper_command(args, command)
except RuntimeError as err:
sys.exit(str(err))
if __name__ == "__main__":
main() # pragma: no cover