docs: def attr_matches(self, text):
          """Compute matches when text contains a dot.
  
          Assuming the text is of the form NAME.NAME....[NAME], and is
          evaluable in self.namespace, it will be evaluated and its attributes
          (as revealed by dir()) are used as possible completions.  (For class
          instances, class members are also considered.)
  
          WARNING: this can still invoke arbitrary C code, if an object
          with a __getattr__ hook is evaluated.
  
          """
          import re
          m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
          if not m:
              return []
          expr, attr = m.group(1, 3)
          try:
              thisobject = eval(expr, self.namespace)
          except Exception:
              return []
  
          # get the content of the object, except __builtins__
          words = set(dir(thisobject))
          words.discard("__builtins__")
  
          if hasattr(thisobject, '__class__'):
              words.add('__class__')
              words.update(get_class_members(thisobject.__class__))
          matches = []
          n = len(attr)
          for word in words:
              if word[:n] == attr:
                  try:
                      val = getattr(thisobject, word)
                  except Exception:
                      continue  # Exclude properties that are not set
                  word = self._callable_postfix(val, "%s.%s" % (expr, word))
                  matches.append(word)
          matches.sort()
          return matches