docs: def _build_cache(source_file, skip_cache=False):
      """Build the cached data.
  
      Either by parsing the RDF taxonomy file or a vocabulary file.
  
      :param source_file: source file of the taxonomy, RDF file
      :param skip_cache: if True, build cache will not be
          saved (pickled) - it is saved as <source_file.db>
      """
      store = rdflib.ConjunctiveGraph()
  
      if skip_cache:
          current_app.logger.info("You requested not to save the cache to disk.")
      else:
          cache_path = _get_cache_path(source_file)
          cache_dir = os.path.dirname(cache_path)
          # Make sure we have a cache_dir readable and writable.
          if not os.path.isdir(cache_dir):
              os.makedirs(cache_dir)
          if os.access(cache_dir, os.R_OK):
              if not os.access(cache_dir, os.W_OK):
                  raise TaxonomyError("Cache directory exists but is not"
                                      " writable. Check your permissions"
                                      " for: %s" % cache_dir)
          else:
              raise TaxonomyError("Cache directory does not exist"
                                  " (and could not be created): %s" % cache_dir)
  
      timer_start = time.clock()
  
      namespace = None
      single_keywords, composite_keywords = {}, {}
  
      try:
          current_app.logger.info(
              "Building RDFLib's conjunctive graph from: %s" % source_file)
          try:
              store.parse(source_file)
          except urllib_error.URLError:
              if source_file[0] == '/':
                  store.parse("file://" + source_file)
              else:
                  store.parse("file:///" + source_file)
  
      except rdflib.exceptions.Error as e:
          current_app.logger.exception("Serious error reading RDF file")
          raise
  
      except (xml.sax.SAXParseException, ImportError) as e:
          # File is not a RDF file. We assume it is a controlled vocabulary.
          current_app.logger.error(e)
          current_app.logger.warning("The ontology file is probably not a valid RDF file. \
              Assuming it is a controlled vocabulary file.")
  
          filestream = open(source_file, "r")
          for line in filestream:
              keyword = line.strip()
              kt = KeywordToken(keyword)
              single_keywords[kt.short_id] = kt
          if not len(single_keywords):
              raise TaxonomyError('The ontology file is not well formated')
  
      else:  # ok, no exception happened
          current_app.logger.info("Now building cache of keywords")
          # File is a RDF file.
          namespace = rdflib.Namespace("http://www.w3.org/2004/02/skos/core#")
  
          single_count = 0
          composite_count = 0
  
          subject_objects = store.subject_objects(namespace["prefLabel"])
          for subject, pref_label in subject_objects:
              kt = KeywordToken(subject, store=store, namespace=namespace)
              if kt.isComposite():
                  composite_count += 1
                  composite_keywords[kt.short_id] = kt
              else:
                  single_keywords[kt.short_id] = kt
                  single_count += 1
  
      cached_data = {}
      cached_data["single"] = single_keywords
      cached_data["composite"] = composite_keywords
      cached_data["creation_time"] = time.gmtime()
      cached_data["version_info"] = {'rdflib': rdflib.__version__}
      current_app.logger.debug(
          "Building taxonomy... %d terms built in %.1f sec." %
          (len(single_keywords) + len(composite_keywords),
           time.clock() - timer_start))
  
      current_app.logger.info(
          "Total count of single keywords: %d "
          % len(single_keywords)
      )
      current_app.logger.info(
          "Total count of composite keywords: %d "
          % len(composite_keywords)
      )
  
      if not skip_cache:
          cache_path = _get_cache_path(source_file)
          cache_dir = os.path.dirname(cache_path)
          current_app.logger.debug("Writing the cache into: %s" % cache_path)
          # test again, it could have changed
          if os.access(cache_dir, os.R_OK):
              if os.access(cache_dir, os.W_OK):
                  # Serialize.
                  filestream = None
                  try:
                      filestream = open(cache_path, "wb")
                  except IOError as msg:
                      # Impossible to write the cache.
                      current_app.logger.error(
                          "Impossible to write cache to '%s'."
                          % cache_path)
                      current_app.logger.error(msg)
                  else:
                      current_app.logger.debug(
                          "Writing cache to file %s" % cache_path)
                      cPickle.dump(cached_data, filestream, 1)
                  if filestream:
                      filestream.close()
  
              else:
                  raise TaxonomyError("Cache directory exists but is not "
                                      "writable. Check your permissions "
                                      "for: %s" % cache_dir)
          else:
              raise TaxonomyError("Cache directory does not exist"
                                  " (and could not be created): %s" % cache_dir)
  
      # now when the whole taxonomy was parsed,
      # find sub-components of the composite kws
      # it is important to keep this call after the taxonomy was saved,
      # because we don't  want to pickle regexes multiple times
      # (as they are must be re-compiled at load time)
      for kt in composite_keywords.values():
          kt.refreshCompositeOf(single_keywords, composite_keywords,
                                store=store, namespace=namespace)
  
      # house-cleaning
      if store:
          store.close()
  
      return (single_keywords, composite_keywords)