# Copyright (c) 2025, TU Wien
# of Geodesy and Geoinformation (GEO).
# All rights reserved.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL VIENNA UNIVERSITY OF TECHNOLOGY,
# DEPARTMENT OF GEODESY AND GEOINFORMATION BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
eoDR file name definition.
"""
import copy
import os
from datetime import datetime
from collections import OrderedDict
from geopathfinder.file_naming import SmartFilename
[docs]
class EODRFilename(SmartFilename):
"""
eoDataReaders file name definition using SmartFilename class.
"""
fields_def = OrderedDict([('counter', {
'len': 5
}), ('id', {
'len': 12
}), ('dt_1', {
'len': 15
}), ('dt_2', {
'len': 15
}), ('file_num', {}), ('band', {})])
pad = "-"
delimiter = "_"
def __init__(self, fields, ext='.vrt', convert=False, compact=False):
"""
Constructor of eoDRFilename class.
Parameters
----------
fields: dict
Dictionary specifying the different parts of the filename.
ext: str, optional
Extension of the filename (default is '.vrt' for GDAL VRT files)
convert: bool, optional
If true, decoding is applied to parts of the filename, where such an operation is available (default is False).
"""
self.dt_format = "%Y%m%dT%H%M%S"
fields_def_ext = copy.deepcopy(EODRFilename.fields_def)
fields_def_ext['counter']['decoder'] = lambda x: self.decode_counter(x)
fields_def_ext['counter']['encoder'] = lambda x: self.encode_counter(x)
fields_def_ext['dt_1']['decoder'] = lambda x: self.decode_datetime(x)
fields_def_ext['dt_1']['encoder'] = lambda x: self.encode_datetime(x)
fields_def_ext['dt_2']['decoder'] = lambda x: self.decode_datetime(x)
fields_def_ext['dt_2']['encoder'] = lambda x: self.encode_datetime(x)
fields_def_ext['file_num']['decoder'] = lambda x: int(x)
fields_def_ext['file_num']['encoder'] = lambda x: str(x)
fields_def_ext['band']['encoder'] = lambda x: str(x)
fields_def_keys = list(fields_def_ext.keys())
for key in fields.keys():
if key not in fields_def_keys:
fields_def_ext[key] = {}
super(EODRFilename, self).__init__(fields,
fields_def_ext,
delimiter=EODRFilename.delimiter,
pad=EODRFilename.pad,
ext=ext,
convert=convert,
compact=compact)
[docs]
@classmethod
def from_filename(cls, filename_str, convert=False, compact=False):
"""
Converts a filename given as a string into an EODRFilename class object.
Parameters
----------
filename_str : str
Filename without any paths (e.g., "00001_123456------_20181220T232333_---------------_2_B5_34_aug.vrt").
convert: bool, optional
If true, decoding is applied to parts of the filename, where such an operation is available (default is False).
Returns
-------
EODRFilename
Class representing an EODR filename.
"""
fn_parts = os.path.splitext(os.path.basename(filename_str))[0].split(
EODRFilename.delimiter)
fields_def_ext = copy.deepcopy(EODRFilename.fields_def)
fields_def_ext['file_num']['len'] = len(fn_parts[4])
fields_def_ext['band']['len'] = len(
fn_parts[5]) # get length of the band in the filename
# if the filename consists of more than 4 parts, additional "dimensions" are added to the fields dictionary
if len(fn_parts) > 6:
for i, fn_part in enumerate(fn_parts[6:]):
key = 'd' + str(i + 1)
fields_def_ext[key] = {'len': len(fn_part)}
return super().from_filename(filename_str,
fields_def_ext,
pad=EODRFilename.pad,
delimiter=EODRFilename.delimiter,
convert=convert,
compact=compact)
@property
def stime(self):
"""
Start time.
Returns
-------
datetime.datetime
Start time.
"""
try:
if "-" not in self['dt_1']:
return self.decode_datetime(self['dt_1'])
else:
return None
except TypeError:
return None
@property
def etime(self):
""""
End time.
Returns
-------
datetime.datetime
End time.
"""
try:
if "-" not in self['dt_2']:
return self.decode_datetime(self['dt_2'])
else:
return None
except TypeError:
return None
[docs]
def decode_datetime(self, string):
"""
Decodes a string into a datetime object. The format is given by the class.
Parameters
----------
string: str, object
String needed to be decoded to a datetime object.
Returns
-------
datetime.datetime, object
Original object or datetime object parsed from the given string.
"""
if isinstance(string, str):
return datetime.strptime(string, self.dt_format)
else:
return string
[docs]
def encode_datetime(self, time_obj):
"""
Encodes a datetime object into a string. The format is given by the class.
Parameters
----------
time_obj: datetime.datetime, object
Datetime object needed to be encoded to a string.
Returns
-------
str, object
Original object or str object parsed from the given datetime object.
"""
if isinstance(time_obj, datetime):
return time_obj.strftime(self.dt_format)
else:
return time_obj
[docs]
def decode_counter(self, string):
"""
Decodes a string into an integer.
Parameters
----------
string: str, object
String needed to be decoded to an integer.
Returns
-------
int, object
Original object or integer object parsed from the given string.
"""
if isinstance(string, str):
return int(string)
else:
return string
[docs]
def encode_counter(self, file_counter):
"""
Encodes a file counter into a string.
Parameters
----------
file_counter: int
Integer needed to be encoded to a string.
Returns
-------
str, object
Original object or str object parsed from the given integer.
"""
if isinstance(file_counter, int):
return "{:05d}".format(file_counter)
else:
return file_counter
if __name__ == '__main__':
pass