docs: def writes(mdict, filename='data.h5', truncate_existing=False,
             truncate_invalid_matlab=False, options=None, **keywords):
      """ Writes data into an HDF5 file (high level).
  
      High level function to store one or more Python types (data) to
      specified pathes in an HDF5 file. The paths are specified as POSIX
      style paths where the directory name is the Group to put it in and
      the basename is the name to write it to.
  
      There are various options that can be used to influence how the data
      is written. They can be passed as an already constructed ``Options``
      into `options` or as additional keywords that will be used to make
      one by ``options = Options(**keywords)``.
  
      Two very important options are ``store_python_metadata`` and
      ``matlab_compatible``, which are ``bool``. The first makes it so
      that enough metadata (HDF5 Attributes) are written that `data` can
      be read back accurately without it (or its contents if it is a
      container type) ending up different types, transposed in the case of
      numpy arrays, etc. The latter makes it so that the appropriate
      metadata is written, string and bool and complex types are converted
      properly, and numpy arrays are transposed; which is needed to make
      sure that MATLAB can import `data` correctly (the HDF5 header is
      also set so MATLAB will recognize it).
  
      Paths are POSIX style and can either be given directly as ``str`` or
      ``bytes``, or the separated path can be given as an iterable of
      ``str`` and ``bytes``. Each part of a separated path is escaped
      using ``utilities.escape_path``. Otherwise, the path is assumed to
      be already escaped. Escaping is done so that targets with a part
      that starts with one or more periods, contain slashes, and/or
      contain nulls can be used without causing the wrong Group to be
      looked in or the wrong target to be looked at. It essentially allows
      one to make a Dataset named ``'..'`` or ``'a/a'`` instead of moving
      around in the Dataset hierarchy.
  
      Parameters
      ----------
      mdict : dict, dict like
          The ``dict`` or other dictionary type object of paths
          and data to write to the file. The paths, the keys, must be
          POSIX style paths where the directory name is the Group to put
          it in and the basename is the name to write it to. The values
          are the data to write.
      filename : str, optional
          The name of the HDF5 file to write `data` to.
      truncate_existing : bool, optional
          Whether to truncate the file if it already exists before writing
          to it.
      truncate_invalid_matlab : bool, optional
          Whether to truncate a file if matlab_compatibility is being
          done and the file doesn't have the proper header (userblock in
          HDF5 terms) setup for MATLAB metadata to be placed.
      options : Options, optional
          The options to use when writing. Is mutually exclusive with any
          additional keyword arguments given (set to ``None`` or don't
          provide to use them).
      **keywords :
          If `options` was not provided or was ``None``, these are used as
          arguments to make a ``Options``.
  
      Raises
      ------
      TypeError
          If a path is of an invalid type.
      NotImplementedError
          If writing `data` is not supported.
      exceptions.TypeNotMatlabCompatibleError
          If writing a type not compatible with MATLAB and
          `options.action_for_matlab_incompatible` is set to ``'error'``.
  
      See Also
      --------
      utilities.process_path
      utilities.escape_path
      write : Writes just a single piece of data
      reads
      read
      Options
      utilities.write_data : Low level version
  
      """
      # Pack the different options into an Options class if an Options was
      # not given.
      if not isinstance(options, Options):
          options = Options(**keywords)
  
      # Go through mdict, extract the paths and data, and process the
      # paths. A list of tulpes for each piece of data to write will be
      # constructed where he first element is the group name, the second
      # the target name (name of the Dataset/Group holding the data), and
      # the third element the data to write.
      towrite = []
      for p, v in mdict.items():
          groupname, targetname = utilities.process_path(p)
  
          # Pack into towrite.
          towrite.append((groupname, targetname, v))
  
      # Open/create the hdf5 file but don't write the data yet since the
      # userblock still needs to be set. This is all wrapped in a try
      # block, so that the file can be closed if any errors happen (the
      # error is re-raised).
      f = None
      try:
  
          # If the file doesn't already exist or the option is set to
          # truncate it if it does, just open it truncating whatever is
          # there. Otherwise, open it for read/write access without
          # truncating. Now, if we are doing matlab compatibility and it
          # doesn't have a big enough userblock (for metadata for MATLAB
          # to be able to tell it is a valid .mat file) and the
          # truncate_invalid_matlab is set, then it needs to be closed and
          # re-opened with truncation. Whenever we create the file from
          # scratch, even if matlab compatibility isn't being done, a
          # sufficiently sized userblock is going to be allocated
          # (smallest size is 512) for future use (after all, someone
          # might want to turn it to a .mat file later and need it and it
          # is only 512 bytes).
  
          if truncate_existing or not os.path.isfile(filename):
              f = h5py.File(filename, mode='w', userblock_size=512)
          else:
              f = h5py.File(filename)
              if options.matlab_compatible and truncate_invalid_matlab \
                      and f.userblock_size < 128:
                  f.close()
                  f = h5py.File(filename, mode='w', userblock_size=512)
      except:
          raise
      finally:
          # If the hdf5 file was opened at all, get the userblock size and
          # close it since we need to set the userblock.
          if isinstance(f, h5py.File):
              userblock_size = f.userblock_size
              f.close()
          else:
              raise IOError('Unable to create or open file.')
  
      # If we are doing MATLAB formatting and there is a sufficiently
      # large userblock, write the new userblock. The same sort of error
      # handling is used.
      if options.matlab_compatible and userblock_size >= 128:
          # Get the time.
          now = datetime.datetime.now()
  
          # Construct the leading string. The MATLAB one looks like
          #
          # s = 'MATLAB 7.3 MAT-file, Platform: GLNXA64, Created on: ' \
          #     + now.strftime('%a %b %d %H:%M:%S %Y') \
          #     + ' HDF5 schema 1.00 .'
          #
          # Platform is going to be changed to hdf5storage version.
  
          s = 'MATLAB 7.3 MAT-file, Platform: hdf5storage ' \
              + __version__ + ', Created on: ' \
              + now.strftime('%a %b %d %H:%M:%S %Y') \
              + ' HDF5 schema 1.00 .'
  
          # Make the bytearray while padding with spaces up to 128-12
          # (the minus 12 is there since the last 12 bytes are special.
  
          b = bytearray(s + (128-12-len(s))*' ', encoding='utf-8')
  
          # Add 8 nulls (0) and the magic number (or something) that
          # MATLAB uses.
  
          b.extend(bytearray.fromhex('00000000 00000000 0002494D'))
  
          # Now, write it to the beginning of the file.
  
          try:
              fd = open(filename, 'r+b')
              fd.write(b)
          except:
              raise
          finally:
              fd.close()
  
      # Open the hdf5 file again and write the data, making the Group if
      # necessary. This is all wrapped in a try block, so that the file
      # can be closed if any errors happen (the error is re-raised).
      f = None
      try:
          f = h5py.File(filename)
  
          # Go through each element of towrite and write them.
          for groupname, targetname, data in towrite:
              # Need to make sure groupname is a valid group in f and grab its
              # handle to pass on to the low level function.
              if groupname not in f:
                  grp = f.require_group(groupname)
              else:
                  grp = f[groupname]
  
              # Hand off to the low level function.
              utilities.write_data(f, grp, targetname, data,
                                   None, options)
      except:
          raise
      finally:
          if isinstance(f, h5py.File):
              f.close()