r"""
        Generate a list of module callables and gets their attributes.

        Callables are functions, classes, methods and class properties; their
        attributes are callable type, file name, and lines span

        :param fnames: File names of the modules to trace
        :type  fnames: list

        :raises:
         * OSError (File *[fname]* could not be found)

         * RuntimeError (Argument \`fnames\` is not valid)

def trace(self, fnames, _refresh=False):
        r"""
        Generate a list of module callables and gets their attributes.

        Callables are functions, classes, methods and class properties; their
        attributes are callable type, file name, and lines span

        :param fnames: File names of the modules to trace
        :type  fnames: list

        :raises:
         * OSError (File *[fname]* could not be found)

         * RuntimeError (Argument \`fnames\` is not valid)
        """
        # pylint: disable=R0101
        if fnames and (not isinstance(fnames, list)):
            raise RuntimeError("Argument `fnames` is not valid")
        if fnames and any([not isinstance(item, str) for item in fnames]):
            raise RuntimeError("Argument `fnames` is not valid")
        for fname in fnames:
            if not os.path.exists(fname):
                raise OSError("File {0} could not be found".format(fname))
        fnames = [item.replace(".pyc", ".py") for item in fnames]
        bobj = collections.namedtuple("Bundle", ["lineno", "col_offset"])
        for fname in fnames:
            if (fname not in self._fnames) or (
                _refresh
                and (fname in self._fnames)
                and (self._fnames[fname]["date"] < os.path.getmtime(fname))
            ):
                module_name = (
                    _get_module_name_from_fname(fname)
                    if not _refresh
                    else self._fnames[fname]["name"]
                )
                # Remove old module information if it is going to be refreshed
                if _refresh:
                    self._module_names.pop(self._module_names.index(module_name))
                    for cls in self._fnames[fname]["classes"]:
                        self._class_names.pop(self._class_names.index(cls))
                    dlist = []
                    for key, value in self._reverse_callables_db.items():
                        if key[0] == fname:
                            dlist.append(key)
                            try:
                                del self._callables_db[value]
                            except KeyError:
                                pass
                    for item in set(dlist):
                        del self._reverse_callables_db[item]
                lines = _readlines(fname)
                # Eliminate all Unicode characters till the first ASCII
                # character is found in first line of file, to deal with
                # Unicode-encoded source files
                for num, char in enumerate(lines[0]):  # pragma: no cover
                    if not _unicode_char(char):
                        break
                lines[0] = lines[0][num:]
                tree = ast.parse("".join(lines))
                aobj = _AstTreeScanner(module_name, fname, lines)
                aobj.visit(tree)
                # Create a fake callable at the end of the file to properly
                # 'close', i.e. assign a last line number to the last
                # callable in file
                fake_node = bobj(len(lines) + 1, -1)
                aobj._close_callable(fake_node, force=True)
                self._class_names += aobj._class_names[:]
                self._module_names.append(module_name)
                self._callables_db.update(aobj._callables_db)
                self._reverse_callables_db.update(aobj._reverse_callables_db)
                # Split into modules
                self._modules_dict[module_name] = []
                iobj = [
                    item
                    for item in self._callables_db.values()
                    if item["name"].startswith(module_name + ".")
                ]
                for entry in iobj:
                    self._modules_dict[module_name].append(entry)
                self._fnames[fname] = {
                    "name": module_name,
                    "date": os.path.getmtime(fname),
                    "classes": aobj._class_names[:],
                }