docs: def _GetValue(self, name, context, default=utils.NotAValue):
      """Search for the value based on the context."""
      container = self.defaults
  
      # The caller provided a default value.
      if default is not utils.NotAValue:
        value = default
  
      # Take the default from the definition.
      elif name in self.defaults:
        value = self.defaults[name]
  
      else:
        raise UnknownOption("Option %s not defined." % name)
  
      # We resolve the required key with the default raw data, and then iterate
      # over all elements in the context to see if there are overriding context
      # configurations.
      new_value = self.raw_data.get(name)
      if new_value is not None:
        value = new_value
        container = self.raw_data
  
      # Now check for any contexts. We enumerate all the possible resolutions and
      # sort by their path length. The last one will be the match with the deepest
      # path (i.e .the most specific match).
      matches = list(self._ResolveContext(context, name, self.raw_data))
  
      if matches:
        # Sort by the length of the path - longest match path will be at the end.
        matches.sort(key=lambda x: len(x[2]))
        value = matches[-1][1]
        container = matches[-1][0]
  
        if (len(matches) >= 2 and len(matches[-1][2]) == len(matches[-2][2]) and
            matches[-1][2] != matches[-2][2] and
            matches[-1][1] != matches[-2][1]):
          # This warning specifies that there is an ambiguous match, the config
          # attempts to find the most specific value e.g. if you have a value
          # for X.y in context A,B,C, and a value for X.y in D,B it should choose
          # the one in A,B,C. This warning is for if you have a value in context
          # A,B and one in A,C. The config doesn't know which one to pick so picks
          # one and displays this warning.
          logging.warning(
              "Ambiguous configuration for key %s: "
              "Contexts of equal length: %s (%s) and %s (%s)", name,
              matches[-1][2], matches[-1][1], matches[-2][2], matches[-2][1])
  
      # If there is a writeback location this overrides any previous
      # values.
      if self.writeback_data:
        new_value = self.writeback_data.get(name)
        if new_value is not None:
          value = new_value
          container = self.writeback_data
  
      # Allow the global override to force an option value.
      if name in self.global_override:
        return self.global_override, self.global_override[name]
  
      return container, value