Source code for dfttools.simple

"""
This submodule contains commonly used shortcuts to parse the data.
"""
import inspect

import numericalunits

import parsers
    
from parsers.generic import AbstractParser, ParseError

[docs]def tag_method(*tags, **kwargs): """ A generic decorator tagging some method. Kwargs: take_file (bool): set to True and the File object will be passed to this method. """ take_file = kwargs.get("take_file", False) def f_w(func): if "__tags__" in dir(func): func.__tags__ += list(tags) else: func.__tags__ = list(tags) func.__take_file__ = take_file if len(tags)>0 and not (func.__doc__ is None): func.__doc__ += """ .. note:: This method can be shortcut """ + (", ".join("``dfttools.simple.parse(file,\""+i+"\")``" for i in tags)) + ".\n" return func return f_w
band_structure = tag_method("band-structure") unit_cell = tag_method("unit-cell")
[docs]def get_all_parsers(*modules): """ Retrieves all parsers. Kwargs: modules (list): a list of names of ``parsers`` submodules to search at. Returns: A list of parsing classes. """ parsers.__import_all_parsers__() if len(modules) == 0: modules = [] for name in dir(parsers): obj = getattr(parsers, name) if inspect.ismodule(obj): modules.append(name) result = [] for name in modules: module = getattr(parsers, name) for obj_name in dir(module): obj = getattr(module, obj_name) if inspect.isclass(obj) and issubclass(obj, AbstractParser) and not obj == AbstractParser and not obj in result: result.append(obj) return result
[docs]def guess_parser(f): """ Guesses parsers for a given data. Args: f (file): a file to parse. Returns: A list of parser candidates. """ result = [] # Guess by contents f.seek(0) header = f.read(1024*1024) for parser_class in get_all_parsers(): try: if parser_class.valid_header(header): result.append(parser_class) except NotImplementedError: pass f.seek(0) # Guess by name if "name" in dir(f) and isinstance(f.name, str): for parser_class in get_all_parsers(): try: if parser_class.valid_filename(f.name): result.append(parser_class) except NotImplementedError: pass return result
[docs]def parse(f, tag, *args): """ Identifies and parses data. Args: f (file): a file to parse; tag (str): the data tag, such as ``unit-cell`` or ``band-structure``; Returns: The parsed data. """ candidates = guess_parser(f) debug_data = "Candidate classes:\n" + "\n".join(" - "+str(i) for i in candidates) if len(candidates) == 0: raise ParseError("Unidentified data: no parser match") data = f.read() attempted = [] for parser_class in candidates: parser = parser_class(data) for a in dir(parser): attr = getattr(parser, a) if "__tags__" in dir(attr) and tag in attr.__tags__: try: attempted.append(parser.__class__.__name__+"."+attr.__name__) if attr.__take_file__: return attr(f, *args) else: return attr(*args) except (StopIteration, ParseError): pass if len(attempted) == 0: raise ParseError("No matching parser found\n"+debug_data) else: raise ParseError("Parsing failed, attempted following candidates:\n" + "\n".join(tuple( " - "+i for i in cadidates )))