| 14 | 1 '''Classes and functions for working with variant callers. | 
|  | 2 | 
|  | 3 Created on 22 Sep 2015 | 
|  | 4 | 
|  | 5 @author: alex | 
|  | 6 ''' | 
|  | 7 import glob | 
|  | 8 import inspect | 
|  | 9 import logging | 
|  | 10 import os | 
|  | 11 import sys | 
|  | 12 | 
|  | 13 from phe.variant import VariantCaller | 
|  | 14 | 
|  | 15 def dynamic_caller_loader(): | 
|  | 16     """Fancy way of dynamically importing existing variant callers. | 
|  | 17 | 
|  | 18     Returns | 
|  | 19     ------- | 
|  | 20     dict: | 
|  | 21         Available variant callers dictionary. Keys are parameters that | 
|  | 22         can be used to call variants. | 
|  | 23     """ | 
|  | 24 | 
|  | 25     # We assume the caller are in the same directory as THIS file. | 
|  | 26     variants_dir = os.path.dirname(__file__) | 
|  | 27     variants_dir = os.path.abspath(variants_dir) | 
|  | 28 | 
|  | 29     # This is populated when the module is first imported. | 
|  | 30     avail_callers = {} | 
|  | 31 | 
|  | 32     # Add this directory to the syspath. | 
|  | 33     sys.path.insert(0, variants_dir) | 
|  | 34 | 
|  | 35     # Find all "py" files. | 
|  | 36     for caller_mod in glob.glob(os.path.join(variants_dir, "*.py")): | 
|  | 37 | 
|  | 38         # Derive name of the module where caller is. | 
|  | 39         caller_mod_file = os.path.basename(caller_mod) | 
|  | 40 | 
|  | 41         # Ignore __init__ file, only base class is there. | 
|  | 42         if caller_mod_file.startswith("__init__"): | 
|  | 43             continue | 
|  | 44 | 
|  | 45         # Import the module with a caller. | 
|  | 46         mod = __import__(caller_mod_file.replace(".pyc", "").replace(".py", "")) | 
|  | 47 | 
|  | 48         # Find all the classes contained in this module. | 
|  | 49         classes = inspect.getmembers(mod, inspect.isclass) | 
|  | 50         for cls_name, cls in classes: | 
|  | 51             # For each class, if it is a sublass of VariantCaller, add it. | 
|  | 52             if cls_name != "VariantCaller" and issubclass(cls, VariantCaller): | 
|  | 53                 # The name is inherited and defined within each caller. | 
|  | 54                 avail_callers[cls.name] = cls | 
|  | 55 | 
|  | 56     sys.path.remove(variants_dir) | 
|  | 57 | 
|  | 58     return avail_callers | 
|  | 59 | 
|  | 60 _avail_variant_callers = dynamic_caller_loader() | 
|  | 61 | 
|  | 62 def available_callers(): | 
|  | 63     """Return list of available variant callers.""" | 
|  | 64     return _avail_variant_callers.keys() | 
|  | 65 | 
|  | 66 def factory(variant=None, custom_options=None): | 
|  | 67     """Make an instance of a variant class. | 
|  | 68 | 
|  | 69     Parameters: | 
|  | 70     ----------- | 
|  | 71     variant: str, optional | 
|  | 72         Name of the variant class to instantiate. | 
|  | 73     custom_options: str, optional | 
|  | 74         Custom options to be passed directly to the implementing class. | 
|  | 75 | 
|  | 76     Returns: | 
|  | 77     -------- | 
|  | 78     :py:class:`phe.variant.VariantCaller`: | 
|  | 79         Instance of the :py:class:`phe.variant.VariantCaller` for given | 
|  | 80         variant name, or None if one couldn't be found. | 
|  | 81     """ | 
|  | 82     if variant is not None and isinstance(variant, str): | 
|  | 83 | 
|  | 84         variant = variant.lower() | 
|  | 85         if variant in _avail_variant_callers: | 
|  | 86             return _avail_variant_callers[variant](cmd_options=custom_options) | 
|  | 87         else: | 
|  | 88             logging.error("No implementation for %s mapper.") | 
|  | 89             return None | 
|  | 90 | 
|  | 91     logging.warn("Unknown parameters. Mapper could not be initialised.") | 
|  | 92     return None |