Represent the data linked to the basename of a file.
Use instances of this class to hold data related to the root of a file. The root of a file is its name without the pattern nor the extension.
Represent the data linked to the basename of a file.
Use instances of this class to hold data related to the root of a file. The root of a file is its name without the pattern nor the extension.
Constructor of a FileRoot.
def __init__(self, name):
"""Constructor of a FileRoot.
:param name: (str) Filename or root name
"""
if os.path.exists(name):
root_name = FileRoot.root(name)
else:
root_name = name
super(FileRoot, self).__init__(root_name)
self.__files = list()
self.__references = None
self.subjoined = None
Return the pattern of the given filename.
A pattern is the end of the filename, after the '-'. It can't contain '_' and must be between 1 and 12 characters (not including the '-').
Notice that the '_' can't be supported (too many side effects).
@staticmethod
def pattern(filename):
"""Return the pattern of the given filename.
A pattern is the end of the filename, after the '-'.
It can't contain '_' and must be between 1 and 12 characters
(not including the '-').
Notice that the '_' can't be supported (too many side effects).
:param filename: (str) Name of a file (absolute or relative)
:returns: (str) Root pattern or an empty string if no pattern is detected
"""
fn = os.path.basename(filename)
base = os.path.basename(os.path.splitext(fn)[0])
pos = 0
if '-' in base:
pos = base.rindex('-')
p = base[pos:]
if '_' in p or len(p) < 2 or len(p) > 13:
pos = 0
if pos > 0:
return base[pos:]
return ''
Return the root of the given filename.
@staticmethod
def root(filename):
"""Return the root of the given filename.
:param filename: (str) Name of a file (absolute or relative)
:returns: (str) Root
"""
p = FileRoot.pattern(filename)
base_file, ext_file = os.path.splitext(filename)
return filename[:len(filename) - len(p) - len(ext_file)]
Set a state value to a filename of this fileroot.
sppasTypeError
def set_object_state(self, value, filename):
"""Set a state value to a filename of this fileroot.
:param value: (int) A state of FileName.
:param filename: (FileName) The instance to change state
:return: (list) Modified instances
:raises: sppasTypeError
"""
for fn in self.__files:
if fn == filename:
m = fn.set_state(value)
if m is True:
changed = list()
changed.append(fn)
m = self.update_state()
if m is True:
changed.append(self)
return changed
return list()
Set a value to represent the state of this root.
It is not allowed to manually assign one of the "ATLEAST" states (they are automatically fixed by setting the state of a FileName with setobject_state method).
The state of LOCKED files can't be changed with this method. Use setobjectstate() instead.
def set_state(self, value):
"""Set a value to represent the state of this root.
It is not allowed to manually assign one of the "AT_LEAST" states
(they are automatically fixed by setting the state of a FileName
with set_object_state method).
The state of LOCKED files can't be changed with this method.
Use set_object_state() instead.
:param value: (State) A state of FileName.
:return: (list) Modified instances
"""
if value not in FileName.FILENAME_STATES:
raise sppasTypeError(value, str(FileName.FILENAME_STATES))
modified = list()
for fn in self.__files:
if fn.get_state() != States().LOCKED:
m = fn.set_state(value)
if m is True:
modified.append(fn)
if len(modified) > 0:
m = self.update_state()
if m is True:
modified.append(self)
return modified
Update the state depending on the checked and locked filenames.
The state of a root is assigned as it: - locked if all files are locked, - atleastonelocked if at least one of its filenames is locked, - checked if all filenames are checked, - atleastonechecked if at least one of its filenames is checked and none of the others are locked, - missing if at least one of its filenames is missing and none of the others are locked nor checked, - missing if all its filenames are missing, - unused if none of its filenames are neither locked nor checked.
def update_state(self):
"""Update the state depending on the checked and locked filenames.
The state of a root is assigned as it:
- locked if all files are locked,
- at_least_one_locked if at least one of its filenames is locked,
- checked if all filenames are checked,
- at_least_one_checked if at least one of its filenames is checked and none of the others are locked,
- missing if at least one of its filenames is missing and none of the others are locked nor checked,
- missing if all its filenames are missing,
- unused if none of its filenames are neither locked nor checked.
:return: (bool) State is changed or not
"""
missing = 0
if len(self.__files) == 0:
new_state = States().UNUSED
else:
checked = 0
locked = 0
for fn in self.__files:
if fn.get_state() == States().CHECKED:
checked += 1
elif fn.get_state() == States().LOCKED:
locked += 1
elif fn.get_state() == States().MISSING:
missing += 1
if locked == len(self.__files):
new_state = States().LOCKED
elif locked > 0:
new_state = States().AT_LEAST_ONE_LOCKED
elif checked == len(self.__files):
new_state = States().CHECKED
elif checked > 0:
new_state = States().AT_LEAST_ONE_CHECKED
elif missing == len(self.__files):
new_state = States().MISSING
else:
new_state = States().UNUSED
if self._state != new_state:
self._state = new_state
return True
return False
Return the list of references of the catalog.
def get_references(self):
"""Return the list of references of the catalog.
:returns: (list)
"""
if self.__references is None:
return list()
return self.__references
Return True if the root contains the given reference.
def has_ref(self, ref):
"""Return True if the root contains the given reference.
:param ref: (sppasReference)
:returns: (bool)
"""
if isinstance(ref, sppasCatReference) is False:
raise sppasTypeError(ref, 'sppasCatReference')
if len(self.get_references()) == 0:
return False
for r in self.get_references():
if r.id == ref.id:
return True
return False
Associate a new reference to the root.
def add_ref(self, ref):
"""Associate a new reference to the root.
:param ref: (sppasReference)
:return: (bool)
"""
has = self.has_ref(ref)
if has is True:
return False
if self.__references is None:
self.__references = list()
self.__references.append(ref)
return True
Remove a reference to unlink it to this root.
def remove_ref(self, ref):
"""Remove a reference to unlink it to this root.
:param ref: (sppasReference)
:return: (bool)
"""
for r in self.get_references():
if r.id == ref.id:
self.__references.remove(r)
return True
return False
Fix the list of references.
The current list is overridden.
sppasTypeError
def set_references(self, list_of_references):
"""Fix the list of references.
The current list is overridden.
:param list_of_references: (list)
:raises: sppasTypeError
"""
self.__references = list()
if isinstance(list_of_references, list):
if len(list_of_references) > 0:
for reference in list_of_references:
if isinstance(reference, sppasCatReference) is False:
raise sppasTypeError(reference, 'sppasCatReference')
self.__references = list_of_references
else:
raise sppasTypeError(list_of_references, 'list')
Return the instance matching the given filename.
Return self if filename is matching the id.
def get_object(self, filename):
"""Return the instance matching the given filename.
Return self if filename is matching the id.
:param filename: Full name of a file
:returns: (FileName of None)
"""
fr = FileRoot.root(filename)
if fr != self.id:
return None
if fr == filename:
return self
fn = FileName(filename)
for frn in self.__files:
if frn.id == fn.id:
return frn
return None
Append a filename in the list of files.
'filename' must be the absolute name of a file or an instance of FileName.
def append(self, filename, all_root=False, ctime=0.0):
"""Append a filename in the list of files.
'filename' must be the absolute name of a file or an instance
of FileName.
:param filename: (str, FileName) Absolute name of a file
:param all_root: (bool) Add all files sharing the same root
:param ctime: (float) Add files only if created/modified after time in seconds since the epoch
:returns: (list of FileName) the appended FileName() instances or None
"""
if filename is None:
self.update_state()
return list()
fns = list()
fn = filename
if isinstance(filename, FileName) is False:
fn = FileName(filename)
if fn.get_state() != States().MISSING:
if self.id != FileRoot.root(fn.id):
raise FileRootValueError(fn.id, self.id)
if all_root is False and fn not in self:
if os.path.getmtime(fn.get_id()) > ctime:
self.__files.append(fn)
fns.append(fn)
if all_root is True:
for new_filename in sorted(glob.glob(self.id + '*')):
if os.path.isfile(new_filename) is True:
fnx = FileName(new_filename)
frx = FileRoot(fnx.id)
if frx.id == self.id and fnx.get_id() not in self:
if os.path.getmtime(fnx.get_id()) > ctime:
self.__files.append(fnx)
fns.append(fnx)
else:
self.__files.append(fn)
fns.append(fn)
self.update_state()
return fns
Remove a filename of the list of files.
Given filename must be the absolute name of a file or an instance of FileName.
def remove(self, filename):
"""Remove a filename of the list of files.
Given filename must be the absolute name of a file or an instance
of FileName.
:param filename: (str, FileName) Absolute name of a file
:returns: (identifier) Identifier of the removed FileName or None if nothing removed.
"""
idx = -1
if isinstance(filename, FileName):
try:
idx = self.__files.index(filename)
except ValueError:
idx = -1
else:
for i, fn in enumerate(self.__files):
if fn.id == filename:
idx = i
break
identifier = None
if idx != -1:
identifier = self.__files[idx].get_id()
self.__files.pop(idx)
upd = self.update_state()
if upd is True:
logging.debug('FileRoot {:s} state changed to {:d}'.format(self.get_id(), self.get_state()))
return identifier
def __repr__(self):
return 'Root: ' + self.id + ' contains ' + str(len(self.__files)) + ' files\n'
def __iter__(self):
for a in self.__files:
yield a
def __getitem__(self, i):
return self.__files[i]
def __len__(self):
return len(self.__files)
def __contains__(self, value):
if isinstance(value, FileName):
return value in self.__files
for fn in self.__files:
if fn.id == value:
return True
return False