In [6]:
try:
    from ..base import AttributeObject
except:
    from harness.python.base import AttributeObject

from toolz.curried import *
import importlib, inspect, jinja2.ext

__all__ = ['HarnessExtension']

In [4]:
class HarnessExtension(jinja2.ext.Extension):
    """Use the jinja2 extension framework to create build Harness templates.
    imports - string object that can load a module.
    module_ - a derived object containing the main module of the extension.
    """
    
    imports = None 
    mixin = None
    alias = ""
    
    def __init__(self, environment):
        self.function = identity
        if self.imports:
            self.module_= importlib.import_module(self.imports)

    def pipe(self, dataframe, attr,):
        function = None
        try: # to access the attribute from the module
            function = getattr(self.module_, attr)
        except AttributeError: pass

        try: # to access the attriubte from the class superceding the module
            function = getattr(self, attr)
        except AttributeError: pass

        if not(function is None):
            if not callable(function):
                return function # which is a non-callable datatype
            value = AttributeObject(
                func=function, 
                callback=partial(self.callback, dataframe),
                arguments=self.arguments(function),
                keywords=self.keywords(dataframe),
            )
            return value
        
        
    def callback(self, dataframe, value):
        
        return value
        
    def arguments(self, function):
        try:
             return inspect.getfullargspec(function).args
        except TypeError: pass
        return []
    
    def keywords(self, dataframe):
        return {}
    
    def __dir__(self):
        return list(
            concatv(
                super().__dir__(), 
                dir(self.module_) if hasattr(self, 'module_') else []
            )
        )

In [6]:
class JinjaExtension(HarnessExtension):
    alias = 'jinja2'
    def __init__(self, environment):
        super().__init__(environment)
        self.env = environment
        self.module_ = environment
        
    def callback(self, dataframe, value):
        if isinstance(value, jinja2.Template):
            value = value.render(df=dataframe)
        if isinstance(value, jinja2.BaseLoader):
            return dataframe
        return value
    
    def add_template(self, **kwargs):
        # This will break with a custom environment
        first(self.env.loader.loaders).mapping.update(**kwargs)
        return self.env.loader