PySMI library
*************

The *MibCompiler* object is the top-most interface to PySMI library
features. It holds together the otherwise isolated pieces of the
compiler infrastructure and manages the workflow of ASN.1 MIB
transformation.

This example showcases some of its features:

   from pysmi.reader import HttpReader
   from pysmi.searcher import StubSearcher
   from pysmi.writer import CallbackWriter
   from pysmi.parser import SmiStarParser
   from pysmi.codegen import JsonCodeGen
   from pysmi.compiler import MibCompiler

   inputMibs = ['IF-MIB', 'IP-MIB']

   httpSources = [('mibs.snmplabs.com', 80, '/asn1/@mib@')]

   # store compiled MIBs by calling this function
   def store_mibs(mibName, jsonDoc, cbCtx):
       print('# MIB module %s' % mibName)
       print(jsonDoc)

   mibCompiler = MibCompiler(
       SmiStarParser(), JsonCodeGen(), CallbackWriter(store_mibs)
   )

   # pull ASN.1 MIBs over HTTP
   mibCompiler.addSources(*[HttpReader(*x) for x in httpSources])

   # never recompile MIBs with ASN.1 MACROs
   mibCompiler.addSearchers(StubSearcher(*JsonCodeGen.baseMibs))

   status = mibCompiler.compile(*inputMibs)

   print(status)

* MIB compiler

  * "MibCompiler"

* Compilation status

  * "MibStatus"


MIB sources
===========

PySMI offers a handful of distinct transport mechanisms for fetching
MIBs by name from specific locations. In all cases MIB module name to
file name match may not be exact -- some name fuzzying can be
performed to mitigate possible changes to MIB file name.

* Local file reader

  * "FileReader"

* ZIP archive reader

  * "ZipReader"

* HTTP reader

  * "HttpReader"

* FTP reader

  * "FtpReader"

* Callback reader

  * "CallbackReader"


Conditional compilation
=======================

There are cases when MIB transformation may or must not be performed.
Such cases include:

* foundation MIBs containing manually implemented pieces or ASN.1
  MACRO's

* obsolete MIBs fully reimplemented within modern MIBs

* already transformed MIBs

MibCompiler expects user to supply a *searcher* object that would
allow or skip MIB transformation for particular name based on whatever
reason it is aware of.

In general, *searcher* logic is specific to target format. At the time
being, only pysnmp code generation backend requires such filtering.

* Python files searcher

  * "PyFileSearcher"

* Search Python packages

  * "PyPackageSearcher"

* Unconditionally ignore MIBs

  * "StubSearcher"


Parser configuration
====================

MIBs may be written in one of the two major SMI language versions (v1
and v2). Some MIBs may contain typical errors.

PySMI offers a way to customize the parser to consume either of the
major SMI grammars as well as to recover from well-known errors in MIB
files.

* SMI parser

  * "parserFactory()"

* SMI language dialects


Code generators
===============

Once ASN.1 MIB is parsed up, AST is passed to a code generator which
turns AST into desired representation of the MIB.

* JSON document generator

  * "JsonCodeGen"

* PySNMP MIB generator

  * "PySnmpCodeGen"

* Code generation stub

  * "NullCodeGen"


Borrow pre-compiled MIBs
========================

Some MIBs in circulation appear broken beyond automatic repair. To
handle such cases PySMI introduces the *MIB borrowing* functionality.
When MibCompiler gives up compiling a MIB, it can try to go out and
take a copy of already transformed MIB to complete the request
successfully.

* Any file borrower

  * "AnyFileBorrower"

* Python file borrower

  * "PyFileBorrower"


Write compiled MIBs
===================

Successfully transformed MIB modules' contents will be passed to
*writer* object given to MibCompiler on instantiation.

* File writer

  * "FileWriter"

* Python file writer

  * "PyFileWriter"

* Callback writer

  * "CallbackWriter"


Examples
========

The following examples focus on various feature of the PySMI library.

* Compile MIBs into JSON

* Compile MIBs from web

* Compile SMIv1/v2 MIBs

* Compile SMIv2 MIBs

* Borrow pysnmp MIBs on failure

* Always borrow pysnmp MIBs

In case of any troubles or confusion, try enabling PySMI debugging and
watch the output:

   from pysmi import debug

   debug.setLogger(debug.Debug('all'))
