# Path: sacred/serializer.py
# def restore(flat):
#     return json.decode(_json.dumps(flat), keys=True)
# 
# Path: sacred/settings.py
# SETTINGS = FrozenKeyMunch.fromDict(
#     {
#         "CONFIG": {
#             # make sure all config keys are compatible with MongoDB
#             "ENFORCE_KEYS_MONGO_COMPATIBLE": True,
#             # make sure all config keys are serializable with jsonpickle
#             # THIS IS IMPORTANT. Only deactivate if you know what you're doing.
#             "ENFORCE_KEYS_JSONPICKLE_COMPATIBLE": True,
#             # make sure all config keys are valid python identifiers
#             "ENFORCE_VALID_PYTHON_IDENTIFIER_KEYS": False,
#             # make sure all config keys are strings
#             "ENFORCE_STRING_KEYS": False,
#             # make sure no config key contains an equals sign
#             "ENFORCE_KEYS_NO_EQUALS": True,
#             # if true, all dicts and lists in the configuration of a captured
#             # function are replaced with a read-only container that raises an
#             # Exception if it is attempted to write to those containers
#             "READ_ONLY_CONFIG": True,
#             # regex patterns to filter out certain IDE or linter directives
#             # from inline comments in the documentation
#             "IGNORED_COMMENTS": ["^pylint:", "^noinspection"],
#             # if true uses the numpy legacy API, i.e. _rnd in captured functions is
#             # a numpy.random.RandomState rather than numpy.random.Generator.
#             # numpy.random.RandomState became legacy with numpy v1.19.
#             "NUMPY_RANDOM_LEGACY_API": version.parse(opt.np.__version__)
#             < version.parse("1.19")
#             if opt.has_numpy
#             else False,
#         },
#         "HOST_INFO": {
#             # Collect information about GPUs using the nvidia-smi tool
#             "INCLUDE_GPU_INFO": True,
#             # List of ENVIRONMENT variables to store in host-info
#             "CAPTURED_ENV": [],
#         },
#         "COMMAND_LINE": {
#             # disallow string fallback, if parsing a value from command-line
#             # failed
#             "STRICT_PARSING": False,
#             # show command line options that are disabled (e.g. unmet
#             # dependencies)
#             "SHOW_DISABLED_OPTIONS": True,
#         },
#         # configure how stdout/stderr are captured. ['no', 'sys', 'fd']
#         "CAPTURE_MODE": "sys" if platform.system() == "Windows" else "fd",
#         # configure how dependencies are discovered. [none, imported, sys, pkg]
#         "DISCOVER_DEPENDENCIES": "imported",
#         # configure how source-files are discovered. [none, imported, sys, dir]
#         "DISCOVER_SOURCES": "imported",
#     },
# )
# 
# Path: sacred/utils.py
# def set_by_dotted_path(d, path, value):
#     """
#     Set an entry in a nested dict using a dotted path.
# 
#     Will create dictionaries as needed.
# 
#     Examples
#     --------
#     >>> d = {'foo': {'bar': 7}}
#     >>> set_by_dotted_path(d, 'foo.bar', 10)
#     >>> d
#     {'foo': {'bar': 10}}
#     >>> set_by_dotted_path(d, 'foo.d.baz', 3)
#     >>> d
#     {'foo': {'bar': 10, 'd': {'baz': 3}}}
# 
#     """
#     split_path = path.split(".")
#     current_option = d
#     for p in split_path[:-1]:
#         if p not in current_option:
#             current_option[p] = dict()
#         current_option = current_option[p]
#     current_option[split_path[-1]] = value
# 
# Path: sacred/commandline_options.py
# class CLIOption:
#     def __init__(
#         self,
#         apply_function: CLIFunction,
#         short_flag: str,
#         long_flag: str,
#         is_flag: bool,
#     ):
# 
#         if not re.match(r"-\w$", short_flag):
#             raise ValueError(
#                 "Short flag malformed. " "One correct short flag would be: `-j`."
#             )
#         if not re.match(r"--[\w-]+\w$", long_flag):
#             raise ValueError(
#                 "Long flag malformed. One correct long flag "
#                 "would be: `--my-pretty-flag`"
#             )
#         self.apply_function = apply_function
#         self.short_flag = short_flag
#         self.long_flag = long_flag
#         self.is_flag = is_flag
# 
#         # trick for backward compatibility:
#         self.arg = None if is_flag else "VALUE"
#         self.arg_description = None if is_flag else ""
# 
#     def __call__(self, *args, **kwargs):
#         return self.apply_function(*args, **kwargs)
# 
#     def get_flag(self):
#         """Legacy function. Should be removed at some point."""
#         return self.long_flag
# 
#     def get_short_flag(self):
#         """Legacy function. Should be removed at some point."""
#         return self.short_flag
# 
#     def get_flags(self):
#         """Legacy function. Should be removed at some point."""
#         return self.short_flag, self.long_flag
# 
#     def apply(self, args, run):
#         """Legacy function. Should be removed at some point."""
#         return self.apply_function(args, run)
# 
#     def get_name(self):
#         return self.apply_function.__name__
# 
#     def get_description(self):
#         return inspect.getdoc(self.apply_function) or ""


import ast
import textwrap
import inspect
from shlex import quote
from sacred.serializer import restore
from sacred.settings import SETTINGS
from sacred.utils import set_by_dotted_path
from sacred.commandline_options import CLIOption

The command-line interface of sacred is built on top of ``docopt``, which
constructs a command-line parser from a usage text. Curiously in sacred we
first programmatically generate a usage text and then parse it with ``docopt``.
"""




__all__ = ("get_config_updates", "format_usage")


USAGE_TEMPLATE = """Usage:
  {program_name} [(with UPDATE...)] [options]
  {program_name} help [COMMAND]
  {program_name} (-h | --help)
  {program_name} COMMAND [(with UPDATE...)] [options]

{description}

Options:
{options}

Arguments:
  COMMAND   Name of command to run (see below for list of commands)
  UPDATE    Configuration assignments of the form foo.bar=17
{arguments}
{commands}"""



# Path: sacred/serializer.py
# def restore(flat):
#     return json.decode(_json.dumps(flat), keys=True)
# 
# Path: sacred/settings.py
# SETTINGS = FrozenKeyMunch.fromDict(
#     {
#         "CONFIG": {
#             # make sure all config keys are compatible with MongoDB
#             "ENFORCE_KEYS_MONGO_COMPATIBLE": True,
#             # make sure all config keys are serializable with jsonpickle
#             # THIS IS IMPORTANT. Only deactivate if you know what you're doing.
#             "ENFORCE_KEYS_JSONPICKLE_COMPATIBLE": True,
#             # make sure all config keys are valid python identifiers
#             "ENFORCE_VALID_PYTHON_IDENTIFIER_KEYS": False,
#             # make sure all config keys are strings
#             "ENFORCE_STRING_KEYS": False,
#             # make sure no config key contains an equals sign
#             "ENFORCE_KEYS_NO_EQUALS": True,
#             # if true, all dicts and lists in the configuration of a captured
#             # function are replaced with a read-only container that raises an
#             # Exception if it is attempted to write to those containers
#             "READ_ONLY_CONFIG": True,
#             # regex patterns to filter out certain IDE or linter directives
#             # from inline comments in the documentation
#             "IGNORED_COMMENTS": ["^pylint:", "^noinspection"],
#             # if true uses the numpy legacy API, i.e. _rnd in captured functions is
#             # a numpy.random.RandomState rather than numpy.random.Generator.
#             # numpy.random.RandomState became legacy with numpy v1.19.
#             "NUMPY_RANDOM_LEGACY_API": version.parse(opt.np.__version__)
#             < version.parse("1.19")
#             if opt.has_numpy
#             else False,
#         },
#         "HOST_INFO": {
#             # Collect information about GPUs using the nvidia-smi tool
#             "INCLUDE_GPU_INFO": True,
#             # List of ENVIRONMENT variables to store in host-info
#             "CAPTURED_ENV": [],
#         },
#         "COMMAND_LINE": {
#             # disallow string fallback, if parsing a value from command-line
#             # failed
#             "STRICT_PARSING": False,
#             # show command line options that are disabled (e.g. unmet
#             # dependencies)
#             "SHOW_DISABLED_OPTIONS": True,
#         },
#         # configure how stdout/stderr are captured. ['no', 'sys', 'fd']
#         "CAPTURE_MODE": "sys" if platform.system() == "Windows" else "fd",
#         # configure how dependencies are discovered. [none, imported, sys, pkg]
#         "DISCOVER_DEPENDENCIES": "imported",
#         # configure how source-files are discovered. [none, imported, sys, dir]
#         "DISCOVER_SOURCES": "imported",
#     },
# )
# 
# Path: sacred/utils.py
# def set_by_dotted_path(d, path, value):
#     """
#     Set an entry in a nested dict using a dotted path.
# 
#     Will create dictionaries as needed.
# 
#     Examples
#     --------
#     >>> d = {'foo': {'bar': 7}}
#     >>> set_by_dotted_path(d, 'foo.bar', 10)
#     >>> d
#     {'foo': {'bar': 10}}
#     >>> set_by_dotted_path(d, 'foo.d.baz', 3)
#     >>> d
#     {'foo': {'bar': 10, 'd': {'baz': 3}}}
# 
#     """
#     split_path = path.split(".")
#     current_option = d
#     for p in split_path[:-1]:
#         if p not in current_option:
#             current_option[p] = dict()
#         current_option = current_option[p]
#     current_option[split_path[-1]] = value
# 
# Path: sacred/commandline_options.py
# class CLIOption:
#     def __init__(
#         self,
#         apply_function: CLIFunction,
#         short_flag: str,
#         long_flag: str,
#         is_flag: bool,
#     ):
# 
#         if not re.match(r"-\w$", short_flag):
#             raise ValueError(
#                 "Short flag malformed. " "One correct short flag would be: `-j`."
#             )
#         if not re.match(r"--[\w-]+\w$", long_flag):
#             raise ValueError(
#                 "Long flag malformed. One correct long flag "
#                 "would be: `--my-pretty-flag`"
#             )
#         self.apply_function = apply_function
#         self.short_flag = short_flag
#         self.long_flag = long_flag
#         self.is_flag = is_flag
# 
#         # trick for backward compatibility:
#         self.arg = None if is_flag else "VALUE"
#         self.arg_description = None if is_flag else ""
# 
#     def __call__(self, *args, **kwargs):
#         return self.apply_function(*args, **kwargs)
# 
#     def get_flag(self):
#         """Legacy function. Should be removed at some point."""
#         return self.long_flag
# 
#     def get_short_flag(self):
#         """Legacy function. Should be removed at some point."""
#         return self.short_flag
# 
#     def get_flags(self):
#         """Legacy function. Should be removed at some point."""
#         return self.short_flag, self.long_flag
# 
#     def apply(self, args, run):
#         """Legacy function. Should be removed at some point."""
#         return self.apply_function(args, run)
# 
#     def get_name(self):
#         return self.apply_function.__name__
# 
#     def get_description(self):
#         return inspect.getdoc(self.apply_function) or ""


# Path: sacred/arg_parser.py
import ast
import textwrap
import inspect
from shlex import quote
from sacred.serializer import restore
from sacred.settings import SETTINGS
from sacred.utils import set_by_dotted_path
from sacred.commandline_options import CLIOption


The command-line interface of sacred is built on top of ``docopt``, which
constructs a command-line parser from a usage text. Curiously in sacred we
first programmatically generate a usage text and then parse it with ``docopt``.
"""




__all__ = ("get_config_updates", "format_usage")


USAGE_TEMPLATE = """Usage:
  {program_name} [(with UPDATE...)] [options]
  {program_name} help [COMMAND]
  {program_name} (-h | --help)
  {program_name} COMMAND [(with UPDATE...)] [options]

{description}

Options:
{options}

Arguments:
  COMMAND   Name of command to run (see below for list of commands)
  UPDATE    Configuration assignments of the form foo.bar=17
{arguments}
{commands}"""



def get_config_updates(updates):