def output_sync_map_file(self, container_root_path=None): """ Output the sync map file for this task. If ``container_root_path`` is specified, the output sync map file will be created at the path obtained by joining the ``container_root_path`` and the relative path of the sync map inside the container. Otherwise, the sync map file will be created at the path ``self.sync_map_file_path_absolute``. Return the the path of the sync map file created, or ``None`` if an error occurred. :param string container_root_path: the path to the root directory for the output container :rtype: string """ if self.sync_map is None: self.log_exc(u"The sync_map object has not been set", None, True, TypeError) if (container_root_path is not None) and (self.sync_map_file_path is None): self.log_exc(u"The (internal) path of the sync map has been set", None, True, TypeError) self.log([u"container_root_path is %s", container_root_path]) self.log([u"self.sync_map_file_path is %s", self.sync_map_file_path]) self.log([u"self.sync_map_file_path_absolute is %s", self.sync_map_file_path_absolute]) if (container_root_path is not None) and (self.sync_map_file_path is not None): path = os.path.join(container_root_path, self.sync_map_file_path) elif self.sync_map_file_path_absolute: path = self.sync_map_file_path_absolute gf.ensure_parent_directory(path) self.log([u"Output sync map to %s", path]) sync_map_format = self.configuration["o_format"] audio_ref = self.configuration["o_smil_audio_ref"] page_ref = self.configuration["o_smil_page_ref"] self.log([u"sync_map_format is %s", sync_map_format]) self.log([u"page_ref is %s", page_ref]) self.log([u"audio_ref is %s", audio_ref]) self.log(u"Calling sync_map.write...") afpa = self.audio_file_path_absolute if afpa is not None: afpa = os.path.abspath(afpa) parameters = { "audio_file_path_absolute": afpa, gc.PPN_TASK_OS_FILE_SMIL_PAGE_REF : page_ref, gc.PPN_TASK_OS_FILE_SMIL_AUDIO_REF : audio_ref } self.sync_map.write(sync_map_format, path, parameters) self.log(u"Calling sync_map.write... done") return path
def compress(self, input_path): """ Compress the contents of the given directory. :param string input_path: path of the input directory :raises: TypeError: if the container path has not been set :raises: ValueError: if ``input_path`` is not an existing directory :raises: OSError: if an error occurred compressing the given container (e.g., empty file, damaged file, etc.) """ self.log([u"Compressing '%s' into this container", input_path]) if self.file_path is None: self.log_exc(u"The container path has not been set", None, True, TypeError) if self.actual_container is None: self.log_exc(u"The actual container object has not been set", None, True, TypeError) if not gf.directory_exists(input_path): self.log_exc(u"The input path is not an existing directory", None, True, ValueError) gf.ensure_parent_directory(input_path) self.actual_container.compress(input_path)
def test_ensure_parent_directory(self): orig = gf.tmp_directory() tmp_path = os.path.join(orig, "foo.bar") tmp_parent = orig gf.ensure_parent_directory(tmp_path) self.assertTrue(gf.directory_exists(tmp_parent)) tmp_path = os.path.join(orig, "foo/bar.baz") tmp_parent = os.path.join(orig, "foo") gf.ensure_parent_directory(tmp_path) self.assertTrue(gf.directory_exists(tmp_parent)) tmp_path = os.path.join(orig, "bar") gf.ensure_parent_directory(tmp_path, ensure_parent=False) self.assertTrue(gf.directory_exists(tmp_path)) gf.delete_directory(orig)
def test_ensure_parent_directory_no_parent_error(self): with self.assertRaises(OSError): gf.ensure_parent_directory("/foo/bar/baz", ensure_parent=False)
def output_sync_map_file(self, container_root_path=None): """ Output the sync map file for this task. If ``container_root_path`` is specified, the output sync map file will be created at the path obtained by joining the ``container_root_path`` and the relative path of the sync map inside the container. Otherwise, the sync map file will be created at the path ``self.sync_map_file_path_absolute``. Return the the path of the sync map file created, or ``None`` if an error occurred. :param string container_root_path: the path to the root directory for the output container :rtype: string """ if self.sync_map is None: self.log_exc(u"The sync_map object has not been set", None, True, TypeError) if (container_root_path is not None) and (self.sync_map_file_path is None): self.log_exc(u"The (internal) path of the sync map has been set", None, True, TypeError) self.log([u"container_root_path is %s", container_root_path]) self.log([u"self.sync_map_file_path is %s", self.sync_map_file_path]) self.log([ u"self.sync_map_file_path_absolute is %s", self.sync_map_file_path_absolute ]) if (container_root_path is not None) and (self.sync_map_file_path is not None): path = os.path.join(container_root_path, self.sync_map_file_path) elif self.sync_map_file_path_absolute: path = self.sync_map_file_path_absolute gf.ensure_parent_directory(path) self.log([u"Output sync map to %s", path]) eaf_audio_ref = self.configuration["o_eaf_audio_ref"] head_tail_format = self.configuration["o_h_t_format"] levels = self.configuration["o_levels"] smil_audio_ref = self.configuration["o_smil_audio_ref"] smil_page_ref = self.configuration["o_smil_page_ref"] sync_map_format = self.configuration["o_format"] self.log([u"eaf_audio_ref is %s", eaf_audio_ref]) self.log([u"head_tail_format is %s", head_tail_format]) self.log([u"levels is %s", levels]) self.log([u"smil_audio_ref is %s", smil_audio_ref]) self.log([u"smil_page_ref is %s", smil_page_ref]) self.log([u"sync_map_format is %s", sync_map_format]) self.log(u"Calling sync_map.write...") parameters = { gc.PPN_TASK_OS_FILE_EAF_AUDIO_REF: eaf_audio_ref, gc.PPN_TASK_OS_FILE_HEAD_TAIL_FORMAT: head_tail_format, gc.PPN_TASK_OS_FILE_LEVELS: levels, gc.PPN_TASK_OS_FILE_SMIL_AUDIO_REF: smil_audio_ref, gc.PPN_TASK_OS_FILE_SMIL_PAGE_REF: smil_page_ref, } self.sync_map.write(sync_map_format, path, parameters) self.log(u"Calling sync_map.write... done") return path
def write(self, sync_map_format, output_file_path, parameters=None): """ Write the current sync map to file in the requested format. Return ``True`` if the call succeeded, ``False`` if an error occurred. :param sync_map_format: the format of the sync map :type sync_map_format: :class:`~aeneas.syncmap.SyncMapFormat` :param string output_file_path: the path to the output file to write :param dict parameters: additional parameters (e.g., for ``SMIL`` output) :raises: ValueError: if ``sync_map_format`` is ``None`` or it is not an allowed value :raises: TypeError: if a required parameter is missing :raises: OSError: if ``output_file_path`` cannot be written """ def select_levels(syncmap, levels): """ Select the given levels of the fragments tree, modifying the given syncmap (always pass a copy of it!). """ self.log([u"Levels: '%s'", levels]) if levels is None: return try: levels = [int(l) for l in levels if int(l) > 0] syncmap.fragments_tree.keep_levels(levels) self.log([u"Selected levels: %s", levels]) except ValueError: self.log_warn(u"Cannot convert levels to list of int, returning unchanged") def set_head_tail_format(syncmap, head_tail_format=None): """ Set the appropriate head/tail nodes of the fragments tree, modifying the given syncmap (always pass a copy of it!). """ self.log([u"Head/tail format: '%s'", str(head_tail_format)]) tree = syncmap.fragments_tree head = tree.get_child(0) first = tree.get_child(1) last = tree.get_child(-2) tail = tree.get_child(-1) # mark HEAD as REGULAR if needed if head_tail_format == SyncMapHeadTailFormat.ADD: head.value.fragment_type = SyncMapFragment.REGULAR self.log(u"Marked HEAD as REGULAR") # stretch first and last fragment timings if needed if head_tail_format == SyncMapHeadTailFormat.STRETCH: self.log([u"Stretched first.begin: %.3f => %.3f (head)", first.value.begin, head.value.begin]) self.log([u"Stretched last.end: %.3f => %.3f (tail)", last.value.end, tail.value.end]) first.value.begin = head.value.begin last.value.end = tail.value.end # mark TAIL as REGULAR if needed if head_tail_format == SyncMapHeadTailFormat.ADD: tail.value.fragment_type = SyncMapFragment.REGULAR self.log(u"Marked TAIL as REGULAR") # remove all fragments that are not REGULAR for node in list(tree.dfs): if (node.value is not None) and (node.value.fragment_type != SyncMapFragment.REGULAR): node.remove() if sync_map_format is None: self.log_exc(u"Sync map format is None", None, True, ValueError) if sync_map_format not in SyncMapFormat.CODE_TO_CLASS: self.log_exc(u"Sync map format '%s' is not allowed" % (sync_map_format), None, True, ValueError) if not gf.file_can_be_written(output_file_path): self.log_exc(u"Cannot write sync map file '%s'. Wrong permissions?" % (output_file_path), None, True, OSError) self.log([u"Output format: '%s'", sync_map_format]) self.log([u"Output path: '%s'", output_file_path]) self.log([u"Output parameters: '%s'", parameters]) # select levels and head/tail format pruned_syncmap = self.clone() try: select_levels(pruned_syncmap, parameters[gc.PPN_TASK_OS_FILE_LEVELS]) except: self.log_warn([u"No %s parameter specified", gc.PPN_TASK_OS_FILE_LEVELS]) try: set_head_tail_format(pruned_syncmap, parameters[gc.PPN_TASK_OS_FILE_HEAD_TAIL_FORMAT]) except: self.log_warn([u"No %s parameter specified", gc.PPN_TASK_OS_FILE_HEAD_TAIL_FORMAT]) # create writer # the constructor will check for required parameters, if any # if some are missing, it will raise a SyncMapMissingParameterError writer = (SyncMapFormat.CODE_TO_CLASS[sync_map_format])( variant=sync_map_format, parameters=parameters, rconf=self.rconf, logger=self.logger ) # create dir hierarchy, if needed gf.ensure_parent_directory(output_file_path) # open file for writing self.log(u"Writing output file...") with io.open(output_file_path, "w", encoding="utf-8") as output_file: output_file.write(writer.format(syncmap=pruned_syncmap)) self.log(u"Writing output file... done")
def write(self, sync_map_format, output_file_path, parameters=None): """ Write the current sync map to file in the requested format. Return ``True`` if the call succeeded, ``False`` if an error occurred. :param sync_map_format: the format of the sync map :type sync_map_format: :class:`~aeneas.syncmap.SyncMapFormat` :param string output_file_path: the path to the output file to write :param dict parameters: additional parameters (e.g., for ``SMIL`` output) :raises: ValueError: if ``sync_map_format`` is ``None`` or it is not an allowed value :raises: TypeError: if a required parameter is missing :raises: OSError: if ``output_file_path`` cannot be written """ def select_levels(syncmap, levels): """ Select the given levels of the fragments tree, modifying the given syncmap (always pass a copy of it!). """ self.log([u"Levels: '%s'", levels]) if levels is None: return try: levels = [int(l) for l in levels if int(l) > 0] syncmap.fragments_tree.keep_levels(levels) self.log([u"Selected levels: %s", levels]) except ValueError: self.log_warn( u"Cannot convert levels to list of int, returning unchanged" ) def set_head_tail_format(syncmap, head_tail_format=None): """ Set the appropriate head/tail nodes of the fragments tree, modifying the given syncmap (always pass a copy of it!). """ self.log([u"Head/tail format: '%s'", str(head_tail_format)]) tree = syncmap.fragments_tree head = tree.get_child(0) first = tree.get_child(1) last = tree.get_child(-2) tail = tree.get_child(-1) # mark HEAD as REGULAR if needed if head_tail_format == SyncMapHeadTailFormat.ADD: head.value.fragment_type = SyncMapFragment.REGULAR self.log(u"Marked HEAD as REGULAR") # stretch first and last fragment timings if needed if head_tail_format == SyncMapHeadTailFormat.STRETCH: self.log([ u"Stretched first.begin: %.3f => %.3f (head)", first.value.begin, head.value.begin ]) self.log([ u"Stretched last.end: %.3f => %.3f (tail)", last.value.end, tail.value.end ]) first.value.begin = head.value.begin last.value.end = tail.value.end # mark TAIL as REGULAR if needed if head_tail_format == SyncMapHeadTailFormat.ADD: tail.value.fragment_type = SyncMapFragment.REGULAR self.log(u"Marked TAIL as REGULAR") # remove all fragments that are not REGULAR for node in list(tree.dfs): if (node.value is not None) and (node.value.fragment_type != SyncMapFragment.REGULAR): node.remove() if sync_map_format is None: self.log_exc(u"Sync map format is None", None, True, ValueError) if sync_map_format not in SyncMapFormat.CODE_TO_CLASS: self.log_exc( u"Sync map format '%s' is not allowed" % (sync_map_format), None, True, ValueError) if not gf.file_can_be_written(output_file_path): self.log_exc( u"Cannot write sync map file '%s'. Wrong permissions?" % (output_file_path), None, True, OSError) self.log([u"Output format: '%s'", sync_map_format]) self.log([u"Output path: '%s'", output_file_path]) self.log([u"Output parameters: '%s'", parameters]) # select levels and head/tail format pruned_syncmap = self.clone() try: select_levels(pruned_syncmap, parameters[gc.PPN_TASK_OS_FILE_LEVELS]) except: self.log_warn( [u"No %s parameter specified", gc.PPN_TASK_OS_FILE_LEVELS]) try: set_head_tail_format( pruned_syncmap, parameters[gc.PPN_TASK_OS_FILE_HEAD_TAIL_FORMAT]) except: self.log_warn([ u"No %s parameter specified", gc.PPN_TASK_OS_FILE_HEAD_TAIL_FORMAT ]) # create writer # the constructor will check for required parameters, if any # if some are missing, it will raise a SyncMapMissingParameterError writer = (SyncMapFormat.CODE_TO_CLASS[sync_map_format])( variant=sync_map_format, parameters=parameters, rconf=self.rconf, logger=self.logger) # create dir hierarchy, if needed gf.ensure_parent_directory(output_file_path) # open file for writing self.log(u"Writing output file...") with io.open(output_file_path, "w", encoding="utf-8") as output_file: output_file.write(writer.format(syncmap=pruned_syncmap)) self.log(u"Writing output file... done")