Coverage for netbox/cli.py: 0%

51 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 18:35 +0000

1"""Console entry point for pip-installed NetBox.""" 

2 

3import argparse 

4import os 

5import sys 

6from importlib.metadata import PackageNotFoundError, version 

7 

8# Commands handled here must not require Django settings. These names are intentionally 

9# reserved by the console wrapper and are never dispatched to Django management commands. 

10# 'setup' is not listed: the early-dispatch branch in main() owns it and always returns 

11# before this tuple is consulted. 

12_RESERVED_COMMANDS = ('secret-key', 'version') 

13 

14_EPILOG = """Any other command is dispatched to the Django management commands, which 

15require a valid NetBox configuration, e.g.: 

16 {prog} upgrade 

17 {prog} check 

18 {prog} createsuperuser 

19 

20Run "{prog} help" (once configured) for the full management command listing.""" 

21 

22 

23def _prog(): 

24 if sys.argv and sys.argv[0]: 

25 name = os.path.basename(sys.argv[0]) 

26 # `python -m netbox` executes __main__.py; show the user-facing name instead. 

27 if name != '__main__.py': 

28 return name 

29 return 'netbox' 

30 

31 

32def _print_version(): 

33 try: 

34 print(version('netbox')) 

35 except PackageNotFoundError: # pragma: no cover - only in a non-installed checkout 

36 print('unknown') 

37 

38 

39def _build_parser(prog): 

40 parser = argparse.ArgumentParser( 

41 prog=prog, 

42 description='NetBox command line interface.', 

43 epilog=_EPILOG.format(prog=prog), 

44 formatter_class=argparse.RawDescriptionHelpFormatter, 

45 ) 

46 subparsers = parser.add_subparsers( 

47 dest='command', 

48 title='pre-configuration commands (no NetBox configuration required)', 

49 ) 

50 subparsers.add_parser( 

51 'version', help='Print the installed NetBox package version.', 

52 description='Print the installed NetBox package version.') 

53 subparsers.add_parser( 

54 'setup', add_help=False, 

55 help='Create the local configuration files for a pip-installed instance.') 

56 subparsers.add_parser( 

57 'secret-key', help='Generate a new 50-character SECRET_KEY value.', 

58 description='Generate a new 50-character SECRET_KEY value.') 

59 return parser 

60 

61 

62def main(argv=None): 

63 prog = _prog() 

64 args = list(sys.argv[1:] if argv is None else argv) 

65 

66 # `setup` owns its own parser (netbox.scaffold); dispatch before the wrapper parser. 

67 if args and args[0] == 'setup': 

68 # Deferred so the command works before Django or a configuration exists. 

69 from netbox.scaffold import main as setup_main 

70 return setup_main(args[1:], prog=f'{prog} setup') 

71 

72 if not args: 

73 _build_parser(prog).print_help() 

74 return 0 

75 

76 if args[0] in _RESERVED_COMMANDS or args[0] in ('-h', '--help', '--version'): 

77 parser = _build_parser(prog) 

78 if args[0] == '--version': 

79 args = ['version', *args[1:]] 

80 try: 

81 options = parser.parse_args(args) 

82 except SystemExit as e: # argparse already printed help (0) or an error (2) 

83 return int(e.code or 0) 

84 if options.command == 'version': 

85 _print_version() 

86 elif options.command == 'secret-key': 

87 # Deferred so the command works before Django or a configuration exists. 

88 from utilities.secret_key import generate_secret_key 

89 print(generate_secret_key()) 

90 return 0 

91 

92 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'netbox.settings') 

93 

94 # Deferred on purpose: Django must not import until DJANGO_SETTINGS_MODULE is set. 

95 from django.core.management import execute_from_command_line 

96 

97 execute_from_command_line([prog, *args]) 

98 return 0