2017-03-29 1 views
1

Fondamentalement, je veux charger toutes les fonctions d'un module spécifique (s'il existe) et les fusionner avec les méthodes de classe. Si j'avais le __module__ de la classe en cours de construction à l'intérieur __new__, je pourrais construire le chemin directement au module et l'importer. Je suis à la recherche d'un get_module_fns pour résoudre mon problème. Je souhaite faire quelque chose comme:Problèmes avec la découverte de modules à l'intérieur de la métaclasse __new__

get_module_fns('pathto.mod1.toimport') 

et si elle existe, elle renverra toutes les fonctions comme dict. Voici le link pour le code et les tests.

# mtcl.py 
import inspect 
import imp 


def get_module_fns(module_name, module_path): 
    try: 
     mod_loaded = imp.load_source(module_name, module_path) 
     module_fns = [(name, func) for name, func in 
         inspect.getmembers(mod_loaded, inspect.isfunction)] 
    except FileNotFoundError as e: 
     return {} 
    except ImportError as e: 
     return {} 
    return dict(module_fns) 


class GetModuleFunctions(type): 

    def __new__(cls, name, bases, namespaces, **kwargs): 

     module_functions = get_module_fns('toimport', './toimport.py') 
     namespaces.update(module_functions) 

     new_class = super(GetModuleFunctions, cls).__new__(
      cls, name, bases, namespaces) 

     new_class._mdl_fns = module_functions 

     return new_class 


class ClassBase(metaclass=GetModuleFunctions): 

    def __init__(self, *args, **kwargs): 
     super(ClassBase, self).__init__(*args, **kwargs) 

    @property 
    def module_functions(self): 
     return self.__class__._mdl_fns 
# mod0.py 
from .mtcl import ClassBase 


class M0(ClassBase): 

    def function_m0(self): 
     return 0 
# mod1/__init__.py 
from ..mtcl import ClassBase 


class M1(ClassBase): 

    def function_m1(self): 
     return 1 
# mod1/toimport.py 

def function_1(obj, *args, **kwargs): 
    return 1 
# mod1/mod2/__init__.py 
from ...mtcl import ClassBase 


class M2(ClassBase): 

    def function_m2(self): 
     return 2 
# mod1/mod2/toimport.py 

def function_2(obj, *args, **kwargs): 
    return 2 

Répondre

1

Tr y les éléments suivants:

import inspect 
import importlib 


def get_module_fns(cls, module_name): 
    try: 
     mod_loaded = importlib.import_module(
      '%s.%s' % (cls.__module__, module_name) 
     ) 
     module_fns = [(name, func) for name, func in 
         inspect.getmembers(mod_loaded, inspect.isfunction)] 
    except ModuleNotFoundError as e: 
     return {} 
    except ImportError as e: 
     return {} 
    return dict(module_fns) 


class GetModuleFunctions(type): 

    def __new__(cls, *args, **kwargs): 
     new_class = super(GetModuleFunctions, cls).__new__(
      cls, *args, **kwargs) 
     module_functions = get_module_fns(new_class, 'toimport') 
     for name, fn in module_functions.items(): 
      setattr(new_class, name, fn) 
     new_class._mdl_fns = module_functions 
     return new_class 

Puisque vous êtes à la recherche d'un module dans votre module de classe, cela devrait le faire:

mod_loaded = importlib.import_module(
    '%s.%s' % (cls.__module__, module_name) 
) 

Malheureusement, vous ne pouvez pas utiliser namespace après __new__.super:

for name, fn in module_functions.items():     
    setattr(new_class, name, fn)