docs: def copytree(self, dest_dir, src=None, newname=None,
                   exclude=None, overwrite=False):
          """
          Copy this directory or just one contained object into another
          directory.
  
          Parameters
          ----------
  
          dest_dir : string or Directory
              The destination directory.
  
          src : string, optional (default=None)
              If ``src`` is None then this entire directory is copied recursively
              otherwise if ``src`` is a string path to an object relative to this
              directory, only that object will be copied. The copied object can
              optionally be given a ``newname``.
  
          newname : string, optional (default=None)
              An optional new name for the copied object.
  
          exclude : callable, optional (default=None)
              ``exclude`` can optionally be a function which takes
              ``(path, object_name)`` and if returns True excludes
              objects from being copied if the entire directory is being copied
              recursively.
  
          overwrite : bool, optional (default=False)
              If True, then overwrite existing objects with the same name.
  
          """
          def copy_object(obj, dest, name=None):
              if name is None:
                  name = obj.GetName()
              if not overwrite and name in dest:
                  raise ValueError(
                      "{0} already exists in {1} and `overwrite=False`".format(
                          name, dest._path))
              dest.cd()
              if isinstance(obj, ROOT.R.TTree):
                  new_obj = obj.CloneTree(-1, "fast")
                  new_obj.Write(name, ROOT.R.TObject.kOverwrite)
              else:
                  obj.Write(name, ROOT.R.TObject.kOverwrite)
  
          with preserve_current_directory():
              if isinstance(src, string_types):
                  src = asrootpy(self.Get(src))
              else:
                  src = self
              if isinstance(dest_dir, string_types):
                  try:
                      dest_dir = asrootpy(self.GetDirectory(dest_dir))
                  except DoesNotExist:
                      dest_dir = self.mkdir(dest_dir)
              if isinstance(src, ROOT.R.TDirectory):
                  # Copy a directory
                  cp_name = newname if newname is not None else src.GetName()
                  # See if the directory already exists
                  if cp_name not in dest_dir:
                      # Destination directory doesn't exist, so make a new one
                      new_dir = dest_dir.mkdir(cp_name)
                  else:
                      new_dir = dest_dir.get(cp_name)
                  # Copy everything in the src directory to the destination
                  for (path, dirnames, objects) in src.walk(maxdepth=0):
                      # Copy all the objects
                      for object_name in objects:
                          if exclude and exclude(path, object_name):
                              continue
                          thing = src.Get(object_name)
                          copy_object(thing, new_dir)
                      for dirname in dirnames:
                          if exclude and exclude(path, dirname):
                              continue
                          rdir = src.GetDirectory(dirname)
                          # Recursively copy objects in subdirectories
                          rdir.copytree(
                              new_dir,
                              exclude=exclude, overwrite=overwrite)
              else:
                  # Copy an object
                  copy_object(src, dest_dir, name=newname)