Coverage for apio/__main__.py: 89%

35 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-23 03:53 +0000

1#!venv/bin/python 

2"""Apio starting point.""" 

3 

4import sys 

5import atexit 

6from apio.common.debug_util import is_debug 

7 

8# -- IMPORTANT: This module is an entry point for both the Apio 

9# -- process and the Scons process (when using under pyinstaller) and 

10# -- therefore can depend only on common functionality under 

11# -- apio.common. 

12 

13 

14debug_enabled = is_debug(1) 

15 

16 

17def on_exit(msg): 

18 """Prints a debug message on process exit. The msg string is passed 

19 from the handler registrations below. 

20 """ 

21 if debug_enabled: 

22 print(msg) 

23 

24 

25def main(): 

26 """Apio starting point.""" 

27 

28 if debug_enabled: 

29 print(f"Apio main(): original argv: {sys.argv}") 

30 

31 # pylint: disable=import-outside-toplevel 

32 

33 # -- Handle the case of the scons subprocess. Because we also use 

34 # -- pyinstaller, without standard pip packages, we can't simply invoke 

35 # -- the 'scons' binary so we invoke the SCons module from the apio main. 

36 # -- See more details at: 

37 # -- See https://github.com/orgs/pyinstaller/discussions/9023. 

38 # -- 

39 # -- In this case argv goes through these stages 

40 # -- Original: <binary> -m apio --scons ... 

41 # -- Under python: <binary> --scons ... 

42 # -- Under pyinstaller: <binary> -m apio --scons ... 

43 # -- After fixing for scons: <binary> ... 

44 # -- 

45 # -- Notice that the -m apio args are automatically removed by the 

46 # -- python interpreter but are preserved by the pyinstaller, hence 

47 # -- the two cases. 

48 python_scons = sys.argv[1:2] == ["--scons"] 

49 pyinstaller_scons = sys.argv[1:4] == ["-m", "apio", "--scons"] 

50 

51 if debug_enabled: 

52 print(f"Apio main(): {python_scons=}") 

53 print(f"Apio main(): {pyinstaller_scons=}") 

54 

55 if python_scons or pyinstaller_scons: 

56 

57 if debug_enabled: 57 ↛ 58line 57 didn't jump to line 58 because the condition on line 57 was never true

58 print("Apio main(): this is an scons process") 

59 

60 # -- Since scons_main() doesn't return, we use this handler to print 

61 # -- an exit message for debugging. 

62 atexit.register(on_exit, "Apio main(): scons process exit") 

63 

64 # -- Import and initialize scons only when running the scons 

65 # -- subprocess. 

66 from SCons.Script.Main import main as scons_main 

67 from apio.common.common_util import maybe_wait_for_remote_debugger 

68 

69 # -- If system env var APIO_SCONS_DEBUGGER is defined, regardless of 

70 # -- its value, we wait on a remote debugger to be attached, e.g. 

71 # -- from Visual Studio Code. 

72 # -- 

73 # -- You can place a breakpoint for example at SconsHandler.start(). 

74 maybe_wait_for_remote_debugger("APIO_SCONS_DEBUGGER") 

75 

76 # -- Drop the scons trigger args 

77 if python_scons: 77 ↛ 84line 77 didn't jump to line 84 because the condition on line 77 was always true

78 # -- Case 1: Using a python interpreter which already dropped 

79 # -- the ["-m", "apio"]. Dropping just ["--scons"] 

80 sys.argv[1:] = sys.argv[2:] 

81 else: 

82 # -- Case 2: Using pyinstaller which preserved the ["-m", "apio"]. 

83 # -- Dropping ["-m", "apio", "--scons"] 

84 sys.argv[1:] = sys.argv[4:] 

85 

86 if debug_enabled: 86 ↛ 87line 86 didn't jump to line 87 because the condition on line 86 was never true

87 print(f"Apio main(): scons fixed argv: {sys.argv}") 

88 

89 # -- Invoke the scons main function. It gets the modified argv from sys 

90 # -- and doesn't return. 

91 scons_main() 

92 

93 # -- Handle the case of a normal apio invocation. 

94 else: 

95 if debug_enabled: 

96 print("Apio main(): this is an apio process") 

97 

98 # -- Since apio_top_cli() doesn't return, we use this handler to print 

99 # -- an exit message for debugging. 

100 atexit.register(on_exit, "Apio main(): apio process exit") 

101 

102 # -- Import the apio CLI only when running the apio process 

103 # -- (as opposed to the scons sub process). 

104 from apio.commands.apio import apio_top_cli 

105 

106 # -- Due to the Click decorations of apio_top_cli() and the Click 

107 # -- magic, this function is not really invoked but Click dispatches 

108 # -- it to its subcommands that was selected by the user command line. 

109 # -- This function call doesn't return. 

110 apio_top_cli() 

111 

112 

113if __name__ == "__main__": 

114 main()