1"""pyang plugin handling""" 2 3import os 4import sys 5import pkg_resources 6 7plugins = [] 8"""List of registered PyangPlugin instances""" 9 10def init(plugindirs=[]): 11 """Initialize the plugin framework""" 12 13 # initialize the builtin plugins 14 from .translators import yang,yin,dsdl 15 yang.pyang_plugin_init() 16 yin.pyang_plugin_init() 17 dsdl.pyang_plugin_init() 18 19 # initialize installed plugins 20 for ep in pkg_resources.iter_entry_points(group='pyang.plugin'): 21 plugin_init = ep.load() 22 plugin_init() 23 24 # search for plugins in std directories (plugins directory first) 25 basedir = os.path.split(sys.modules['pyang'].__file__)[0] 26 plugindirs.insert(0, basedir + "/transforms") 27 plugindirs.insert(0, basedir + "/plugins") 28 29 # add paths from env 30 pluginpath = os.getenv('PYANG_PLUGINPATH') 31 if pluginpath is not None: 32 plugindirs.extend(pluginpath.split(os.pathsep)) 33 34 syspath = sys.path 35 for plugindir in plugindirs: 36 sys.path = [plugindir] + syspath 37 try: 38 fnames = os.listdir(plugindir) 39 except OSError: 40 continue 41 for fname in fnames: 42 if not fname.startswith(".#") and fname.endswith(".py") and \ 43 fname != '__init__.py' and not fname.endswith("_flymake.py"): 44 pluginmod = __import__(fname[:-3]) 45 try: 46 pluginmod.pyang_plugin_init() 47 except AttributeError as s: 48 print(pluginmod.__dict__) 49 raise AttributeError(pluginmod.__file__ + ': ' + str(s)) 50 sys.path = syspath 51 52def register_plugin(plugin): 53 """Call this to register a pyang plugin. See class PyangPlugin 54 for more info. 55 """ 56 plugins.append(plugin) 57 58def is_plugin_registered(name): 59 for plugin in plugins: 60 if plugin.name == name: 61 return True 62 return False 63 64class PyangPlugin(object): 65 """Abstract base class for pyang plugins 66 67 A pyang plugin is a module found in the plugins directory of the 68 pyang installation, or in the dynamic pluginpath. 69 70 Such a module must export a function 'pyang_plugin_init()', which 71 may call pyang.plugin.register_plugin() with an instance of a class 72 derived from this class as argument. 73 74 A plugin can extend the base pyang library functions, or the pyang 75 front-end program, or both. 76 """ 77 78 def __init__(self, name=None): 79 self.name = name 80 self.multiple_modules = False 81 self.handle_comments = False 82 83 ## pyang front-end program methods 84 85 def add_output_format(self, fmts): 86 """Add an output format to the pyang program. 87 88 `fmts` is a dict which maps the format name string to a plugin 89 instance. 90 91 Override this method and update `fmts` with the output format 92 name. 93 """ 94 return 95 96 def add_transform(self, xforms): 97 """Add a transform to the pyang program. 98 99 `xforms` is a dict which maps the transform name string to a plugin 100 instance. 101 102 Override this method and update `xforms` with the transform name. 103 """ 104 return 105 106 def add_opts(self, optparser): 107 """Add command line options to the pyang program. 108 109 Override this method and add the plugin related options as an 110 option group. 111 """ 112 return 113 114 ## library methods 115 116 def setup_ctx(self, ctx): 117 """Modify the Context at setup time. Called for all plugins. 118 119 Override this method to modify the Context before the module 120 repository is accessed. 121 """ 122 return 123 124 def setup_fmt(self, ctx): 125 """Modify the Context at setup time. Called for the selected 126 output format plugin. 127 128 Override this method to modify the Context before the module 129 repository is accessed. 130 """ 131 return 132 133 def setup_xform(self, ctx): 134 """Modify the Context at setup time. Called for the selected 135 transform plugin. 136 137 Override this method to modify the Context before the module 138 repository is accessed. 139 """ 140 return 141 142 def pre_load_modules(self, ctx): 143 """Called for the selected plugin, before any modules are loaded""" 144 return 145 146 def pre_validate_ctx(self, ctx, modules): 147 """Called for all plugins, before the modules are validated""" 148 return 149 150 def pre_validate(self, ctx, modules): 151 """Called for the selected plugin, before the modules are validated""" 152 return 153 154 def post_validate(self, ctx, modules): 155 """Called for the selected plugin, after the modules 156 have been validated""" 157 return 158 159 def post_validate_ctx(self, ctx, modules): 160 """Called for all plugins, after the modules 161 have been validated""" 162 return 163 164 def emit(self, ctx, modules, writef): 165 """Produce the plugin output. 166 167 Override this method to perform the output conversion. 168 `writef` is a function that takes one string to print as argument. 169 170 Raise error.EmitError on failure. 171 """ 172 return 173 174 def transform(self, ctx, modules): 175 """Transform the modules (called after modules have been validated). 176 177 Override this method to modify the modules. 178 Return `True` to indicate either that none of the modifications 179 require modules to be re-validated or that the modules have already 180 been re-validated. 181 182 Raise error.TransformError on failure.""" 183