Source code for s1tiling.libs.file_naming

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# =========================================================================
#   Program:   S1Processor
#
#   All rights reserved.
#   Copyright 2017-2025 (c) CNES.
#
#   This file is part of S1Tiling project
#       https://gitlab.orfeo-toolbox.org/s1-tiling/s1tiling
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       https://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
# =========================================================================
#
# Authors: Thierry KOLECK (CNES)
#          Luc HERMITTE (CS Group)
# =========================================================================

"""
This module provide filename generator classes
"""

import os
from abc import ABC, abstractmethod
from typing import Dict, List, Union

from .utils.formatters import ExtendedFormatter


class OutputFilenameGenerator(ABC):
    """
    Abstract class for generating filenames.
    Several policies are supported as of now:
    - return the input string (default implementation)
    - replace a text with another one
    - {template} strings
    - list of any of the other two
    """
    def generate(self, basename: str, keys: Dict) -> Union[str, List[str]]:  # pylint: disable=unused-argument
        """
        Default implementation does nothing.
        """
        return basename

    @abstractmethod
    def has_several_outputs(self) -> bool:
        """
        Tells whether the generator is specialized for several outputs
        """


[docs] class ReplaceOutputFilenameGenerator(OutputFilenameGenerator): """ Given a pair ``[text_to_search, text_to_replace_with]``, replace the exact matching text with new text in ``basename`` metadata. """ def __init__(self, before_afters: List) -> None: assert isinstance(before_afters, list) self.__before_afters = before_afters
[docs] def generate(self, basename, keys: Dict) -> str: filename = basename.replace(*self.__before_afters) return filename
[docs] def has_several_outputs(self) -> bool: return False
class CannotGenerateFilename(KeyError): """ Exception used to filter out cases where a meta cannot serve as a direct input of a :class:`StepFactory`. """ pass
[docs] class TemplateOutputFilenameGenerator(OutputFilenameGenerator): """ Given a template: ``"text{key1}_{another_key}_.."``, inject the metadata instead of the template keys. Most filename format templates can be fine tuned to end-user ideal filenames. While the filenames used for intermediary products may be changed, it's not recommended for data flow stability. :ref:`All Python standard format specifiers <formatspec>` plus extra conversion fields are supported: - ``!c`` will capitalize a field -- only the first letter will be in uppercase - ``!l`` will output the field in lowercase - ``!u`` will output the field in uppercase See :ref:`[Processing].fname_fmt.* <Processing.fname_fmt>` for the short list of filenames meant to be adapted, and the list of available fields. """ def __init__(self, template) -> None: assert isinstance(template, str) self.__template = template
[docs] def generate(self, basename, keys: Dict) -> str: try: rootname = os.path.splitext(basename)[0] filename = ExtendedFormatter().format(self.__template, **keys, rootname=rootname) return filename except KeyError as e: raise CannotGenerateFilename(f'Impossible to generate a filename matching {self.__template} from {keys}') from e
[docs] def has_several_outputs(self) -> bool: return False
[docs] class OutputFilenameGeneratorList(OutputFilenameGenerator): """ Some steps produce several products. This specialization permits to generate several output filenames. It's constructed from other filename generators. """ def __init__(self, generators) -> None: assert isinstance(generators, list) self.__generators = generators
[docs] def generate(self, basename, keys) -> List[str]: filenames = [generator.generate(basename, keys) for generator in self.__generators] return filenames
[docs] def has_several_outputs(self) -> bool: return True