text: """Framework for small scripts in Python 3
  
  You'll get the whole environment by importing just
  one file, and you can start working immediately.
  
  The output will be colored with support of multiple
  log levels, easy-to-add command line arguments, etc."""
  import argparse
  import inspect
  import logging
  import logging.handlers
  import pathlib
  import sys
  import warnings
  
  import coloredlogs
  from colorful import colorful  # type: ignore
  import prettyprinter
  import tqdm
  import verboselogs
  from traceback_with_variables.core import ColorSchemes, Format, iter_exc_lines
  
  _with_colors = None
  
  logger = logging.getLogger(__name__)
  
  __all__ = [
      # Logging
      "getLogger",
      "CRITICAL",
      "ERROR",
      "WARNING",
      "INFO",
      "VERBOSE",
      "DEBUG",
      "SPAM",
      # Argument parsing and bootstrap
      "bootstrap",
      "bootstrap_args",
      "add_arguments",
      "args",
      # Progressbar
      "progressbar",
      # For debugging
      "pprint",
      "pp",
      "warn",
  ]
  
  CRITICAL = logging.CRITICAL
  ERROR = logging.ERROR
  WARNING = logging.WARNING
  INFO = logging.INFO
  VERBOSE = verboselogs.VERBOSE
  DEBUG = logging.DEBUG
  SPAM = verboselogs.SPAM
  warn = warnings.warn
  
  
  class CustomLogFormatter(coloredlogs.ColoredFormatter):
      def __init__(self, format_str, *, colors):
          self.colors = colors
          super().__init__(
              format_str,
              level_styles=self._coloredlogs_styles(),
              field_styles=self._coloredlogs_styles(),
          )
  
      def _coloredlogs_styles(self):
          if self.colors:
              return None  # Default value
          else:
              return {}  # Disable coloring
  
      def formatException(self, stack_info):
          if self.colors:
              color_scheme = ColorSchemes.common
          else:
              color_scheme = ColorSchemes.none
  
          return "\n".join(
              iter_exc_lines(
                  e=stack_info[1],
                  num_skipped_frames=1,
                  fmt=Format(color_scheme=color_scheme),
              )
          )
  
  
  class ConsoleLogHandler(logging.StreamHandler):
      def __init__(self):
          logging.StreamHandler.__init__(self)
          self.setFormatter(
              CustomLogFormatter("%(levelname)s %(message)s", colors=_with_colors)
          )
  
      def emit(self, record):
          msg = self.format(record)
          tqdm.tqdm.write(msg)
  
  
  def _exception_handler(exc_type, exc_value, exc_traceback):
      if issubclass(exc_type, KeyboardInterrupt):
          sys.__excepthook__(exc_type, exc_value, exc_traceback)
          return
  
      message = f"Uncaught {exc_type.__name__}: {exc_value}"
      logger.critical(message, exc_info=exc_value)
  
  
  def _setup_logger(console_log_level):
      with warnings.catch_warnings():
          warnings.simplefilter("ignore")
          prettyprinter.install_extras()
      verboselogs.install()
      if sys.platform == "win32":
          # In Windows the default black is black, which is invisible on the default terminal.
          coloredlogs.DEFAULT_FIELD_STYLES["levelname"] = {"color": "blue"}
  
      root_logger = logging.getLogger()
      root_logger.setLevel(min(console_log_level, logging.DEBUG))
  
      console_log_handler = ConsoleLogHandler()
      console_log_handler.setLevel(console_log_level)
      root_logger.addHandler(console_log_handler)
  
      sys.excepthook = _exception_handler
      logging.captureWarnings(True)
  
  
  def _log_level_from_verbosity(console_verbosity):
      levels = [
          logging.ERROR,
          logging.WARNING,
          logging.INFO,
          verboselogs.VERBOSE,
          logging.DEBUG,
          verboselogs.SPAM,
      ]
      default_level = logging.INFO
  
      new_index = levels.index(default_level) + console_verbosity
      new_index = max(0, min(len(levels) - 1, new_index))
      log_level = levels[new_index]
      return log_level
  
  
  ########################################################################################v
  
  
  def getLogger(name="__main__"):
      """Return a verbose logger for a module
  
      It is an alias for verboselogs.VerboseLogger.
      Can be used as the logging.getLogger() method.
      Extends built-in logger with levels: verbose, spam
      """
      return verboselogs.VerboseLogger(name)
  
  
  def get_logger(name="__main__"):
      warnings.warn(
          "get_logger is deprecated in favor of getLogger. Will be removed in 2022.",
          category=DeprecationWarning,
      )
      return getLogger(name)
  
  
  args = None  # Will be set during bootstrap
  
  parser = argparse.ArgumentParser()
  parser.add_argument(
      "-v",
      "--verbose",
      action="count",
      help="Increase verbosity. Can be applied multiple times, like -vv",
  )
  parser.add_argument(
      "-q",
      "--quiet",
      action="count",
      help="Decrease verbosity. Can be applied multiple times, like -qq",
  )
  parser.add_argument(
      "--colors",
      action="store_true",
      default=None,
      help="Force set colored output",
  )
  parser.add_argument(
      "--no-colors",
      action="store_false",
      dest="colors",
      help="Force set non-colored output",
  )
  
  
  def add_argument(*args, **kw):
      """See: ArgumentParser.add_argument()"""
      parser.add_argument(*args, **kw)
  
  
  def setup_file_logging(*, level="INFO", filename=None):
      """Setups logging to file
  
      The default filename is the name of the main script.
      It uses RotatingFileHandler."""
      if filename is None:
          caller_module = inspect.getmodule(inspect.stack()[1][0])
          filename = pathlib.Path(caller_module.__file__).with_suffix(".log")
  
      file_log_handler = logging.handlers.RotatingFileHandler(
          filename, encoding="utf-8", maxBytes=10 * 1024 * 1024, backupCount=9
      )
      formatter = CustomLogFormatter(
          "%(asctime)s %(levelname)s %(message)s", colors=False
      )
      file_log_handler.setFormatter(formatter)
      file_log_handler.setLevel(level)
      logging.getLogger().addHandler(file_log_handler)
  
  
  progressbar = tqdm.tqdm
  
  
  def pprint(*args, **kwargs):
      """PrettyPrint with or without colors"""
      if _with_colors:
          prettyprinter.cpprint(*args, **kwargs)
      else:
          prettyprinter.pprint(*args, **kwargs)
  
  
  pp = pprint
  
  
  def bootstrap_args():
      """Bootstraps the framework
  
      returns (logger, args)
          The logger for main scripts
          And the parsed argument"""
      global args
      global _with_colors
  
      args = parser.parse_args()
  
      if args.colors is None:
          _with_colors = sys.stdout.isatty()
      else:
          _with_colors = args.colors
          if args.colors:
              # Hack for pretty printer on force colors
              colorful.use_16_ansi_colors()
  
      console_verbosity = (args.verbose or 0) - (args.quiet or 0)
      console_log_level = _log_level_from_verbosity(console_verbosity)
      _setup_logger(console_log_level)
  
      logger.debug(f"Arguments: {args}")
  
      return getLogger(), args
  
  
  def bootstrap():
      """Bootstraps the framework
  
      returns logger - the logger for the main script"""
      return bootstrap_args()[0]
  