CrayLabs / SmartSim

SmartSim Infrastructure Library.
BSD 2-Clause "Simplified" License
229 stars 36 forks source link

Enumerate and Expose the Smart CLI Return Codes #402

Open MattToast opened 11 months ago

MattToast commented 11 months ago

From review feedback for #397 that was decided to be moved to its own issue

Description

It was noticed that the smart CLI could exit with the same return code in two distinctly different ways: 1) With malformed commands/arguments (e.g. smart validaet) 2) The mini-experiment from smart validate raises an exception

Furthermore the smart does not actually exit the python interpreter with the returned code:

# In `smartsim._core._cli.__main__`

if __name__ == "__main__"
    main()
#   ^^^^^^
#   To actually expose the return value of this fn, a `SystemExit`
#   exception must be raised

This could make debugging a shell script using smart difficult, particularly if that script wanted to branch based on a return code. We should consider making the smart menu items return a distinct SmartCLIReturnCode enumeration and expose that value to callers of smart.

Justification

By having the menu items return a distinct enumeration type, it will be much easier to check to make sure that a singe return code is not mapped to multiple meanings. It also has the added benefit of making menu items more readable.

By exposing the return code, users will be able automate their use of smart by adding branching logic to scripts.

Implementation Strategy

In smartsim._core._cli.utils add a new enum to the nature of:

class SmartCLIReturnCode(enum.Enum):
    UNKNOWN_ERROR = -1
    NO_ERROR = 0
    GENERIC_FAILURE = 1
    MALFORMED_ARGS = 2
    # etc. as needed

and update the _CliHandler type alias to:

_CliHandler = t.Callable[[Namespace], SmartCLIReturnCode]

This will lead to type errors that mypy can find and should be addressed by having the integer return types substituted with the appropriate return enum.

Finally, update smartsim._core._cli.__main__ to have the main method "unwrap" the enumeration and raise a SystemExit to expose to the end user.

def main() -> int:
    # yada, yada
    my_returned_enum: SmartCLIReturnCode = ...
    return my_returned_enum.value

if __name__ == '__main__'
    sys.exit(main())

Implementation Strategy Note

With the merge of #397, it may be required to workshop this approach to make sure that is extensible with other plugins (programs external to SmartSim that can still be found, registered, and launched through smart) that may not map the same meanings to the same return code values and as such should not be expected to use the enumeration.

mellis13 commented 11 months ago

@mellis13 Let's make at CLI tag to track this.