SPPAS 4.22

https://sppas.org/

Module sppas.src.wkps

Class FileRoot

Description

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

Constructor of a FileRoot.

Parameters
  • name: (str) Filename or root name
View Source
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

Public functions

pattern

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).

Parameters
  • filename: (str) Name of a file (absolute or relative)
Returns
  • (str) Root pattern or an empty string if no pattern is detected
View Source
@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 ''

root

Return the root of the given filename.

Parameters
  • filename: (str) Name of a file (absolute or relative)
Returns
  • (str) Root
View Source
@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_object_state

Set a state value to a filename of this fileroot.

Parameters
  • value: (int) A state of FileName.
  • filename: (FileName) The instance to change state
Returns
  • (list) Modified instances
Raises

sppasTypeError

View Source
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_state

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.

Parameters
  • value: (State) A state of FileName.
Returns
  • (list) Modified instances
View Source
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_state

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.

Returns
  • (bool) State is changed or not
View Source
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

get_references

Return the list of references of the catalog.

Returns
  • (list)
View Source
def get_references(self):
    """Return the list of references of the catalog.

        :returns: (list)

        """
    if self.__references is None:
        return list()
    return self.__references

has_ref

Return True if the root contains the given reference.

Parameters
  • ref: (sppasReference)
Returns
  • (bool)
View Source
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

add_ref

Associate a new reference to the root.

Parameters
  • ref: (sppasReference)
Returns
  • (bool)
View Source
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_ref

Remove a reference to unlink it to this root.

Parameters
  • ref: (sppasReference)
Returns
  • (bool)
View Source
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

set_references

Fix the list of references.

The current list is overridden.

Parameters
  • listofreferences: (list)
Raises

sppasTypeError

View Source
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')

get_object

Return the instance matching the given filename.

Return self if filename is matching the id.

Parameters
  • filename: Full name of a file
Returns
  • (FileName of None)
View Source
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

Append a filename in the list of files.

'filename' must be the absolute name of a file or an instance of FileName.

Parameters
  • filename: (str, FileName) Absolute name of a file
  • all_root: (bool) Add all files sharing the same root
  • 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
View Source
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

Remove a filename of the list of files.

Given filename must be the absolute name of a file or an instance of FileName.

Parameters
  • filename: (str, FileName) Absolute name of a file
Returns
  • (identifier) Identifier of the removed FileName or None if nothing removed.
View Source
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

Overloads

__repr__

View Source
def __repr__(self):
    return 'Root: ' + self.id + ' contains ' + str(len(self.__files)) + ' files\n'

__iter__

View Source
def __iter__(self):
    for a in self.__files:
        yield a

__getitem__

View Source
def __getitem__(self, i):
    return self.__files[i]

__len__

View Source
def __len__(self):
    return len(self.__files)

__contains__

View Source
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