given a path to a management directory return a list of all the command names that are available given a command name and an application name return the command class instance allow all errors raised by the import process importerror attributeerror to propagate return a dictionary mapping command names to their callback applications look for a management commands package in django core and in each installed application if a commands package exists register all commands in that package core commands are always included if a settings module has been specified also include userdefined commands the dictionary is in the format commandname appname keyvalue pairs from this dictionary can then be used in calls to loadcommandclassappname commandname the dictionary is cached on the first call and reused on subsequent calls call the given command with the given options and argskwargs this is the primary api you should use for calling specific commands commandname may be a string or a command object using a string is preferred unless the command object is required for further processing or testing some examples callcommand migrate callcommand shell plaintrue callcommand sqlmigrate myapp from django core management commands import flush cmd flush command callcommandcmd verbosity0 interactivefalse do something with cmd command object passed in load the command object by name if the command is already loaded use it directly simulate argument parsing to get the option defaults see 10080 for details use the dest option name from the parser option parser actions and actions from subparser choices any required arguments which are passed in via options must be passed to parseargs raise an error if any unknown options were passed move positional args out of options to mimic legacy optparse encapsulate the logic of the djangoadmin and manage py utilities return the script s main help text as a string if commandsonly usage sortedgetcommands else usage type s help subcommand for help on a specific subcommand self progname available subcommands commandsdict defaultdictlambda for name app in getcommands items if app django core app django else app app rpartition 1 commandsdictapp appendname style colorstyle for app in sortedcommandsdict usage append usage appendstyle notices app for name in sortedcommandsdictapp usage append s name output an extra note if settings are not properly configured if self settingsexception is not none usage append style notice note that only django core commands are listed as settings are not properly configured error s self settingsexception return n joinusage def fetchcommandself subcommand get commands outside of try block to prevent swallowing exceptions commands getcommands try appname commandssubcommand except keyerror if os environ getdjangosettingsmodule if subcommand is missing due to misconfigured settings the following line will retrigger an improperlyconfigured exception getcommands swallows the original one so the user is informed about it settings installedapps elif not settings configured sys stderr writeno django settings specified n possiblematches getclosematchessubcommand commands sys stderr writeunknown command r subcommand if possiblematches sys stderr write did you mean s possiblematches0 sys stderr writentype s help for usage n self progname sys exit1 if isinstanceappname basecommand if the command is already loaded use it directly klass appname else klass loadcommandclassappname subcommand return klass def autocompleteself don t complete if user hasn t sourced bashcompletion file if djangoautocomplete not in os environ return cwords os environcompwords split1 cword intos environcompcword try curr cwordscword 1 except indexerror curr subcommands getcommands help options help false subcommand if cword 1 print joinsortedfilterlambda x x startswithcurr subcommands subcommand options special case the help subcommand has no options elif cwords0 in subcommands and cwords0 help subcommandcls self fetchcommandcwords0 special case add the names of installed apps to options if cwords0 in dumpdata sqlmigrate sqlsequencereset test try appconfigs apps getappconfigs get the last part of the dotted path as the app name options extendappconfig label 0 for appconfig in appconfigs except importerror fail silently if djangosettingsmodule isn t set the user will find out once they execute the command pass parser subcommandcls createparser cwords0 options extend minsopt optionstrings sopt nargs 0 for sopt in parser actions if sopt optionstrings filter out previously specified options from available options prevopts x split0 for x in cwords1 cword 1 options opt for opt in options if opt0 not in prevopts filter options by current input options sortedk v for k v in options if k startswithcurr for optlabel requirearg in options append to options which require args if requirearg optlabel printoptlabel exit code of the bash completion function is never passed back to the user so it s safe to always exit with 0 for more details see 25420 sys exit0 def executeself try subcommand self argv1 except indexerror subcommand help display help if no arguments were given preprocess options to extract settings and pythonpath these options could affect the commands that are available so they must be processed early parser commandparser progself progname usageprogs subcommand options args addhelpfalse allowabbrevfalse parser addargumentsettings parser addargumentpythonpath parser addargumentargs nargs catchall try options args parser parseknownargsself argv2 handledefaultoptionsoptions except commanderror pass ignore any option errors at this point try settings installedapps except improperlyconfigured as exc self settingsexception exc except importerror as exc self settingsexception exc if settings configured start the autoreloading dev server even if the code is broken the hardcoded condition is a code smell but we can t rely on a flag on the command class because we haven t located it yet if subcommand runserver and noreload not in self argv try autoreload checkerrorsdjango setup except exception the exception will be raised later in the child process started by the autoreloader pretend it didn t happen by loading an empty list of applications apps allmodels defaultdictdict apps appconfigs apps appsready apps modelsready apps ready true remove options not compatible with the builtin runserver e g options for the contrib staticfiles runserver changes here require manually testing as described in 27522 parser self fetchcommandrunserver createparser django runserver options args parser parseknownargsself argv2 for arg in args self argv removearg in all other cases django setup is required to succeed else django setup self autocomplete if subcommand help if commands in args sys stdout writeself mainhelptextcommandsonlytrue n elif not options args sys stdout writeself mainhelptext n else self fetchcommandoptions args0 printhelp self progname options args0 specialcases we want djangoadmin version and djangoadmin help to work for backwards compatibility elif subcommand version or self argv1 version sys stdout writedjango getversion n elif self argv1 in help h sys stdout writeself mainhelptext n else self fetchcommandsubcommand runfromargvself argv def executefromcommandlineargvnone given a path to a management directory return a list of all the command names that are available given a command name and an application name return the command class instance allow all errors raised by the import process importerror attributeerror to propagate return a dictionary mapping command names to their callback applications look for a management commands package in django core and in each installed application if a commands package exists register all commands in that package core commands are always included if a settings module has been specified also include user defined commands the dictionary is in the format command_name app_name key value pairs from this dictionary can then be used in calls to load_command_class app_name command_name the dictionary is cached on the first call and reused on subsequent calls call the given command with the given options and args kwargs this is the primary api you should use for calling specific commands command_name may be a string or a command object using a string is preferred unless the command object is required for further processing or testing some examples call_command migrate call_command shell plain true call_command sqlmigrate myapp from django core management commands import flush cmd flush command call_command cmd verbosity 0 interactive false do something with cmd command object passed in load the command object by name if the command is already loaded use it directly simulate argument parsing to get the option defaults see 10080 for details use the dest option name from the parser option parser actions and actions from sub parser choices any required arguments which are passed in via options must be passed to parse_args raise an error if any unknown options were passed move positional args out of options to mimic legacy optparse encapsulate the logic of the django admin and manage py utilities return the script s main help text as a string output an extra note if settings are not properly configured try to fetch the given subcommand printing a message with the appropriate command called from the command line usually django admin or manage py if it can t be found get commands outside of try block to prevent swallowing exceptions if subcommand is missing due to misconfigured settings the following line will retrigger an improperlyconfigured exception get_commands swallows the original one so the user is informed about it if the command is already loaded use it directly output completion suggestions for bash the output of this function is passed to bash s compreply variable and treated as completion suggestions compreply expects a space separated string as the result the comp_words and comp_cword bash environment variables are used to get information about the cli input please refer to the bash man page for more information about this variables subcommand options are saved as pairs a pair consists of the long option string e g exclude and a boolean value indicating if the option requires arguments when printing to stdout an equal sign is appended to options which require arguments note if debugging this function it is recommended to write the debug output in a separate file otherwise the debug output will be treated and formatted as potential completion suggestions don t complete if user hasn t sourced bash_completion file subcommand subcommand options special case the help subcommand has no options special case add the names of installed apps to options get the last part of the dotted path as the app name fail silently if django_settings_module isn t set the user will find out once they execute the command filter out previously specified options from available options filter options by current input append to options which require args exit code of the bash completion function is never passed back to the user so it s safe to always exit with 0 for more details see 25420 given the command line arguments figure out which subcommand is being run create a parser appropriate to that command and run it display help if no arguments were given preprocess options to extract settings and pythonpath these options could affect the commands that are available so they must be processed early catch all ignore any option errors at this point start the auto reloading dev server even if the code is broken the hardcoded condition is a code smell but we can t rely on a flag on the command class because we haven t located it yet the exception will be raised later in the child process started by the autoreloader pretend it didn t happen by loading an empty list of applications remove options not compatible with the built in runserver e g options for the contrib staticfiles runserver changes here require manually testing as described in 27522 in all other cases django setup is required to succeed special cases we want django admin version and django admin help to work for backwards compatibility run a managementutility
import functools
import os
import pkgutil
import sys
from argparse import (
    _AppendConstAction,
    _CountAction,
    _StoreConstAction,
    _SubParsersAction,
)
from collections import defaultdict
from difflib import get_close_matches
from importlib import import_module

import django
from django.apps import apps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.management.base import (
    BaseCommand,
    CommandError,
    CommandParser,
    handle_default_options,
)
from django.core.management.color import color_style
from django.utils import autoreload


def find_commands(management_dir):
    
    command_dir = os.path.join(management_dir, "commands")
    return [
        name
        for _, name, is_pkg in pkgutil.iter_modules([command_dir])
        if not is_pkg and not name.startswith("_")
    ]


def load_command_class(app_name, name):
    
    module = import_module("%s.management.commands.%s" % (app_name, name))
    return module.Command()


@functools.cache
def get_commands():
    
    commands = {name: "django.core" for name in find_commands(__path__[0])}

    if not settings.configured:
        return commands

    for app_config in reversed(apps.get_app_configs()):
        path = os.path.join(app_config.path, "management")
        commands.update({name: app_config.name for name in find_commands(path)})

    return commands


def call_command(command_name, *args, **options):
    
    if isinstance(command_name, BaseCommand):
        
        command = command_name
        command_name = command.__class__.__module__.split(".")[-1]
    else:
        
        try:
            app_name = get_commands()[command_name]
        except KeyError:
            raise CommandError("Unknown command: %r" % command_name)

        if isinstance(app_name, BaseCommand):
            
            command = app_name
        else:
            command = load_command_class(app_name, command_name)

    
    parser = command.create_parser("", command_name)
    
    opt_mapping = {
        min(s_opt.option_strings).lstrip("-").replace("-", "_"): s_opt.dest
        for s_opt in parser._actions
        if s_opt.option_strings
    }
    arg_options = {opt_mapping.get(key, key): value for key, value in options.items()}
    parse_args = []
    for arg in args:
        if isinstance(arg, (list, tuple)):
            parse_args += map(str, arg)
        else:
            parse_args.append(str(arg))

    def get_actions(parser):
        
        for opt in parser._actions:
            if isinstance(opt, _SubParsersAction):
                for sub_opt in opt.choices.values():
                    yield from get_actions(sub_opt)
            else:
                yield opt

    parser_actions = list(get_actions(parser))
    mutually_exclusive_required_options = {
        opt
        for group in parser._mutually_exclusive_groups
        for opt in group._group_actions
        if group.required
    }
    
    
    for opt in parser_actions:
        if opt.dest in options and (
            opt.required or opt in mutually_exclusive_required_options
        ):
            opt_dest_count = sum(v == opt.dest for v in opt_mapping.values())
            if opt_dest_count > 1:
                raise TypeError(
                    f"Cannot pass the dest {opt.dest!r} that matches multiple "
                    f"arguments via **options."
                )
            parse_args.append(min(opt.option_strings))
            if isinstance(opt, (_AppendConstAction, _CountAction, _StoreConstAction)):
                continue
            value = arg_options[opt.dest]
            if isinstance(value, (list, tuple)):
                parse_args += map(str, value)
            else:
                parse_args.append(str(value))
    defaults = parser.parse_args(args=parse_args)
    defaults = dict(defaults._get_kwargs(), **arg_options)
    
    stealth_options = set(command.base_stealth_options + command.stealth_options)
    dest_parameters = {action.dest for action in parser_actions}
    valid_options = (dest_parameters | stealth_options).union(opt_mapping)
    unknown_options = set(options) - valid_options
    if unknown_options:
        raise TypeError(
            "Unknown option(s) for %s command: %s. "
            "Valid options are: %s."
            % (
                command_name,
                ", ".join(sorted(unknown_options)),
                ", ".join(sorted(valid_options)),
            )
        )
    
    args = defaults.pop("args", ())
    if "skip_checks" not in options:
        defaults["skip_checks"] = True

    return command.execute(*args, **defaults)


class ManagementUtility:
    

    def __init__(self, argv=None):
        self.argv = argv or sys.argv[:]
        self.prog_name = os.path.basename(self.argv[0])
        if self.prog_name == "__main__.py":
            self.prog_name = "python -m django"
        self.settings_exception = None

    def main_help_text(self, commands_only=False):
        
        if commands_only:
            usage = sorted(get_commands())
        else:
            usage = [
                "",
                "Type '%s help <subcommand>' for help on a specific subcommand."
                % self.prog_name,
                "",
                "Available subcommands:",
            ]
            commands_dict = defaultdict(lambda: [])
            for name, app in get_commands().items():
                if app == "django.core":
                    app = "django"
                else:
                    app = app.rpartition(".")[-1]
                commands_dict[app].append(name)
            style = color_style()
            for app in sorted(commands_dict):
                usage.append("")
                usage.append(style.NOTICE("[%s]" % app))
                for name in sorted(commands_dict[app]):
                    usage.append("    %s" % name)
            
            if self.settings_exception is not None:
                usage.append(
                    style.NOTICE(
                        "Note that only Django core commands are listed "
                        "as settings are not properly configured (error: %s)."
                        % self.settings_exception
                    )
                )

        return "\n".join(usage)

    def fetch_command(self, subcommand):
        
        
        commands = get_commands()
        try:
            app_name = commands[subcommand]
        except KeyError:
            if os.environ.get("DJANGO_SETTINGS_MODULE"):
                
                
                
                
                settings.INSTALLED_APPS
            elif not settings.configured:
                sys.stderr.write("No Django settings specified.\n")
            possible_matches = get_close_matches(subcommand, commands)
            sys.stderr.write("Unknown command: %r" % subcommand)
            if possible_matches:
                sys.stderr.write(". Did you mean %s?" % possible_matches[0])
            sys.stderr.write("\nType '%s help' for usage.\n" % self.prog_name)
            sys.exit(1)
        if isinstance(app_name, BaseCommand):
            
            klass = app_name
        else:
            klass = load_command_class(app_name, subcommand)
        return klass

    def autocomplete(self):
        
        
        if "DJANGO_AUTO_COMPLETE" not in os.environ:
            return

        cwords = os.environ["COMP_WORDS"].split()[1:]
        cword = int(os.environ["COMP_CWORD"])

        try:
            curr = cwords[cword - 1]
        except IndexError:
            curr = ""

        subcommands = [*get_commands(), "help"]
        options = [("--help", False)]

        
        if cword == 1:
            print(" ".join(sorted(filter(lambda x: x.startswith(curr), subcommands))))
        
        
        elif cwords[0] in subcommands and cwords[0] != "help":
            subcommand_cls = self.fetch_command(cwords[0])
            
            if cwords[0] in ("dumpdata", "sqlmigrate", "sqlsequencereset", "test"):
                try:
                    app_configs = apps.get_app_configs()
                    
                    options.extend((app_config.label, 0) for app_config in app_configs)
                except ImportError:
                    
                    
                    pass
            parser = subcommand_cls.create_parser("", cwords[0])
            options.extend(
                (min(s_opt.option_strings), s_opt.nargs != 0)
                for s_opt in parser._actions
                if s_opt.option_strings
            )
            
            prev_opts = {x.split("=")[0] for x in cwords[1 : cword - 1]}
            options = (opt for opt in options if opt[0] not in prev_opts)

            
            options = sorted((k, v) for k, v in options if k.startswith(curr))
            for opt_label, require_arg in options:
                
                if require_arg:
                    opt_label += "="
                print(opt_label)
        
        
        
        sys.exit(0)

    def execute(self):
        
        try:
            subcommand = self.argv[1]
        except IndexError:
            subcommand = "help"  

        
        
        
        parser = CommandParser(
            prog=self.prog_name,
            usage="%(prog)s subcommand [options] [args]",
            add_help=False,
            allow_abbrev=False,
        )
        parser.add_argument("--settings")
        parser.add_argument("--pythonpath")
        parser.add_argument("args", nargs="*")  
        try:
            options, args = parser.parse_known_args(self.argv[2:])
            handle_default_options(options)
        except CommandError:
            pass  

        try:
            settings.INSTALLED_APPS
        except ImproperlyConfigured as exc:
            self.settings_exception = exc
        except ImportError as exc:
            self.settings_exception = exc

        if settings.configured:
            
            
            
            if subcommand == "runserver" and "--noreload" not in self.argv:
                try:
                    autoreload.check_errors(django.setup)()
                except Exception:
                    
                    
                    
                    apps.all_models = defaultdict(dict)
                    apps.app_configs = {}
                    apps.apps_ready = apps.models_ready = apps.ready = True

                    
                    
                    
                    
                    _parser = self.fetch_command("runserver").create_parser(
                        "django", "runserver"
                    )
                    _options, _args = _parser.parse_known_args(self.argv[2:])
                    for _arg in _args:
                        self.argv.remove(_arg)

            
            else:
                django.setup()

        self.autocomplete()

        if subcommand == "help":
            if "--commands" in args:
                sys.stdout.write(self.main_help_text(commands_only=True) + "\n")
            elif not options.args:
                sys.stdout.write(self.main_help_text() + "\n")
            else:
                self.fetch_command(options.args[0]).print_help(
                    self.prog_name, options.args[0]
                )
        
        
        elif subcommand == "version" or self.argv[1:] == ["--version"]:
            sys.stdout.write(django.get_version() + "\n")
        elif self.argv[1:] in (["--help"], ["-h"]):
            sys.stdout.write(self.main_help_text() + "\n")
        else:
            self.fetch_command(subcommand).run_from_argv(self.argv)


def execute_from_command_line(argv=None):
    
    utility = ManagementUtility(argv)
    utility.execute()