class_docstr: So we could provide handling for URLs with corresponding credentials
  and specific (reusable) downloader.  Internally it contains
  Providers and interfaces them based on a given URL.  Each provider
  in turn takes care about associated with it Downloader.
class_docstr_tok: ["So","we","could","provide","handling","for","URLs","with","corresponding","credentials","and","specific","(","reusable",")","downloader",".","Internally","it","contains","Providers","and","interfaces","them","based","on","a","given","URL",".","Each","provider","in","turn","takes","care","about","associated","with","it","Downloader","."]
docstr: Loads information about related/possible websites requiring authentication from:
  
  - datalad/downloaders/configs/*.cfg files provided by the codebase
  - current dataset .datalad/providers/
  - User's home directory directory (ie ~/.config/datalad/providers/*.cfg)
  - system-wide datalad installation/config (ie /etc/datalad/providers/*.cfg)
  
  For sample configs files see datalad/downloaders/configs/providers.cfg
  
  If files is None, loading is cached between calls.  Specify reload=True to force
  reloading of files from the filesystem.  The class method reset_default_providers
  can also be called to reset the cached providers.
code: def from_config_files(cls, files=None, reload=False):
      """Loads information about related/possible websites requiring authentication from:
  
      - datalad/downloaders/configs/*.cfg files provided by the codebase
      - current dataset .datalad/providers/
      - User's home directory directory (ie ~/.config/datalad/providers/*.cfg)
      - system-wide datalad installation/config (ie /etc/datalad/providers/*.cfg)
  
      For sample configs files see datalad/downloaders/configs/providers.cfg
  
      If files is None, loading is cached between calls.  Specify reload=True to force
      reloading of files from the filesystem.  The class method reset_default_providers
      can also be called to reset the cached providers.
      """
      # lazy part
      # Note, that "" is effectively the same as ".". If CWD is in a dataset's
      # root already, `get_dataset_root` will just return its input. While
      # this is technically correct, we want to use it here in order to
      # figure, whether the dsroot is the same as when we called last time.
      # However, "", ".", etc. would stay the same, whenever we switch into
      # another dataset, causing `from_config_files` to "think" nothing
      # changed. Therefore use abspath here.
      dsroot_rel = get_dataset_root("")
      dsroot = abspath(dsroot_rel) if dsroot_rel is not None else None
      if (
          files is None
          and cls._DEFAULT_PROVIDERS
          and not reload
          and dsroot == cls._DS_ROOT
      ):
          return cls._DEFAULT_PROVIDERS
  
      config = SafeConfigParserWithIncludes()
      files_orig = files
      if files is None:
          cls._DS_ROOT = dsroot
          files = []
          for p in cls._get_providers_dirs(dsroot).values():
              files.extend(cls._get_configs(p))
      config.read(files)
  
      # We need first to load Providers and credentials
      # Order matters, because we need to ensure that when
      # there's a conflict between configuration files declared
      # at different precedence levels (ie. dataset vs system)
      # the appropriate precedence config wins.
      providers = dict()
      credentials = {}
  
      for section in config.sections():
          if ":" in section:
              type_, name = section.split(":", 1)
              assert type_ in {"provider", "credential"}, (
                  "we know only providers and credentials, got type %s"
                  % type_
              )
              items = {
                  o: config.get(section, o)
                  for o in config.options(section)
              }
              # side-effect -- items get popped
              locals().get(type_ + "s")[name] = getattr(
                  cls, "_process_" + type_
              )(name, items)
              if len(items):
                  raise ValueError(
                      "Unprocessed fields left for %s: %s"
                      % (name, str(items))
                  )
          else:
              lgr.warning(
                  "Do not know how to treat section %s here" % section
              )
  
      # link credentials into providers
      lgr.debug(
          "Assigning credentials into %d providers", len(providers)
      )
      for provider in providers.values():
          if provider.credential:
              if provider.credential not in credentials:
                  raise ValueError(
                      "Unknown credential %s. Known are: %s"
                      % (
                          provider.credential,
                          ", ".join(credentials.keys()),
                      )
                  )
              provider.credential = credentials[provider.credential]
              # TODO: Is this the right place to pass dataset to credential?
              provider.credential.set_context(dataset=cls._DS_ROOT)
  
      providers = Providers(list(providers.values()))
  
      if files_orig is None:
          # Store providers for lazy access
          cls._DEFAULT_PROVIDERS = providers
  
      return providers
  
imports: from glob import glob
  from logging import getLogger
  import re
  from os.path import dirname, abspath, join
  from urllib.parse import urlparse
  from .base import NoneAuthenticator, NotImplementedAuthenticator
  from .http import HTMLFormAuthenticator, HTTPAnonBearerTokenAuthenticator, HTTPAuthAuthenticator, HTTPBasicAuthAuthenticator, HTTPDigestAuthAuthenticator, HTTPBearerTokenAuthenticator, HTTPDownloader
  from .s3 import S3Authenticator, S3Downloader
  from .shub import SHubDownloader
  from configparser import ConfigParser
  from datalad.support.external_versions import external_versions
  from datalad.support.network import RI
  from datalad.support import path
  from datalad.utils import auto_repr, ensure_list_from_str, get_dataset_root, Path
  from ..interface.common_cfg import dirs
  from datalad.downloaders import CREDENTIAL_TYPES
label_desc: Use image node_id 8 for calling the Providers obj's underlying member method code with example usage: obj.from_config_files(cls, files, reload) and returns: providers, cls