Coverage for netbox/cli.py: 0%
51 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1"""Console entry point for pip-installed NetBox."""
3import argparse
4import os
5import sys
6from importlib.metadata import PackageNotFoundError, version
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')
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
20Run "{prog} help" (once configured) for the full management command listing."""
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'
32def _print_version():
33 try:
34 print(version('netbox'))
35 except PackageNotFoundError: # pragma: no cover - only in a non-installed checkout
36 print('unknown')
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
62def main(argv=None):
63 prog = _prog()
64 args = list(sys.argv[1:] if argv is None else argv)
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')
72 if not args:
73 _build_parser(prog).print_help()
74 return 0
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
92 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'netbox.settings')
94 # Deferred on purpose: Django must not import until DJANGO_SETTINGS_MODULE is set.
95 from django.core.management import execute_from_command_line
97 execute_from_command_line([prog, *args])
98 return 0