Mini Shell
#
# This file is part of pysmi software.
#
# Copyright (c) 2015-2019, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pysmi/license.html
#
import sys
import re
from time import strptime, strftime
from keyword import iskeyword
from pysmi.mibinfo import MibInfo
from pysmi.codegen.base import AbstractCodeGen, dorepr
from pysmi import error
from pysmi import debug
if sys.version_info[0] > 2:
# noinspection PyShadowingBuiltins
unicode = str
# noinspection PyShadowingBuiltins
long = int
class PySnmpCodeGen(AbstractCodeGen):
"""Builds PySNMP-specific Python code representing MIB module supplied
in form of an Abstract Syntax Tree on input.
Instance of this class is supposed to be passed to *MibCompiler*,
the rest is internal to *MibCompiler*.
"""
defaultMibPackages = ('pysnmp.smi.mibs', 'pysnmp_mibs')
symsTable = {
'MODULE-IDENTITY': ('ModuleIdentity',),
'OBJECT-TYPE': ('MibScalar', 'MibTable', 'MibTableRow', 'MibTableColumn'),
'NOTIFICATION-TYPE': ('NotificationType',),
'TEXTUAL-CONVENTION': ('TextualConvention',),
'MODULE-COMPLIANCE': ('ModuleCompliance',),
'OBJECT-GROUP': ('ObjectGroup',),
'NOTIFICATION-GROUP': ('NotificationGroup',),
'AGENT-CAPABILITIES': ('AgentCapabilities',),
'OBJECT-IDENTITY': ('ObjectIdentity',),
'TRAP-TYPE': ('NotificationType',), # smidump always uses NotificationType
'BITS': ('Bits',),
}
constImports = {
'ASN1': ('Integer', 'OctetString', 'ObjectIdentifier'),
'ASN1-ENUMERATION': ('NamedValues',),
'ASN1-REFINEMENT': ('ConstraintsUnion', 'ConstraintsIntersection', 'SingleValueConstraint',
'ValueRangeConstraint', 'ValueSizeConstraint'),
'SNMPv2-SMI': ('iso',
'Bits', # XXX
'Integer32', # XXX
'TimeTicks', # bug in some IETF MIBs
'Counter32', # bug in some IETF MIBs (e.g. DSA-MIB)
'Counter64', # bug in some MIBs (e.g.A3COM-HUAWEI-LswINF-MIB)
'NOTIFICATION-TYPE', # bug in some MIBs (e.g. A3COM-HUAWEI-DHCPSNOOP-MIB)
'Gauge32', # bug in some IETF MIBs (e.g. DSA-MIB)
'MODULE-IDENTITY', 'OBJECT-TYPE', 'OBJECT-IDENTITY', 'Unsigned32', 'IpAddress', # XXX
'MibIdentifier'), # OBJECT IDENTIFIER
'SNMPv2-TC': ('DisplayString', 'TEXTUAL-CONVENTION',), # XXX
'SNMPv2-CONF': ('MODULE-COMPLIANCE', 'NOTIFICATION-GROUP',), # XXX
}
# never compile these, they either:
# - define MACROs (implementation supplies them)
# - or carry conflicting OIDs (so that all IMPORT's of them will be rewritten)
# - or have manual fixes
# - or import base ASN.1 types from implementation-specific MIBs
fakeMibs = ('ASN1',
'ASN1-ENUMERATION',
'ASN1-REFINEMENT')
baseMibs = ('PYSNMP-USM-MIB',
'SNMP-FRAMEWORK-MIB',
'SNMP-TARGET-MIB',
'TRANSPORT-ADDRESS-MIB',
'INET-ADDRESS-MIB') + AbstractCodeGen.baseMibs
baseTypes = ['Integer', 'Integer32', 'Bits', 'ObjectIdentifier', 'OctetString']
typeClasses = {
'COUNTER32': 'Counter32',
'COUNTER64': 'Counter64',
'GAUGE32': 'Gauge32',
'INTEGER': 'Integer32', # XXX
'INTEGER32': 'Integer32',
'IPADDRESS': 'IpAddress',
'NETWORKADDRESS': 'IpAddress',
'OBJECT IDENTIFIER': 'ObjectIdentifier',
'OCTET STRING': 'OctetString',
'OPAQUE': 'Opaque',
'TIMETICKS': 'TimeTicks',
'UNSIGNED32': 'Unsigned32',
'Counter': 'Counter32',
'Gauge': 'Gauge32',
'NetworkAddress': 'IpAddress', # RFC1065-SMI, RFC1155-SMI -> SNMPv2-SMI
'nullSpecific': 'zeroDotZero', # RFC1158-MIB -> SNMPv2-SMI
'ipRoutingTable': 'ipRouteTable', # RFC1158-MIB -> RFC1213-MIB
'snmpEnableAuthTraps': 'snmpEnableAuthenTraps' # RFC1158-MIB -> SNMPv2-MIB
}
smiv1IdxTypes = ['INTEGER', 'OCTET STRING', 'IPADDRESS', 'NETWORKADDRESS']
ifTextStr = 'if mibBuilder.loadTexts: '
indent = ' ' * 4
fakeidx = 1000 # starting index for fake symbols
def __init__(self):
self._snmpTypes = set(self.typeClasses.values())
self._snmpTypes.add('Bits')
self._rows = set()
self._cols = {} # k, v = name, datatype
self._exports = set()
self._seenSyms = set()
self._importMap = {}
self._out = {} # k, v = name, generated code
self._moduleIdentityOid = None
self._moduleRevision = None
self.moduleName = ['DUMMY']
self.genRules = {'text': True}
self.symbolTable = {}
def symTrans(self, symbol):
if symbol in self.symsTable:
return self.symsTable[symbol]
return symbol,
@staticmethod
def transOpers(symbol):
if iskeyword(symbol):
symbol = 'pysmi_' + symbol
return symbol.replace('-', '_')
def prepData(self, pdata, classmode=False):
data = []
for el in pdata:
if not isinstance(el, tuple):
data.append(el)
elif len(el) == 1:
data.append(el[0])
else:
data.append(
self.handlersTable[el[0]](self, self.prepData(el[1:], classmode=classmode), classmode=classmode)
)
return data
def genImports(self, imports):
outStr = ''
# conversion to SNMPv2
toDel = []
for module in list(imports):
if module in self.convertImportv2:
for symbol in imports[module]:
if symbol in self.convertImportv2[module]:
toDel.append((module, symbol))
for newImport in self.convertImportv2[module][symbol]:
newModule, newSymbol = newImport
if newModule in imports:
imports[newModule].append(newSymbol)
else:
imports[newModule] = [newSymbol]
# removing converted symbols
for d in toDel:
imports[d[0]].remove(d[1])
# merging mib and constant imports
for module in self.constImports:
if module in imports:
imports[module] += self.constImports[module]
else:
imports[module] = self.constImports[module]
for module in sorted(imports):
symbols = ()
for symbol in set(imports[module]):
symbols += self.symTrans(symbol)
if symbols:
self._seenSyms.update([self.transOpers(s) for s in symbols])
self._importMap.update([(self.transOpers(s), module) for s in symbols])
outStr += ', '.join([self.transOpers(s) for s in symbols])
if len(symbols) < 2:
outStr += ','
outStr += ' = mibBuilder.importSymbols("%s")\n' % ('", "'.join((module,) + symbols))
return outStr, tuple(sorted(imports))
def genExports(self, ):
exports = list(self._exports)
if not exports:
return ''
numFuncCalls = len(exports) // 254 + 1
outStr = ''
for idx in range(numFuncCalls):
outStr += 'mibBuilder.exportSymbols("' + self.moduleName[0] + '", '
outStr += ', '.join(exports[254 * idx:254 * (idx + 1)]) + ')\n'
return outStr
# noinspection PyMethodMayBeStatic
def genLabel(self, symbol, classmode=False):
if '-' in symbol or iskeyword(symbol):
return classmode and 'label = "' + symbol + '"\n' or '.setLabel("' + symbol + '")'
return ''
def addToExports(self, symbol, moduleIdentity=0):
if moduleIdentity:
self._exports.add('PYSNMP_MODULE_ID=%s' % symbol)
self._exports.add('%s=%s' % (symbol, symbol))
self._seenSyms.add(symbol)
# noinspection PyUnusedLocal
def regSym(self, symbol, outStr, oidStr=None, moduleIdentity=False):
if symbol in self._seenSyms and symbol not in self._importMap:
raise error.PySmiSemanticError('Duplicate symbol found: %s' % symbol)
self.addToExports(symbol, moduleIdentity)
self._out[symbol] = outStr
if moduleIdentity:
if self._moduleIdentityOid:
raise error.PySmiSemanticError('Duplicate module identity')
# TODO: turning literal tuple into a string - hackerish
self._moduleIdentityOid = '.'.join(oidStr.split(', '))[1:-1]
def genNumericOid(self, oid):
numericOid = ()
for part in oid:
if isinstance(part, tuple):
parent, module = part
if parent == 'iso':
numericOid += (1,)
continue
if module not in self.symbolTable:
# XXX do getname for possible future borrowed mibs
raise error.PySmiSemanticError('no module "%s" in symbolTable' % module)
if parent not in self.symbolTable[module]:
raise error.PySmiSemanticError('no symbol "%s" in module "%s"' % (parent, module))
numericOid += self.genNumericOid(self.symbolTable[module][parent]['oid'])
else:
numericOid += (part,)
return numericOid
def getBaseType(self, symName, module):
if module not in self.symbolTable:
raise error.PySmiSemanticError('no module "%s" in symbolTable' % module)
if symName not in self.symbolTable[module]:
raise error.PySmiSemanticError('no symbol "%s" in module "%s"' % (symName, module))
symType, symSubtype = self.symbolTable[module][symName].get('syntax', (('', ''), ''))
if not symType[0]:
raise error.PySmiSemanticError('unknown type for symbol "%s"' % symName)
if symType[0] in self.baseTypes:
return symType, symSubtype
else:
baseSymType, baseSymSubtype = self.getBaseType(*symType)
if isinstance(baseSymSubtype, list):
if isinstance(symSubtype, list):
symSubtype += baseSymSubtype
else:
symSubtype = baseSymSubtype
return baseSymType, symSubtype
# Clause generation functions
# noinspection PyUnusedLocal
def genAgentCapabilities(self, data, classmode=False):
name, productRelease, status, description, reference, oid = data
label = self.genLabel(name)
name = self.transOpers(name)
oidStr, parentOid = oid
outStr = name + ' = AgentCapabilities(' + oidStr + ')' + label + '\n'
if productRelease:
outStr += """\
if getattr(mibBuilder, 'version', (0, 0, 0)) > (4, 4, 0):
%(name)s = %(name)s%(productRelease)s
""" % dict(name=name, productRelease=productRelease)
if status:
outStr += """\
if getattr(mibBuilder, 'version', (0, 0, 0)) > (4, 4, 0):
%(name)s = %(name)s%(status)s
""" % dict(name=name, status=status)
if self.genRules['text'] and description:
outStr += self.ifTextStr + name + description + '\n'
if self.genRules['text'] and reference:
outStr += name + reference + '\n'
self.regSym(name, outStr, oidStr)
return outStr
# noinspection PyUnusedLocal
def genModuleIdentity(self, data, classmode=False):
name, lastUpdated, organization, contactInfo, description, revisionsAndDescrs, oid = data
label = self.genLabel(name)
name = self.transOpers(name)
oidStr, parentOid = oid
outStr = name + ' = ModuleIdentity(' + oidStr + ')' + label + '\n'
if revisionsAndDescrs:
last_revision, revisions, descriptions = revisionsAndDescrs
self._moduleRevision = last_revision
if revisions:
outStr += name + revisions + '\n'
if self.genRules['text'] and descriptions:
outStr += """
if getattr(mibBuilder, 'version', (0, 0, 0)) > (4, 4, 0):
%(ifTextStr)s%(name)s%(descriptions)s
""" % dict(ifTextStr=self.ifTextStr, name=name, descriptions=descriptions)
if lastUpdated:
outStr += self.ifTextStr + name + lastUpdated + '\n'
if organization:
outStr += self.ifTextStr + name + organization + '\n'
if self.genRules['text'] and contactInfo:
outStr += self.ifTextStr + name + contactInfo + '\n'
if self.genRules['text'] and description:
outStr += self.ifTextStr + name + description + '\n'
self.regSym(name, outStr, oidStr, moduleIdentity=True)
return outStr
# noinspection PyUnusedLocal
def genModuleCompliance(self, data, classmode=False):
name, status, description, reference, compliances, oid = data
label = self.genLabel(name)
name = self.transOpers(name)
oidStr, parentOid = oid
outStr = name + ' = ModuleCompliance(' + oidStr + ')' + label
outStr += compliances + '\n'
if status:
outStr += """\
if getattr(mibBuilder, 'version', (0, 0, 0)) > (4, 4, 0):
%(name)s = %(name)s%(status)s
""" % dict(name=name, status=status)
if self.genRules['text'] and description:
outStr += self.ifTextStr + name + description + '\n'
if self.genRules['text'] and reference:
outStr += self.ifTextStr + name + reference + '\n'
self.regSym(name, outStr, oidStr)
return outStr
# noinspection PyUnusedLocal
def genNotificationGroup(self, data, classmode=False):
name, objects, status, description, reference, oid = data
label = self.genLabel(name)
name = self.transOpers(name)
oidStr, parentOid = oid
outStr = name + ' = NotificationGroup(' + oidStr + ')' + label
if objects:
objects = ['("' + self._importMap.get(obj, self.moduleName[0]) + '", "' + self.transOpers(obj) + '")'
for obj in objects]
numFuncCalls = len(objects) // 255 + 1
if numFuncCalls > 1:
objStrParts = []
for idx in range(numFuncCalls):
objStrParts.append('[' + ', '.join(objects[255 * idx:255 * (idx + 1)]) + ']')
outStr += """
for _%(name)s_obj in [%(objects)s]:
if getattr(mibBuilder, 'version', 0) < (4, 4, 2):
# WARNING: leading objects get lost here! Upgrade your pysnmp version!
%(name)s = %(name)s.setObjects(*_%(name)s_obj)
else:
%(name)s = %(name)s.setObjects(*_%(name)s_obj, **dict(append=True))\
""" % dict(name=name, objects=', '.join(objStrParts))
else:
outStr += '.setObjects(' + ', '.join(objects) + ')'
outStr += '\n'
if status:
outStr += """\
if getattr(mibBuilder, 'version', (0, 0, 0)) > (4, 4, 0):
%(name)s = %(name)s%(status)s
""" % dict(name=name, status=status)
if self.genRules['text'] and description:
outStr += self.ifTextStr + name + description + '\n'
if self.genRules['text'] and reference:
outStr += name + reference + '\n'
self.regSym(name, outStr, oidStr)
return outStr
# noinspection PyUnusedLocal
def genNotificationType(self, data, classmode=False):
name, objects, status, description, reference, oid = data
label = self.genLabel(name)
name = self.transOpers(name)
oidStr, parentOid = oid
outStr = name + ' = NotificationType(' + oidStr + ')' + label
if objects:
objects = ['("' + self._importMap.get(obj, self.moduleName[0]) + '", "' + self.transOpers(obj) + '")'
for obj in objects]
numFuncCalls = len(objects) // 255 + 1
if numFuncCalls > 1:
objStrParts = []
for idx in range(numFuncCalls):
objStrParts.append('[' + ', '.join(objects[255 * idx:255 * (idx + 1)]) + ']')
outStr += """
for _%(name)s_obj in [%(objects)s]:
if getattr(mibBuilder, 'version', 0) < (4, 4, 2):
# WARNING: leading objects get lost here! Upgrade your pysnmp version!
%(name)s = %(name)s.setObjects(*_%(name)s_obj)
else:
%(name)s = %(name)s.setObjects(*_%(name)s_obj, **dict(append=True))\
""" % dict(name=name, objects=', '.join(objStrParts))
else:
outStr += '.setObjects(' + ', '.join(objects) + ')'
outStr += '\n'
if status:
outStr += self.ifTextStr + name + status + '\n'
if self.genRules['text'] and description:
outStr += self.ifTextStr + name + description + '\n'
if self.genRules['text'] and reference:
outStr += self.ifTextStr + name + reference + '\n'
self.regSym(name, outStr, oidStr)
return outStr
# noinspection PyUnusedLocal
def genObjectGroup(self, data, classmode=False):
name, objects, status, description, reference, oid = data
label = self.genLabel(name)
name = self.transOpers(name)
oidStr, parentOid = oid
outStr = name + ' = ObjectGroup(' + oidStr + ')' + label
if objects:
objects = ['("' + self._importMap.get(obj, self.moduleName[0]) + '", "' + self.transOpers(obj) + '")'
for obj in objects]
numFuncCalls = len(objects) // 255 + 1
if numFuncCalls > 1:
objStrParts = []
for idx in range(numFuncCalls):
objStrParts.append('[' + ', '.join(objects[255 * idx:255 * (idx + 1)]) + ']')
outStr += """
for _%(name)s_obj in [%(objects)s]:
if getattr(mibBuilder, 'version', 0) < (4, 4, 2):
# WARNING: leading objects get lost here!
%(name)s = %(name)s.setObjects(*_%(name)s_obj)
else:
%(name)s = %(name)s.setObjects(*_%(name)s_obj, **dict(append=True))\
""" % dict(name=name, objects=', '.join(objStrParts))
else:
outStr += '.setObjects(' + ', '.join(objects) + ')'
outStr += '\n'
if status:
outStr += """\
if getattr(mibBuilder, 'version', (0, 0, 0)) > (4, 4, 0):
%(name)s = %(name)s%(status)s
""" % dict(name=name, status=status)
if self.genRules['text'] and description:
outStr += self.ifTextStr + name + description + '\n'
if self.genRules['text'] and reference:
outStr += self.ifTextStr + name + reference + '\n'
self.regSym(name, outStr, oidStr)
return outStr
# noinspection PyUnusedLocal
def genObjectIdentity(self, data, classmode=False):
name, status, description, reference, oid = data
label = self.genLabel(name)
name = self.transOpers(name)
oidStr, parentOid = oid
outStr = name + ' = ObjectIdentity(' + oidStr + ')' + label + '\n'
if status:
outStr += self.ifTextStr + name + status + '\n'
if self.genRules['text'] and description:
outStr += self.ifTextStr + name + description + '\n'
if self.genRules['text'] and reference:
outStr += self.ifTextStr + name + reference + '\n'
self.regSym(name, outStr, oidStr)
return outStr
# noinspection PyUnusedLocal
def genObjectType(self, data, classmode=False):
name, syntax, units, maxaccess, status, description, reference, augmention, index, defval, oid = data
label = self.genLabel(name)
name = self.transOpers(name)
oidStr, parentOid = oid
indexStr, fakeStrlist, fakeSyms = index or ('', '', [])
subtype = syntax[0] == 'Bits' and 'Bits()' + syntax[1] or syntax[1] # Bits hack #1
classtype = self.typeClasses.get(syntax[0], syntax[0])
classtype = self.transOpers(classtype)
classtype = syntax[0] == 'Bits' and 'MibScalar' or classtype # Bits hack #2
classtype = name in self.symbolTable[self.moduleName[0]]['_symtable_cols'] and 'MibTableColumn' or classtype
defval = self.genDefVal(defval, objname=name)
outStr = name + ' = ' + classtype + '(' + oidStr + ', ' + subtype + (defval or '') + ')' + label
outStr += units or ''
outStr += maxaccess or ''
outStr += indexStr or ''
outStr += '\n'
if self.genRules['text'] and reference:
outStr += self.ifTextStr + name + reference + '\n'
if augmention:
augmention = self.transOpers(augmention)
outStr += augmention + '.registerAugmentions(("' + self._importMap.get(name, self.moduleName[0]) + '", "' + name + '"))\n'
outStr += name + '.setIndexNames(*' + augmention + '.getIndexNames())\n'
if status:
outStr += self.ifTextStr + name + status + '\n'
if self.genRules['text'] and description:
outStr += self.ifTextStr + name + description + '\n'
self.regSym(name, outStr, parentOid)
if fakeSyms: # fake symbols for INDEX to support SMIv1
for idx, fakeSym in enumerate(fakeSyms):
fakeOutStr = fakeStrlist[idx] % oidStr
self.regSym(fakeSym, fakeOutStr, oidStr)
return outStr
# noinspection PyUnusedLocal
def genTrapType(self, data, classmode=False):
name, enterprise, objects, description, reference, value = data
label = self.genLabel(name)
name = self.transOpers(name)
enterpriseStr, parentOid = enterprise
outStr = name + ' = NotificationType(' + enterpriseStr + ' + (0,' + str(value) + '))' + label
if objects:
objects = ['("' + self._importMap.get(obj, self.moduleName[0]) + '", "' + self.transOpers(obj) + '")'
for obj in objects]
numFuncCalls = len(objects) // 255 + 1
if numFuncCalls > 1:
objStrParts = []
for idx in range(numFuncCalls):
objStrParts.append('[' + ', '.join(objects[255 * idx:255 * (idx + 1)]) + ']')
outStr += """
for _%(name)s_obj in [%(objects)s]:
if getattr(mibBuilder, 'version', 0) < (4, 4, 2):
# WARNING: leading objects get lost here! Upgrade your pysnmp version!
%(name)s = %(name)s.setObjects(*_%(name)s_obj)
else:
%(name)s = %(name)s.setObjects(*_%(name)s_obj, **dict(append=True))\
""" % dict(name=name, objects=', '.join(objStrParts))
else:
outStr += '.setObjects(' + ', '.join(objects) + ')'
outStr += '\n'
if self.genRules['text'] and description:
outStr += self.ifTextStr + name + description + '\n'
if self.genRules['text'] and reference:
outStr += self.ifTextStr + name + reference + '\n'
self.regSym(name, outStr, enterpriseStr)
return outStr
# noinspection PyUnusedLocal
def genTypeDeclaration(self, data, classmode=False):
outStr = ''
name, declaration = data
if declaration:
parentType, attrs = declaration
if parentType: # skipping SEQUENCE case
name = self.transOpers(name)
outStr = 'class ' + name + '(' + parentType + '):\n' + attrs + '\n'
self.regSym(name, outStr)
return outStr
# noinspection PyUnusedLocal
def genValueDeclaration(self, data, classmode=False):
name, oid = data
label = self.genLabel(name)
name = self.transOpers(name)
oidStr, parentOid = oid
outStr = name + ' = MibIdentifier(' + oidStr + ')' + label + '\n'
self.regSym(name, outStr, oidStr)
return outStr
# Subparts generation functions
# noinspection PyMethodMayBeStatic,PyUnusedLocal
def ftNames(self, data, classmode=False):
names = data[0]
return names
def genBitNames(self, data, classmode=False):
names = data[0]
return names
def genBits(self, data, classmode=False):
bits = data[0]
namedval = ['("' + bit[0] + '", ' + str(bit[1]) + ')' for bit in bits]
numFuncCalls = len(namedval) // 255 + 1
funcCalls = ''
for idx in range(numFuncCalls):
funcCalls += 'NamedValues(' + ', '.join(namedval[255 * idx:255 * (idx + 1)]) + ') + '
funcCalls = funcCalls[:-3]
outStr = classmode and self.indent + 'namedValues = ' + funcCalls + '\n' or '.clone(namedValues=' + funcCalls + ')'
return 'Bits', outStr
# noinspection PyUnusedLocal
def genCompliances(self, data, classmode=False):
if not data[0]:
return ''
objects = []
for complianceModule in data[0]:
name = complianceModule[0] or self.moduleName[0]
objects += ['("' + name + '", "' + self.transOpers(compl) + '")' for compl in complianceModule[1]]
outStr = ''
numFuncCalls = len(objects) // 255 + 1
if numFuncCalls > 1:
objStrParts = []
for idx in range(numFuncCalls):
objStrParts.append('[' + ', '.join(objects[255 * idx:255 * (idx + 1)]) + ']')
outStr += """
for _%(name)s_obj in [%(objects)s]:
if getattr(mibBuilder, 'version', 0) < (4, 4, 2):
# WARNING: leading objects get lost here! Upgrade your pysnmp version!
%(name)s = %(name)s.setObjects(*_%(name)s_obj)
else:
%(name)s = %(name)s.setObjects(*_%(name)s_obj, **dict(append=True))
""" % dict(name=name, objects=', '.join(objStrParts))
else:
outStr += '.setObjects(' + ', '.join(objects) + ')\n'
return outStr
# noinspection PyUnusedLocal
def genConceptualTable(self, data, classmode=False):
row = data[0]
if row[1] and row[1][-2:] == '()':
row = row[1][:-2]
self._rows.add(row)
return 'MibTable', ''
# noinspection PyMethodMayBeStatic,PyUnusedLocal
def genContactInfo(self, data, classmode=False):
text = self.textFilter('contact-info', data[0])
return '.setContactInfo(' + dorepr(text) + ')'
# noinspection PyUnusedLocal
def genDisplayHint(self, data, classmode=False):
return self.indent + 'displayHint = ' + dorepr(data[0]) + '\n'
# noinspection PyUnusedLocal
def genDefVal(self, data, classmode=False, objname=None):
if not data:
return ''
if not objname:
return data
defval = data[0]
defvalType = self.getBaseType(objname, self.moduleName[0])
if isinstance(defval, (int, long)): # number
val = str(defval)
elif self.isHex(defval): # hex
if defvalType[0][0] in ('Integer32', 'Integer'): # common bug in MIBs
val = str(int(defval[1:-2], 16))
else:
val = 'hexValue="' + defval[1:-2] + '"'
elif self.isBinary(defval): # binary
binval = defval[1:-2]
if defvalType[0][0] in ('Integer32', 'Integer'): # common bug in MIBs
val = str(int(binval or '0', 2))
else:
hexval = binval and hex(int(binval, 2))[2:] or ''
val = 'hexValue="' + hexval + '"'
elif defval[0] == defval[-1] and defval[0] == '"': # quoted string
if defval[1:-1] == '' and defvalType != 'OctetString': # common bug
# a warning should be here
return False # we will set no default value
val = dorepr(defval[1:-1])
else: # symbol (oid as defval) or name for enumeration member
if (defvalType[0][0] == 'ObjectIdentifier' and
(defval in self.symbolTable[self.moduleName[0]] or defval in self._importMap)): # oid
module = self._importMap.get(defval, self.moduleName[0])
try:
val = str(self.genNumericOid(self.symbolTable[module][defval]['oid']))
except:
# or no module if it will be borrowed later
raise error.PySmiSemanticError('no symbol "%s" in module "%s"' % (defval, module))
# enumeration
elif defvalType[0][0] in ('Integer32', 'Integer') and isinstance(defvalType[1], list):
if isinstance(defval, list): # buggy MIB: DEFVAL { { ... } }
defval = [dv for dv in defval if dv in dict(defvalType[1])]
val = defval and dorepr(defval[0]) or ''
elif defval in dict(defvalType[1]): # good MIB: DEFVAL { ... }
val = dorepr(defval)
else:
val = ''
elif defvalType[0][0] == 'Bits':
defvalBits = []
bits = dict(defvalType[1])
for bit in defval:
bitValue = bits.get(bit, None)
if bitValue is not None:
defvalBits.append((bit, bitValue))
else:
raise error.PySmiSemanticError('no such bit as "%s" for symbol "%s"' % (bit, objname))
return self.genBits([defvalBits])[1]
else:
raise error.PySmiSemanticError(
'unknown type "%s" for defval "%s" of symbol "%s"' % (defvalType, defval, objname))
return '.clone(' + val + ')'
# noinspection PyMethodMayBeStatic,PyUnusedLocal
def genDescription(self, data, classmode=False):
text = self.textFilter('description', data[0])
return classmode and self.indent + 'description = ' + dorepr(text) + '\n' or '.setDescription(' + dorepr(text) + ')'
# noinspection PyMethodMayBeStatic
def genReference(self, data, classmode=False):
text = self.textFilter('reference', data[0])
return classmode and self.indent + 'reference = ' + dorepr(text) + '\n' or '.setReference(' + dorepr(text) + ')'
# noinspection PyMethodMayBeStatic
def genStatus(self, data, classmode=False):
text = data[0]
return classmode and self.indent + 'status = ' + dorepr(text) + '\n' or '.setStatus(' + dorepr(text) + ')'
# noinspection PyMethodMayBeStatic
def genProductRelease(self, data, classmode=False):
text = data[0]
return classmode and self.indent + 'productRelease = ' + dorepr(text) + '\n' or '.setProductRelease(' + dorepr(text) + ')'
def genEnumSpec(self, data, classmode=False):
items = data[0]
singleval = [str(item[1]) for item in items]
outStr = classmode and self.indent + 'subtypeSpec = %s.subtypeSpec + ' or '.subtype(subtypeSpec='
numFuncCalls = len(singleval) / 255 + 1
singleCall = numFuncCalls == 1
funcCalls = ''
outStr += not singleCall and 'ConstraintsUnion(' or ''
for idx in range(int(numFuncCalls)):
if funcCalls:
funcCalls += ', '
funcCalls += 'SingleValueConstraint(' + ', '.join(singleval[255 * idx:255 * (idx + 1)]) + ')'
outStr += funcCalls
outStr += not singleCall and (classmode and ')\n' or '))') or (not classmode and ')' or '\n')
outStr += self.genBits(data, classmode=classmode)[1]
return outStr
# noinspection PyUnusedLocal
def genTableIndex(self, data, classmode=False):
def genFakeSyms(fakeidx, idxType):
fakeSymName = 'pysmiFakeCol%s' % fakeidx
objType = self.typeClasses.get(idxType, idxType)
objType = self.transOpers(objType)
return (fakeSymName + ' = MibTableColumn(%s + (' + str(fakeidx) +
', ), ' + objType + '())\n', # stub for parentOid
fakeSymName)
indexes = data[0]
idxStrlist, fakeSyms, fakeStrlist = [], [], []
for idx in indexes:
idxName = idx[1]
if idxName in self.smiv1IdxTypes: # SMIv1 support
idxType = idxName
fakeSymStr, idxName = genFakeSyms(self.fakeidx, idxType)
fakeStrlist.append(fakeSymStr)
fakeSyms.append(idxName)
self.fakeidx += 1
idxStrlist.append('(' + str(idx[0]) + ', "' +
self._importMap.get(idxName, self.moduleName[0]) +
'", "' + idxName + '")')
return '.setIndexNames(' + ', '.join(idxStrlist) + ')', fakeStrlist, fakeSyms
def genIntegerSubType(self, data, classmode=False):
singleRange = len(data[0]) == 1
outStr = classmode and self.indent + 'subtypeSpec = %s.subtypeSpec + ' or '.subtype(subtypeSpec='
outStr += not singleRange and 'ConstraintsUnion(' or ''
for rng in data[0]:
vmin, vmax = len(rng) == 1 and (rng[0], rng[0]) or rng
vmin, vmax = str(self.str2int(vmin)), str(self.str2int(vmax))
outStr += 'ValueRangeConstraint(' + vmin + ', ' + vmax + ')' + (not singleRange and ', ' or '')
outStr += not singleRange and (classmode and ')' or '))') or (not classmode and ')' or '\n')
return outStr
# noinspection PyMethodMayBeStatic,PyUnusedLocal
def genMaxAccess(self, data, classmode=False):
access = data[0].replace('-', '')
return access != 'notaccessible' and '.setMaxAccess("' + access + '")' or ''
def genOctetStringSubType(self, data, classmode=False):
singleRange = len(data[0]) == 1
outStr = classmode and self.indent + 'subtypeSpec = %s.subtypeSpec + ' or '.subtype(subtypeSpec='
outStr += not singleRange and 'ConstraintsUnion(' or ''
for rng in data[0]:
vmin, vmax = len(rng) == 1 and (rng[0], rng[0]) or rng
vmin, vmax = str(self.str2int(vmin)), str(self.str2int(vmax))
outStr += ('ValueSizeConstraint(' + vmin + ', ' + vmax + ')' +
(not singleRange and ', ' or ''))
outStr += not singleRange and (classmode and ')' or '))') or (not classmode and ')' or '\n')
if data[0]:
# noinspection PyUnboundLocalVariable
outStr += (singleRange
and vmin == vmax
and (classmode and self.indent + 'fixedLength = ' + vmin + '\n' or '.setFixedLength(' + vmin + ')') or '')
return outStr
# noinspection PyUnusedLocal
def genOid(self, data, classmode=False):
out = ()
parent = ''
for el in data[0]:
if isinstance(el, (str, unicode)):
parent = self.transOpers(el)
out += ((parent, self._importMap.get(parent, self.moduleName[0])),)
elif isinstance(el, (int, long)):
out += (el,)
elif isinstance(el, tuple):
out += (el[1],) # XXX Do we need to create a new object el[0]?
else:
raise error.PySmiSemanticError('unknown datatype for OID: %s' % el)
return str(self.genNumericOid(out)), parent
# noinspection PyUnusedLocal
def genObjects(self, data, classmode=False):
if data[0]:
return [self.transOpers(obj) for obj in data[0]] # XXX self.transOpers or not??
return []
# noinspection PyMethodMayBeStatic,PyUnusedLocal
def genTime(self, data, classmode=False):
times = []
for timeStr in data:
if len(timeStr) == 11:
timeStr = '19' + timeStr
# XXX raise in strict mode
# elif lenTimeStr != 13:
# raise error.PySmiSemanticError("Invalid date %s" % t)
try:
times.append(strftime('%Y-%m-%d %H:%M', strptime(timeStr, '%Y%m%d%H%MZ')))
except ValueError:
# XXX raise in strict mode
# raise error.PySmiSemanticError("Invalid date %s: %s" % (t, sys.exc_info()[1]))
timeStr = '197001010000Z' # dummy date for dates with typos
times.append(strftime('%Y-%m-%d %H:%M', strptime(timeStr, '%Y%m%d%H%MZ')))
return times
# noinspection PyMethodMayBeStatic,PyUnusedLocal
def genLastUpdated(self, data, classmode=False):
text = data[0]
return '.setLastUpdated(' + dorepr(text) + ')'
# noinspection PyMethodMayBeStatic,PyUnusedLocal
def genOrganization(self, data, classmode=False):
text = self.textFilter('organization', data[0])
return '.setOrganization(' + dorepr(text) + ')'
# noinspection PyUnusedLocal
def genRevisions(self, data, classmode=False):
times = self.genTime([x[0] for x in data[0]])
times = [dorepr(x) for x in times]
revisions = '.setRevisions((%s,))' % ', '.join(times)
descriptions = '.setRevisionsDescriptions((%s,))' % ', '.join(
[dorepr(self.textFilter('description', x[1][1])) for x in data[0]]
)
lastRevision = data[0][0][0]
return lastRevision, revisions, descriptions
def genRow(self, data, classmode=False):
row = data[0]
row = self.transOpers(row)
return row in self.symbolTable[self.moduleName[0]]['_symtable_rows'] and (
'MibTableRow', '') or self.genSimpleSyntax(data, classmode=classmode)
# noinspection PyUnusedLocal
def genSequence(self, data, classmode=False):
cols = data[0]
self._cols.update(cols)
return '', ''
def genSimpleSyntax(self, data, classmode=False):
objType = data[0]
objType = self.typeClasses.get(objType, objType)
objType = self.transOpers(objType)
subtype = len(data) == 2 and data[1] or ''
if classmode:
subtype = '%s' in subtype and subtype % objType or subtype # XXX hack?
return objType, subtype
outStr = objType + '()' + subtype
return 'MibScalar', outStr
# noinspection PyUnusedLocal
def genTypeDeclarationRHS(self, data, classmode=False):
if len(data) == 1:
parentType, attrs = data[0] # just syntax
else:
# Textual convention
display, status, description, reference, syntax = data
parentType, attrs = syntax
if parentType in self._snmpTypes:
parentType = 'TextualConvention, ' + parentType
if display:
attrs = display + attrs
if status:
attrs = status + attrs
if self.genRules['text'] and description:
attrs = description + attrs
if reference:
attrs = reference + attrs
attrs = attrs or self.indent + 'pass\n'
return parentType, attrs
# noinspection PyMethodMayBeStatic,PyUnusedLocal
def genUnits(self, data, classmode=False):
text = data[0]
return '.setUnits(' + dorepr(self.textFilter('units', text)) + ')'
handlersTable = {
'agentCapabilitiesClause': genAgentCapabilities,
'moduleIdentityClause': genModuleIdentity,
'moduleComplianceClause': genModuleCompliance,
'notificationGroupClause': genNotificationGroup,
'notificationTypeClause': genNotificationType,
'objectGroupClause': genObjectGroup,
'objectIdentityClause': genObjectIdentity,
'objectTypeClause': genObjectType,
'trapTypeClause': genTrapType,
'typeDeclaration': genTypeDeclaration,
'valueDeclaration': genValueDeclaration,
'ApplicationSyntax': genSimpleSyntax,
'BitNames': genBitNames,
'BITS': genBits,
'ComplianceModules': genCompliances,
'conceptualTable': genConceptualTable,
'CONTACT-INFO': genContactInfo,
'DISPLAY-HINT': genDisplayHint,
'DEFVAL': genDefVal,
'DESCRIPTION': genDescription,
'REFERENCE': genReference,
'Status': genStatus,
'PRODUCT-RELEASE': genProductRelease,
'enumSpec': genEnumSpec,
'INDEX': genTableIndex,
'integerSubType': genIntegerSubType,
'MaxAccessPart': genMaxAccess,
'Notifications': genObjects,
'octetStringSubType': genOctetStringSubType,
'objectIdentifier': genOid,
'Objects': genObjects,
'LAST-UPDATED': genLastUpdated,
'ORGANIZATION': genOrganization,
'Revisions': genRevisions,
'row': genRow,
'SEQUENCE': genSequence,
'SimpleSyntax': genSimpleSyntax,
'typeDeclarationRHS': genTypeDeclarationRHS,
'UNITS': genUnits,
'VarTypes': genObjects,
# 'a': lambda x: genXXX(x, 'CONSTRAINT')
}
def genCode(self, ast, symbolTable, **kwargs):
self.genRules['text'] = kwargs.get('genTexts', False)
self.textFilter = kwargs.get('textFilter') or (lambda symbol, text: re.sub('\s+', ' ', text))
self.symbolTable = symbolTable
self._rows.clear()
self._cols.clear()
self._exports.clear()
self._seenSyms.clear()
self._importMap.clear()
self._out.clear()
self._moduleIdentityOid = None
self.moduleName[0], moduleOid, imports, declarations = ast
out, importedModules = self.genImports(imports or {})
for declr in declarations or []:
if declr:
clausetype = declr[0]
classmode = clausetype == 'typeDeclaration'
self.handlersTable[declr[0]](self, self.prepData(declr[1:], classmode), classmode)
for sym in self.symbolTable[self.moduleName[0]]['_symtable_order']:
if sym not in self._out:
raise error.PySmiCodegenError('No generated code for symbol %s' % sym)
out += self._out[sym]
out += self.genExports()
if 'comments' in kwargs:
out = ''.join(['# %s\n' % x for x in kwargs['comments']]) + '#\n' + out
out = '#\n# PySNMP MIB module %s (http://snmplabs.com/pysmi)\n' % self.moduleName[0] + out
debug.logger & debug.flagCodegen and debug.logger(
'canonical MIB name %s (%s), imported MIB(s) %s, Python code size %s bytes' % (
self.moduleName[0], moduleOid, ','.join(importedModules) or '<none>', len(out)))
return MibInfo(oid=moduleOid,
identity=self._moduleIdentityOid,
name=self.moduleName[0],
revision=self._moduleRevision,
oids=[],
enterprise=None,
compliance=[],
imported=tuple([x for x in importedModules if x not in self.fakeMibs])), out
def genIndex(self, processed, **kwargs):
out = '\nfrom pysnmp.proto.rfc1902 import ObjectName\n\noidToMibMap = {\n'
count = 0
for module, status in processed.items():
value = getattr(status, 'oid', None)
if value:
out += 'ObjectName("%s"): "%s",\n' % (value, module)
count += 1
out += '}\n'
if 'comments' in kwargs:
out = ''.join(['# %s\n' % x for x in kwargs['comments']]) + '#\n' + out
out = '#\n# PySNMP MIB indices (http://snmplabs.com/pysmi)\n' + out
debug.logger & debug.flagCodegen and debug.logger(
'OID->MIB index built, %s entries, %s bytes' % (count, len(out)))
return out
# backward compatibility
baseMibs = PySnmpCodeGen.baseMibs
fakeMibs = PySnmpCodeGen.fakeMibs
Zerion Mini Shell 1.0