code: def rmtree(path, ignore_errors=False, onerror=None):
      
      if ignore_errors:
          def onerror(*args):
              pass
      elif onerror is None:
          def onerror(*args):
              raise
      try:
          if os.path.islink(path):
              # symlinks to directories are forbidden, see bug #1669
              raise OSError("Cannot call rmtree on a symbolic link")
      except OSError:
          onerror(os.path.islink, path, sys.exc_info())
          # can't continue even if onerror hook returns
          return
      names = []
      try:
          names = os.listdir(path)
      except os.error:
          onerror(os.listdir, path, sys.exc_info())
      for name in names:
          fullname = os.path.join(path, name)
          try:
              mode = os.lstat(fullname).st_mode
          except os.error:
              mode = 0
          if stat.S_ISDIR(mode):
              rmtree(fullname, ignore_errors, onerror)
          else:
              try:
                  os.remove(fullname)
              except os.error:
                  onerror(os.remove, fullname, sys.exc_info())
      try:
          os.rmdir(path)
      except os.error:
          onerror(os.rmdir, path, sys.exc_info())
docs: Recursively delete a directory tree.
  
      If ignore_errors is set, errors are ignored; otherwise, if onerror
      is set, it is called to handle the error with arguments (func,
      path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
      path is the argument to that function that caused it to fail; and
      exc_info is a tuple returned by sys.exc_info().  If ignore_errors
      is false and onerror is None, an exception is raised.