import asyncio import sys from jw.pkg.lib.Cmd import Cmd from jw.pkg.lib.ExecApp import ExecApp # -- A minimal root command so the app can be built without a command tree. class RootCmd(Cmd): def __init__(self, parent): super().__init__(parent, 'root', 'Root command') async def _run(self, args): pass # -- Counts the close() calls made by App.__aexit__() when the async context # manager exits. class RecordingExecApp(ExecApp): closed = 0 def close(self): RecordingExecApp.closed += 1 super().close() # -- App.__init__ builds the parser from sys.argv, so point it at a clean # command line while constructing the app. saved_argv = sys.argv sys.argv = ['jw-pkg-test'] try: app = RecordingExecApp(description = 'ExecApp test', root = RootCmd) finally: sys.argv = saved_argv # -- ExecApp registers the exec-related options on the top-level parser. opts = [ o for a in app.parser._actions for o in getattr(a, 'option_strings', ()) ] for opt in ('--interactive', '--verbose', '--target'): assert opt in opts, f'{opt} must be registered by ExecApp' # -- Exiting the async context must close the app, through the # App.__aexit__() that ExecApp.__aexit__() chains to. async def exit_context(): async with app: pass asyncio.run(exit_context()) assert RecordingExecApp.closed == 1, 'exiting the app context must close the app' print('All ExecApp tests passed')