Skip to content

Commit

Permalink
Merge pull request #7 from dcvmoole/display-hints-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
lextm authored Oct 29, 2024
2 parents a9e0424 + 8663d9c commit baa4dc2
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 11 deletions.
27 changes: 27 additions & 0 deletions pysmi/codegen/intermediate.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,20 @@ def get_base_type(self, symName, module):

return baseSymType, symSubtype

def is_type_derived_from_tc(self, symName, module):
"""Is the given type derived from a Textual-Convention declaration?
Given that deriving simple types from textual conventions is currently
not supported altogether, this method tests only the immediate parent.
Any problems are ignored: if the given type is not definitely derived
from a textual convention, this method returns False.
"""
if module not in self.symbolTable or symName not in self.symbolTable[module]:
return False

return self.symbolTable[module][symName]["isTC"]

# Clause generation functions

# noinspection PyUnusedLocal
Expand Down Expand Up @@ -564,6 +578,19 @@ def gen_type_declaration(self, data):
outDict.update(attrs)
self.reg_sym(pysmiName, outDict)

# Establish if this type is derived from a Textual-Convention
# declaration, as needed for pysnmp code generation.
typeType = outDict["type"]["type"]
if (
typeType in self.symbolTable[self.moduleName[0]]
or typeType in self._importMap
):
module = self._importMap.get(typeType, self.moduleName[0])
isDerivedFromTC = self.is_type_derived_from_tc(typeType, module)
else:
isDerivedFromTC = False
outDict["type"]["tcbase"] = isDerivedFromTC

return outDict

# noinspection PyUnusedLocal
Expand Down
10 changes: 7 additions & 3 deletions pysmi/codegen/symtable.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,14 @@ def gen_type_declaration(self, data, classmode=False):
pysmiName = self.trans_opers(origName)

if declaration:
parentType, attrs = declaration
parentType, attrs, isTC = declaration

if parentType: # skipping SEQUENCE case
symProps = {
"type": "TypeDeclaration",
"syntax": declaration, # (type, module), subtype
"syntax": (parentType, attrs), # (type, module), subtype
"origName": origName,
"isTC": isTC,
}

self.reg_sym(pysmiName, symProps, [declaration[0][0]])
Expand Down Expand Up @@ -555,13 +557,15 @@ def gen_simple_syntax(self, data, classmode=False):
def gen_type_declaration_rhs(self, data, classmode=False):
if len(data) == 1:
parentType, attrs = data[0] # just syntax
isTC = False

else:
# Textual convention
display, status, description, reference, syntax = data
parentType, attrs = syntax
isTC = True

return parentType, attrs
return parentType, attrs, isTC

# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def gen_units(self, data, classmode=False):
Expand Down
6 changes: 5 additions & 1 deletion pysmi/codegen/templates/pysnmp/mib-definitions.j2
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,11 @@ class {{ symbol }}({{ definition['type']['type'] }}):
{% for symbol, definition in mib.items() if definition['class'] == 'textualconvention' %}


class {{ symbol }}({{ definition['type']['type'] }}, TextualConvention):
{% if definition['type']['tcbase'] %}
class {{ symbol }}({{ definition['type']['type'] }}):
{% else %}
class {{ symbol }}(TextualConvention, {{ definition['type']['type'] }}):
{% endif %}
status = "{{ definition.get('status', 'current') }}"
{% if 'displayhint' in definition %}
displayHint = {{ definition['displayhint']|pythonstr }}
Expand Down
57 changes: 54 additions & 3 deletions tests/test_imports_smiv2_pysnmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,18 @@ class ImportTypeTestCase(unittest.TestCase):
FROM SNMPv2-SMI
TEXTUAL-CONVENTION
FROM SNMPv2-TC
ImportedType1, Imported-Type-2, True
ImportedType1,
Imported-Type-2,
True,
ImportedType3
FROM IMPORTED-MIB;
testObject1 OBJECT-TYPE
SYNTAX ImportedType1
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Test object"
DEFVAL { '01020304'H }
::= { 1 3 }
Test-Type-2 ::= TEXTUAL-CONVENTION
Expand All @@ -155,6 +159,7 @@ class ImportTypeTestCase(unittest.TestCase):
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Test object"
DEFVAL { 'aabbccdd'H }
::= { 1 4 }
False ::= TEXTUAL-CONVENTION
Expand All @@ -177,6 +182,20 @@ class ImportTypeTestCase(unittest.TestCase):
DESCRIPTION "Test object"
::= { 1 6 }
TestType3 ::= TEXTUAL-CONVENTION
DISPLAY-HINT "2d:"
STATUS current
DESCRIPTION "Test TC"
SYNTAX ImportedType3
testObject3 OBJECT-TYPE
SYNTAX TestType3
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Test object"
DEFVAL { '000100020003'H }
::= { 1 7 }
END
"""

Expand All @@ -189,7 +208,7 @@ class ImportTypeTestCase(unittest.TestCase):
FROM SNMPv2-TC;
ImportedType1 ::= TEXTUAL-CONVENTION
DISPLAY-HINT "255a"
DISPLAY-HINT "1d:"
STATUS current
DESCRIPTION "Test TC with display hint"
SYNTAX OCTET STRING
Expand All @@ -204,6 +223,8 @@ class ImportTypeTestCase(unittest.TestCase):
DESCRIPTION "Test TC"
SYNTAX OCTET STRING
ImportedType3 ::= OCTET STRING
END
"""

Expand All @@ -230,10 +251,15 @@ def testObjectTypeLabel1(self):
def testObjectTypeDisplayHint1(self):
self.assertEqual(
self.ctx["testObject1"].getSyntax().getDisplayHint(),
"255a",
"1d:",
"bad display hint",
)

def testObjectTypePrettyValue1(self):
self.assertEqual(
self.ctx["testObject1"].getSyntax().prettyPrint(), "1:2:3:4", "bad defval"
)

def testObjectTypeName2(self):
self.assertEqual(self.ctx["test_object_2"].getName(), (1, 4), "bad value")

Expand All @@ -249,6 +275,13 @@ def testObjectTypeDisplayHint2(self):
"bad display hint",
)

def testObjectTypePrettyValue2(self):
self.assertEqual(
self.ctx["test_object_2"].getSyntax().prettyPrint(),
"aa:bb:cc:dd",
"bad defval",
)

def testObjectTypeNameReservedKeyword1(self):
self.assertEqual(self.ctx["_pysmi_global"].getName(), (1, 5), "bad value")

Expand All @@ -275,6 +308,24 @@ def testObjectTypeDisplayHintReservedKeyword2(self):
"bad display hint",
)

def testObjectTypeName3(self):
self.assertEqual(self.ctx["testObject3"].getName(), (1, 7), "bad value")

def testObjectTypeLabel3(self):
self.assertEqual(self.ctx["testObject3"].getLabel(), "testObject3", "bad label")

def testObjectTypeDisplayHint3(self):
self.assertEqual(
self.ctx["testObject3"].getSyntax().getDisplayHint(),
"2d:",
"bad display hint",
)

def testObjectTypePrettyValue3(self):
self.assertEqual(
self.ctx["testObject3"].getSyntax().prettyPrint(), "1:2:3", "bad defval"
)


class ImportSelfTestCase(unittest.TestCase):
"""
Expand Down
77 changes: 73 additions & 4 deletions tests/test_typedeclaration_smiv2_pysnmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,12 +343,12 @@ class TypeDeclarationInheritanceTestCase(unittest.TestCase):
"""
TEST-MIB DEFINITIONS ::= BEGIN
IMPORTS
Unsigned32
OBJECT-TYPE
FROM SNMPv2-SMI
TEXTUAL-CONVENTION
FROM SNMPv2-TC;
TestTypeUnsigned32 ::= Unsigned32
TestTypeInteger ::= INTEGER
--
-- without constraints
Expand All @@ -359,14 +359,14 @@ class TypeDeclarationInheritanceTestCase(unittest.TestCase):
DISPLAY-HINT "d-1"
STATUS current
DESCRIPTION "Test TC 1"
SYNTAX Unsigned32
SYNTAX INTEGER
-- textual convention for simple type, derived from base type
TestTC-SB ::= TEXTUAL-CONVENTION
DISPLAY-HINT "d-2"
STATUS current
DESCRIPTION "Test TC 2"
SYNTAX TestTypeUnsigned32
SYNTAX TestTypeInteger
-- textual convention for textual convention, derived from base type
TestTC-TB ::= TEXTUAL-CONVENTION
Expand Down Expand Up @@ -431,6 +431,50 @@ class TypeDeclarationInheritanceTestCase(unittest.TestCase):
DESCRIPTION "Test TC 10"
SYNTAX TestTC-TC (SIZE (20..23))
--
-- test objects (without constraints only)
--
testObjectB OBJECT-TYPE
SYNTAX TestTC-B
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Test object"
DEFVAL { 123456 }
::= { 1 4 1 }
testObjectSB OBJECT-TYPE
SYNTAX TestTC-SB
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Test object"
DEFVAL { 123456 }
::= { 1 4 2 }
testObjectTB OBJECT-TYPE
SYNTAX TestTC-TB
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Test object"
DEFVAL { 123456 }
::= { 1 4 3 }
testObjectTSB OBJECT-TYPE
SYNTAX TestTC-TSB
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Test object"
DEFVAL { 123456 }
::= { 1 4 4 }
testObjectTTB OBJECT-TYPE
SYNTAX TestTC-TTB
MAX-ACCESS read-only
STATUS current
DESCRIPTION "Test object"
DEFVAL { 123456 }
::= { 1 4 5 }
END
"""

Expand Down Expand Up @@ -551,6 +595,31 @@ def testTextualConventionDisplayHintTTC(self):
"bad DISPLAY-HINT",
)

def testObjectTypePrettyValueB(self):
self.assertEqual(
self.ctx["testObjectB"].getSyntax().prettyPrint(), "12345.6", "bad DEFVAL"
)

def testObjectTypePrettyValueSB(self):
self.assertEqual(
self.ctx["testObjectSB"].getSyntax().prettyPrint(), "1234.56", "bad DEFVAL"
)

def testObjectTypePrettyValueTB(self):
self.assertEqual(
self.ctx["testObjectTB"].getSyntax().prettyPrint(), "123.456", "bad DEFVAL"
)

def testObjectTypePrettyValueTSB(self):
self.assertEqual(
self.ctx["testObjectTSB"].getSyntax().prettyPrint(), "12.3456", "bad DEFVAL"
)

def testObjectTypePrettyValueTTB(self):
self.assertEqual(
self.ctx["testObjectTTB"].getSyntax().prettyPrint(), "1.23456", "bad DEFVAL"
)


class TypeDeclarationBitsTextualConventionSyntaxTestCase(unittest.TestCase):
"""
Expand Down

0 comments on commit baa4dc2

Please sign in to comment.