# Buggy code
def copy(
    self,
    source,
    dest,
    name=None,
    shallow=False,
    expand_soft=False,
    expand_external=False,
    expand_refs=False,
    without_attrs=False,
):
    """Copy an object or group.

     The source can be a path, Group, Dataset, or Datatype object.  The
     destination can be either a path or a Group object.  The source and
     destinations need not be in the same file.

     If the source is a Group object, all objects contained in that group
     will be copied recursively.

     When the destination is a Group object, by default the target will
     be created in that group with its current name (basename of obj.name).
     You can override that by setting "name" to a string.

     There are various options which all default to "False":

      - shallow: copy only immediate members of a group.

      - expand_soft: expand soft links into new objects.

      - expand_external: expand external links into new objects.

      - expand_refs: copy objects that are pointed to by references.

      - without_attrs: copy object without copying attributes.

    Example:

     >>> f = File('myfile.hdf5')
     >>> f.listnames()
     ['MyGroup']
     >>> f.copy('MyGroup', 'MyCopy')
     >>> f.listnames()
     ['MyGroup', 'MyCopy']

    """
    with phil:
        if isinstance(source, HLObject):
            source_path = "."
        else:
            # Interpret source as a path relative to this group
            source_path = source
            source = self

        if isinstance(dest, Group):
            if name is not None:
                dest_path = name
            else:
                # copy source into dest group: dest_name/source_name
                dest_path = pp.basename(h5i.get_name(source[source_path].id))

        elif isinstance(dest, HLObject):
            raise TypeError("Destination must be path or Group object")
        else:
            # Interpret destination as a path relative to this group
            dest_path = dest
            dest = self

        flags = 0
        if shallow:
            flags |= h5o.COPY_SHALLOW_HIERARCHY_FLAG
        if expand_soft:
            flags |= h5o.COPY_EXPAND_SOFT_LINK_FLAG
        if expand_external:
            flags |= h5o.COPY_EXPAND_EXT_LINK_FLAG
        if expand_refs:
            flags |= h5o.COPY_EXPAND_REFERENCE_FLAG
        if without_attrs:
            flags |= h5o.COPY_WITHOUT_ATTR_FLAG
        if flags:
            copypl = h5p.create(h5p.OBJECT_COPY)
            copypl.set_copy_object(flags)
        else:
            copypl = None

        h5o.copy(
            source.id,
            self._e(source_path),
            dest.id,
            self._e(dest_path),
            copypl,
            base.dlcpl,
        )


# Traceback (ValueError)
Traceback (most recent call last):
File "/home/challtdow/workspace/pytest/bin/h5_bugtest.py", line 14, in <module>
h5_file.copy(h5_source, h5_group)
File "/usr/local/lib/python3.5/dist-packages/h5py/_hl/group.py", line 372, in copy
dest_path = pp.basename(h5i.get_name(source[source_path].id))
File "h5py/_objects.pyx", line 54, in h5py._objects.with_phil.wrapper
File "h5py/_objects.pyx", line 55, in h5py._objects.with_phil.wrapper
File "/usr/local/lib/python3.5/dist-packages/h5py/_hl/dataset.py", line 429, in __getitem__
new_dtype = readtime_dtype(self.id.dtype, names)
File "/usr/local/lib/python3.5/dist-packages/h5py/_hl/dataset.py", line 44, in readtime_dtype
raise ValueError("Field names only allowed for compound types")
ValueError: Field names only allowed for compound types

# Fixed code
def copy(
    self,
    source,
    dest,
    name=None,
    shallow=False,
    expand_soft=False,
    expand_external=False,
    expand_refs=False,
    without_attrs=False,
):
    """Copy an object or group.

     The source can be a path, Group, Dataset, or Datatype object.  The
     destination can be either a path or a Group object.  The source and
     destinations need not be in the same file.

     If the source is a Group object, all objects contained in that group
     will be copied recursively.

     When the destination is a Group object, by default the target will
     be created in that group with its current name (basename of obj.name).
     You can override that by setting "name" to a string.

     There are various options which all default to "False":

      - shallow: copy only immediate members of a group.

      - expand_soft: expand soft links into new objects.

      - expand_external: expand external links into new objects.

      - expand_refs: copy objects that are pointed to by references.

      - without_attrs: copy object without copying attributes.

    Example:

     >>> f = File('myfile.hdf5')
     >>> f.listnames()
     ['MyGroup']
     >>> f.copy('MyGroup', 'MyCopy')
     >>> f.listnames()
     ['MyGroup', 'MyCopy']

    """
    with phil:
        if isinstance(source, HLObject):
            source_path = "."
        else:
            # Interpret source as a path relative to this group
            source_path = source
            source = self

        if isinstance(dest, Group):
            if name is not None:
                dest_path = name
            elif source_path == ".":
                dest_path = pp.basename(h5i.get_name(source.id))
            else:
                # copy source into dest group: dest_name/source_name
                dest_path = pp.basename(h5i.get_name(source[source_path].id))

        elif isinstance(dest, HLObject):
            raise TypeError("Destination must be path or Group object")
        else:
            # Interpret destination as a path relative to this group
            dest_path = dest
            dest = self

        flags = 0
        if shallow:
            flags |= h5o.COPY_SHALLOW_HIERARCHY_FLAG
        if expand_soft:
            flags |= h5o.COPY_EXPAND_SOFT_LINK_FLAG
        if expand_external:
            flags |= h5o.COPY_EXPAND_EXT_LINK_FLAG
        if expand_refs:
            flags |= h5o.COPY_EXPAND_REFERENCE_FLAG
        if without_attrs:
            flags |= h5o.COPY_WITHOUT_ATTR_FLAG
        if flags:
            copypl = h5p.create(h5p.OBJECT_COPY)
            copypl.set_copy_object(flags)
        else:
            copypl = None

        h5o.copy(
            source.id,
            self._e(source_path),
            dest.id,
            self._e(dest_path),
            copypl,
            base.dlcpl,
        )