pysmi-0.3.4/0000775006321400632140000000000013454602625014330 5ustar ietingofietingof00000000000000pysmi-0.3.4/CHANGES.rst0000664006321400632140000001360413454602510016127 0ustar ietingofietingof00000000000000 Revision 0.3.4, XX-01-2019 -------------------------- - Added `implied` key to JSON SNMP table index structure - Rebased MIB importing code onto `importlib` because `imp` is long deprecated - Fixed Py file borrower to become functional Revision 0.3.3, 29-12-2018 -------------------------- - Added mibcopy.py documentation - Copyright notice bumped up to year 2019 Revision 0.3.2, 22-10-2018 -------------------------- - Bumped upper Python version to 3.7 and enabled pip cache - Exit code indication of the command-line tools aligned with sysexits.h to report more useful termination status Revision 0.3.1, 10-06-2018 -------------------------- - Fixed pysnmp lower version in test-requirements.txt - Fixed compiler crash when building comments at a platform which has broken users/groups databases Revision 0.3.0, 29-04-2018 -------------------------- - The `mibcopy` tool implemented to copy MIB modules from files with potentially messed up names into a directory under canonical MIB names picking up the latest MIB revision along the way. - ZIP archive reader implemented to pull ASN.1 MIB files from .zip archives pretty much in the same way as from plain directories - HTTP/S proxy support added (through respecting `http_proxy` environment variable) by switching from `httplib` to `urllib2` internally - Copyright notice bumped up to year 2018 - Project site in the docs changes from SourceForge to snmplabs.com - PRODUCT-RELEASE generation added to the JSON code generator - Added special handling of BITS-like DEFVAL syntax for Integers that occurs in buggy MIBs - Fixed missing REVISIONS generations in MODULE-IDENTITY Revision 0.2.2, 13-11-2017 -------------------------- - Library documentation refactored and updated - Fixed malformed Python code being produced by pysnmp code generator Revision 0.2.1, 11-11-2017 -------------------------- - Added MIB *status*, *product release* and *revision description* set calls at pysnmp code generator - Changed REVISION field format in JSON representation - it is now a list of dicts each with *revision* timestamp and *description* text - MIB REFERENCE fields are only exported if --with-mib-text is on - Sphinx documentation theme changed to Alabaster - Multiple fixes to pysnmp codegen not to produce function calls with more than 255 parameters Revision 0.1.4, 14-10-2017 -------------------------- - Fix to SMI lexer to treat tokens starting from a digit as belonging to a lower-cased class. This fixes sub-OID parsing bug (specifically, 802dot3(10006)) - Fix to the mibdump.py local MIB path automatic injection in front of existing --mib-sources Revision 0.1.3, 19-05-2017 -------------------------- * INET-ADDRESS-MIB configured as pre-built at pysnmp codegen * JSON codegen produces "nodetype" element for OBJECT-TYPE * Fix to mibdump.py --destination-directory option * Fix to pysnmp and JSON code generators to properly refer to MIB module defining particular MIB object Revision 0.1.2, 12-04-2017 -------------------------- * The @mib@ magic in reader's URL template made optional. If it is not present, MIB module name is just appended to URL template * Send User-Agent containing pysmi and Python versions as well as platform name. * Fixed missing STATUS/DISPLAY-HINT/REFERENCE/etc fields generation at pysnmp backend when running in the non-full-text mode * Fixed broken `ordereddict` dependency on Python 2.6- Revision 0.1.1, 30-03-2017 -------------------------- * Generate REFERENCE and STATUS fields at various SMI objects * Generate DESCRIPTION field followed REVISION field at MODULE-IDENTITY objects * Generate PRODUCT-RELEASE field at AGENT-CAPABILITIES objects * Generated Python source aligned with PEP8 * MIB texts cleaned up by default, --keep-texts-layout preserves original formatting * Fix to the `ordereddict` conditional dependency * Missing test module recovered * Failing tests fixed Revision 0.1.0, 25-03-2017 -------------------------- * JSON code generating backend implemented * Experimental JSON OID->MIB indices generation implemented * Package structure flattened for easier use * Minor refactoring to the test suite * Source code statically analyzed, hardened and PEP8-ized * Files closed explicitly to mute ResourceWarnings * Fixed to Python 2.4 (and aged ply) compatibility * Added a workaround to avoid generating pysnmp TextualConvention classes inheriting from TextualConvention (when MIB defines a TEXTUAL-CONVENTION based on another TEXTUAL-CONVENTION as SYNTAX) * Author's e-mail changed, copyright extended to year 2017 Revision 0.0.7, 12-02-2016 -------------------------- * Crash on existing .py file handling fixed. * Fix to __doc__ use in setup.py to make -O0 installation mode working. * Fix to PyPackageSearcher not to fail on broken Python packages. * Source code pep8'ed * Copyright added to source files. Revision 0.0.6, 01-10-2015 -------------------------- * Several typos fixed, source code linted again. * Some dead code cleaned up. Revision 0.0.5, 28-09-2015 -------------------------- * Wheel distribution format now supported. * Handle the case of MIB symbols conflict with Python reserved words. * Handle binary DEFVAL initializer for INTEGER's. * Generate LAST-UPDATED at pysnmp code generator. Revision 0.0.4, 01-07-2015 -------------------------- * Fix to MRO compliance for mixin classes generation at pysnmp backend * Fix to repeated imports in generated code at pysnmp backend * Fix to mibdump tool to properly handle the --generate-mib-texts option. * Fix to Python compile() - optimize flag is valid only past Python 3.1 * Fix to SMIv1 INDEX clause code generation for pysnmp backend. * Tighten file creation security at pysmi.writer.pyfile Revision 0.0.3, 28-06-2015 -------------------------- * Two-pass compiler design allows for much accurate code generation. * Sphinx-based documentation first introduced Revision 0.0.0, 11-04-2015 -------------------------- * First public release, not fully operational yet pysmi-0.3.4/LICENSE.rst0000664006321400632140000000246513411726453016152 0ustar ietingofietingof00000000000000Copyright (c) 2015-2019 Ilya Etingof All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pysmi-0.3.4/MANIFEST.in0000664006321400632140000000021513200041462016045 0ustar ietingofietingof00000000000000include *.txt *.rst *.md recursive-include tests *.py recursive-include examples *.py recursive-include docs *.txt *.rst *.svg *.py Makefile pysmi-0.3.4/PKG-INFO0000664006321400632140000000313413454602625015426 0ustar ietingofietingof00000000000000Metadata-Version: 1.2 Name: pysmi Version: 0.3.4 Summary: SNMP SMI/MIB Parser Home-page: https://github.com/etingof/pysmi Author: Ilya Etingof Author-email: etingof@gmail.com Maintainer: Ilya Etingof License: BSD Description: A pure-Python implementation of SNMP/SMI MIB parsing and conversion library. Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Communications Classifier: Topic :: System :: Monitoring Classifier: Topic :: System :: Networking :: Monitoring Classifier: Topic :: Software Development :: Libraries :: Python Modules pysmi-0.3.4/README.md0000664006321400632140000001456613411726453015622 0ustar ietingofietingof00000000000000 SNMP MIB parser --------------- [![Python Versions](https://img.shields.io/pypi/pyversions/pysmi.svg)](https://pypi.org/project/pysmi/) [![Build status](https://travis-ci.org/etingof/pysmi.svg?branch=master)](https://secure.travis-ci.org/etingof/pysmi) [![Coverage Status](https://img.shields.io/codecov/c/github/etingof/pysmi.svg)](https://codecov.io/github/etingof/pysmi) [![GitHub license](https://img.shields.io/badge/license-BSD-blue.svg)](https://raw.githubusercontent.com/etingof/pysmi/master/LICENSE.rst) PySMI is a pure-Python implementation of [SNMP SMI](https://en.wikipedia.org/wiki/Management_information_base) MIB parser. This tool is designed to turn ASN.1 MIBs into various formats. As of this moment, JSON and [pysnmp](https://github.com/etingof/pysnmp) modules can be generated from ASN.1 MIBs. Features -------- * Understands SMIv1, SMIv2 and de-facto SMI dialects * Turns MIBs into pysnmp classes and JSON documents * Maintains an index of MIB objects over many MIB modules * Automatically pulls ASN.1 MIBs from local directories, ZIP archives, HTTP and FTP servers * 100% Python, works with Python 2.4 up to Python 3.7 Rendered PySMI documentation can be found at [pysmi site](http://snmplabs.com/pysmi). How to use PySMI ---------------- If you are using pysnmp, you might never notice pysmi presence - pysnmp calls pysmi for MIB download and compilation behind the scenes (you can still can do that manually by invoking *mibdump.py* tool). To turn ASN.1 MIB into a JSON document, call *mibdump.py* tool like this: ``` $ mibdump.py --generate-mib-texts --destination-format json IF-MIB Source MIB repositories: file:///usr/share/snmp/mibs, http://mibs.snmplabs.com/asn1/@mib@ Borrow missing/failed MIBs from: http://mibs.snmplabs.com/json/fulltexts/@mib@ Existing/compiled MIB locations: Compiled MIBs destination directory: . MIBs excluded from code generation: RFC-1212, RFC-1215, RFC1065-SMI, RFC1155-SMI, RFC1158-MIB, RFC1213-MIB, SNMPv2-CONF, SNMPv2-SMI, SNMPv2-TC, SNMPv2-TM MIBs to compile: IF-MIB Destination format: json Parser grammar cache directory: not used Also compile all relevant MIBs: yes Rebuild MIBs regardless of age: yes Do not create/update MIBs: no Byte-compile Python modules: no (optimization level no) Ignore compilation errors: no Generate OID->MIB index: no Generate texts in MIBs: yes Keep original texts layout: no Try various filenames while searching for MIB module: yes Created/updated MIBs: IANAifType-MIB, IF-MIB, SNMPv2-MIB Pre-compiled MIBs borrowed: Up to date MIBs: SNMPv2-CONF, SNMPv2-SMI, SNMPv2-TC Missing source MIBs: Ignored MIBs: Failed MIBs: ``` JSON document build from [IF-MIB module](http://mibs.snmplabs.com/asn1/IF-MIB) would hold information such as: ``` { "ifMIB": { "name": "ifMIB", "oid": "1.3.6.1.2.1.31", "class": "moduleidentity", "revisions": [ "2007-02-15 00:00", "1996-02-28 21:55", "1993-11-08 21:55" ] }, ... "ifTestTable": { "name": "ifTestTable", "oid": "1.3.6.1.2.1.31.1.3", "nodetype": "table", "class": "objecttype", "maxaccess": "not-accessible" }, "ifTestEntry": { "name": "ifTestEntry", "oid": "1.3.6.1.2.1.31.1.3.1", "nodetype": "row", "class": "objecttype", "maxaccess": "not-accessible", "augmention": { "name": "ifTestEntry", "module": "IF-MIB", "object": "ifEntry" } }, "ifTestId": { "name": "ifTestId", "oid": "1.3.6.1.2.1.31.1.3.1.1", "nodetype": "column", "class": "objecttype", "syntax": { "type": "TestAndIncr", "class": "type" }, "maxaccess": "read-write" }, ... } ``` In general, converted MIBs capture all aspects of original (ASN.1) MIB contents and layout. The snippet above is just a partial example, but here is the complete [IF-MIB.json](http://mibs.snmplabs.com/json/fulltexts/IF-MIB.json) file. Besides one-to-one MIB conversion, PySMI library can produce JSON index to facilitate fast MIB information lookup across large collection of MIB files. For example, JSON index for [IP-MIB.json](http://mibs.snmplabs.com/json/asn1/IP-MIB), [TCP-MIB.json](http://mibs.snmplabs.com/json/asn1/TCP-MIB) and [UDP-MIB.json](http://mibs.snmplabs.com/json/asn1/UDP-MIB) modules would keep information like this: ``` { "compliance": { "1.3.6.1.2.1.48.2.1.1": [ "IP-MIB" ], "1.3.6.1.2.1.49.2.1.1": [ "TCP-MIB" ], "1.3.6.1.2.1.50.2.1.1": [ "UDP-MIB" ] }, "identity": { "1.3.6.1.2.1.48": [ "IP-MIB" ], "1.3.6.1.2.1.49": [ "TCP-MIB" ], "1.3.6.1.2.1.50": [ "UDP-MIB" ] }, "oids": { "1.3.6.1.2.1.4": [ "IP-MIB" ], "1.3.6.1.2.1.5": [ "IP-MIB" ], "1.3.6.1.2.1.6": [ "TCP-MIB" ], "1.3.6.1.2.1.7": [ "UDP-MIB" ], "1.3.6.1.2.1.49": [ "TCP-MIB" ], "1.3.6.1.2.1.50": [ "UDP-MIB" ] } } ``` With this example, *compliance* and *identity* keys point to *MODULE-COMPLIANCE* and *MODULE-IDENTITY* MIB objects, *oids* list top-level OIDs branches defined in MIB modules. Full index build over thousands of MIBs could be seen [here](http://mibs.snmplabs.com/json/index.json). The PySMI library can automatically fetch required MIBs from HTTP, FTP sites or local directories. You could configure any MIB source available to you (including [http://mibs.snmplabs.com/asn1/](http://mibs.snmplabs.com/asn1/)) for that purpose. How to get PySMI ---------------- The pysmi package is distributed under terms and conditions of 2-clause BSD [license](http://snmplabs.com/pysmi/license.html). Source code is freely available as a GitHub [repo](https://github.com/etingof/pysmi). You could `pip install pysmi` or download it from [PyPI](https://pypi.org/project/pysmi/). If something does not work as expected, [open an issue](https://github.com/etingof/pysmi/issues) at GitHub or post your question [on Stack Overflow](http://stackoverflow.com/questions/ask). Copyright (c) 2015-2019, [Ilya Etingof](mailto:etingof@gmail.com). All rights reserved. pysmi-0.3.4/THANKS.txt0000664006321400632140000000004112775215065016057 0ustar ietingofietingof00000000000000Lars Michelsen Tanya Tereschenko pysmi-0.3.4/TODO.txt0000664006321400632140000000357313200041462015627 0ustar ietingofietingof00000000000000* add more tests on edge cases * generate reverse OID -> MIB index * handle SMIv1 MAX clause in range constraint * support MAX clause mapping it into type-specific value * possibly split symbol table code generator onto imported modules and symbol table code generators. * support more common broken SMI constructs * DEFVAL and AUGMENTS should not depend on the order of symbols in MIB * make a collection of fixed MIBs (e.g. Huawei has lots of bad/broken MIBs) * some MIBs use hex as DEFVAL for types other than OCTET STRING (additional AST processing phase will help) * handle the case when the symbol and the enumaration value (which can be in DEFVAL) have the same name - llc2 in NETLINK-SPECIFIC-MIB (additional AST processing phase will help) * check imports and try to add necessary ones if missed (like OBJECT-TYPE, MODULE-IDENTITY, etc) * generate TextualConvention first or add additional AST processing phase * implement a cache of available files at abstract reader path * create a command-line tool for splitting MIBs stored in a single file * create a MIB querying tool: get MIB module's OIDs, enterprise IDs, canonical name(s); search MIB objects by regexp; build source .index * implement xml/html/yaml codegeneration backend * write a tool to fetch canonical MIB name from MIB file, rename MIB file, split merged MIBs onto individual files * write a tool to turn IANA assigned numbers into JSON * introduce cached MIBs invalidation feature -- may be useful when we screw up and produce bad MIBs * json codegen: - make schema configurable - further simplify/review codegen code - rebuild the docs - conditionally require simplejson and ordereddict - add tests - is it a good idea to make writers also reading data? - review symtable for unused pieces - write a tool to split json index onto separate documents - index NOTIFICATION-TYPE's - add example script on index build pysmi-0.3.4/devel-requirements.txt0000664006321400632140000000013313411726453020705 0ustar ietingofietingof00000000000000Sphinx <= 1.6; python_version < '2.7' Sphinx > 1.6; python_version >= '2.7' pysnmp < 5.0.0 pysmi-0.3.4/docs/0000775006321400632140000000000013454602625015260 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/Makefile0000664006321400632140000001636612775215065016737 0ustar ietingofietingof00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PySMI.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PySMI.qhc" applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/PySMI" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PySMI" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." pysmi-0.3.4/docs/README.txt0000664006321400632140000000033212775215065016757 0ustar ietingofietingof00000000000000You need Sphinx too build this documentation. Or you can read it in ASCII. ;) Better run: # pip sphinx and once Sphinx is installed on your system, run: $ make html To build a copy of HTML'ed PySMI documentation. pysmi-0.3.4/docs/source/0000775006321400632140000000000013454602625016560 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/.static/0000775006321400632140000000000013454602625020125 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/.static/logo.svg0000664006321400632140000003276313200041462021602 0ustar ietingofietingof00000000000000 pysmi-0.3.4/docs/source/changelog.rst0000664006321400632140000000006513200041462021223 0ustar ietingofietingof00000000000000 Changelog ========= .. include:: ../../CHANGES.rst pysmi-0.3.4/docs/source/conf.py0000664006321400632140000002423413411726453020063 0ustar ietingofietingof00000000000000# -*- coding: utf-8 -*- # # PySMI documentation build configuration file, created by # sphinx-quickstart on Sat Jun 27 23:15:54 2015. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os import shlex # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['.templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'contents' # General information about the project. project = u'SNMP SMI compiler' copyright = u'2015-2019, Ilya Etingof ' author = u'Ilya Etingof ' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '0.1' # The full version, including alpha/beta/rc tags. release = '0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = { 'collapse_navigation': False } html_theme_options = { 'logo': 'logo.svg', 'description': '

Brewing free software for the greater good

', 'show_powered_by': False, 'github_user': 'etingof', 'github_repo': 'pysmi', 'fixed_sidebar': True, } html_sidebars = { '**': [ 'about.html', 'navigation.html', 'relations.html', 'searchbox.html', 'donate.html', ] } # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = '.static/favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['.static'] # Custom CSS theme #html_style = 'css/rtdimproved.css' # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. html_domain_indices = False # If false, no index is generated. html_use_index = False # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' #html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value #html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'PySMIdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', # Latex figure (float) alignment #'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'PySMI.tex', u'SNMP SMI compiler', u'Ilya Etingof \\textless{}etingof@gmail.com\\textgreater{}', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'pysmi', u'SNMP SMI compiler', [author], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'PySMI', u'SNMP SMI compiler', author, 'PySMI', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://docs.python.org/': None} # this merges constructor docstring with class docstring autoclass_content = 'both' # Napoleon settings napoleon_google_docstring = True napoleon_numpy_docstring = False napoleon_include_private_with_doc = False napoleon_include_special_with_doc = True napoleon_use_admonition_for_examples = False napoleon_use_admonition_for_notes = False napoleon_use_admonition_for_references = False napoleon_use_ivar = False napoleon_use_param = False napoleon_use_rtype = False pysmi-0.3.4/docs/source/contents.rst0000664006321400632140000000335013200041462021131 0ustar ietingofietingof00000000000000 SNMP SMI compiler ================= .. toctree:: :maxdepth: 2 The PySMI library and tools are designed to parse, verify and transform `SNMP SMI `_ MIB modules from their original ASN.1 form into JSON or `pysnmp `_ representation. Documentation ------------- .. toctree:: :maxdepth: 2 /documentation Source code & Changelog ----------------------- Project source code is hosted at `GitHub `_. Everyone is welcome to fork and contribute back! We maintain the detailed :doc:`log of changes ` to our software. Download & Install ------------------ .. toctree:: :maxdepth: 2 /download Changes ------- .. toctree:: :maxdepth: 1 /changelog License ------- The SNMP SMI library software is distributed under 2-clause BSD License. .. toctree:: :maxdepth: 2 /license MIB files archive ----------------- The PySMI project maintains a `collection `_ of publicly available ASN.1 MIB files collected on the Internet. You are welcome to use this MIBs archive however we can't guarantee any degree of consistency or reliability when it comes to these MIB modules. The *mibdump.py* tool as well as many other utilities based on PySMI are programmed to use this MIB repository for automatic download and dependency resolution. You can always reconfigure PySMI to use some other remote MIB repository instead or in addition to this one. Contact ------- In case of questions or troubles using SNMP SMI library, please open up an `issue `_ at GitHub or ask at `Stack Overflow `_ . pysmi-0.3.4/docs/source/documentation.rst0000664006321400632140000000366013411726453022167 0ustar ietingofietingof00000000000000 PySMI documentation =================== PySMI library is highly modular. The top-level component is called *compiler* and it acts as main user-facing object. Most of other components are plugged into the *compiler* object prior to its use. Normally, user asks *compiler* to perform certain transformation of named MIB module. Compiler will: * Search its data sources for given MIB module (identified by name) noting their last modification times. * Search compiler-managed repositories of already converted MIB modules for modules that are more recent than corresponding source MIB module. * If freshly transformed MIB module is found, processing stops here. * Otherwise compiler passes ASN.1 MIB module content to the *lexer* component. * Lexer returns a sequence of tokenized ASN.1 MIB contents. Compiler then passes that sequence of tokens to the *parser* component. * Parser runs LR algorithm on tokenized MIB thus transforming MIB contents into Abstract Syntax Tree (AST) and also noting what other MIB modules are referred to from the MIB being parsed. * In case of parser failure, what is usually an indication of broken ASN.1 MIB syntax, compiler may attempt to fetch pre-transformed MIB contents from configured source. This process is called *borrowing* in PySMI. * In case of successful parser completion, compiler will pass produced AST to *code generator* component. * Code generator walks its input AST and performs actual data transformation. * The above steps may be repeated for each of the MIB modules referred to as parser figures out. Once no more unresolved dependencies remain, compiler will call its *writer* component to store all transformed MIB modules. The location of ASN.1 MIB modules and flavor of their syntax, as well as desired transformation format, is determined by respective components chosen and configured to compiler. .. toctree:: :maxdepth: 2 /mibdump /mibcopy /library-reference pysmi-0.3.4/docs/source/download.rst0000664006321400632140000000054313267650112021117 0ustar ietingofietingof00000000000000 Download & Install ================== The best way to obtain SNMP SMI library is by running `pip`: .. code-block:: bash $ virtualenv venv $ source venv/bin/activate $ pip install pysmi Alternatively, you can download the latest release from `GitHub `_ or `PyPI `_. pysmi-0.3.4/docs/source/examples/0000775006321400632140000000000013454602625020376 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/examples/always-borrow-precompiled-pysnmp-files.rst0000664006321400632140000000050613202162514030653 0ustar ietingofietingof00000000000000 .. include:: /../../examples/always-borrow-precompiled-pysnmp-files.py :start-after: """ :end-before: """# .. literalinclude:: /../../examples/always-borrow-precompiled-pysnmp-files.py :start-after: """# :language: python :download:`Download` script. pysmi-0.3.4/docs/source/examples/borrow-precompiled-pysnmp-files-on-failure.rst0000664006321400632140000000052213202162514031412 0ustar ietingofietingof00000000000000 .. include:: /../../examples/borrow-precompiled-pysnmp-files-on-failure.py :start-after: """ :end-before: """# .. literalinclude:: /../../examples/borrow-precompiled-pysnmp-files-on-failure.py :start-after: """# :language: python :download:`Download` script. pysmi-0.3.4/docs/source/examples/compile-smistar-mibs-into-pysnmp-files-if-needed.rst0000664006321400632140000000054413202162514032371 0ustar ietingofietingof00000000000000 .. include:: /../../examples/compile-smistar-mibs-into-pysnmp-files-if-needed.py :start-after: """ :end-before: """# .. literalinclude:: /../../examples/compile-smistar-mibs-into-pysnmp-files-if-needed.py :start-after: """# :language: python :download:`Download` script. pysmi-0.3.4/docs/source/examples/compile-smiv2-mibs-from-text-into-pysnmp-code.rst0000664006321400632140000000053313202162514031662 0ustar ietingofietingof00000000000000 .. include:: /../../examples/compile-smiv2-mibs-from-text-into-pysnmp-code.py :start-after: """ :end-before: """# .. literalinclude:: /../../examples/compile-smiv2-mibs-from-text-into-pysnmp-code.py :start-after: """# :language: python :download:`Download` script. pysmi-0.3.4/docs/source/examples/download-and-compile-smistar-mibs-into-json.rst0000664006321400632140000000052513202162514031442 0ustar ietingofietingof00000000000000 .. include:: /../../examples/download-and-compile-smistar-mibs-into-json.py :start-after: """ :end-before: """# .. literalinclude:: /../../examples/download-and-compile-smistar-mibs-into-json.py :start-after: """# :language: python :download:`Download` script. pysmi-0.3.4/docs/source/examples/download-and-compile-smistar-mibs-into-pysnmp-files.rst0000664006321400632140000000055513202162514033122 0ustar ietingofietingof00000000000000 .. include:: /../../examples/download-and-compile-smistar-mibs-into-pysnmp-files.py :start-after: """ :end-before: """# .. literalinclude:: /../../examples/download-and-compile-smistar-mibs-into-pysnmp-files.py :start-after: """# :language: python :download:`Download` script. pysmi-0.3.4/docs/source/library-reference.rst0000664006321400632140000001130213202162514022674 0ustar ietingofietingof00000000000000 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: .. code-block:: python 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) .. toctree:: :maxdepth: 2 /pysmi/compiler/mibcompiler /pysmi/compiler/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. .. toctree:: :maxdepth: 2 /pysmi/reader/localfile/filereader /pysmi/reader/zipreader/zipreader /pysmi/reader/httpclient/httpreader /pysmi/reader/ftpclient/ftpreader /pysmi/reader/callback/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 :ref:`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. .. toctree:: :maxdepth: 2 /pysmi/searcher/pyfile/pyfilesearcher /pysmi/searcher/pypackage/pypackagesearcher /pysmi/searcher/stub/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. .. toctree:: :maxdepth: 2 /pysmi/parser/smi/parserfactory /pysmi/parser/smi/dialect 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. .. toctree:: :maxdepth: 2 /pysmi/codegen/jsondoc/jsoncodegen /pysmi/codegen/pysnmp/pysnmpcodegen /pysmi/codegen/null/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 :ref:`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. .. toctree:: :maxdepth: 2 /pysmi/borrower/anyfile/anyfileborrower /pysmi/borrower/pyfile/pyfileborrower Write compiled MIBs ------------------- Successfully transformed MIB modules' contents will be passed to *writer* object given to :ref:`MibCompiler ` on instantiation. .. toctree:: :maxdepth: 2 /pysmi/writer/localfile/filewriter /pysmi/writer/pyfile/pyfilewriter /pysmi/writer/callback/callbackwriter Examples -------- The following examples focus on various feature of the PySMI library. .. toctree:: :maxdepth: 2 /examples/download-and-compile-smistar-mibs-into-json.rst /examples/download-and-compile-smistar-mibs-into-pysnmp-files.rst /examples/compile-smistar-mibs-into-pysnmp-files-if-needed.rst /examples/compile-smiv2-mibs-from-text-into-pysnmp-code.rst /examples/borrow-precompiled-pysnmp-files-on-failure.rst /examples/always-borrow-precompiled-pysnmp-files.rst In case of any troubles or confusion, try enabling PySMI debugging and watch the output: .. code-block:: python from pysmi import debug debug.setLogger(debug.Debug('all')) pysmi-0.3.4/docs/source/license.rst0000664006321400632140000000006113200041462020712 0ustar ietingofietingof00000000000000 License ======= .. include:: ../../LICENSE.rst pysmi-0.3.4/docs/source/mibcopy.rst0000664006321400632140000001102013411726453020745 0ustar ietingofietingof00000000000000 The *mibcopy* tool ================== .. toctree:: :maxdepth: 2 The *mibcopy.py* tool attempts to normalize the file name of the MIB file. It turned out that sometimes vendors name their MIBs in any possible way, not necessarily after the canonical MIB name. This causes problems to the MIB consumers as they may not be able to locate the MIB they need on the file system. The way how *mibcopy.py* works is that it tries to read the MIB from the given file (or all files from a given directory or archive), parse MIB's canonical name from the contents of the file. Based on that, the tool tries to rename MIB file into the name which is the same as canonical MIB name. If *mibcopy.py* encounters the same named file already present on the file system, it reads it up to see its revision date. Then the tool compares the revision dates of the colliding MIB files and either overrides the offending file or drops the file being copied as outdated. The ultimate goal is to end up with the latest versions of the MIB files all named after their canonical names. .. code-block:: bash $ mibcopy.py --help Synopsis: SNMP SMI/MIB files copying tool. When given MIB file(s) or directory(ies) on input and a destination directory, the tool parses MIBs to figure out their canonical MIB module name and the latest revision date, then copies MIB module on input into the destination directory under its MIB module name *if* there is no such file already or its revision date is older. Documentation: http://snmplabs.com/pysmi Usage: mibcopy.py [--help] [--version] [--verbose] [--quiet] [--debug=] [--mib-source=] [--cache-directory=] [--ignore-errors] [--dry-run] Where: URI - file, zip, http, https, ftp, sftp schemes are supported. Use @mib@ placeholder token in URI to refer directly to the required MIB module when source does not support directory listing (e.g. HTTP). Specifying MIB source --------------------- The --mib-source option can be given multiple times. Each instance of --mib-source must specify a URL where ASN.1 MIB modules should be looked up and downloaded from. At this moment three MIB sourcing methods are supported: * Local files. This could be a top-level directory where MIB files are located. Subdirectories will be automatically traversed as well. Example: file:///usr/share/snmp * ZIP archives containing MIB files. Subdirectories and embedded ZIP archives will be automatically traversed. Example: zip://mymibs.zip * HTTP/HTTPS. A fully specified URL where MIB module name is specified by a @mib@ placeholder. When specific MIB is looked up, PySMI will replace that placeholder with MIB module name it is looking for. Example: `http://mibs.snmplabs.com/asn1/@mib@ `_ * SFTP/FTP. A fully specified URL including FTP username and password. MIB module name is specified by a @mib@ placeholder. When specific MIB is looked up, PySMI will replace that placeholder with MIB module name it is looking for. Example: `http://mibs.snmplabs.com/asn1/@mib@ `_ When trying to fetch a MIB module, the *mibcopy.py* tool will try each of configured --mib-source transports in order of specification till first successful hit. By default *mibcopy.py* will search: * file:///usr/share/snmp * http://mibs.snmplabs.com/asn1/@mib@ Once another --mib-source option is given, those defaults will not be used and should be manually given to *mibcopy.py* if needed. Setting destination directory ----------------------------- The *mibcopy.py* writes MIBs into the ** directory. Ignoring transformation errors ------------------------------ By default PySMI will stop on first fatal error occurred during transformations of a series of MIBs. If you wish PySMI to ignore fatal errors and therefore skipping failed MIB, use the --ignore-errors option. Keep in mind that skipping transformation of MIBs that are imported by other MIBs might make dependant MIBs inconsistent for use. Minor speedups -------------- The --cache-directory option may be used to point to a temporary writable directory where PySMI parser (e.g. Ply) would store its lookup tables. That should improve PySMI performance a tad bit. pysmi-0.3.4/docs/source/mibdump.rst0000664006321400632140000003064313411726453020754 0ustar ietingofietingof00000000000000 The *mibdump* tool ================== .. toctree:: :maxdepth: 2 The *mibdump.py* tool is a command-line frontend to the PySMI library. This tool can be used for automatic downloading and transforming SNMP MIB modules into various formats. .. code-block:: bash $ mibdump.py --help Synopsis: SNMP SMI/MIB files conversion tool Documentation: http://snmplabs.com/pysmi Usage: mibdump.py [--help] [--version] [--quiet] [--debug=] [--mib-source=] [--mib-searcher=] [--mib-stub=] [--mib-borrower=] [--destination-format=] [--destination-directory=] [--cache-directory=] [--disable-fuzzy-source] [--no-dependencies] [--no-python-compile] [--python-optimization-level] [--ignore-errors] [--build-index] [--rebuild] [--dry-run] [--no-mib-writes] [--generate-mib-texts] [--keep-texts-layout] [MIB-NAME [...]]] Where: URI - file, zip, http, https, ftp, sftp schemes are supported. Use @mib@ placeholder token in URI to refer directly to the required MIB module when source does not support directory listing (e.g. HTTP). FORMAT - pysnmp, json, null When JSON destination format is requested, for each MIB module *mibdump.py* will produce a JSON document containing all MIB objects. For example, `IF-MIB `_ module in JSON form would look like: .. code-block:: python { "ifMIB": { "name": "ifMIB", "oid": "1.3.6.1.2.1.31", "class": "moduleidentity", "revisions": [ "2007-02-15 00:00", "1996-02-28 21:55", "1993-11-08 21:55" ] }, ... "ifTestTable": { "name": "ifTestTable", "oid": "1.3.6.1.2.1.31.1.3", "class": "objecttype", "maxaccess": "not-accessible" }, "ifTestEntry": { "name": "ifTestEntry", "oid": "1.3.6.1.2.1.31.1.3.1", "class": "objecttype", "maxaccess": "not-accessible", "augmention": { "name": "ifTestEntry", "module": "IF-MIB", "object": "ifEntry" } }, "ifTestId": { "name": "ifTestId", "oid": "1.3.6.1.2.1.31.1.3.1.1", "class": "objecttype", "syntax": { "type": "TestAndIncr", "class": "type" }, "maxaccess": "read-write" }, ... } In general, JSON MIB captures all aspects of original (ASN.1) MIB contents and layout. The snippet above is just an example, here is the complete `IF-MIB.json `_ file. Specifying MIB source --------------------- The --mib-source option can be given multiple times. Each instance of --mib-source must specify a URL where ASN.1 MIB modules should be looked up and downloaded from. At this moment three MIB sourcing methods are supported: * Local files. This could be a top-level directory where MIB files are located. Subdirectories will be automatically traversed as well. Example: file:///usr/share/snmp * ZIP archives containing MIB files. Subdirectories and embedded ZIP archives will be automatically traversed. Example: zip://mymibs.zip * HTTP/HTTPS. A fully specified URL where MIB module name is specified by a @mib@ placeholder. When specific MIB is looked up, PySMI will replace that placeholder with MIB module name it is looking for. Example: `http://mibs.snmplabs.com/asn1/@mib@ `_ * SFTP/FTP. A fully specified URL including FTP username and password. MIB module name is specified by a @mib@ placeholder. When specific MIB is looked up, PySMI will replace that placeholder with MIB module name it is looking for. Example: `http://mibs.snmplabs.com/asn1/@mib@ `_ When trying to fetch a MIB module, the *mibdump.py* tool will try each of configured --mib-source transports in order of specification till first successful hit. By default *mibdump.py* will search: * file:///usr/share/snmp * http://mibs.snmplabs.com/asn1/@mib@ Once another --mib-source option is given, those defaults will not be used and should be manually given to *mibdump.py* if needed. Fuzzying MIB module names ------------------------- There is no single convention on how MIB module files should be named. By default *mibdump.py* will try a handful of guesses when trying to find a file containing specific MIB module. It will try upper and lower cases, a file named after MIB module, try adding different extensions to a file (.mib, .my etc), try adding/cutting the '-MIB' part of the file name. If nothing matches, *mibdump.py* will consider that probed --mib-source does not contain MIB module it is looking for. There is a small chance, though, that fuzzy natching may result in getting a wrong MIB. If that happens, you can disable the above fuzzyness by giving *mibdump.py* the --disable-fuzzy-source flag. Avoiding excessive transformation --------------------------------- It well may happen that many MIB modules refer to a common single MIB module. In that case *mibdump.py* may transform it many times unless you tell *mibdump.py* where to search for already transformed MIBs. That place could of course be a directory where *mibdump.py* writes its transforms into and/or some other local locations. The --mib-searcher option specifies either local directory or importable Python package (applicable to pysnmp transformation) containing transformed MIB modules. Multiple --mib-searcher options could be given, *mibdump.py* will use each of them in order of specification till first hit. If no transformed MIB module is found, *mibdump.py* will go on running its full transformation cycle. By default *mibdump.py* will use: * --mib-searcher=$HOME/.pysnmp/mibs * --mib-searcher=pysnmp_mibs Once another --mib-searcher option is given, those defaults will not be used and should be manually given to *mibdump.py* if needed. Blacklisting MIBs ----------------- Some MIBs may not be automatically transformed into another form and therefore must be explicitly excluded from processing. Such MIBs are normally manually implemented for each target MIB format. Examples include MIBs containing base SMI types or ASN.1 MACRO definitions (SNMPv2-SMI, SNMPV2-TC), initially compiled but later manually modified MIBs and others. Default list of blacklisted MIBs for pysnmp transformation target is: RFC-1212, RFC-1215, RFC1065-SMI, RFC1155-SMI, RFC1158-MIB, RFC1213-MIB, SNMP-FRAMEWORK-MIB, SNMP-TARGET-MIB, SNMPv2-CONF, SNMPv2-SMI, SNMPv2-TC, SNMPv2-TM, TRANSPORT-ADDRESS-MIB. If you need to modify this list use the --mib-stub option. Dealing with broken MIBs ------------------------ Curiously enough, some MIBs coming from quite prominent vendors appear syntactically incorrect. That leads to MIB compilers fail on such MIBs. While many MIB compiler implementations (PySMI included) introduce workarounds and grammar relaxations allowing slightly broken MIBs to compile, however severely broken MIBs can't be reliably compiled. As another workaround PySMI offers the *borrow* feature. It allows PySMI to fetch already transformed MIBs even if corresponding ASN.1 MIB can't be found or parsed. Default source of pre-compiled MIBs for pysnmp target is: * http://mibs.snmplabs.com/pysnmp/fulltexts/@mib@ * http://mibs.snmplabs.com/pysnmp/notexts/@mib@ If you wish to modify this default list use one or more --mib-borrower options. Choosing target transformation ------------------------------ PySMI design allows many transformation formats to be supported in form of specialized code generation components. At the moment PySMI can produce MIBs in form of pysnmp classes and JSON documents. JSON document schema is chosen to preserve as much of MIB information as possible. There's no established JSON schema known to the authors. Setting destination directory ----------------------------- By default *mibdump.py* writes pysnmp MIBs into: * $HOME/.pysnmp/mibs (on UNIX) * @HOME@\PySNMP Configuration\MIBs\ (on Windows) and JSON files in current working directory. Use --destination-directory option to change default output directory. Performing unconditional transformation --------------------------------------- By default PySMI will avoid creating new transformations if fresh enough versions already exist. By using --rebuild option you could trick PySMI doing requested transformation for all given MIB modules. Ignoring transformation errors ------------------------------ By default PySMI will stop on first fatal error occurred during transformations of a series of MIBs. If you wish PySMI to ignore fatal errors and therefore skipping failed MIB, use the --ignore-errors option. Keep in mind that skipping transformation of MIBs that are imported by other MIBs might make dependant MIBs inconsistent for use. Skipping dependencies --------------------- Most MIBs rely on other MIBs for their operations. This is indicated by the IMPORT statement in ASN.1 language. PySMI attempts to transform all MIBs IMPORT'ed by MIB being transformed. That is done in recursive manner. By using --no-dependencies flag you can tell PySMI not to transform any MIBs other than those explicitly requested to be transformed. Keep in mind that skipping dependencies may make the whole set of transformed MIBs inconsistent. Generating MIB texts -------------------- Most MIBs are very verbose. They contain many human-oriented descriptions and clarifications written in plain English. Those texts may be useful for MIB browser applications (to display those texts to human operator) but might not make any sense in other applications. To save space and CPU time, PySMI does not by default include those texts into transformed MIBs. However this can be reverted by adding --generate-mib-texts option. When MIB texts are generated, whitespaces and new lines are stripped by default. Sometimes that breaks down ASCII art should it occur in MIB texts. To preserve original text formatting, --keep-texts-layout option may be used. Building MIB indices -------------------- If --build-index option is given, depending on the destination format chosen, the *mibdump.py* tool may create new (or update existing) document containing MIB information in a form that is convenient for querying cornerstone properties of MIB files. For example, building JSON index for `IP-MIB.json `_, `TCP-MIB.json `_ and `UDP-MIB.json `_ MIB modules would emit something like this: .. code-block:: json { "compliance": { "1.3.6.1.2.1.48.2.1.1": [ "IP-MIB" ], "1.3.6.1.2.1.49.2.1.1": [ "TCP-MIB" ], "1.3.6.1.2.1.50.2.1.1": [ "UDP-MIB" ] }, "identity": { "1.3.6.1.2.1.48": [ "IP-MIB" ], "1.3.6.1.2.1.49": [ "TCP-MIB" ], "1.3.6.1.2.1.50": [ "UDP-MIB" ] }, "oids": { "1.3.6.1.2.1.4": [ "IP-MIB" ], "1.3.6.1.2.1.5": [ "IP-MIB" ], "1.3.6.1.2.1.6": [ "TCP-MIB" ], "1.3.6.1.2.1.7": [ "UDP-MIB" ], "1.3.6.1.2.1.49": [ "TCP-MIB" ], "1.3.6.1.2.1.50": [ "UDP-MIB" ] } } With this example, *compliance* and *identity* keys point to *MODULE-COMPLIANCE* and *MODULE-IDENTITY* MIB objects, *oids* list top-level OIDs branches defined in MIB modules. Full index build over thousands of MIBs could be seen `here `_. Minor speedups -------------- There are a few options that may improve PySMI performance. The --cache-directory option may be used to point to a temporary writable directory where PySMI parser (e.g. Ply) would store its lookup tables. By default PySMI performing transformation into pysnmp format will also pre-compile Python source into interpreter bytecode. That takes some time and space. If you wish not to cache Python bytecode or to do that later, use the --no-python-compile option. pysmi-0.3.4/docs/source/pysmi/0000775006321400632140000000000013454602625017721 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/borrower/0000775006321400632140000000000013454602625021562 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/borrower/anyfile/0000775006321400632140000000000013454602625023211 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/borrower/anyfile/anyfileborrower.rst0000664006321400632140000000022013202162514027133 0ustar ietingofietingof00000000000000 .. _borrower.anyfile.AnyFileBorrower: Any file borrower ----------------- .. autoclass:: pysmi.borrower.anyfile.AnyFileBorrower :members: pysmi-0.3.4/docs/source/pysmi/borrower/pyfile/0000775006321400632140000000000013454602625023052 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/borrower/pyfile/pyfileborrower.rst0000664006321400632140000000022213202162514026637 0ustar ietingofietingof00000000000000 .. _borrower.pyfile.PyFileBorrower: Python file borrower -------------------- .. autoclass:: pysmi.borrower.pyfile.PyFileBorrower :members: pysmi-0.3.4/docs/source/pysmi/codegen/0000775006321400632140000000000013454602625021325 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/codegen/jsondoc/0000775006321400632140000000000013454602625022764 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/codegen/jsondoc/jsoncodegen.rst0000664006321400632140000000022213202162514025775 0ustar ietingofietingof00000000000000 .. _codegen.jsondoc.JsonCodeGen: JSON document generator ----------------------- .. autoclass:: pysmi.codegen.jsondoc.JsonCodeGen :members: pysmi-0.3.4/docs/source/pysmi/codegen/null/0000775006321400632140000000000013454602625022277 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/codegen/null/nullcodegen.rst0000664006321400632140000000020613202162514025313 0ustar ietingofietingof00000000000000 .. _codegen.null.NullCodeGen: Code generation stub -------------------- .. autoclass:: pysmi.codegen.null.NullCodeGen :members: pysmi-0.3.4/docs/source/pysmi/codegen/pysnmp/0000775006321400632140000000000013454602625022653 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/codegen/pysnmp/pysnmpcodegen.rst0000664006321400632140000000021613202162514026244 0ustar ietingofietingof00000000000000 .. _codegen.pysnmp.PySnmpCodeGen: PySNMP MIB generator -------------------- .. autoclass:: pysmi.codegen.pysnmp.PySnmpCodeGen :members: pysmi-0.3.4/docs/source/pysmi/compiler/0000775006321400632140000000000013454602625021533 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/compiler/mibcompiler.rst0000664006321400632140000000015513202162514024555 0ustar ietingofietingof00000000000000 .. _compiler.MibCompiler: MIB compiler ------------ .. autoclass:: pysmi.compiler.MibCompiler :members: pysmi-0.3.4/docs/source/pysmi/compiler/mibstatus.rst0000664006321400632140000000037113202162514024266 0ustar ietingofietingof00000000000000 .. _reader.compiler.MibStatus: Compilation status ------------------ *MibStatus* class instance is used by :func:`MibCompiler.compiler` to indicate the outcome of MIB transformation operation. .. autoclass:: pysmi.compiler.MibStatus :members: pysmi-0.3.4/docs/source/pysmi/parser/0000775006321400632140000000000013454602625021215 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/parser/smi/0000775006321400632140000000000013454602625022005 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/parser/smi/dialect.rst0000664006321400632140000000207313202162514024133 0ustar ietingofietingof00000000000000 .. _parser.smi.dialect: SMI language dialects --------------------- PySMI offers a pre-built collection of parser grammar relaxation options to simplify its use: * *pysmi.parser.dialect.smiV2* - canonical SMIv2 grammar * *pysmi.parser.dialect.smiV1* - canonical SMIv1 grammar * *pysmi.parser.dialect.smiV1Relaxed* - relaxed SMIv1 grammar allowing some deviations The grammar object should be passed to the :ref:`parserFactory ` function. .. code-block:: python from pysmi.parser.dialect import smiV1 from pysmi.parser.smi import parserFactory SmiV1Parser = parserFactory(**smiV1) Apparently, many production MIBs were shipped in syntactically broken condition. PySMI attempts to work around such issues by allowing some extra SMI grammar relaxations. You can enable all those relaxations at once to maximize the number of MIBs, found in the wild, successfully compiled. .. code-block:: python from pysmi.parser.dialect import smiV1Relaxed from pysmi.parser.smi import parserFactory RelaxedSmiV1Parser = parserFactory(**smiV1Relaxed) pysmi-0.3.4/docs/source/pysmi/parser/smi/parserfactory.rst0000664006321400632140000000174013202162514025412 0ustar ietingofietingof00000000000000 .. _parser.smi.parserFactory: SMI parser ---------- SNMP MIBs are written in two kinds of special language - SMIv1 and SMIv2. The first SMI version is obsolete, most MIBs by now are written in SMIv2 grammar. There are also efforts aimed at improving SMIv2, but those MIBs are in great minority at the time of this writing. PySMI is designed to handle both SMIv1 and SMIv2. The way it is done is that SMIv2 is considered the most basic and complete, whereas SMIv1 is a specialization of SMIv2 syntax. For a user to acquire SMIv2 parser the *parserFactory* function should be called with the :ref:`SMI dialect object `. The parser object should be passed to the :ref:`MibCompiler ` object. .. autofunction:: pysmi.parser.smi.parserFactory .. note:: Please, note that *parserFactory* function returns a class, not class instance. Make sure to instantiate it when passing to :ref:`MibCompiler ` class constructor. pysmi-0.3.4/docs/source/pysmi/reader/0000775006321400632140000000000013454602625021163 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/reader/callback/0000775006321400632140000000000013454602625022717 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/reader/callback/callbackreader.rst0000664006321400632140000000033113202162514026352 0ustar ietingofietingof00000000000000 .. _reader.callback.CallbackReader: Callback reader --------------- *CallbackReader* class instance tries to fetch MIB files by calling user object. .. autoclass:: pysmi.reader.callback.CallbackReader :members: pysmi-0.3.4/docs/source/pysmi/reader/ftpclient/0000775006321400632140000000000013454602625023153 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/reader/ftpclient/ftpreader.rst0000664006321400632140000000031113202162514025641 0ustar ietingofietingof00000000000000 .. _reader.ftpclient.FtpReader: FTP reader ---------- *FtpReader* class instance tries to download MIB files from configured FTP server. .. autoclass:: pysmi.reader.ftpclient.FtpReader :members: pysmi-0.3.4/docs/source/pysmi/reader/httpclient/0000775006321400632140000000000013454602625023341 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/reader/httpclient/httpreader.rst0000664006321400632140000000031213202162514026216 0ustar ietingofietingof00000000000000 .. _reader.httpclient.HttpReader: HTTP reader ----------- *HttpReader* class instance tries to download MIB files using configured URL. .. autoclass:: pysmi.reader.httpclient.HttpReader :members: pysmi-0.3.4/docs/source/pysmi/reader/localfile/0000775006321400632140000000000013454602625023115 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/reader/localfile/filereader.rst0000664006321400632140000000034513202162514025740 0ustar ietingofietingof00000000000000 .. _reader.localfile.FileReader: Local file reader ----------------- *FileReader* class instance looks up MIB files in given directories on the host running PySMI. .. autoclass:: pysmi.reader.localfile.FileReader :members: pysmi-0.3.4/docs/source/pysmi/reader/zipreader/0000775006321400632140000000000013454602625023150 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/reader/zipreader/zipreader.rst0000664006321400632140000000041313202162514025652 0ustar ietingofietingof00000000000000 .. _reader.zipreader.ZipReader: ZIP archive reader ------------------ *ZipReader* class instance looks up MIB files in local ZIP archive. ZIP subdirectories and embedded ZIP archives would be traversed. .. autoclass:: pysmi.reader.zipreader.ZipReader :members: pysmi-0.3.4/docs/source/pysmi/searcher/0000775006321400632140000000000013454602625021515 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/searcher/pyfile/0000775006321400632140000000000013454602625023005 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/searcher/pyfile/pyfilesearcher.rst0000664006321400632140000000040413202162514026527 0ustar ietingofietingof00000000000000 .. _searcher.pyfile.PyFileSearcher: Python files searcher --------------------- Transformed MIBs that were saved in form of Python files can be checked with *PyFileSearcher* class instances. .. autoclass:: pysmi.searcher.pyfile.PyFileSearcher :members: pysmi-0.3.4/docs/source/pysmi/searcher/pypackage/0000775006321400632140000000000013454602625023461 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/searcher/pypackage/pypackagesearcher.rst0000664006321400632140000000047513202162514027667 0ustar ietingofietingof00000000000000 .. _searcher.pypackage.PyPackageSearcher: Search Python packages ---------------------- Some MIBs, most frequently the base ones, can be stored at a Python package. There existence can be checked with the *PyPackageSearcher* class instances. .. autoclass:: pysmi.searcher.pypackage.PyPackageSearcher :members: pysmi-0.3.4/docs/source/pysmi/searcher/stub/0000775006321400632140000000000013454602625022472 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/searcher/stub/stubsearcher.rst0000664006321400632140000000072413202162514025706 0ustar ietingofietingof00000000000000 .. _searcher.stub.StubSearcher: Unconditionally ignore MIBs --------------------------- Foundation or obsolete MIBs that should never be transformed can be blindly excluded by listing their names at the *StubSearcher* class instance. .. autoclass:: pysmi.searcher.stub.StubSearcher :members: .. note:: A pysnmp-specific list of MIB names to be permanently excluded from transformation can be found at :py:const:`pysmi.codegen.pysnmp.baseMibs`. pysmi-0.3.4/docs/source/pysmi/writer/0000775006321400632140000000000013454602625021235 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/writer/callback/0000775006321400632140000000000013454602625022771 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/writer/callback/callbackwriter.rst0000664006321400632140000000035013202162514026477 0ustar ietingofietingof00000000000000 .. _writer.callback.CallbackReader: Callback writer --------------- *CallbackWriter* class instance passes the contents of the compiled MIB files to a user object. .. autoclass:: pysmi.writer.callback.CallbackWriter :members: pysmi-0.3.4/docs/source/pysmi/writer/localfile/0000775006321400632140000000000013454602625023167 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/writer/localfile/filewriter.rst0000664006321400632140000000017113202162514026061 0ustar ietingofietingof00000000000000 .. _writer.localfile.FileWriter: File writer ----------- .. autoclass:: pysmi.writer.localfile.FileWriter :members: pysmi-0.3.4/docs/source/pysmi/writer/pyfile/0000775006321400632140000000000013454602625022525 5ustar ietingofietingof00000000000000pysmi-0.3.4/docs/source/pysmi/writer/pyfile/pyfilewriter.rst0000664006321400632140000000020513202162514025766 0ustar ietingofietingof00000000000000 .. _writer.pyfile.PyFileWriter: Python file writer ------------------ .. autoclass:: pysmi.writer.pyfile.PyFileWriter :members: pysmi-0.3.4/examples/0000775006321400632140000000000013454602625016146 5ustar ietingofietingof00000000000000pysmi-0.3.4/examples/always-borrow-precompiled-pysnmp-files.py0000664006321400632140000000223113202162514026240 0ustar ietingofietingof00000000000000""" Always borrow pysnmp MIBs +++++++++++++++++++++++++ Try to borrow precompiled pysnmp MIB file(s) from a web-site. In this example no attempt is made to find and compile ASN.1 MIB source. Fetched pysnmp MIB(s) are stored in a local directory. """# from pysmi.reader import HttpReader from pysmi.searcher import PyFileSearcher from pysmi.borrower import PyFileBorrower from pysmi.writer import PyFileWriter from pysmi.parser import NullParser from pysmi.codegen import NullCodeGen from pysmi.compiler import MibCompiler inputMibs = ['BORROWED-MIB'] httpBorrowers = [ ('mibs.snmplabs.com', 80, '/pysnmp/notexts/@mib@') ] dstDirectory = '.pysnmp-mibs' # Initialize compiler infrastructure mibCompiler = MibCompiler( NullParser(), NullCodeGen(), PyFileWriter(dstDirectory) ) # check compiled/borrowed MIBs in our own productions mibCompiler.addSearchers(PyFileSearcher(dstDirectory)) # search for precompiled MIBs at Web sites mibCompiler.addBorrowers( *[PyFileBorrower(HttpReader(*x)) for x in httpBorrowers] ) # run MIB compilation results = mibCompiler.compile(*inputMibs) print('Results: %s' % ', '.join(['%s:%s' % (x, results[x]) for x in results])) pysmi-0.3.4/examples/borrow-precompiled-pysnmp-files-on-failure.py0000664006321400632140000000324113202162514027003 0ustar ietingofietingof00000000000000""" Borrow pysnmp MIBs on failure +++++++++++++++++++++++++++++ Look up specific ASN.1 MIBs at configured Web/FTP sites. If no required MIB is found or its compilation fails for some reason, attempt to download precompiled version of failed MIB and store it locally as if we had compiled it. """# from pysmi.reader import HttpReader from pysmi.searcher import PyFileSearcher from pysmi.searcher import StubSearcher from pysmi.borrower import PyFileBorrower from pysmi.writer import PyFileWriter from pysmi.parser import SmiStarParser from pysmi.codegen import PySnmpCodeGen from pysmi.compiler import MibCompiler # from pysmi import debug # debug.setLogger(debug.Debug('borrower', 'reader', 'searcher')) inputMibs = ['BORROWED-MIB'] httpSources = [ ('mibs.snmplabs.com', 80, '/asn1/@mib@') ] httpBorrowers = [ ('mibs.snmplabs.com', 80, '/pysnmp/notexts/@mib@') ] dstDirectory = '.pysnmp-mibs' # Initialize compiler infrastructure mibCompiler = MibCompiler( SmiStarParser(), PySnmpCodeGen(), PyFileWriter(dstDirectory) ) # search for source MIBs at Web sites mibCompiler.addSources(*[HttpReader(*x) for x in httpSources]) # never recompile MIBs with MACROs mibCompiler.addSearchers(StubSearcher(*PySnmpCodeGen.baseMibs)) # check compiled/borrowed MIBs in our own productions mibCompiler.addSearchers(PyFileSearcher(dstDirectory)) # search for compiled MIBs at Web sites if source is not available or broken mibCompiler.addBorrowers(*[PyFileBorrower(HttpReader(*x)).setOptions(genTexts=False) for x in httpBorrowers]) # run non-recursive MIB compilation results = mibCompiler.compile(*inputMibs) print('Results: %s' % ', '.join(['%s:%s' % (x, results[x]) for x in results])) pysmi-0.3.4/examples/compile-smistar-mibs-into-pysnmp-files-if-needed.py0000664006321400632140000000357513202162514027770 0ustar ietingofietingof00000000000000""" Compile SMIv1/v2 MIBs +++++++++++++++++++++ Look up specific ASN.1 MIBs at configured local directories, compile them into pysnmp form if not done yet and save Python modules as plain-text files in a local directory. Try to support both SMIv1 and SMIv2 flavors of SMI as well as popular deviations from official syntax found in the wild. When figuring out if compilation is needed, check all known places where pysnmp MIBs could possibly be found. You can force MIB re-compilation by passing rebuild flag to MIB compiler (see below). Default invocation of MIB compiler does not generate [potentially large] comments and texts found in MIBs. If you need them in pysnmp MIB modules, just pass genTexts flag to MIB compiler. """# from pysmi.reader import FileReader from pysmi.searcher import PyFileSearcher, PyPackageSearcher, StubSearcher from pysmi.writer import PyFileWriter from pysmi.parser import SmiStarParser from pysmi.codegen import PySnmpCodeGen from pysmi.compiler import MibCompiler inputMibs = ['IF-MIB', 'IP-MIB'] srcDirectories = ['/usr/share/snmp/mibs'] dstDirectory = '.pysnmp-mibs' # Initialize compiler infrastructure mibCompiler = MibCompiler(SmiStarParser(), PySnmpCodeGen(), PyFileWriter(dstDirectory)) # search for source MIBs here mibCompiler.addSources(*[FileReader(x) for x in srcDirectories]) # check compiled MIBs in our own productions mibCompiler.addSearchers(PyFileSearcher(dstDirectory)) # ...and at default PySNMP MIBs packages mibCompiler.addSearchers(*[PyPackageSearcher(x) for x in PySnmpCodeGen.defaultMibPackages]) # never recompile MIBs with MACROs mibCompiler.addSearchers(StubSearcher(*PySnmpCodeGen.baseMibs)) # run [possibly recursive] MIB compilation results = mibCompiler.compile(*inputMibs) #, rebuild=True, genTexts=True) print('Results: %s' % ', '.join(['%s:%s' % (x, results[x]) for x in results])) pysmi-0.3.4/examples/compile-smiv2-mibs-from-text-into-pysnmp-code.py0000664006321400632140000000250613202162514027254 0ustar ietingofietingof00000000000000""" Compile SMIv2 MIBs ++++++++++++++++++ Invoke user callback function to provide MIB text, compile given text string into pysnmp MIB form and pass results to another user callback function for storing. Here we expect to deal only with SMIv2-valid MIBs. We use noDeps flag to prevent MIB compiler from attemping to compile IMPORT'ed MIBs as well. """# import sys from pysmi.reader import CallbackReader from pysmi.searcher import StubSearcher from pysmi.writer import CallbackWriter from pysmi.parser import SmiV2Parser from pysmi.codegen import PySnmpCodeGen from pysmi.compiler import MibCompiler inputMibs = ['IF-MIB', 'IP-MIB'] srcDir = '/usr/share/snmp/mibs/' # we will read MIBs from here # Initialize compiler infrastructure mibCompiler = MibCompiler( SmiV2Parser(), PySnmpCodeGen(), # out own callback function stores results in its own way CallbackWriter(lambda m, d, c: sys.stdout.write(d)) ) # our own callback function serves as a MIB source here mibCompiler.addSources( CallbackReader(lambda m, c: open(srcDir+m+'.txt').read()) ) # never recompile MIBs with MACROs mibCompiler.addSearchers(StubSearcher(*PySnmpCodeGen.baseMibs)) # run non-recursive MIB compilation results = mibCompiler.compile(*inputMibs, **dict(noDeps=True)) print('Results: %s' % ', '.join(['%s:%s' % (x, results[x]) for x in results])) pysmi-0.3.4/examples/download-and-compile-smistar-mibs-into-json.py0000664006321400632140000000265413202162514027037 0ustar ietingofietingof00000000000000""" Compile MIBs into JSON ++++++++++++++++++++++ Look up specific ASN.1 MIBs at configured Web and FTP sites, compile them into JSON documents and print them out to stdout. Try to support both SMIv1 and SMIv2 flavors of SMI as well as popular deviations from official syntax found in the wild. """# from pysmi.reader import FileReader, 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 # from pysmi import debug # debug.setLogger(debug.Debug('reader', 'compiler')) inputMibs = ['IF-MIB', 'IP-MIB'] srcDirectories = ['/usr/share/snmp/mibs'] httpSources = [ ('mibs.snmplabs.com', 80, '/asn1/@mib@') ] def printOut(mibName, jsonDoc, cbCtx): print('\n\n# MIB module %s' % mibName) print(jsonDoc) # Initialize compiler infrastructure mibCompiler = MibCompiler( SmiStarParser(), JsonCodeGen(), CallbackWriter(printOut) ) # search for source MIBs here mibCompiler.addSources(*[FileReader(x) for x in srcDirectories]) # search for source MIBs at Web sites mibCompiler.addSources(*[HttpReader(*x) for x in httpSources]) # never recompile MIBs with MACROs mibCompiler.addSearchers(StubSearcher(*JsonCodeGen.baseMibs)) # run recursive MIB compilation results = mibCompiler.compile(*inputMibs) print('\n# Results: %s' % ', '.join(['%s:%s' % (x, results[x]) for x in results])) pysmi-0.3.4/examples/download-and-compile-smistar-mibs-into-pysnmp-files.py0000664006321400632140000000304213202162514030504 0ustar ietingofietingof00000000000000""" Compile MIBs from web +++++++++++++++++++++ Look up specific ASN.1 MIBs at configured Web and FTP sites, compile them into pysnmp form and save Python modules as plain-text files in a local directory. Try to support both SMIv1 and SMIv2 flavors of SMI as well as popular deviations from official syntax found in the wild. In this example we disable automatic dependency checking on MIB compilation using noDeps flag. Also, we do not check if target file already exists thus MIB compilation occurs on every invocation. """# from pysmi.reader import HttpReader from pysmi.reader import FtpReader from pysmi.searcher import StubSearcher from pysmi.writer import PyFileWriter from pysmi.parser import SmiStarParser from pysmi.codegen import PySnmpCodeGen from pysmi.compiler import MibCompiler inputMibs = ['IF-MIB', 'IP-MIB'] httpSources = [ ('mibs.snmplabs.com', 80, '/asn1/@mib@') ] ftpSources = [ ('ftp.cisco.com', '/pub/mibs/v2/@mib@') ] dstDirectory = '.pysnmp-mibs' # Initialize compiler infrastructure mibCompiler = MibCompiler( SmiStarParser(), PySnmpCodeGen(), PyFileWriter(dstDirectory) ) # search for source MIBs at Web and FTP sites mibCompiler.addSources(*[HttpReader(*x) for x in httpSources]) mibCompiler.addSources(*[FtpReader(*x) for x in ftpSources]) # never recompile MIBs with MACROs mibCompiler.addSearchers(StubSearcher(*PySnmpCodeGen.baseMibs)) # run non-recursive MIB compilation results = mibCompiler.compile(*inputMibs, **dict(noDeps=True)) print('Results: %s' % ', '.join(['%s:%s' % (x, results[x]) for x in results])) pysmi-0.3.4/pysmi/0000775006321400632140000000000013454602625015471 5ustar ietingofietingof00000000000000pysmi-0.3.4/pysmi/__init__.py0000664006321400632140000000025513454602510017575 0ustar ietingofietingof00000000000000# http://www.python.org/dev/peps/pep-0396/ __version__ = '0.3.4' import sys if sys.version_info[:2] < (2, 4): raise RuntimeError('PySMI requires Python 2.4 or later') pysmi-0.3.4/pysmi/borrower/0000775006321400632140000000000013454602625017332 5ustar ietingofietingof00000000000000pysmi-0.3.4/pysmi/borrower/__init__.py0000664006321400632140000000037713411726453021451 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.borrower.pyfile import PyFileBorrower from pysmi.borrower.anyfile import AnyFileBorrower pysmi-0.3.4/pysmi/borrower/anyfile.py0000664006321400632140000000045413411726453021335 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.borrower.base import AbstractBorrower class AnyFileBorrower(AbstractBorrower): """Create arbitrary MIB file borrowing object""" pysmi-0.3.4/pysmi/borrower/base.py0000664006321400632140000000331313454602500020606 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi import error from pysmi import debug class AbstractBorrower(object): genTexts = False exts = '' def __init__(self, reader, genTexts=False): """Creates an instance of *Borrower* class. Args: reader: a *reader* object Keyword Args: genText: indicates whether this borrower should be looking for transformed MIBs that include human-oriented texts """ if genTexts is not None: self.genTexts = genTexts self._reader = reader def __str__(self): return '%s{%s, genTexts=%s, exts=%s}' % (self.__class__.__name__, self._reader, self.genTexts, self.exts) def setOptions(self, **kwargs): self._reader.setOptions(**kwargs) for k in kwargs: setattr(self, k, kwargs[k]) return self def getData(self, mibname, **options): if bool(options.get('genTexts')) != self.genTexts: debug.logger & debug.flagBorrower and debug.logger( 'skipping incompatible borrower %s for file %s' % (self, mibname)) raise error.PySmiFileNotFoundError(mibname=mibname, reader=self._reader) debug.logger & debug.flagBorrower and ( debug.logger('trying to borrow file %s from %s' % (mibname, self._reader)) ) if 'exts' not in options: options['exts'] = self.exts return self._reader.getData(mibname, **options) pysmi-0.3.4/pysmi/borrower/pyfile.py0000664006321400632140000000114713454602500021167 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # try: import importlib try: SOURCE_SUFFIXES = importlib.machinery.SOURCE_SUFFIXES except Exception: raise ImportError() except ImportError: import imp SOURCE_SUFFIXES = [s[0] for s in imp.get_suffixes() if s[2] == imp.PY_SOURCE] from pysmi.borrower.base import AbstractBorrower class PyFileBorrower(AbstractBorrower): """Create PySNMP MIB file borrowing object""" exts = SOURCE_SUFFIXES pysmi-0.3.4/pysmi/codegen/0000775006321400632140000000000013454602625017075 5ustar ietingofietingof00000000000000pysmi-0.3.4/pysmi/codegen/__init__.py0000664006321400632140000000044413411726453021207 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.jsondoc import JsonCodeGen from pysmi.codegen.null import NullCodeGen pysmi-0.3.4/pysmi/codegen/base.py0000664006321400632140000004320013411726453020357 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys from pysmi import error if sys.version_info[0] > 2: # noinspection PyShadowingBuiltins unicode = str # noinspection PyShadowingBuiltins long = int def dorepr(s): return repr(s) else: def dorepr(s): return repr(s.encode('utf-8')).decode('utf-8') def updateDict(d1, d2): d1.update(d2) return d1 class AbstractCodeGen(object): # 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 baseMibs = ('RFC1065-SMI', 'RFC1155-SMI', 'RFC1158-MIB', 'RFC-1212', 'RFC1213-MIB', 'RFC-1215', 'SNMPv2-SMI', 'SNMPv2-TC', 'SNMPv2-TM', 'SNMPv2-CONF') # Explicit SMIv1 -> SMIv2 mapping for standard MIBs commonSyms = {'RFC1155-SMI/RFC1065-SMI': {'internet': [('SNMPv2-SMI', 'internet')], 'directory': [('SNMPv2-SMI', 'directory')], 'mgmt': [('SNMPv2-SMI', 'mgmt')], 'experimental': [('SNMPv2-SMI', 'experimental')], 'private': [('SNMPv2-SMI', 'private')], 'enterprises': [('SNMPv2-SMI', 'enterprises')], 'OBJECT-TYPE': [('SNMPv2-SMI', 'OBJECT-TYPE')], 'ObjectName': [('SNMPv2-SMI', 'ObjectName')], 'ObjectSyntax': [('SNMPv2-SMI', 'ObjectSyntax')], 'SimpleSyntax': [('SNMPv2-SMI', 'SimpleSyntax')], 'ApplicationSyntax': [('SNMPv2-SMI', 'ApplicationSyntax')], 'NetworkAddress': [('SNMPv2-SMI', 'IpAddress')], 'IpAddress': [('SNMPv2-SMI', 'IpAddress')], 'Counter': [('SNMPv2-SMI', 'Counter32')], 'Gauge': [('SNMPv2-SMI', 'Gauge32')], 'TimeTicks': [('SNMPv2-SMI', 'TimeTicks')], 'Opaque': [('SNMPv2-SMI', 'Opaque')]}, 'RFC1158-MIB/RFC1213-MIB': {'mib-2': [('SNMPv2-SMI', 'mib-2')], 'DisplayString': [('SNMPv2-TC', 'DisplayString')], 'system': [('SNMPv2-MIB', 'system')], 'interfaces': [('IF-MIB', 'interfaces')], 'ip': [('IP-MIB', 'ip')], 'icmp': [('IP-MIB', 'icmp')], 'tcp': [('TCP-MIB', 'tcp')], 'udp': [('UDP-MIB', 'udp')], 'transmission': [('SNMPv2-SMI', 'transmission')], 'snmp': [('SNMPv2-MIB', 'snmp')], 'sysDescr': [('SNMPv2-MIB', 'sysDescr')], 'sysObjectID': [('SNMPv2-MIB', 'sysObjectID')], 'sysUpTime': [('SNMPv2-MIB', 'sysUpTime')], 'sysContact': [('SNMPv2-MIB', 'sysContact')], 'sysName': [('SNMPv2-MIB', 'sysName')], 'sysLocation': [('SNMPv2-MIB', 'sysLocation')], 'sysServices': [('SNMPv2-MIB', 'sysServices')], 'ifNumber': [('IF-MIB', 'ifNumber')], 'ifTable': [('IF-MIB', 'ifTable')], 'ifEntry': [('IF-MIB', 'ifEntry')], 'ifIndex': [('IF-MIB', 'ifIndex')], 'ifDescr': [('IF-MIB', 'ifDescr')], 'ifType': [('IF-MIB', 'ifType')], 'ifMtu': [('IF-MIB', 'ifMtu')], 'ifSpeed': [('IF-MIB', 'ifSpeed')], 'ifPhysAddress': [('IF-MIB', 'ifPhysAddress')], 'ifAdminStatus': [('IF-MIB', 'ifAdminStatus')], 'ifOperStatus': [('IF-MIB', 'ifOperStatus')], 'ifLastChange': [('IF-MIB', 'ifLastChange')], 'ifInOctets': [('IF-MIB', 'ifInOctets')], 'ifInUcastPkts': [('IF-MIB', 'ifInUcastPkts')], 'ifInNUcastPkts': [('IF-MIB', 'ifInNUcastPkts')], 'ifInDiscards': [('IF-MIB', 'ifInDiscards')], 'ifInErrors': [('IF-MIB', 'ifInErrors')], 'ifInUnknownProtos': [('IF-MIB', 'ifInUnknownProtos')], 'ifOutOctets': [('IF-MIB', 'ifOutOctets')], 'ifOutUcastPkts': [('IF-MIB', 'ifOutUcastPkts')], 'ifOutNUcastPkts': [('IF-MIB', 'ifOutNUcastPkts')], 'ifOutDiscards': [('IF-MIB', 'ifOutDiscards')], 'ifOutErrors': [('IF-MIB', 'ifOutErrors')], 'ifOutQLen': [('IF-MIB', 'ifOutQLen')], 'ifSpecific': [('IF-MIB', 'ifSpecific')], 'ipForwarding': [('IP-MIB', 'ipForwarding')], 'ipDefaultTTL': [('IP-MIB', 'ipDefaultTTL')], 'ipInReceives': [('IP-MIB', 'ipInReceives')], 'ipInHdrErrors': [('IP-MIB', 'ipInHdrErrors')], 'ipInAddrErrors': [('IP-MIB', 'ipInAddrErrors')], 'ipForwDatagrams': [('IP-MIB', 'ipForwDatagrams')], 'ipInUnknownProtos': [('IP-MIB', 'ipInUnknownProtos')], 'ipInDiscards': [('IP-MIB', 'ipInDiscards')], 'ipInDelivers': [('IP-MIB', 'ipInDelivers')], 'ipOutRequests': [('IP-MIB', 'ipOutRequests')], 'ipOutDiscards': [('IP-MIB', 'ipOutDiscards')], 'ipOutNoRoutes': [('IP-MIB', 'ipOutNoRoutes')], 'ipReasmTimeout': [('IP-MIB', 'ipReasmTimeout')], 'ipReasmReqds': [('IP-MIB', 'ipReasmReqds')], 'ipReasmOKs': [('IP-MIB', 'ipReasmOKs')], 'ipReasmFails': [('IP-MIB', 'ipReasmFails')], 'ipFragOKs': [('IP-MIB', 'ipFragOKs')], 'ipFragFails': [('IP-MIB', 'ipFragFails')], 'ipFragCreates': [('IP-MIB', 'ipFragCreates')], 'ipAddrTable': [('IP-MIB', 'ipAddrTable')], 'ipAddrEntry': [('IP-MIB', 'ipAddrEntry')], 'ipAdEntAddr': [('IP-MIB', 'ipAdEntAddr')], 'ipAdEntIfIndex': [('IP-MIB', 'ipAdEntIfIndex')], 'ipAdEntNetMask': [('IP-MIB', 'ipAdEntNetMask')], 'ipAdEntBcastAddr': [('IP-MIB', 'ipAdEntBcastAddr')], 'ipAdEntReasmMaxSize': [('IP-MIB', 'ipAdEntReasmMaxSize')], 'ipNetToMediaTable': [('IP-MIB', 'ipNetToMediaTable')], 'ipNetToMediaEntry': [('IP-MIB', 'ipNetToMediaEntry')], 'ipNetToMediaIfIndex': [('IP-MIB', 'ipNetToMediaIfIndex')], 'ipNetToMediaPhysAddress': [('IP-MIB', 'ipNetToMediaPhysAddress')], 'ipNetToMediaNetAddress': [('IP-MIB', 'ipNetToMediaNetAddress')], 'ipNetToMediaType': [('IP-MIB', 'ipNetToMediaType')], 'icmpInMsgs': [('IP-MIB', 'icmpInMsgs')], 'icmpInErrors': [('IP-MIB', 'icmpInErrors')], 'icmpInDestUnreachs': [('IP-MIB', 'icmpInDestUnreachs')], 'icmpInTimeExcds': [('IP-MIB', 'icmpInTimeExcds')], 'icmpInParmProbs': [('IP-MIB', 'icmpInParmProbs')], 'icmpInSrcQuenchs': [('IP-MIB', 'icmpInSrcQuenchs')], 'icmpInRedirects': [('IP-MIB', 'icmpInRedirects')], 'icmpInEchos': [('IP-MIB', 'icmpInEchos')], 'icmpInEchoReps': [('IP-MIB', 'icmpInEchoReps')], 'icmpInTimestamps': [('IP-MIB', 'icmpInTimestamps')], 'icmpInTimestampReps': [('IP-MIB', 'icmpInTimestampReps')], 'icmpInAddrMasks': [('IP-MIB', 'icmpInAddrMasks')], 'icmpInAddrMaskReps': [('IP-MIB', 'icmpInAddrMaskReps')], 'icmpOutMsgs': [('IP-MIB', 'icmpOutMsgs')], 'icmpOutErrors': [('IP-MIB', 'icmpOutErrors')], 'icmpOutDestUnreachs': [('IP-MIB', 'icmpOutDestUnreachs')], 'icmpOutTimeExcds': [('IP-MIB', 'icmpOutTimeExcds')], 'icmpOutParmProbs': [('IP-MIB', 'icmpOutParmProbs')], 'icmpOutSrcQuenchs': [('IP-MIB', 'icmpOutSrcQuenchs')], 'icmpOutRedirects': [('IP-MIB', 'icmpOutRedirects')], 'icmpOutEchos': [('IP-MIB', 'icmpOutEchos')], 'icmpOutEchoReps': [('IP-MIB', 'icmpOutEchoReps')], 'icmpOutTimestamps': [('IP-MIB', 'icmpOutTimestamps')], 'icmpOutTimestampReps': [('IP-MIB', 'icmpOutTimestampReps')], 'icmpOutAddrMasks': [('IP-MIB', 'icmpOutAddrMasks')], 'icmpOutAddrMaskReps': [('IP-MIB', 'icmpOutAddrMaskReps')], 'tcpRtoAlgorithm': [('TCP-MIB', 'tcpRtoAlgorithm')], 'tcpRtoMin': [('TCP-MIB', 'tcpRtoMin')], 'tcpRtoMax': [('TCP-MIB', 'tcpRtoMax')], 'tcpMaxConn': [('TCP-MIB', 'tcpMaxConn')], 'tcpActiveOpens': [('TCP-MIB', 'tcpActiveOpens')], 'tcpPassiveOpens': [('TCP-MIB', 'tcpPassiveOpens')], 'tcpAttemptFails': [('TCP-MIB', 'tcpAttemptFails')], 'tcpEstabResets': [('TCP-MIB', 'tcpEstabResets')], 'tcpCurrEstab': [('TCP-MIB', 'tcpCurrEstab')], 'tcpInSegs': [('TCP-MIB', 'tcpInSegs')], 'tcpOutSegs': [('TCP-MIB', 'tcpOutSegs')], 'tcpRetransSegs': [('TCP-MIB', 'tcpRetransSegs')], 'tcpConnTable': [('TCP-MIB', 'tcpConnTable')], 'tcpConnEntry': [('TCP-MIB', 'tcpConnEntry')], 'tcpConnState': [('TCP-MIB', 'tcpConnState')], 'tcpConnLocalAddress': [('TCP-MIB', 'tcpConnLocalAddress')], 'tcpConnLocalPort': [('TCP-MIB', 'tcpConnLocalPort')], 'tcpConnRemAddress': [('TCP-MIB', 'tcpConnRemAddress')], 'tcpConnRemPort': [('TCP-MIB', 'tcpConnRemPort')], 'tcpInErrs': [('TCP-MIB', 'tcpInErrs')], 'tcpOutRsts': [('TCP-MIB', 'tcpOutRsts')], 'udpInDatagrams': [('UDP-MIB', 'udpInDatagrams')], 'udpNoPorts': [('UDP-MIB', 'udpNoPorts')], 'udpInErrors': [('UDP-MIB', 'udpInErrors')], 'udpOutDatagrams': [('UDP-MIB', 'udpOutDatagrams')], 'udpTable': [('UDP-MIB', 'udpTable')], 'udpEntry': [('UDP-MIB', 'udpEntry')], 'udpLocalAddress': [('UDP-MIB', 'udpLocalAddress')], 'udpLocalPort': [('UDP-MIB', 'udpLocalPort')], 'snmpInPkts': [('SNMPv2-MIB', 'snmpInPkts')], 'snmpOutPkts': [('SNMPv2-MIB', 'snmpOutPkts')], 'snmpInBadVersions': [('SNMPv2-MIB', 'snmpInBadVersions')], 'snmpInBadCommunityNames': [('SNMPv2-MIB', 'snmpInBadCommunityNames')], 'snmpInBadCommunityUses': [('SNMPv2-MIB', 'snmpInBadCommunityUses')], 'snmpInASNParseErrs': [('SNMPv2-MIB', 'snmpInASNParseErrs')], 'snmpInTooBigs': [('SNMPv2-MIB', 'snmpInTooBigs')], 'snmpInNoSuchNames': [('SNMPv2-MIB', 'snmpInNoSuchNames')], 'snmpInBadValues': [('SNMPv2-MIB', 'snmpInBadValues')], 'snmpInReadOnlys': [('SNMPv2-MIB', 'snmpInReadOnlys')], 'snmpInGenErrs': [('SNMPv2-MIB', 'snmpInGenErrs')], 'snmpInTotalReqVars': [('SNMPv2-MIB', 'snmpInTotalReqVars')], 'snmpInTotalSetVars': [('SNMPv2-MIB', 'snmpInTotalSetVars')], 'snmpInGetRequests': [('SNMPv2-MIB', 'snmpInGetRequests')], 'snmpInGetNexts': [('SNMPv2-MIB', 'snmpInGetNexts')], 'snmpInSetRequests': [('SNMPv2-MIB', 'snmpInSetRequests')], 'snmpInGetResponses': [('SNMPv2-MIB', 'snmpInGetResponses')], 'snmpInTraps': [('SNMPv2-MIB', 'snmpInTraps')], 'snmpOutTooBigs': [('SNMPv2-MIB', 'snmpOutTooBigs')], 'snmpOutNoSuchNames': [('SNMPv2-MIB', 'snmpOutNoSuchNames')], 'snmpOutBadValues': [('SNMPv2-MIB', 'snmpOutBadValues')], 'snmpOutGenErrs': [('SNMPv2-MIB', 'snmpOutGenErrs')], 'snmpOutGetRequests': [('SNMPv2-MIB', 'snmpOutGetRequests')], 'snmpOutGetNexts': [('SNMPv2-MIB', 'snmpOutGetNexts')], 'snmpOutSetRequests': [('SNMPv2-MIB', 'snmpOutSetRequests')], 'snmpOutGetResponses': [('SNMPv2-MIB', 'snmpOutGetResponses')], 'snmpOutTraps': [('SNMPv2-MIB', 'snmpOutTraps')], 'snmpEnableAuthenTraps': [('SNMPv2-MIB', 'snmpEnableAuthenTraps')]}} convertImportv2 = { 'RFC1065-SMI': commonSyms['RFC1155-SMI/RFC1065-SMI'], 'RFC1155-SMI': commonSyms['RFC1155-SMI/RFC1065-SMI'], 'RFC1158-MIB': updateDict( dict(commonSyms['RFC1155-SMI/RFC1065-SMI']), (('nullSpecific', [('SNMPv2-SMI', 'zeroDotZero')]), ('ipRoutingTable', [('RFC1213-MIB', 'ipRouteTable')]), ('ipRouteEntry', [('RFC1213-MIB', 'ipRouteEntry')]), ('ipRouteDest', [('RFC1213-MIB', 'ipRouteDest')]), ('ipRouteIfIndex', [('RFC1213-MIB', 'ipRouteIfIndex')]), ('ipRouteMetric1', [('RFC1213-MIB', 'ipRouteMetric1')]), ('ipRouteMetric2', [('RFC1213-MIB', 'ipRouteMetric2')]), ('ipRouteMetric3', [('RFC1213-MIB', 'ipRouteMetric3')]), ('ipRouteMetric4', [('RFC1213-MIB', 'ipRouteMetric4')]), ('ipRouteNextHop', [('RFC1213-MIB', 'ipRouteNextHop')]), ('ipRouteType', [('RFC1213-MIB', 'ipRouteType')]), ('ipRouteProto', [('RFC1213-MIB', 'ipRouteProto')]), ('ipRouteAge', [('RFC1213-MIB', 'ipRouteAge')]), ('ipRouteMask', [('RFC1213-MIB', 'ipRouteMask')]), ('egpInMsgs', [('RFC1213-MIB', 'egpInMsgs')]), ('egpInErrors', [('RFC1213-MIB', 'egpInErrors')]), ('egpOutMsgs', [('RFC1213-MIB', 'egpOutMsgs')]), ('egpOutErrors', [('RFC1213-MIB', 'egpOutErrors')]), ('egpNeighTable', [('RFC1213-MIB', 'egpNeighTable')]), ('egpNeighEntry', [('RFC1213-MIB', 'egpNeighEntry')]), ('egpNeighState', [('RFC1213-MIB', 'egpNeighState')]), ('egpNeighAddr', [('RFC1213-MIB', 'egpNeighAddr')]), ('egpNeighAs', [('RFC1213-MIB', 'egpNeighAs')]), ('egpNeighInMsgs', [('RFC1213-MIB', 'egpNeighInMsgs')]), ('egpNeighInErrs', [('RFC1213-MIB', 'egpNeighInErrs')]), ('egpNeighOutMsgs', [('RFC1213-MIB', 'egpNeighOutMsgs')]), ('egpNeighOutErrs', [('RFC1213-MIB', 'egpNeighOutErrs')]), ('egpNeighInErrMsgs', [('RFC1213-MIB', 'egpNeighInErrMsgs')]), ('egpNeighOutErrMsgs', [('RFC1213-MIB', 'egpNeighOutErrMsgs')]), ('egpNeighStateUps', [('RFC1213-MIB', 'egpNeighStateUps')]), ('egpNeighStateDowns', [('RFC1213-MIB', 'egpNeighStateDowns')]), ('egpNeighIntervalHello', [('RFC1213-MIB', 'egpNeighIntervalHello')]), ('egpNeighIntervalPoll', [('RFC1213-MIB', 'egpNeighIntervalPoll')]), ('egpNeighMode', [('RFC1213-MIB', 'egpNeighMode')]), ('egpNeighEventTrigger', [('RFC1213-MIB', 'egpNeighEventTrigger')]), ('egpAs', [('RFC1213-MIB', 'egpAs')]), ('snmpEnableAuthTraps', [('SNMPv2-MIB', 'snmpEnableAuthenTraps')])) ), 'RFC-1212': {'OBJECT-TYPE': [('SNMPv2-SMI', 'OBJECT-TYPE')]}, # XXX 'IndexSyntax': ??? 'RFC1213-MIB': updateDict(dict(commonSyms['RFC1158-MIB/RFC1213-MIB']), (('PhysAddress', [('SNMPv2-TC', 'PhysAddress')]),)), 'RFC-1215': {'TRAP-TYPE': [('SNMPv2-SMI', 'TRAP-TYPE')]} } def genCode(self, ast, symbolTable, **kwargs): raise NotImplementedError() def genIndex(self, mibsMap, **kwargs): raise NotImplementedError() @staticmethod def isBinary(s): return (isinstance(s, (str, unicode)) and s[0] == '\'' and s[-2:] in ('\'b', '\'B')) @staticmethod def isHex(s): return (isinstance(s, (str, unicode)) and s[0] == '\'' and s[-2:] in ('\'h', '\'H')) def str2int(self, s): if self.isBinary(s): if s[1:-2]: return int(s[1:-2], 2) else: raise error.PySmiSemanticError('empty binary string to int conversion') elif self.isHex(s): if s[1:-2]: return int(s[1:-2], 16) else: raise error.PySmiSemanticError('empty hex string to int conversion') else: return int(s) pysmi-0.3.4/pysmi/codegen/jsondoc.py0000664006321400632140000010577513454602510021116 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys import re from time import strptime, strftime try: import json except ImportError: import simplejson as json try: from collections import OrderedDict except ImportError: from ordereddict import OrderedDict from pysmi.mibinfo import MibInfo from pysmi.codegen.base import AbstractCodeGen from pysmi import error from pysmi import debug if sys.version_info[0] > 2: # noinspection PyShadowingBuiltins unicode = str # noinspection PyShadowingBuiltins long = int class JsonCodeGen(AbstractCodeGen): """Builds JSON document 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*. """ constImports = { 'SNMPv2-SMI': ('iso', 'NOTIFICATION-TYPE', # bug in some MIBs (e.g. A3COM-HUAWEI-DHCPSNOOP-MIB) 'MODULE-IDENTITY', 'OBJECT-TYPE', 'OBJECT-IDENTITY'), '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') + AbstractCodeGen.baseMibs baseTypes = ['Integer', 'Integer32', 'Bits', 'ObjectIdentifier', 'OctetString'] typeClasses = { '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'] indent = ' ' * 4 fakeidx = 1000 # starting index for fake symbols def __init__(self): self._rows = set() self._cols = {} # k, v = name, datatype self._seenSyms = set() self._importMap = {} self._out = {} # k, v = name, generated code self._moduleIdentityOid = None self._moduleRevision = None self._enterpriseOid = None self._oids = set() self._complianceOids = [] self.moduleName = ['DUMMY'] self.genRules = {'text': True} self.symbolTable = {} @staticmethod def transOpers(symbol): return symbol.replace('-', '_') def prepData(self, pdata): 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:])) ) return data def genImports(self, imports): # convertion 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] outDict = OrderedDict() outDict['class'] = 'imports' for module in sorted(imports): symbols = [] for symbol in set(imports[module]): symbols.append(symbol) if symbols: self._seenSyms.update( [self.transOpers(s) for s in symbols] ) self._importMap.update( [(self.transOpers(s), module) for s in symbols] ) if module not in outDict: outDict[module] = [] outDict[module].extend(symbols) return OrderedDict(imports=outDict), tuple(sorted(imports)) # noinspection PyMethodMayBeStatic def genLabel(self, symbol): return '-' in symbol and symbol or '' def addToExports(self, symbol, moduleIdentity=0): self._seenSyms.add(symbol) # noinspection PyUnusedLocal def regSym(self, symbol, outDict, parentOid=None, moduleIdentity=False, moduleCompliance=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] = outDict if 'oid' in outDict: self._oids.add(outDict['oid']) if not self._enterpriseOid and outDict['oid'].startswith('1.3.6.1.4.1.'): self._enterpriseOid = '.'.join(outDict['oid'].split('.')[:7]) if moduleIdentity: if self._moduleIdentityOid: raise error.PySmiSemanticError('Duplicate module identity') self._moduleIdentityOid = outDict['oid'] if moduleCompliance: self._complianceOids.append(outDict['oid']) 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): name, productRelease, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'agentcapabilities' if productRelease: outDict['productrelease'] = productRelease if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genModuleIdentity(self, data): name, lastUpdated, organization, contactInfo, description, revisions, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'moduleidentity' if revisions: outDict['revisions'] = revisions self._moduleRevision = revisions[0]['revision'] if self.genRules['text']: if lastUpdated: outDict['lastupdated'] = lastUpdated if organization: outDict['organization'] = organization if contactInfo: outDict['contactinfo'] = contactInfo if description: outDict['description'] = description self.regSym(name, outDict, parentOid, moduleIdentity=True) return outDict # noinspection PyUnusedLocal def genModuleCompliance(self, data): name, status, description, reference, compliances, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'modulecompliance' if compliances: outDict['modulecompliance'] = compliances if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid, moduleCompliance=True) return outDict # noinspection PyUnusedLocal def genNotificationGroup(self, data): name, objects, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'notificationgroup' if objects: outDict['objects'] = [{'module': self._importMap.get(obj, self.moduleName[0]), 'object': self.transOpers(obj)} for obj in objects] if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genNotificationType(self, data): name, objects, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'notificationtype' if objects: outDict['objects'] = [{'module': self._importMap.get(obj, self.moduleName[0]), 'object': self.transOpers(obj)} for obj in objects] if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genObjectGroup(self, data): name, objects, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict({'name': name, 'oid': oidStr, 'class': 'objectgroup'}) if objects: outDict['objects'] = [{'module': self._importMap.get(obj, self.moduleName[0]), 'object': self.transOpers(obj)} for obj in objects] if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genObjectIdentity(self, data): name, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'objectidentity' if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genObjectType(self, data): 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 ('', '', []) defval = self.genDefVal(defval, objname=name) outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr if syntax[0]: nodetype = syntax[0] == 'Bits' and 'scalar' or syntax[0] # Bits hack nodetype = name in self.symbolTable[self.moduleName[0]]['_symtable_cols'] and 'column' or nodetype outDict['nodetype'] = nodetype outDict['class'] = 'objecttype' if syntax[1]: outDict['syntax'] = syntax[1] if defval: outDict['default'] = defval if units: outDict['units'] = units if maxaccess: outDict['maxaccess'] = maxaccess if indexStr: outDict['indices'] = indexStr if self.genRules['text'] and reference: outDict['reference'] = reference if augmention: augmention = self.transOpers(augmention) outDict['augmention'] = OrderedDict() outDict['augmention']['name'] = name outDict['augmention']['module'] = self.moduleName[0] outDict['augmention']['object'] = augmention if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description self.regSym(name, outDict, parentOid) # TODO # if fakeSyms: # fake symbols for INDEX to support SMIv1 # for i in range(len(fakeSyms)): # fakeOutStr = fakeStrlist[i] % oidStr # self.regSym(fakeSyms[i], fakeOutStr, name) return outDict # noinspection PyUnusedLocal def genTrapType(self, data): name, enterprise, variables, description, reference, value = data label = self.genLabel(name) name = self.transOpers(name) enterpriseStr, parentOid = enterprise outDict = OrderedDict() outDict['name'] = name outDict['oid'] = enterpriseStr + '0.' + str(value) outDict['class'] = 'notificationtype' if variables: outDict['objects'] = [{'module': self._importMap.get(obj, self.moduleName[0]), 'object': self.transOpers(obj)} for obj in variables] if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genTypeDeclaration(self, data): name, declaration = data outDict = OrderedDict() outDict['name'] = name outDict['class'] = 'type' if declaration: parentType, attrs = declaration if parentType: # skipping SEQUENCE case name = self.transOpers(name) outDict.update(attrs) self.regSym(name, outDict) return outDict # noinspection PyUnusedLocal def genValueDeclaration(self, data): name, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'objectidentity' self.regSym(name, outDict, parentOid) return outDict # Subparts generation functions # noinspection PyMethodMayBeStatic,PyUnusedLocal def genBitNames(self, data): names = data[0] return names def genBits(self, data): bits = data[0] outDict = OrderedDict() outDict['type'] = 'Bits' outDict['class'] = 'type' outDict['bits'] = OrderedDict() for name, bit in sorted(bits, key=lambda x: x[1]): outDict['bits'][name] = bit return 'scalar', outDict # noinspection PyUnusedLocal def genCompliances(self, data): compliances = [] for complianceModule in data[0]: name = complianceModule[0] or self.moduleName[0] compliances += [{'object': self.transOpers(compl), 'module': name} for compl in complianceModule[1]] return compliances # noinspection PyUnusedLocal def genConceptualTable(self, data): row = data[0] if row[1] and row[1][-2:] == '()': row = row[1][:-2] self._rows.add(row) return 'table', '' # noinspection PyMethodMayBeStatic,PyUnusedLocal def genContactInfo(self, data): text = data[0] return self.textFilter('contact-info', text) # noinspection PyUnusedLocal def genDisplayHint(self, data): return data[0] # noinspection PyUnusedLocal def genDefVal(self, data, objname=None): if not data: return {} if not objname: return data outDict = OrderedDict() defval = data[0] defvalType = self.getBaseType(objname, self.moduleName[0]) if isinstance(defval, (int, long)): # number outDict.update(value=defval, format='decimal') elif self.isHex(defval): # hex if defvalType[0][0] in ('Integer32', 'Integer'): # common bug in MIBs outDict.update(value=str(int(len(defval) > 3 and defval[1:-2] or '0', 16)), format='hex') else: outDict.update(value=defval[1:-2], format='hex') elif self.isBinary(defval): # binary binval = defval[1:-2] if defvalType[0][0] in ('Integer32', 'Integer'): # common bug in MIBs outDict.update(value=str(int(binval or '0', 2)), format='bin') else: hexval = binval and hex(int(binval, 2))[2:] or '' outDict.update(value=hexval, format='hex') 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 {} # we will set no default value outDict.update(value=defval[1:-1], format='string') 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'])) outDict.update(value=val, format='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])] if defval: outDict.update(value=defval[0], format='enum') elif defval in dict(defvalType[1]): # good MIB: DEFVAL { ... } outDict.update(value=defval, format='enum') 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)) outDict.update(value=self.genBits([defvalBits])[1], format='bits') return outDict else: raise error.PySmiSemanticError( 'unknown type "%s" for defval "%s" of symbol "%s"' % (defvalType, defval, objname)) return {'default': outDict} # noinspection PyMethodMayBeStatic def genDescription(self, data): return self.textFilter('description', data[0]) # noinspection PyMethodMayBeStatic def genReference(self, data): return self.textFilter('reference', data[0]) # noinspection PyMethodMayBeStatic def genStatus(self, data): return data[0] def genProductRelease(self, data): return data[0] def genEnumSpec(self, data): items = data[0] return {'enumeration': dict(items)} # noinspection PyUnusedLocal def genTableIndex(self, data): def genFakeSyms(fakeidx, idxType): objType = self.typeClasses.get(idxType, idxType) objType = self.transOpers(objType) return {'module': self.moduleName[0], object: objType} indexes = data[0] idxStrlist, fakeSyms, fakeStrlist = [], [], [] for idx in indexes: isImplied = idx[0] 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 index = OrderedDict() index['module'] = self._importMap.get(idxName, self.moduleName[0]) index['object'] = idxName index['implied'] = isImplied idxStrlist.append(index) return idxStrlist, fakeStrlist, fakeSyms def genIntegerSubType(self, data): ranges = [] for rng in data[0]: vmin, vmax = len(rng) == 1 and (rng[0], rng[0]) or rng vmin, vmax = self.str2int(vmin), self.str2int(vmax) ran = OrderedDict() ran['min'] = vmin ran['max'] = vmax ranges.append(ran) return {'range': ranges} # noinspection PyMethodMayBeStatic,PyUnusedLocal def genMaxAccess(self, data): return data[0] def genOctetStringSubType(self, data): sizes = [] for rng in data[0]: vmin, vmax = len(rng) == 1 and (rng[0], rng[0]) or rng vmin, vmax = self.str2int(vmin), self.str2int(vmax) size = OrderedDict() size['min'] = vmin size['max'] = vmax sizes.append(size) return {'size': sizes} # noinspection PyUnusedLocal def genOid(self, data): 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 '.'.join([str(x) for x in self.genNumericOid(out)]), parent # noinspection PyUnusedLocal def genObjects(self, data): 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): 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): return data[0] # noinspection PyMethodMayBeStatic,PyUnusedLocal def genOrganization(self, data): return self.textFilter('organization', data[0]) # noinspection PyUnusedLocal def genRevisions(self, data): revisions = [] for x in data[0]: revision = OrderedDict() revision['revision'] = self.genTime([x[0]])[0] revision['description'] = self.textFilter('description', x[1][1]) revisions.append(revision) return revisions def genRow(self, data): row = data[0] row = self.transOpers(row) return row in self.symbolTable[self.moduleName[0]]['_symtable_rows'] and ( 'row', '') or self.genSimpleSyntax(data) # noinspection PyUnusedLocal def genSequence(self, data): cols = data[0] self._cols.update(cols) return '', '' def genSimpleSyntax(self, data): objType = data[0] objType = self.typeClasses.get(objType, objType) objType = self.transOpers(objType) subtype = len(data) == 2 and data[1] or {} outDict = OrderedDict() outDict['type'] = objType outDict['class'] = 'type' if subtype: outDict['constraints'] = subtype return 'scalar', outDict # noinspection PyUnusedLocal def genTypeDeclarationRHS(self, data): if len(data) == 1: parentType, attrs = data[0] outDict = OrderedDict() if not attrs: return outDict # just syntax outDict['type'] = attrs else: # Textual convention display, status, description, reference, syntax = data parentType, attrs = syntax outDict = OrderedDict() outDict['type'] = attrs outDict['class'] = 'textualconvention' if display: outDict['displayhint'] = display if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference return parentType, outDict # noinspection PyMethodMayBeStatic,PyUnusedLocal def genUnits(self, data): text = data[0] return 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, 'PRODUCT-RELEASE': genProductRelease, 'ApplicationSyntax': genSimpleSyntax, 'BitNames': genBitNames, 'BITS': genBits, 'ComplianceModules': genCompliances, 'conceptualTable': genConceptualTable, 'CONTACT-INFO': genContactInfo, 'DISPLAY-HINT': genDisplayHint, 'DEFVAL': genDefVal, 'DESCRIPTION': genDescription, 'REFERENCE': genReference, 'Status': genStatus, '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._seenSyms.clear() self._importMap.clear() self._out.clear() self._moduleIdentityOid = None self._enterpriseOid = None self._oids = set() self._complianceOids = [] self.moduleName[0], moduleOid, imports, declarations = ast outDict, importedModules = self.genImports(imports and imports or {}) for declr in declarations or []: if declr: self.handlersTable[declr[0]](self, self.prepData(declr[1:])) 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) outDict[sym] = self._out[sym] if 'comments' in kwargs: outDict['meta'] = OrderedDict() outDict['meta']['comments'] = kwargs['comments'] outDict['meta']['module'] = self.moduleName[0] 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 '', len(outDict))) return MibInfo(oid=moduleOid, identity=self._moduleIdentityOid, name=self.moduleName[0], revision=self._moduleRevision, oids=self._oids, enterprise=self._enterpriseOid, compliance=self._complianceOids, imported=tuple([x for x in importedModules if x not in self.fakeMibs])), json.dumps(outDict, indent=2) def genIndex(self, processed, **kwargs): outDict = { 'meta': {}, 'identity': {}, 'enterprise': {}, 'compliance': {}, 'oids': {}, } if kwargs.get('old_index_data'): try: outDict.update( json.loads(kwargs['old_index_data']) ) except Exception: raise error.PySmiCodegenError('Index load error: %s' % sys.exc_info()[1]) def order(top): if isinstance(top, dict): new_top = OrderedDict() try: # first try to sort keys as OIDs for k in sorted(top, key=lambda x: [int(y) for y in x.split('.')]): new_top[k] = order(top[k]) except ValueError: for k in sorted(top): new_top[k] = order(top[k]) return new_top elif isinstance(top, list): new_top = [] for e in sorted(set(top)): new_top.append(order(e)) return new_top return top for module, status in processed.items(): modData = outDict['identity'] identity_oid = getattr(status, 'identity', None) if identity_oid: if identity_oid not in modData: modData[identity_oid] = [] modData[identity_oid].append(module) modData = outDict['enterprise'] enterprise_oid = getattr(status, 'enterprise', None) if enterprise_oid: if enterprise_oid not in modData: modData[enterprise_oid] = [] modData[enterprise_oid].append(module) modData = outDict['compliance'] compliance_oids = getattr(status, 'compliance', ()) for compliance_oid in compliance_oids: if compliance_oid not in modData: modData[compliance_oid] = [] modData[compliance_oid].append(module) modData = outDict['oids'] objects_oids = getattr(status, 'oids', ()) for object_oid in objects_oids: if object_oid not in modData: modData[object_oid] = [] modData[object_oid].append(module) if modData: unique_prefixes = {} for oid in sorted(modData, key=lambda x: x.count('.')): for oid_prefix, modules in unique_prefixes.items(): if oid.startswith(oid_prefix) and set(modules).issuperset(modData[oid]): break else: unique_prefixes[oid] = modData[oid] outDict['oids'] = unique_prefixes if 'comments' in kwargs: outDict['meta']['comments'] = kwargs['comments'] debug.logger & debug.flagCodegen and debug.logger( 'OID->MIB index built, %s entries' % len(processed)) return json.dumps(order(outDict), indent=2) pysmi-0.3.4/pysmi/codegen/null.py0000664006321400632140000000125513411726453020423 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.mibinfo import MibInfo from pysmi.codegen.base import AbstractCodeGen from pysmi import debug class NullCodeGen(AbstractCodeGen): """Dummy code generation backend. Could be used for disabling code generation at *MibCompiler*. """ def genCode(self, ast, symbolTable, **kwargs): debug.logger & debug.flagCodegen and debug.logger('%s invoked' % self.__class__.__name__) return MibInfo(oid=None, name='', imported=[]), '' def genIndex(self, mibsMap, **kwargs): return '' pysmi-0.3.4/pysmi/codegen/pysnmp.py0000664006321400632140000012543113454602510020774 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # 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 '', 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 pysmi-0.3.4/pysmi/codegen/symtable.py0000664006321400632140000005262113411726453021274 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # # Build an internally used symbol table for each passed MIB. # import sys 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 SymtableCodeGen(AbstractCodeGen): 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 = { '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 } 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._rows = set() self._cols = {} # k, v = name, datatype self._exports = set() self._postponedSyms = {} # k, v = symbol, (parents, properties) self._parentOids = set() self._importMap = {} # k, v = symbol, MIB self._symsOrder = [] self._out = {} # k, v = symbol, properties self.moduleName = ['DUMMY'] self._moduleRevision = None self.genRules = {'text': True} 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): # convertion 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._importMap.update([(self.transOpers(s), module) for s in symbols]) return {}, tuple(sorted(imports)) def allParentsExists(self, parents): parentsExists = True for parent in parents: if not (parent in self._out or parent in self._importMap or parent in self.baseTypes or parent in ('MibTable', 'MibTableRow', 'MibTableColumn') or parent in self._rows): parentsExists = False break return parentsExists def regSym(self, symbol, symProps, parents=()): if symbol in self._out or symbol in self._postponedSyms: # add to strict mode - or symbol in self._importMap: raise error.PySmiSemanticError('Duplicate symbol found: %s' % symbol) if self.allParentsExists(parents): self._out[symbol] = symProps self._symsOrder.append(symbol) self.regPostponedSyms() else: self._postponedSyms[symbol] = (parents, symProps) def regPostponedSyms(self): regedSyms = [] for sym, val in self._postponedSyms.items(): parents, symProps = val if self.allParentsExists(parents): self._out[sym] = symProps self._symsOrder.append(sym) regedSyms.append(sym) for sym in regedSyms: self._postponedSyms.pop(sym) # Clause handlers # noinspection PyUnusedLocal def genAgentCapabilities(self, data, classmode=False): origName, release, status, description, reference, oid = data pysmiName = self.transOpers(origName) symProps = {'type': 'AgentCapabilities', 'oid': oid, 'origName': origName} self.regSym(pysmiName, symProps) # noinspection PyUnusedLocal def genModuleIdentity(self, data, classmode=False): origName, lastUpdated, organization, contactInfo, description, revisions, oid = data pysmiName = self.transOpers(origName) symProps = {'type': 'ModuleIdentity', 'oid': oid, 'origName': origName} if revisions: self._moduleRevision = revisions[0] self.regSym(pysmiName, symProps) # noinspection PyUnusedLocal def genModuleCompliance(self, data, classmode=False): origName, status, description, reference, compliances, oid = data pysmiName = self.transOpers(origName) symProps = {'type': 'ModuleCompliance', 'oid': oid, 'origName': origName} self.regSym(pysmiName, symProps) # noinspection PyUnusedLocal def genNotificationGroup(self, data, classmode=False): origName, objects, status, description, reference, oid = data pysmiName = self.transOpers(origName) symProps = {'type': 'NotificationGroup', 'oid': oid, 'origName': origName} self.regSym(pysmiName, symProps) # noinspection PyUnusedLocal def genNotificationType(self, data, classmode=False): origName, objects, status, description, reference, oid = data pysmiName = self.transOpers(origName) symProps = {'type': 'NotificationType', 'oid': oid, 'origName': origName} self.regSym(pysmiName, symProps) # noinspection PyUnusedLocal def genObjectGroup(self, data, classmode=False): origName, objects, status, description, reference, oid = data pysmiName = self.transOpers(origName) symProps = {'type': 'ObjectGroup', 'oid': oid, 'origName': origName} self.regSym(pysmiName, symProps) # noinspection PyUnusedLocal def genObjectIdentity(self, data, classmode=False): origName, status, description, reference, oid = data pysmiName = self.transOpers(origName) symProps = {'type': 'ObjectIdentity', 'oid': oid, 'origName': origName} self.regSym(pysmiName, symProps) # noinspection PyUnusedLocal def genObjectType(self, data, classmode=False): origName, syntax, units, maxaccess, status, description, reference, augmention, index, defval, oid = data pysmiName = self.transOpers(origName) symProps = {'type': 'ObjectType', 'oid': oid, 'syntax': syntax, # (type, module), subtype 'origName': origName} parents = [syntax[0][0]] if augmention: parents.append(self.transOpers(augmention)) if defval: # XXX symProps['defval'] = defval if index and index[1]: namepart, fakeIndexes, fakeSymSyntax = index for fakeIdx, fakeSyntax in zip(fakeIndexes, fakeSymSyntax): fakeName = namepart + str(fakeIdx) fakeSymProps = {'type': 'fakeColumn', 'oid': oid + (fakeIdx,), 'syntax': fakeSyntax, 'origName': fakeName} self.regSym(fakeName, fakeSymProps) self.regSym(pysmiName, symProps, parents) # noinspection PyUnusedLocal def genTrapType(self, data, classmode=False): origName, enterprise, variables, description, reference, value = data pysmiName = self.transOpers(origName) symProps = {'type': 'NotificationType', 'oid': enterprise + (0, value), 'origName': origName} self.regSym(pysmiName, symProps) # noinspection PyUnusedLocal def genTypeDeclaration(self, data, classmode=False): origName, declaration = data pysmiName = self.transOpers(origName) if declaration: parentType, attrs = declaration if parentType: # skipping SEQUENCE case symProps = {'type': 'TypeDeclaration', 'syntax': declaration, # (type, module), subtype 'origName': origName} self.regSym(pysmiName, symProps, [declaration[0][0]]) # noinspection PyUnusedLocal def genValueDeclaration(self, data, classmode=False): origName, oid = data pysmiName = self.transOpers(origName) symProps = {'type': 'MibIdentifier', 'oid': oid, 'origName': origName} self.regSym(pysmiName, symProps) # Subparts generation functions # noinspection PyUnusedLocal,PyMethodMayBeStatic def genBitNames(self, data, classmode=False): names = data[0] return names # noinspection PyUnusedLocal,PyMethodMayBeStatic def genBits(self, data, classmode=False): bits = data[0] return ('Bits', ''), bits # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genCompliances(self, data, classmode=False): return '' # noinspection PyUnusedLocal def genConceptualTable(self, data, classmode=False): row = data[0] if row[0] and row[0][0]: self._rows.add(self.transOpers(row[0][0])) return ('MibTable', ''), '' # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genContactInfo(self, data, classmode=False): return '' # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genDisplayHint(self, data, classmode=False): return '' # noinspection PyUnusedLocal def genDefVal(self, data, classmode=False): # XXX should be fixed, see pysnmp.py defval = data[0] if isinstance(defval, (int, long)): # number val = str(defval) elif self.isHex(defval): # hex val = 'hexValue="' + defval[1:-2] + '"' # not working for Integer baseTypes elif self.isBinary(defval): # binary binval = defval[1:-2] hexval = binval and hex(int(binval, 2))[2:] or '' val = 'hexValue="' + hexval + '"' elif isinstance(defval, list): # bits list val = defval elif defval[0] == defval[-1] and defval[0] == '"': # quoted strimg val = dorepr(defval[1:-1]) else: # symbol (oid as defval) or name for enumeration member if defval in self._out or defval in self._importMap: val = defval + '.getName()' else: val = dorepr(defval) return val # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genDescription(self, data, classmode=False): return '' def genReference(self, data, classmode=False): return '' def genStatus(self, data, classmode=False): return '' def genProductRelease(self, data, classmode=False): return '' def genEnumSpec(self, data, classmode=False): return self.genBits(data, classmode=classmode)[1] def genIndex(self, data, classmode=False): indexes = data[0] fakeIdxName = 'pysmiFakeCol' fakeIndexes, fakeSymsSyntax = [], [] for idx in indexes: idxName = idx[1] if idxName in self.smiv1IdxTypes: # SMIv1 support idxType = idxName objType = self.typeClasses.get(idxType, idxType) objType = self.transOpers(objType) fakeIndexes.append(self.fakeidx) fakeSymsSyntax.append((('MibTableColumn', ''), objType)) self.fakeidx += 1 return fakeIdxName, fakeIndexes, fakeSymsSyntax # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genIntegerSubType(self, data, classmode=False): return '' # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genMaxAccess(self, data, classmode=False): return '' # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genOctetStringSubType(self, data, classmode=False): return '' # noinspection PyUnusedLocal def genOid(self, data, classmode=False): out = () for el in data[0]: if isinstance(el, (str, unicode)): parent = self.transOpers(el) self._parentOids.add(parent) 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 out # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genObjects(self, data, classmode=False): return '' # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genTime(self, data, classmode=False): return '' # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genLastUpdated(self, data, classmode=False): return data[0] # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genOrganization(self, data, classmode=False): return data[0] # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genRevisions(self, data, classmode=False): lastRevision, lastDescription = data[0][0][0], data[0][0][1][1] return lastRevision, lastDescription def genRow(self, data, classmode=False): row = data[0] row = self.transOpers(row) return row in self._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 '', '' # noinspection PyUnusedLocal def genSimpleSyntax(self, data, classmode=False): objType = data[0] module = '' objType = self.typeClasses.get(objType, objType) objType = self.transOpers(objType) if objType not in self.baseTypes: module = self._importMap.get(objType, self.moduleName[0]) subtype = len(data) == 2 and data[1] or '' return (objType, module), subtype # noinspection PyUnusedLocal,PyMethodMayBeStatic 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 return parentType, attrs # noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic def genUnits(self, data, classmode=False): return '' 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': genIndex, '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, } def genCode(self, ast, symbolTable, **kwargs): self.genRules['text'] = kwargs.get('genTexts', False) self._rows.clear() self._cols.clear() self._parentOids.clear() self._symsOrder = [] self._postponedSyms.clear() self._importMap.clear() self._out = {} # should be new object, do not use `clear` method 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) if self._postponedSyms: raise error.PySmiSemanticError('Unknown parents for symbols: %s' % ', '.join(self._postponedSyms)) for sym in self._parentOids: if sym not in self._out and sym not in self._importMap: raise error.PySmiSemanticError('Unknown parent symbol: %s' % sym) self._out['_symtable_order'] = list(self._symsOrder) self._out['_symtable_cols'] = list(self._cols) self._out['_symtable_rows'] = list(self._rows) debug.logger & debug.flagCodegen and debug.logger( 'canonical MIB name %s (%s), imported MIB(s) %s, Symbol table size %s symbols' % ( self.moduleName[0], moduleOid, ','.join(importedModules) or '', len(self._out))) return MibInfo(oid=None, name=self.moduleName[0], revision=self._moduleRevision, imported=tuple([x for x in importedModules])), self._out pysmi-0.3.4/pysmi/compat.py0000664006321400632140000000121713411726453017326 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys if sys.version_info[0] > 2: def encode(s): if isinstance(s, str): s = s.encode('utf-8', 'ignore') return s def decode(s): if isinstance(s, bytes): s = s.decode('utf-8', 'ignore') return s else: def encode(s): if isinstance(s, unicode): s = s.encode('utf-8', 'ignore') return s def decode(s): if isinstance(s, str): s = s.decode('utf-8', 'ignore') return s pysmi-0.3.4/pysmi/compiler.py0000664006321400632140000005202413454602510017651 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys import os import time try: from pwd import getpwuid except ImportError: # noinspection PyPep8 getpwuid = lambda x: [''] from pysmi import __name__ as packageName from pysmi import __version__ as packageVersion from pysmi.mibinfo import MibInfo from pysmi.codegen.symtable import SymtableCodeGen from pysmi import error from pysmi import debug class MibStatus(str): """Indicate MIB transformation result. *MibStatus* is a subclass of Python string type. Some additional attributes may be set to indicate the details. The following *MibStatus* class instances are defined: * *compiled* - MIB is successfully transformed * *untouched* - fresh transformed version of this MIB already exisits * *failed* - MIB transformation failed. *error* attribute carries details. * *unprocessed* - MIB transformation required but waived for some reason * *missing* - ASN.1 MIB source can't be found * *borrowed* - MIB transformation failed but pre-transformed version was used """ def setOptions(self, **kwargs): n = self.__class__(self) for k in kwargs: setattr(n, k, kwargs[k]) return n statusCompiled = MibStatus('compiled') statusUntouched = MibStatus('untouched') statusFailed = MibStatus('failed') statusUnprocessed = MibStatus('unprocessed') statusMissing = MibStatus('missing') statusBorrowed = MibStatus('borrowed') class MibCompiler(object): """Top-level, user-facing, composite MIB compiler object. MibCompiler implements high-level MIB transformation processing logic. It executes its actions by calling the following specialized objects: * *readers* - to acquire ASN.1 MIB data * *searchers* - to see if transformed MIB already exists and no processing is necessary * *parser* - to parse ASN.1 MIB into AST * *code generator* - to perform actual MIB transformation * *borrowers* - to fetch pre-transformed MIB if transformation is impossible * *writer* - to store transformed MIB data Required components must be passed to MibCompiler on instantiation. Those components are: *parser*, *codegenerator* and *writer*. Optional components could be set or modified at later phases of MibCompiler life. Unlike singular, required components, optional one can be present in sequences to address many possible sources of data. They are *readers*, *searchers* and *borrowers*. """ indexFile = 'index' def __init__(self, parser, codegen, writer): """Creates an instance of *MibCompiler* class. Args: parser: ASN.1 MIB parser object codegen: MIB transformation object writer: transformed MIB storing object """ self._parser = parser self._codegen = codegen self._symbolgen = SymtableCodeGen() self._writer = writer self._sources = [] self._searchers = [] self._borrowers = [] def addSources(self, *sources): """Add more ASN.1 MIB source repositories. MibCompiler.compile will invoke each of configured source objects in order of their addition asking each to fetch MIB module specified by name. Args: sources: reader object(s) Returns: reference to itself (can be used for call chaining) """ self._sources.extend(sources) debug.logger & debug.flagCompiler and debug.logger( 'current MIB source(s): %s' % ', '.join([str(x) for x in self._sources])) return self def addSearchers(self, *searchers): """Add more transformed MIBs repositories. MibCompiler.compile will invoke each of configured searcher objects in order of their addition asking each if already transformed MIB module already exists and is more recent than specified. Args: searchers: searcher object(s) Returns: reference to itself (can be used for call chaining) """ self._searchers.extend(searchers) debug.logger & debug.flagCompiler and debug.logger( 'current compiled MIBs location(s): %s' % ', '.join([str(x) for x in self._searchers])) return self def addBorrowers(self, *borrowers): """Add more transformed MIBs repositories to borrow MIBs from. Whenever MibCompiler.compile encounters MIB module which neither of the *searchers* can find or fetched ASN.1 MIB module can not be parsed (due to syntax errors), these *borrowers* objects will be invoked in order of their addition asking each if already transformed MIB can be fetched (borrowed). Args: borrowers: borrower object(s) Returns: reference to itself (can be used for call chaining) """ self._borrowers.extend(borrowers) debug.logger & debug.flagCompiler and debug.logger( 'current MIB borrower(s): %s' % ', '.join([str(x) for x in self._borrowers])) return self def _get_system_info(self): try: platform_info = os.uname() except AttributeError: platform_info = ('?',) * 6 try: user_info = getpwuid(os.getuid()) except Exception: user_info = ('?',) * 7 return platform_info, user_info def compile(self, *mibnames, **options): """Transform requested and possibly referred MIBs. The *compile* method should be invoked when *MibCompiler* object is operational meaning at least *sources* are specified. Once called with a MIB module name, *compile* will: * fetch ASN.1 MIB module with given name by calling *sources* * make sure no such transformed MIB already exists (with *searchers*) * parse ASN.1 MIB text with *parser* * perform actual MIB transformation into target format with *code generator* * may attempt to borrow pre-transformed MIB through *borrowers* * write transformed MIB through *writer* The above sequence will be performed for each MIB name given in *mibnames* and may be performed for all MIBs referred to from MIBs being processed. Args: mibnames: list of ASN.1 MIBs names options: options that affect the way PySMI components work Returns: A dictionary of MIB module names processed (keys) and *MibStatus* class instances (values) """ processed = {} parsedMibs = {} failedMibs = {} borrowedMibs = {} builtMibs = {} symbolTableMap = {} mibsToParse = [x for x in mibnames] canonicalMibNames = {} while mibsToParse: mibname = mibsToParse.pop(0) if mibname in parsedMibs: debug.logger & debug.flagCompiler and debug.logger('MIB %s already parsed' % mibname) continue if mibname in failedMibs: debug.logger & debug.flagCompiler and debug.logger('MIB %s already failed' % mibname) continue for source in self._sources: debug.logger & debug.flagCompiler and debug.logger('trying source %s' % source) try: fileInfo, fileData = source.getData(mibname) for mibTree in self._parser.parse(fileData): mibInfo, symbolTable = self._symbolgen.genCode( mibTree, symbolTableMap ) symbolTableMap[mibInfo.name] = symbolTable parsedMibs[mibInfo.name] = fileInfo, mibInfo, mibTree if mibname in failedMibs: del failedMibs[mibname] mibsToParse.extend(mibInfo.imported) if fileInfo.name in mibnames: if mibInfo.name not in canonicalMibNames: canonicalMibNames[mibInfo.name] = [] canonicalMibNames[mibInfo.name].append(fileInfo.name) debug.logger & debug.flagCompiler and debug.logger( '%s (%s) read from %s, immediate dependencies: %s' % ( mibInfo.name, mibname, fileInfo.path, ', '.join(mibInfo.imported) or '')) break except error.PySmiReaderFileNotFoundError: debug.logger & debug.flagCompiler and debug.logger('no %s found at %s' % (mibname, source)) continue except error.PySmiError: exc_class, exc, tb = sys.exc_info() exc.source = source exc.mibname = mibname exc.msg += ' at MIB %s' % mibname debug.logger & debug.flagCompiler and debug.logger('%serror %s from %s' % ( options.get('ignoreErrors') and 'ignoring ' or 'failing on ', exc, source)) failedMibs[mibname] = exc processed[mibname] = statusFailed.setOptions(error=exc) else: exc = error.PySmiError('MIB source %s not found' % mibname) exc.mibname = mibname debug.logger & debug.flagCompiler and debug.logger('no %s found everywhere' % mibname) if mibname not in failedMibs: failedMibs[mibname] = exc if mibname not in processed: processed[mibname] = statusMissing debug.logger & debug.flagCompiler and debug.logger( 'MIBs analyzed %s, MIBs failed %s' % (len(parsedMibs), len(failedMibs))) # # See what MIBs need generating # for mibname in tuple(parsedMibs): fileInfo, mibInfo, mibTree = parsedMibs[mibname] debug.logger & debug.flagCompiler and debug.logger('checking if %s requires updating' % mibname) for searcher in self._searchers: try: searcher.fileExists(mibname, fileInfo.mtime, rebuild=options.get('rebuild')) except error.PySmiFileNotFoundError: debug.logger & debug.flagCompiler and debug.logger( 'no compiled MIB %s available through %s' % (mibname, searcher)) continue except error.PySmiFileNotModifiedError: debug.logger & debug.flagCompiler and debug.logger( 'will be using existing compiled MIB %s found by %s' % (mibname, searcher)) del parsedMibs[mibname] processed[mibname] = statusUntouched break except error.PySmiError: exc_class, exc, tb = sys.exc_info() exc.searcher = searcher exc.mibname = mibname exc.msg += ' at MIB %s' % mibname debug.logger & debug.flagCompiler and debug.logger('error from %s: %s' % (searcher, exc)) continue else: debug.logger & debug.flagCompiler and debug.logger( 'no suitable compiled MIB %s found anywhere' % mibname) if options.get('noDeps') and mibname not in canonicalMibNames: debug.logger & debug.flagCompiler and debug.logger( 'excluding imported MIB %s from code generation' % mibname) del parsedMibs[mibname] processed[mibname] = statusUntouched continue debug.logger & debug.flagCompiler and debug.logger( 'MIBs parsed %s, MIBs failed %s' % (len(parsedMibs), len(failedMibs))) # # Generate code for parsed MIBs # for mibname in parsedMibs.copy(): fileInfo, mibInfo, mibTree = parsedMibs[mibname] debug.logger & debug.flagCompiler and debug.logger('compiling %s read from %s' % (mibname, fileInfo.path)) platform_info, user_info = self._get_system_info() comments = [ 'ASN.1 source %s' % fileInfo.path, 'Produced by %s-%s at %s' % (packageName, packageVersion, time.asctime()), 'On host %s platform %s version %s by user %s' % (platform_info[1], platform_info[0], platform_info[2], user_info[0]), 'Using Python version %s' % sys.version.split('\n')[0] ] try: mibInfo, mibData = self._codegen.genCode( mibTree, symbolTableMap, comments=comments, genTexts=options.get('genTexts'), textFilter=options.get('textFilter') ) builtMibs[mibname] = fileInfo, mibInfo, mibData del parsedMibs[mibname] debug.logger & debug.flagCompiler and debug.logger( '%s read from %s and compiled by %s' % (mibname, fileInfo.path, self._writer)) except error.PySmiError: exc_class, exc, tb = sys.exc_info() exc.handler = self._codegen exc.mibname = mibname exc.msg += ' at MIB %s' % mibname debug.logger & debug.flagCompiler and debug.logger('error from %s: %s' % (self._codegen, exc)) processed[mibname] = statusFailed.setOptions(error=exc) failedMibs[mibname] = exc del parsedMibs[mibname] debug.logger & debug.flagCompiler and debug.logger( 'MIBs built %s, MIBs failed %s' % (len(parsedMibs), len(failedMibs))) # # Try to borrow pre-compiled MIBs for failed ones # for mibname in failedMibs.copy(): if options.get('noDeps') and mibname not in canonicalMibNames: debug.logger & debug.flagCompiler and debug.logger('excluding imported MIB %s from borrowing' % mibname) continue for borrower in self._borrowers: debug.logger & debug.flagCompiler and debug.logger('trying to borrow %s from %s' % (mibname, borrower)) try: fileInfo, fileData = borrower.getData( mibname, genTexts=options.get('genTexts') ) borrowedMibs[mibname] = fileInfo, MibInfo(name=mibname, imported=[]), fileData del failedMibs[mibname] debug.logger & debug.flagCompiler and debug.logger('%s borrowed with %s' % (mibname, borrower)) break except error.PySmiError: debug.logger & debug.flagCompiler and debug.logger('error from %s: %s' % (borrower, sys.exc_info()[1])) debug.logger & debug.flagCompiler and debug.logger( 'MIBs available for borrowing %s, MIBs failed %s' % (len(borrowedMibs), len(failedMibs))) # # See what MIBs need borrowing # for mibname in borrowedMibs.copy(): debug.logger & debug.flagCompiler and debug.logger('checking if failed MIB %s requires borrowing' % mibname) fileInfo, mibInfo, mibData = borrowedMibs[mibname] for searcher in self._searchers: try: searcher.fileExists(mibname, fileInfo.mtime, rebuild=options.get('rebuild')) except error.PySmiFileNotFoundError: debug.logger & debug.flagCompiler and debug.logger( 'no compiled MIB %s available through %s' % (mibname, searcher)) continue except error.PySmiFileNotModifiedError: debug.logger & debug.flagCompiler and debug.logger( 'will be using existing compiled MIB %s found by %s' % (mibname, searcher)) del borrowedMibs[mibname] processed[mibname] = statusUntouched break except error.PySmiError: exc_class, exc, tb = sys.exc_info() exc.searcher = searcher exc.mibname = mibname exc.msg += ' at MIB %s' % mibname debug.logger & debug.flagCompiler and debug.logger('error from %s: %s' % (searcher, exc)) continue else: debug.logger & debug.flagCompiler and debug.logger( 'no suitable compiled MIB %s found anywhere' % mibname) if options.get('noDeps') and mibname not in canonicalMibNames: debug.logger & debug.flagCompiler and debug.logger( 'excluding imported MIB %s from borrowing' % mibname) processed[mibname] = statusUntouched else: debug.logger & debug.flagCompiler and debug.logger('will borrow MIB %s' % mibname) builtMibs[mibname] = borrowedMibs[mibname] processed[mibname] = statusBorrowed.setOptions( path=fileInfo.path, file=fileInfo.file, alias=fileInfo.name ) del borrowedMibs[mibname] debug.logger & debug.flagCompiler and debug.logger( 'MIBs built %s, MIBs failed %s' % (len(builtMibs), len(failedMibs))) # # We could attempt to ignore missing/failed MIBs # if failedMibs and not options.get('ignoreErrors'): debug.logger & debug.flagCompiler and debug.logger('failing with problem MIBs %s' % ', '.join(failedMibs)) for mibname in builtMibs: processed[mibname] = statusUnprocessed return processed debug.logger & debug.flagCompiler and debug.logger( 'proceeding with built MIBs %s, failed MIBs %s' % (', '.join(builtMibs), ', '.join(failedMibs))) # # Store compiled MIBs # for mibname in builtMibs.copy(): fileInfo, mibInfo, mibData = builtMibs[mibname] try: if options.get('writeMibs', True): self._writer.putData( mibname, mibData, dryRun=options.get('dryRun') ) debug.logger & debug.flagCompiler and debug.logger('%s stored by %s' % (mibname, self._writer)) del builtMibs[mibname] if mibname not in processed: processed[mibname] = statusCompiled.setOptions( path=fileInfo.path, file=fileInfo.file, alias=fileInfo.name, oid=mibInfo.oid, oids=mibInfo.oids, identity=mibInfo.identity, revision=mibInfo.revision, enterprise=mibInfo.enterprise, compliance=mibInfo.compliance, ) except error.PySmiError: exc_class, exc, tb = sys.exc_info() exc.handler = self._codegen exc.mibname = mibname exc.msg += ' at MIB %s' % mibname debug.logger & debug.flagCompiler and debug.logger('error %s from %s' % (exc, self._writer)) processed[mibname] = statusFailed.setOptions(error=exc) failedMibs[mibname] = exc del builtMibs[mibname] debug.logger & debug.flagCompiler and debug.logger( 'MIBs modified: %s' % ', '.join([x for x in processed if processed[x] in ('compiled', 'borrowed')])) return processed def buildIndex(self, processedMibs, **options): platform_info, user_info = self._get_system_info() comments = [ 'Produced by %s-%s at %s' % (packageName, packageVersion, time.asctime()), 'On host %s platform %s version %s by user %s' % (platform_info[1], platform_info[0], platform_info[2], user_info[0]), 'Using Python version %s' % sys.version.split('\n')[0] ] try: self._writer.putData( self.indexFile, self._codegen.genIndex( processedMibs, comments=comments, old_index_data=self._writer.getData(self.indexFile) ), dryRun=options.get('dryRun') ) except error.PySmiError: exc_class, exc, tb = sys.exc_info() exc.msg += ' at MIB index %s' % self.indexFile debug.logger & debug.flagCompiler and debug.logger('error %s when building %s' % (exc, self.indexFile)) if options.get('ignoreErrors'): return if hasattr(exc, 'with_traceback'): raise exc.with_traceback(tb) else: raise exc pysmi-0.3.4/pysmi/debug.py0000664006321400632140000000660613411726453017140 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import logging from pysmi import error from pysmi import __version__ flagNone = 0x0000 flagSearcher = 0x0001 flagReader = 0x0002 flagLexer = 0x0004 flagParser = 0x0008 flagGrammar = 0x0010 flagCodegen = 0x0020 flagWriter = 0x0040 flagCompiler = 0x0080 flagBorrower = 0x0100 flagAll = 0xffff flagMap = { 'searcher': flagSearcher, 'reader': flagReader, 'lexer': flagLexer, 'parser': flagParser, 'grammar': flagGrammar, 'codegen': flagCodegen, 'writer': flagWriter, 'compiler': flagCompiler, 'borrower': flagBorrower, 'all': flagAll } class Printer(object): def __init__(self, logger=None, handler=None, formatter=None): if logger is None: logger = logging.getLogger('pysmi') logger.setLevel(logging.DEBUG) if handler is None: handler = logging.StreamHandler() if formatter is None: formatter = logging.Formatter('%(asctime)s %(name)s: %(message)s') handler.setFormatter(formatter) handler.setLevel(logging.DEBUG) logger.addHandler(handler) self.__logger = logger def __call__(self, msg): self.__logger.debug(msg) def __str__(self): return '' def getCurrentLogger(self): return self.__logger if hasattr(logging, 'NullHandler'): NullHandler = logging.NullHandler else: # Python 2.6 and older class NullHandler(logging.Handler): def emit(self, record): pass class Debug(object): defaultPrinter = None def __init__(self, *flags, **options): self._flags = flagNone if options.get('printer') is not None: self._printer = options.get('printer') elif self.defaultPrinter is not None: self._printer = self.defaultPrinter else: if 'loggerName' in options: # route our logs to parent logger self._printer = Printer( logger=logging.getLogger(options['loggerName']), handler=NullHandler() ) else: self._printer = Printer() self('running pysmi version %s' % __version__) for flag in flags: inverse = flag and flag[0] in ('!', '~') if inverse: flag = flag[1:] try: if inverse: self._flags &= ~flagMap[flag] else: self._flags |= flagMap[flag] except KeyError: raise error.PySmiError('bad debug flag %s' % flag) self('debug category \'%s\' %s' % (flag, inverse and 'disabled' or 'enabled')) def __str__(self): return 'logger %s, flags %x' % (self._printer, self._flags) def __call__(self, msg): self._printer(msg) def __and__(self, flag): return self._flags & flag def __rand__(self, flag): return flag & self._flags def getCurrentPrinter(self): return self._printer def getCurrentLogger(self): return self._printer and self._printer.getCurrentLogger() or None # This will yield false from bitwise and with a flag, and save # on unnecessary calls logger = 0 def setLogger(l): global logger logger = l pysmi-0.3.4/pysmi/error.py0000664006321400632140000000330413411726453017173 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # # Package exception model: # Here we subclass base Python exception overriding its constructor to # accomodate error message string as its first parameter and an open # set of keyword arguments that become exception object attributes. # While exception object is bubbling up the call stack, intermediate # exception handlers may insert their own attributes into exception # object. # class PySmiError(Exception): def __init__(self, *args, **kwargs): Exception.__init__(self, *args) self.msg = args and args[0] or '' for k in kwargs: setattr(self, k, kwargs[k]) def __repr__(self): return '%s(%s)' % (self.__class__.__name__, ', '.join( ['%s=%r' % (k, getattr(self, k)) for k in dir(self) if k[0] != '_' and k != 'args'])) def __str__(self): return self.msg class PySmiLexerError(PySmiError): lineno = '?' def __str__(self): return self.msg + ', line %s' % self.lineno class PySmiParserError(PySmiLexerError): pass class PySmiSyntaxError(PySmiParserError): pass class PySmiSearcherError(PySmiError): pass class PySmiFileNotModifiedError(PySmiSearcherError): pass class PySmiFileNotFoundError(PySmiSearcherError): pass class PySmiReaderError(PySmiError): pass class PySmiReaderFileNotModifiedError(PySmiReaderError): pass class PySmiReaderFileNotFoundError(PySmiReaderError): pass class PySmiCodegenError(PySmiError): pass class PySmiSemanticError(PySmiCodegenError): pass class PySmiWriterError(PySmiError): pass pysmi-0.3.4/pysmi/lexer/0000775006321400632140000000000013454602625016610 5ustar ietingofietingof00000000000000pysmi-0.3.4/pysmi/lexer/__init__.py0000664006321400632140000000030213411726453020713 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.lexer.smi import SmiV2Lexer pysmi-0.3.4/pysmi/lexer/base.py0000664006321400632140000000036313411726453020075 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # class AbstractLexer(object): def reset(self): raise NotImplementedError() pysmi-0.3.4/pysmi/lexer/smi.py0000664006321400632140000002716013411726453017757 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys import re import ply.lex as lex from pysmi.lexer.base import AbstractLexer from pysmi import error from pysmi import debug UNSIGNED32_MAX = 4294967295 UNSIGNED64_MAX = 18446744073709551615 LEX_VERSION = [int(x) for x in lex.__version__.split('.')] # Do not overload single lexer methods - overload all or none of them! # noinspection PySingleQuotedDocstring,PyMethodMayBeStatic,PyIncorrectDocstring class SmiV2Lexer(AbstractLexer): reserved_words = [ 'ACCESS', 'AGENT-CAPABILITIES', 'APPLICATION', 'AUGMENTS', 'BEGIN', 'BITS', 'CONTACT-INFO', 'CREATION-REQUIRES', 'Counter', 'Counter32', 'Counter64', 'DEFINITIONS', 'DEFVAL', 'DESCRIPTION', 'DISPLAY-HINT', 'END', 'ENTERPRISE', 'EXTENDS', 'FROM', 'GROUP', 'Gauge', 'Gauge32', 'IDENTIFIER', 'IMPLICIT', 'IMPLIED', 'IMPORTS', 'INCLUDES', 'INDEX', 'INSTALL-ERRORS', 'INTEGER', 'Integer32', 'IpAddress', 'LAST-UPDATED', 'MANDATORY-GROUPS', 'MAX-ACCESS', 'MIN-ACCESS', 'MODULE', 'MODULE-COMPLIANCE', 'MODULE-IDENTITY', 'NOTIFICATION-GROUP', 'NOTIFICATION-TYPE', 'NOTIFICATIONS', 'OBJECT', 'OBJECT-GROUP', 'OBJECT-IDENTITY', 'OBJECT-TYPE', 'OBJECTS', 'OCTET', 'OF', 'ORGANIZATION', 'Opaque', 'PIB-ACCESS', 'PIB-DEFINITIONS', 'PIB-INDEX', 'PIB-MIN-ACCESS', 'PIB-REFERENCES', 'PIB-TAG', 'POLICY-ACCESS', 'PRODUCT-RELEASE', 'REFERENCE', 'REVISION', 'SEQUENCE', 'SIZE', 'STATUS', 'STRING', 'SUBJECT-CATEGORIES', 'SUPPORTS', 'SYNTAX', 'TEXTUAL-CONVENTION', 'TimeTicks', 'TRAP-TYPE', 'UNIQUENESS', 'UNITS', 'UNIVERSAL', 'Unsigned32', 'VALUE', 'VARIABLES', 'VARIATION', 'WRITE-SYNTAX' ] reserved = {} for w in reserved_words: reserved[w] = w.replace('-', '_').upper() # hack to support SMIv1 if w == 'Counter': reserved[w] = 'COUNTER32' elif w == 'Gauge': reserved[w] = 'GAUGE32' forbidden_words = [ 'ABSENT', 'ANY', 'BIT', 'BOOLEAN', 'BY', 'COMPONENT', 'COMPONENTS', 'DEFAULT', 'DEFINED', 'ENUMERATED', 'EXPLICIT', 'EXTERNAL', 'FALSE', 'MAX', 'MIN', 'MINUS-INFINITY', 'NULL', 'OPTIONAL', 'PLUS-INFINITY', 'PRESENT', 'PRIVATE', 'REAL', 'SET', 'TAGS', 'TRUE', 'WITH' ] # Token names required! tokens = list(set([ 'BIN_STRING', 'CHOICE', 'COLON_COLON_EQUAL', 'DOT_DOT', 'EXPORTS', 'HEX_STRING', 'LOWERCASE_IDENTIFIER', 'MACRO', 'NEGATIVENUMBER', 'NEGATIVENUMBER64', 'NUMBER', 'NUMBER64', 'QUOTED_STRING', 'UPPERCASE_IDENTIFIER', ] + list(reserved.values()) )) states = ( ('macro', 'exclusive'), ('choice', 'exclusive'), ('exports', 'exclusive'), ('comment', 'exclusive'), ) literals = '[]{}():;,-.|' t_DOT_DOT = r'\.\.' t_COLON_COLON_EQUAL = r'::=' t_ignore = ' \t' def __init__(self, tempdir=''): self._tempdir = tempdir self.lexer = None self.reset() def reset(self): if LEX_VERSION < [3, 0]: self.lexer = lex.lex(module=self, reflags=re.DOTALL, outputdir=self._tempdir, debug=False) else: if debug.logger & debug.flagLexer: logger = debug.logger.getCurrentLogger() else: logger = lex.NullLogger() if debug.logger & debug.flagGrammar: debuglogger = debug.logger.getCurrentLogger() else: debuglogger = None self.lexer = lex.lex(module=self, reflags=re.DOTALL, outputdir=self._tempdir, debuglog=debuglogger, errorlog=logger) def t_newline(self, t): r'\r\n|\n|\r' t.lexer.lineno += 1 # Skipping MACRO def t_MACRO(self, t): r'MACRO' t.lexer.begin('macro') return t def t_macro_newline(self, t): r'\r\n|\n|\r' t.lexer.lineno += 1 def t_macro_END(self, t): r'END' t.lexer.begin('INITIAL') return t def t_macro_body(self, t): r'.+?(?=END)' pass # Skipping EXPORTS def t_EXPORTS(self, t): r'EXPORTS' t.lexer.begin('exports') return t def t_exports_newline(self, t): r'\r\n|\n|\r' t.lexer.lineno += 1 def t_exports_end(self, t): r';' t.lexer.begin('INITIAL') def t_exports_body(self, t): r'[^;]+' pass # Skipping CHOICE def t_CHOICE(self, t): r'CHOICE' t.lexer.begin('choice') return t def t_choice_newline(self, t): r'\r\n|\n|\r' t.lexer.lineno += 1 def t_choice_end(self, t): r'\}' t.lexer.begin('INITIAL') def t_choice_body(self, t): r'[^\}]+' pass # Comment handling def t_begin_comment(self, t): r'--' t.lexer.begin('comment') def t_comment_newline(self, t): r'\r\n|\n|\r' t.lexer.lineno += 1 t.lexer.begin('INITIAL') # def t_comment_end(self, t): # r'--' # t.lexer.begin('INITIAL') def t_comment_body(self, t): r'[^\r\n]+' pass def t_UPPERCASE_IDENTIFIER(self, t): r'[A-Z][-a-zA-z0-9]*' if t.value in self.forbidden_words: raise error.PySmiLexerError("%s is forbidden" % t.value, lineno=t.lineno) if t.value[-1] == '-': raise error.PySmiLexerError("Identifier should not end with '-': %s" % t.value, lineno=t.lineno) t.type = self.reserved.get(t.value, 'UPPERCASE_IDENTIFIER') return t def t_LOWERCASE_IDENTIFIER(self, t): r'[0-9]*[a-z][-a-zA-z0-9]*' if t.value[-1] == '-': raise error.PySmiLexerError("Identifier should not end with '-': %s" % t.value, lineno=t.lineno) return t def t_NUMBER(self, t): r'-?[0-9]+' t.value = int(t.value) neg = 0 if t.value < 0: neg = 1 val = abs(t.value) if val <= UNSIGNED32_MAX: if neg: t.type = 'NEGATIVENUMBER' elif val <= UNSIGNED64_MAX: if neg: t.type = 'NEGATIVENUMBER64' else: t.type = 'NUMBER64' else: raise error.PySmiLexerError("Number %s is too big" % t.value, lineno=t.lineno) return t def t_BIN_STRING(self, t): r'\'[01]*\'[bB]' value = t.value[1:-2] while value and value[0] == '0' and len(value) % 8: value = value[1:] # XXX raise in strict mode # if len(value) % 8: # raise error.PySmiLexerError("Number of 0s and 1s have to divide by 8 in binary string %s" % t.value, lineno=t.lineno) return t def t_HEX_STRING(self, t): r'\'[0-9a-fA-F]*\'[hH]' value = t.value[1:-2] while value and value[0] == '0' and len(value) % 2: value = value[1:] # XXX raise in strict mode # if len(value) % 2: # raise error.PySmiLexerError("Number of symbols have to be even in hex string %s" % t.value, lineno=t.lineno) return t def t_QUOTED_STRING(self, t): r'\"[^\"]*\"' t.lexer.lineno += len(re.findall(r'\r\n|\n|\r', t.value)) return t def t_error(self, t): raise error.PySmiLexerError( "Illegal character '%s', %s characters left unparsed at this stage" % (t.value[0], len(t.value) - 1), lineno=t.lineno) # t.lexer.skip(1) class SupportSmiV1Keywords(object): @staticmethod def reserved(): reserved_words = [ 'ACCESS', 'AGENT-CAPABILITIES', 'APPLICATION', 'AUGMENTS', 'BEGIN', 'BITS', 'CONTACT-INFO', 'CREATION-REQUIRES', 'Counter', 'Counter32', 'Counter64', 'DEFINITIONS', 'DEFVAL', 'DESCRIPTION', 'DISPLAY-HINT', 'END', 'ENTERPRISE', 'EXTENDS', 'FROM', 'GROUP', 'Gauge', 'Gauge32', 'IDENTIFIER', 'IMPLICIT', 'IMPLIED', 'IMPORTS', 'INCLUDES', 'INDEX', 'INSTALL-ERRORS', 'INTEGER', 'Integer32', 'IpAddress', 'LAST-UPDATED', 'MANDATORY-GROUPS', 'MAX-ACCESS', 'MIN-ACCESS', 'MODULE', 'MODULE-COMPLIANCE', 'MAX', 'MODULE-IDENTITY', 'NetworkAddress', 'NOTIFICATION-GROUP', 'NOTIFICATION-TYPE', 'NOTIFICATIONS', 'OBJECT', 'OBJECT-GROUP', 'OBJECT-IDENTITY', 'OBJECT-TYPE', 'OBJECTS', 'OCTET', 'OF', 'ORGANIZATION', 'Opaque', 'PIB-ACCESS', 'PIB-DEFINITIONS', 'PIB-INDEX', 'PIB-MIN-ACCESS', 'PIB-REFERENCES', 'PIB-TAG', 'POLICY-ACCESS', 'PRODUCT-RELEASE', 'REFERENCE', 'REVISION', 'SEQUENCE', 'SIZE', 'STATUS', 'STRING', 'SUBJECT-CATEGORIES', 'SUPPORTS', 'SYNTAX', 'TEXTUAL-CONVENTION', 'TimeTicks', 'TRAP-TYPE', 'UNIQUENESS', 'UNITS', 'UNIVERSAL', 'Unsigned32', 'VALUE', 'VARIABLES', 'VARIATION', 'WRITE-SYNTAX' ] reserved = {} for w in reserved_words: reserved[w] = w.replace('-', '_').upper() # hack to support SMIv1 if w == 'Counter': reserved[w] = 'COUNTER32' elif w == 'Gauge': reserved[w] = 'GAUGE32' return reserved @staticmethod def forbidden_words(): return [ 'ABSENT', 'ANY', 'BIT', 'BOOLEAN', 'BY', 'COMPONENT', 'COMPONENTS', 'DEFAULT', 'DEFINED', 'ENUMERATED', 'EXPLICIT', 'EXTERNAL', 'FALSE', 'MIN', 'MINUS-INFINITY', 'NULL', 'OPTIONAL', 'PLUS-INFINITY', 'PRESENT', 'PRIVATE', 'REAL', 'SET', 'TAGS', 'TRUE', 'WITH' ] @staticmethod def tokens(): # Token names required! tokens = [ 'BIN_STRING', 'CHOICE', 'COLON_COLON_EQUAL', 'DOT_DOT', 'EXPORTS', 'HEX_STRING', 'LOWERCASE_IDENTIFIER', 'MACRO', 'NEGATIVENUMBER', 'NEGATIVENUMBER64', 'NUMBER', 'NUMBER64', 'QUOTED_STRING', 'UPPERCASE_IDENTIFIER', ] tokens += list(SupportSmiV1Keywords.reserved().values()) return list(set(tokens)) relaxedGrammar = { 'supportSmiV1Keywords': [ SupportSmiV1Keywords.reserved, SupportSmiV1Keywords.forbidden_words, SupportSmiV1Keywords.tokens ], 'supportIndex': [], 'commaAtTheEndOfImport': [], 'commaAtTheEndOfSequence': [], 'mixOfCommasAndSpaces': [], 'uppercaseIdentifier': [], 'lowcaseIdentifier': [], 'curlyBracesAroundEnterpriseInTrap': [], 'noCells': [] } def lexerFactory(**grammarOptions): classAttr = {} for option in grammarOptions: if grammarOptions[option]: if option not in relaxedGrammar: raise error.PySmiError('Unknown lexer relaxation option: %s' % option) for func in relaxedGrammar[option]: if sys.version_info[0] > 2: classAttr[func.__name__] = func() else: classAttr[func.func_name] = func() return type('SmiLexer', (SmiV2Lexer,), classAttr) pysmi-0.3.4/pysmi/mibinfo.py0000664006321400632140000000146613411726453017474 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # class MibInfo(object): #: actual MIB name name = '' #: possible alternative to MIB name alias = '' #: URL to MIB file path = '' #: MIB file name file = '' #: MIB file modification time mtime = 0 #: module OID oid = '' #: MIB revision as `datetime` revision = None #: all OIDs defined in this module oids = () #: MODULE-IDENTITY OID identity = '' #: Enterprise OID enterprise = () #: MODULE-COMPLIANCE OIDs compliance = () #: imported MIB names imported = () def __init__(self, **kwargs): for k in kwargs: setattr(self, k, kwargs[k]) pysmi-0.3.4/pysmi/parser/0000775006321400632140000000000013454602625016765 5ustar ietingofietingof00000000000000pysmi-0.3.4/pysmi/parser/__init__.py0000664006321400632140000000054013411726453021074 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.parser.smiv1 import SmiV1Parser from pysmi.parser.smiv1compat import SmiV1CompatParser, SmiStarParser from pysmi.parser.smiv2 import SmiV2Parser from pysmi.parser.null import NullParser pysmi-0.3.4/pysmi/parser/base.py0000664006321400632140000000047613411726453020257 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # class AbstractParser(object): def reset(self): raise NotImplementedError() def parse(self, data, **kwargs): raise NotImplementedError() pysmi-0.3.4/pysmi/parser/dialect.py0000664006321400632140000000116613411726453020747 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # # # Preconfigured sets of parser options. # Individual options could be used in certain combinations. # smiV2 = {} smiV1 = smiV2.copy() smiV1.update( supportSmiV1Keywords=True, supportIndex=True ) smiV1Relaxed = smiV1.copy() smiV1Relaxed.update( commaAtTheEndOfImport=True, commaAtTheEndOfSequence=True, mixOfCommasAndSpaces=True, uppercaseIdentifier=True, lowcaseIdentifier=True, curlyBracesAroundEnterpriseInTrap=True, noCells=True ) pysmi-0.3.4/pysmi/parser/null.py0000664006321400632140000000061413411726453020311 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.parser.base import AbstractParser class NullParser(AbstractParser): def __init__(self, startSym='mibFile', tempdir=''): pass def reset(self): pass def parse(self, data, **kwargs): return [] pysmi-0.3.4/pysmi/parser/smi.py0000664006321400632140000014062413411726453020135 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os import sys import ply.yacc as yacc from pysmi.lexer.smi import lexerFactory from pysmi.parser.base import AbstractParser from pysmi import error from pysmi import debug YACC_VERSION = [int(x) for x in yacc.__version__.split('.')] # noinspection PyMethodMayBeStatic,PyIncorrectDocstring class SmiV2Parser(AbstractParser): defaultLexer = lexerFactory() def __init__(self, startSym='mibFile', tempdir=''): if tempdir: tempdir = os.path.join(tempdir, startSym) try: os.makedirs(tempdir) except OSError: if sys.exc_info()[1].errno != 17: raise error.PySmiError('Failed to create cache directory %s: %s' % (tempdir, sys.exc_info()[1])) self.lexer = self.defaultLexer(tempdir=tempdir) # tokens are required for parser self.tokens = self.lexer.tokens if YACC_VERSION < [3, 0]: self.parser = yacc.yacc(module=self, start=startSym, write_tables=bool(tempdir), debug=False, outputdir=tempdir) else: if debug.logger & debug.flagParser: logger = debug.logger.getCurrentLogger() else: logger = yacc.NullLogger() if debug.logger & debug.flagGrammar: debuglogger = debug.logger.getCurrentLogger() else: debuglogger = None self.parser = yacc.yacc(module=self, start=startSym, write_tables=bool(tempdir), debug=False, outputdir=tempdir, debuglog=debuglogger, errorlog=logger) def reset(self): # Ply requires lexer reinitialization for (at least) resetting lineno self.lexer.reset() def parse(self, data, **kwargs): debug.logger & debug.flagParser and debug.logger( 'source MIB size is %s characters, first 50 characters are "%s..."' % (len(data), data[:50])) ast = self.parser.parse(data, lexer=self.lexer.lexer) self.reset() if ast and ast[0] == 'mibFile' and ast[1]: # mibfile is not empty return ast[1] else: return [] # # SMIv2 grammar follows # def p_mibFile(self, p): """mibFile : modules | empty""" p[0] = ('mibFile', p[1]) def p_modules(self, p): """modules : modules module | module""" n = len(p) if n == 3: p[0] = p[1] + [p[2]] elif n == 2: p[0] = [p[1]] def p_module(self, p): """module : moduleName moduleOid DEFINITIONS COLON_COLON_EQUAL BEGIN exportsClause linkagePart declarationPart END""" p[0] = (p[1], # name p[2], # oid p[7], # linkage (imports) p[8]) # declaration def p_moduleOid(self, p): """moduleOid : '{' objectIdentifier '}' | empty""" n = len(p) if n == 4: p[0] = p[2] def p_linkagePart(self, p): """linkagePart : linkageClause | empty""" if p[1]: p[0] = p[1] def p_linkageClause(self, p): """linkageClause : IMPORTS importPart ';'""" p[0] = p[2] def p_exportsClause(self, p): """exportsClause : EXPORTS | empty""" def p_importPart(self, p): """importPart : imports | empty""" # libsmi: TODO: ``IMPORTS ;'' allowed? refer ASN.1! if p[1]: importDict = {} for imp in p[1]: # don't do just dict() because moduleNames may be repeated fromModule, symbols = imp if fromModule in importDict: importDict[fromModule] += symbols else: importDict[fromModule] = symbols p[0] = importDict def p_imports(self, p): """imports : imports import | import""" n = len(p) if n == 3: p[0] = p[1] + [p[2]] elif n == 2: p[0] = [p[1]] def p_import(self, p): """import : importIdentifiers FROM moduleName""" # libsmi: TODO: multiple clauses with same moduleName allowed? # I guess so. refer ASN.1! p[0] = (p[3], # moduleName p[1]) # ids def p_importIdentifiers(self, p): """importIdentifiers : importIdentifiers ',' importIdentifier | importIdentifier""" n = len(p) if n == 4: p[0] = p[1] + [p[3]] elif n == 2: p[0] = [p[1]] # Note that some named types must not be imported, REF:RFC1902,590 def p_importIdentifier(self, p): """importIdentifier : LOWERCASE_IDENTIFIER | UPPERCASE_IDENTIFIER | importedKeyword""" p[0] = p[1] def p_importedKeyword(self, p): """importedKeyword : importedSMIKeyword | BITS | INTEGER32 | IPADDRESS | MANDATORY_GROUPS | MODULE_COMPLIANCE | MODULE_IDENTITY | OBJECT_GROUP | OBJECT_IDENTITY | OBJECT_TYPE | OPAQUE | TEXTUAL_CONVENTION | TIMETICKS | UNSIGNED32""" p[0] = p[1] def p_importedSMIKeyword(self, p): """importedSMIKeyword : AGENT_CAPABILITIES | COUNTER32 | COUNTER64 | GAUGE32 | NOTIFICATION_GROUP | NOTIFICATION_TYPE | TRAP_TYPE""" p[0] = p[1] def p_moduleName(self, p): """moduleName : UPPERCASE_IDENTIFIER""" p[0] = p[1] def p_declarationPart(self, p): """declarationPart : declarations | empty""" if p[1]: p[0] = p[1] def p_declarations(self, p): """declarations : declarations declaration | declaration""" n = len(p) if n == 3: p[0] = p[1] + [p[2]] elif n == 2: p[0] = [p[1]] def p_declaration(self, p): """declaration : typeDeclaration | valueDeclaration | objectIdentityClause | objectTypeClause | trapTypeClause | notificationTypeClause | moduleIdentityClause | moduleComplianceClause | objectGroupClause | notificationGroupClause | agentCapabilitiesClause | macroClause""" if p[1]: p[0] = p[1] def p_macroClause(self, p): """macroClause : macroName MACRO END""" def p_macroName(self, p): """macroName : MODULE_IDENTITY | OBJECT_TYPE | TRAP_TYPE | NOTIFICATION_TYPE | OBJECT_IDENTITY | TEXTUAL_CONVENTION | OBJECT_GROUP | NOTIFICATION_GROUP | MODULE_COMPLIANCE | AGENT_CAPABILITIES""" def p_choiceClause(self, p): """choiceClause : CHOICE """ # libsmi: The only ASN.1 value declarations are for OIDs, REF:RFC1902,491. def p_fuzzy_lowercase_identifier(self, p): """fuzzy_lowercase_identifier : LOWERCASE_IDENTIFIER | UPPERCASE_IDENTIFIER""" p[0] = p[1] def p_valueDeclaration(self, p): """valueDeclaration : fuzzy_lowercase_identifier OBJECT IDENTIFIER COLON_COLON_EQUAL '{' objectIdentifier '}'""" p[0] = ('valueDeclaration', p[1], # id p[6]) # objectIdentifier def p_typeDeclaration(self, p): """typeDeclaration : typeName COLON_COLON_EQUAL typeDeclarationRHS""" p[0] = ('typeDeclaration', p[1], # name p[3]) # declarationRHS def p_typeName(self, p): """typeName : UPPERCASE_IDENTIFIER | typeSMI""" p[0] = p[1] def p_typeSMI(self, p): """typeSMI : typeSMIandSPPI | typeSMIonly""" p[0] = p[1] def p_typeSMIandSPPI(self, p): """typeSMIandSPPI : IPADDRESS | TIMETICKS | OPAQUE | INTEGER32 | UNSIGNED32""" p[0] = p[1] def p_typeSMIonly(self, p): """typeSMIonly : COUNTER32 | GAUGE32 | COUNTER64""" p[0] = p[1] def p_typeDeclarationRHS(self, p): """typeDeclarationRHS : Syntax | TEXTUAL_CONVENTION DisplayPart STATUS Status DESCRIPTION Text ReferPart SYNTAX Syntax | choiceClause""" if p[1]: if p[1] == 'TEXTUAL-CONVENTION': p[0] = ('typeDeclarationRHS', p[2], # display p[4], # status (p[5], p[6]), # description p[7], # reference p[9]) # syntax else: p[0] = ('typeDeclarationRHS', p[1]) # ignore the choiceClause def p_conceptualTable(self, p): """conceptualTable : SEQUENCE OF row""" p[0] = ('conceptualTable', p[3]) def p_row(self, p): """row : UPPERCASE_IDENTIFIER""" # libsmi: TODO: this must be an entryType p[0] = ('row', p[1]) def p_entryType(self, p): """entryType : SEQUENCE '{' sequenceItems '}'""" p[0] = (p[1], p[3]) def p_sequenceItems(self, p): """sequenceItems : sequenceItems ',' sequenceItem | sequenceItem""" # libsmi: TODO: might this list be emtpy? n = len(p) if n == 4: p[0] = p[1] + [p[3]] elif n == 2: p[0] = [p[1]] def p_sequenceItem(self, p): """sequenceItem : LOWERCASE_IDENTIFIER sequenceSyntax""" p[0] = (p[1], p[2]) def p_Syntax(self, p): """Syntax : ObjectSyntax | BITS '{' NamedBits '}'""" # libsmi: TODO: standalone `BITS' ok? seen in RMON2-MIB # libsmi: -> no, it's only allowed in a SEQUENCE {...} n = len(p) if n == 2: p[0] = p[1] elif n == 5: p[0] = (p[1], p[3]) def p_sequenceSyntax(self, p): """sequenceSyntax : BITS | UPPERCASE_IDENTIFIER anySubType | sequenceObjectSyntax""" p[0] = p[1] # no subtype or complex syntax supported def p_NamedBits(self, p): """NamedBits : NamedBits ',' NamedBit | NamedBit""" n = len(p) if n == 4: p[0] = p[1] + [p[3]] elif n == 2: p[0] = [p[1]] def p_NamedBit(self, p): """NamedBit : LOWERCASE_IDENTIFIER '(' NUMBER ')'""" p[0] = (p[1], p[3]) def p_objectIdentityClause(self, p): """objectIdentityClause : LOWERCASE_IDENTIFIER OBJECT_IDENTITY STATUS Status DESCRIPTION Text ReferPart COLON_COLON_EQUAL '{' objectIdentifier '}'""" p[0] = ('objectIdentityClause', p[1], # id # p[2], # OBJECT_IDENTITY p[4], # status (p[5], p[6]), # description p[7], # reference p[10]) # objectIdentifier def p_objectTypeClause(self, p): """objectTypeClause : LOWERCASE_IDENTIFIER OBJECT_TYPE SYNTAX Syntax UnitsPart MaxOrPIBAccessPart STATUS Status descriptionClause ReferPart IndexPart MibIndex DefValPart COLON_COLON_EQUAL '{' ObjectName '}'""" p[0] = ('objectTypeClause', p[1], # id # p[2], # OBJECT_TYPE p[4], # syntax p[5], # UnitsPart p[6], # MaxOrPIBAccessPart p[8], # status p[9], # descriptionClause p[10], # reference p[11], # augmentions p[12], # index p[13], # DefValPart p[16]) # ObjectName def p_descriptionClause(self, p): """descriptionClause : DESCRIPTION Text | empty""" if p[1]: p[0] = (p[1], p[2]) def p_trapTypeClause(self, p): """trapTypeClause : fuzzy_lowercase_identifier TRAP_TYPE ENTERPRISE objectIdentifier VarPart DescrPart ReferPart COLON_COLON_EQUAL NUMBER""" # libsmi: TODO: range of number? p[0] = ('trapTypeClause', p[1], # fuzzy_lowercase_identifier # p[2], # TRAP_TYPE p[4], # objectIdentifier p[5], # VarPart p[6], # description p[7], # reference p[9]) # NUMBER def p_VarPart(self, p): """VarPart : VARIABLES '{' VarTypes '}' | empty""" p[0] = p[1] and p[3] or [] def p_VarTypes(self, p): """VarTypes : VarTypes ',' VarType | VarType""" n = len(p) if n == 4: p[0] = ('VarTypes', p[1][1] + [p[3]]) elif n == 2: p[0] = ('VarTypes', [p[1]]) def p_VarType(self, p): """VarType : ObjectName""" p[0] = p[1][1][0] def p_DescrPart(self, p): """DescrPart : DESCRIPTION Text | empty""" if p[1]: p[0] = (p[1], p[2]) def p_MaxOrPIBAccessPart(self, p): """MaxOrPIBAccessPart : MaxAccessPart | empty""" if p[1]: p[0] = p[1] def p_MaxAccessPart(self, p): """MaxAccessPart : MAX_ACCESS Access | ACCESS Access""" p[0] = ('MaxAccessPart', p[2]) def p_notificationTypeClause(self, p): """notificationTypeClause : LOWERCASE_IDENTIFIER NOTIFICATION_TYPE NotificationObjectsPart STATUS Status DESCRIPTION Text ReferPart COLON_COLON_EQUAL '{' NotificationName '}'""" p[0] = ('notificationTypeClause', p[1], # id # p[2], # NOTIFICATION_TYPE p[3], # NotificationObjectsPart p[5], # status (p[6], p[7]), # description p[8], # reference p[11]) # NotificationName aka objectIdentifier def p_moduleIdentityClause(self, p): """moduleIdentityClause : LOWERCASE_IDENTIFIER MODULE_IDENTITY SubjectCategoriesPart LAST_UPDATED ExtUTCTime ORGANIZATION Text CONTACT_INFO Text DESCRIPTION Text RevisionPart COLON_COLON_EQUAL '{' objectIdentifier '}'""" p[0] = ('moduleIdentityClause', p[1], # id # p[2], # MODULE_IDENTITY # XXX p[3], # SubjectCategoriesPart (p[4], p[5]), # last updated (p[6], p[7]), # organization (p[8], p[9]), # contact info (p[10], p[11]), # description p[12], # RevisionPart p[15]) # objectIdentifier # Subject categories: RFC3159 def p_SubjectCategoriesPart(self, p): """SubjectCategoriesPart : SUBJECT_CATEGORIES '{' SubjectCategories '}' | empty""" # if p[1]: # p[0] = (p[1], p[3]) def p_SubjectCategories(self, p): """SubjectCategories : CategoryIDs""" # p[0] = p[1] def p_CategoryIDs(self, p): """CategoryIDs : CategoryIDs ',' CategoryID | CategoryID""" # n = len(p) # if n == 4: # p[0] = ('CategoryIDs', p[1][1] + [p[3]]) # elif n == 2: # p[0] = ('CategoryIDs', [p[1]]) def p_CategoryID(self, p): """CategoryID : LOWERCASE_IDENTIFIER '(' NUMBER ')' | LOWERCASE_IDENTIFIER""" # n = len(p) # if n == 2: # p[0] = ('CategoryID', p[1]) # elif n == 5: # p[0] = ('CategoryID', p[3]) # ...subject categories def p_ObjectSyntax(self, p): """ObjectSyntax : SimpleSyntax | conceptualTable | row | entryType | ApplicationSyntax | typeTag SimpleSyntax""" n = len(p) if n == 2: p[0] = p[1] elif n == 3: p[0] = p[2] def p_typeTag(self, p): """typeTag : '[' APPLICATION NUMBER ']' IMPLICIT | '[' UNIVERSAL NUMBER ']' IMPLICIT""" def p_sequenceObjectSyntax(self, p): """sequenceObjectSyntax : sequenceSimpleSyntax | sequenceApplicationSyntax""" # libsmi: TO DO: add to this rule conceptualTable, row, entryType p[0] = p[1] def p_valueofObjectSyntax(self, p): """valueofObjectSyntax : valueofSimpleSyntax""" p[0] = p[1] def p_SimpleSyntax(self, p): """SimpleSyntax : INTEGER | INTEGER integerSubType | INTEGER enumSpec | INTEGER32 | INTEGER32 integerSubType | UPPERCASE_IDENTIFIER enumSpec | UPPERCASE_IDENTIFIER integerSubType | OCTET STRING | OCTET STRING octetStringSubType | UPPERCASE_IDENTIFIER octetStringSubType | OBJECT IDENTIFIER anySubType""" n = len(p) if n == 2: p[0] = ('SimpleSyntax', p[1]) elif n == 3: if p[1] == 'OCTET': p[0] = ('SimpleSyntax', p[1] + ' ' + p[2]) else: p[0] = ('SimpleSyntax', p[1], p[2]) elif n == 4: p[0] = ('SimpleSyntax', p[1] + ' ' + p[2], p[3]) def p_valueofSimpleSyntax(self, p): """valueofSimpleSyntax : NUMBER | NEGATIVENUMBER | NUMBER64 | NEGATIVENUMBER64 | HEX_STRING | BIN_STRING | LOWERCASE_IDENTIFIER | QUOTED_STRING | '{' objectIdentifier_defval '}'""" # libsmi for objectIdentifier_defval: # This is only for some MIBs with invalid numerical # OID notation for DEFVALs. We DO NOT parse them # correctly. We just don't want to produce a # parser error. n = len(p) if n == 2: p[0] = p[1] elif n == 4: # XXX pass def p_sequenceSimpleSyntax(self, p): """sequenceSimpleSyntax : INTEGER anySubType | INTEGER32 anySubType | OCTET STRING anySubType | OBJECT IDENTIFIER anySubType""" n = len(p) if n == 3: p[0] = p[1] # XXX not supporting subtypes here elif n == 4: p[0] = p[1] + ' ' + p[2] # XXX not supporting subtypes here def p_ApplicationSyntax(self, p): """ApplicationSyntax : IPADDRESS anySubType | COUNTER32 | COUNTER32 integerSubType | GAUGE32 | GAUGE32 integerSubType | UNSIGNED32 | UNSIGNED32 integerSubType | TIMETICKS anySubType | OPAQUE | OPAQUE octetStringSubType | COUNTER64 | COUNTER64 integerSubType""" # COUNTER32 and COUNTER64 was with anySubType in libsmi n = len(p) if n == 2: p[0] = ('ApplicationSyntax', p[1]) elif n == 3: p[0] = ('ApplicationSyntax', p[1], p[2]) def p_sequenceApplicationSyntax(self, p): """sequenceApplicationSyntax : IPADDRESS anySubType | COUNTER32 anySubType | GAUGE32 anySubType | UNSIGNED32 anySubType | TIMETICKS anySubType | OPAQUE | COUNTER64 anySubType""" n = len(p) if n == 2: p[0] = p[1] elif n == 3: p[0] = p[1] # XXX not supporting subtypes here def p_anySubType(self, p): """anySubType : integerSubType | octetStringSubType | enumSpec | empty""" if p[1]: p[0] = p[1] def p_integerSubType(self, p): """integerSubType : '(' ranges ')'""" p[0] = ('integerSubType', p[2]) def p_octetStringSubType(self, p): """octetStringSubType : '(' SIZE '(' ranges ')' ')'""" p[0] = ('octetStringSubType', p[4]) def p_ranges(self, p): """ranges : ranges '|' range | range""" n = len(p) if n == 4: p[0] = p[1] + [p[3]] elif n == 2: p[0] = [p[1]] def p_range(self, p): """range : value DOT_DOT value | value""" n = len(p) if n == 2: p[0] = (p[1],) elif n == 4: p[0] = (p[1], p[3]) def p_value(self, p): """value : NEGATIVENUMBER | NUMBER | NEGATIVENUMBER64 | NUMBER64 | HEX_STRING | BIN_STRING""" p[0] = p[1] def p_enumSpec(self, p): """enumSpec : '{' enumItems '}'""" p[0] = ('enumSpec', p[2]) def p_enumItems(self, p): """enumItems : enumItems ',' enumItem | enumItem""" n = len(p) if n == 4: p[0] = p[1] + [p[3]] elif n == 2: p[0] = [p[1]] def p_enumItem(self, p): """enumItem : LOWERCASE_IDENTIFIER '(' enumNumber ')'""" p[0] = (p[1], p[3]) def p_enumNumber(self, p): """enumNumber : NUMBER | NEGATIVENUMBER""" # XXX | LOWERCASE_IDENTIFIER""" p[0] = p[1] def p_Status(self, p): """Status : LOWERCASE_IDENTIFIER""" p[0] = ('Status', p[1]) def p_DisplayPart(self, p): """DisplayPart : DISPLAY_HINT Text | empty""" if p[1]: p[0] = (p[1], p[2]) def p_UnitsPart(self, p): """UnitsPart : UNITS Text | empty""" if p[1]: p[0] = (p[1], p[2]) def p_Access(self, p): """Access : LOWERCASE_IDENTIFIER""" p[0] = p[1] def p_IndexPart(self, p): """IndexPart : AUGMENTS '{' Entry '}' | empty""" if p[1]: p[0] = p[3] def p_MibIndex(self, p): """MibIndex : INDEX '{' IndexTypes '}' | empty""" if p[1]: p[0] = (p[1], p[3]) def p_IndexTypes(self, p): """IndexTypes : IndexTypes ',' IndexType | IndexType""" n = len(p) if n == 4: p[0] = p[1] + [p[3]] elif n == 2: p[0] = [p[1]] def p_IndexType(self, p): """IndexType : IMPLIED Index | Index""" n = len(p) if n == 2: p[0] = (0, p[1]) elif n == 3: p[0] = (1, p[2]) # IMPLIED def p_Index(self, p): """Index : ObjectName""" # libsmi: TODO: use the SYNTAX value of the correspondent # OBJECT-TYPE invocation p[0] = p[1][1][0] # XXX just name??? def p_Entry(self, p): """Entry : ObjectName""" p[0] = p[1][1][0] def p_DefValPart(self, p): """DefValPart : DEFVAL '{' Value '}' | empty""" if p[1] and p[3]: p[0] = (p[1], p[3]) def p_Value(self, p): """Value : valueofObjectSyntax | '{' BitsValue '}'""" n = len(p) if n == 2: p[0] = p[1] elif n == 4: p[0] = p[2] def p_BitsValue(self, p): """BitsValue : BitNames | empty""" if p[1]: p[0] = p[1] def p_BitNames(self, p): """BitNames : BitNames ',' LOWERCASE_IDENTIFIER | LOWERCASE_IDENTIFIER""" n = len(p) if n == 4: p[0] = ('BitNames', p[1][1] + [p[3]]) elif n == 2: p[0] = ('BitNames', [p[1]]) def p_ObjectName(self, p): """ObjectName : objectIdentifier""" p[0] = p[1] def p_NotificationName(self, p): """NotificationName : objectIdentifier""" p[0] = p[1] def p_ReferPart(self, p): """ReferPart : REFERENCE Text | empty""" if p[1]: p[0] = (p[1], p[2]) def p_RevisionPart(self, p): """RevisionPart : Revisions | empty""" if p[1]: p[0] = p[1] def p_Revisions(self, p): """Revisions : Revisions Revision | Revision""" n = len(p) if n == 3: p[0] = ('Revisions', p[1][1] + [p[2]]) elif n == 2: p[0] = ('Revisions', [p[1]]) def p_Revision(self, p): """Revision : REVISION ExtUTCTime DESCRIPTION Text""" p[0] = (p[2], # revision time (p[3], p[4])) # description def p_NotificationObjectsPart(self, p): """NotificationObjectsPart : OBJECTS '{' Objects '}' | empty""" p[0] = p[1] and p[3] or [] def p_ObjectGroupObjectsPart(self, p): """ObjectGroupObjectsPart : OBJECTS '{' Objects '}'""" p[0] = p[3] def p_Objects(self, p): """Objects : Objects ',' Object | Object""" n = len(p) if n == 4: p[0] = ('Objects', p[1][1] + [p[3]]) elif n == 2: p[0] = ('Objects', [p[1]]) def p_Object(self, p): """Object : ObjectName""" p[0] = p[1][1][0] def p_NotificationsPart(self, p): """NotificationsPart : NOTIFICATIONS '{' Notifications '}'""" p[0] = p[3] def p_Notifications(self, p): """Notifications : Notifications ',' Notification | Notification""" n = len(p) if n == 4: p[0] = ('Notifications', p[1][1] + [p[3]]) elif n == 2: p[0] = ('Notifications', [p[1]]) def p_Notification(self, p): """Notification : NotificationName""" p[0] = p[1][1][0] def p_Text(self, p): """Text : QUOTED_STRING""" p[0] = p[1][1:-1] # getting rid of quotes def p_ExtUTCTime(self, p): """ExtUTCTime : QUOTED_STRING""" p[0] = p[1][1:-1] # getting rid of quotes def p_objectIdentifier(self, p): """objectIdentifier : subidentifiers""" p[0] = ('objectIdentifier', p[1]) def p_subidentifiers(self, p): """subidentifiers : subidentifiers subidentifier | subidentifier""" n = len(p) if n == 3: p[0] = p[1] + [p[2]] elif n == 2: p[0] = [p[1]] def p_subidentifier(self, p): """subidentifier : fuzzy_lowercase_identifier | NUMBER | LOWERCASE_IDENTIFIER '(' NUMBER ')'""" n = len(p) if n == 2: p[0] = p[1] elif n == 5: # NOTE: we are not creating new symbol p[1] because formally # it is not defined in *this* MIB p[0] = (p[1], p[3]) def p_objectIdentifier_defval(self, p): """objectIdentifier_defval : subidentifiers_defval""" p[0] = ('objectIdentifier_defval', p[1]) def p_subidentifiers_defval(self, p): """subidentifiers_defval : subidentifiers_defval subidentifier_defval | subidentifier_defval""" n = len(p) if n == 3: p[0] = ('subidentifiers_defval', p[1][1] + [p[2]]) elif n == 2: p[0] = ('subidentifiers_defval', [p[1]]) def p_subidentifier_defval(self, p): """subidentifier_defval : LOWERCASE_IDENTIFIER '(' NUMBER ')' | NUMBER""" n = len(p) if n == 2: p[0] = ('subidentifier_defval', p[1]) elif n == 5: p[0] = ('subidentifier_defval', p[1], p[3]) def p_objectGroupClause(self, p): """objectGroupClause : LOWERCASE_IDENTIFIER OBJECT_GROUP ObjectGroupObjectsPart STATUS Status DESCRIPTION Text ReferPart COLON_COLON_EQUAL '{' objectIdentifier '}'""" p[0] = ('objectGroupClause', p[1], # id p[3], # objects p[5], # status (p[6], p[7]), # description p[8], # reference p[11]) # objectIdentifier def p_notificationGroupClause(self, p): """notificationGroupClause : LOWERCASE_IDENTIFIER NOTIFICATION_GROUP NotificationsPart STATUS Status DESCRIPTION Text ReferPart COLON_COLON_EQUAL '{' objectIdentifier '}'""" p[0] = ('notificationGroupClause', p[1], # id p[3], # notifications p[5], # status (p[6], p[7]), # description p[8], # reference p[11]) # objectIdentifier def p_moduleComplianceClause(self, p): """moduleComplianceClause : LOWERCASE_IDENTIFIER MODULE_COMPLIANCE STATUS Status DESCRIPTION Text ReferPart ComplianceModulePart COLON_COLON_EQUAL '{' objectIdentifier '}'""" p[0] = ('moduleComplianceClause', p[1], # id # p[2], # MODULE_COMPLIANCE p[4], # status (p[5], p[6]), # description p[7], # reference p[8], # ComplianceModules p[11]) # objectIdentifier def p_ComplianceModulePart(self, p): """ComplianceModulePart : ComplianceModules""" p[0] = p[1] def p_ComplianceModules(self, p): """ComplianceModules : ComplianceModules ComplianceModule | ComplianceModule""" n = len(p) if n == 3: p[0] = ('ComplianceModules', p[1][1] + [p[2]]) elif n == 2: p[0] = ('ComplianceModules', [p[1]]) def p_ComplianceModule(self, p): """ComplianceModule : MODULE ComplianceModuleName MandatoryPart CompliancePart""" objects = p[3] and p[3][1] or [] objects += p[4] and p[4][1] or [] p[0] = (p[2], # ModuleName objects) # MandatoryPart + CompliancePart def p_ComplianceModuleName(self, p): """ComplianceModuleName : UPPERCASE_IDENTIFIER | empty""" # XXX | UPPERCASE_IDENTIFIER objectIdentifier p[0] = p[1] def p_MandatoryPart(self, p): """MandatoryPart : MANDATORY_GROUPS '{' MandatoryGroups '}' | empty""" if p[1]: p[0] = p[3] def p_MandatoryGroups(self, p): """MandatoryGroups : MandatoryGroups ',' MandatoryGroup | MandatoryGroup""" n = len(p) if n == 4: p[0] = ('MandatoryGroups', p[1][1] + [p[3]]) elif n == 2: p[0] = ('MandatoryGroups', [p[1]]) def p_MandatoryGroup(self, p): """MandatoryGroup : objectIdentifier""" p[0] = p[1][1][0] # objectIdentifier? Maybe name? def p_CompliancePart(self, p): """CompliancePart : Compliances | empty""" if p[1]: p[0] = p[1] def p_Compliances(self, p): """Compliances : Compliances Compliance | Compliance""" n = len(p) if n == 3: p[0] = p[1] and p[2] and ('Compliances', p[1][1] + [p[2]]) or p[1] elif n == 2: p[0] = p[1] and ('Compliances', [p[1]]) or None def p_Compliance(self, p): """Compliance : ComplianceGroup | ComplianceObject""" if p[1]: p[0] = p[1] def p_ComplianceGroup(self, p): """ComplianceGroup : GROUP objectIdentifier DESCRIPTION Text""" p[0] = p[2][1][0] # objectIdentifier # p[1], # GROUP # (p[3], p[4])) # description def p_ComplianceObject(self, p): """ComplianceObject : OBJECT ObjectName SyntaxPart WriteSyntaxPart AccessPart DESCRIPTION Text""" # p[0] = (p[1], # object # p[2], # name # p[3], # syntax # p[4], # write syntax # p[5], # access # (p[6], p[7])) # description def p_SyntaxPart(self, p): """SyntaxPart : SYNTAX Syntax | empty""" if p[1]: p[0] = p[2] def p_WriteSyntaxPart(self, p): """WriteSyntaxPart : WRITE_SYNTAX WriteSyntax | empty""" if p[1]: p[0] = p[2] def p_WriteSyntax(self, p): """WriteSyntax : Syntax""" p[0] = ('WriteSyntax', p[1]) def p_AccessPart(self, p): """AccessPart : MIN_ACCESS Access | empty""" if p[1]: p[0] = (p[1], p[2]) def p_agentCapabilitiesClause(self, p): """agentCapabilitiesClause : LOWERCASE_IDENTIFIER AGENT_CAPABILITIES PRODUCT_RELEASE Text STATUS Status DESCRIPTION Text ReferPart ModulePart_Capabilities COLON_COLON_EQUAL '{' objectIdentifier '}'""" p[0] = ('agentCapabilitiesClause', p[1], # id # p[2], # AGENT_CAPABILITIES (p[3], p[4]), # product release p[6], # status (p[7], p[8]), # description p[9], # reference # p[10], # module capabilities p[13]) # objectIdentifier def p_ModulePart_Capabilities(self, p): """ModulePart_Capabilities : Modules_Capabilities | empty""" # if p[1]: # p[0] = p[1] def p_Modules_Capabilities(self, p): """Modules_Capabilities : Modules_Capabilities Module_Capabilities | Module_Capabilities""" # n = len(p) # if n == 3: # p[0] = ('Modules_Capabilities', p[1][1] + [p[2]]) # elif n == 2: # p[0] = ('Modules_Capabilities', [p[1]]) def p_Module_Capabilities(self, p): """Module_Capabilities : SUPPORTS ModuleName_Capabilities INCLUDES '{' CapabilitiesGroups '}' VariationPart""" # p[0] = ('Module_Capabilities', (p[1], p[2]), # supports # (p[3], p[5]), # includes # p[7]) # variations def p_CapabilitiesGroups(self, p): """CapabilitiesGroups : CapabilitiesGroups ',' CapabilitiesGroup | CapabilitiesGroup""" # n = len(p) # if n == 4: # p[0] = ('CapabilitiesGroups', p[1][1] + [p[3]]) # elif n == 2: # p[0] = ('CapabilitiesGroups', [p[1]]) def p_CapabilitiesGroup(self, p): """CapabilitiesGroup : objectIdentifier""" # p[0] = ('CapabilitiesGroup', p[1]) def p_ModuleName_Capabilities(self, p): """ModuleName_Capabilities : UPPERCASE_IDENTIFIER objectIdentifier | UPPERCASE_IDENTIFIER""" # n = len(p) # if n == 2: # p[0] = ('ModuleName_Capabilities', p[1]) # elif n == 3: # p[0] = ('ModuleName_Capabilities', p[1], p[2]) def p_VariationPart(self, p): """VariationPart : Variations | empty""" # if p[1]: # p[0] = p[1] def p_Variations(self, p): """Variations : Variations Variation | Variation""" # n = len(p) # if n == 3: # p[0] = ('Variations', p[1][1] + [p[2]]) # elif n == 2: # p[0] = ('Variations', [p[1]]) pass def p_Variation(self, p): """Variation : VARIATION ObjectName SyntaxPart WriteSyntaxPart VariationAccessPart CreationPart DefValPart DESCRIPTION Text""" # p[0] = (p[1], # variation # p[2], # name # p[3], # syntax # p[4], # write syntax # p[5], # access # p[6], # creation # p[7], # defval # (p[8], p[9])) # description def p_VariationAccessPart(self, p): """VariationAccessPart : ACCESS VariationAccess | empty""" # if p[1]: # p[0] = (p[1], p[2]) def p_VariationAccess(self, p): """VariationAccess : LOWERCASE_IDENTIFIER""" # p[0] = p[1] def p_CreationPart(self, p): """CreationPart : CREATION_REQUIRES '{' Cells '}' | empty""" if p[1]: p[0] = (p[1], p[3]) def p_Cells(self, p): """Cells : Cells ',' Cell | Cell""" n = len(p) if n == 4: p[0] = ('Cells', p[1][1] + [p[3]]) elif n == 2: p[0] = ('Cells', [p[1]]) def p_Cell(self, p): """Cell : ObjectName""" p[0] = ('Cell', p[1]) def p_empty(self, p): """empty :""" # Error rule for syntax errors def p_error(self, p): if p: raise error.PySmiParserError("Bad grammar near token type %s, value %s" % (p.type, p.value), lineno=p.lineno) # # Parser grammar relaxation follows. # # The classes that follow serve a purpose of encapsulating assorted functions # into a namespace. The namespace type is not universally supported across all # Python versions we want to run on, thus the hack with `staticmethod` decorator # and `self` first parameter. # # # SMIv1 grammar # # noinspection PyIncorrectDocstring class SupportSmiV1Keywords(object): # NETWORKADDRESS added @staticmethod def p_importedKeyword(self, p): """importedKeyword : importedSMIKeyword | BITS | INTEGER32 | IPADDRESS | NETWORKADDRESS | MANDATORY_GROUPS | MODULE_COMPLIANCE | MODULE_IDENTITY | OBJECT_GROUP | OBJECT_IDENTITY | OBJECT_TYPE | OPAQUE | TEXTUAL_CONVENTION | TIMETICKS | UNSIGNED32""" p[0] = p[1] # NETWORKADDRESS added @staticmethod def p_typeSMIandSPPI(self, p): """typeSMIandSPPI : IPADDRESS | NETWORKADDRESS | TIMETICKS | OPAQUE | INTEGER32 | UNSIGNED32""" p[0] = p[1] # NETWORKADDRESS added @staticmethod def p_ApplicationSyntax(self, p): """ApplicationSyntax : IPADDRESS anySubType | NETWORKADDRESS anySubType | COUNTER32 | COUNTER32 integerSubType | GAUGE32 | GAUGE32 integerSubType | UNSIGNED32 | UNSIGNED32 integerSubType | TIMETICKS anySubType | OPAQUE | OPAQUE octetStringSubType | COUNTER64 | COUNTER64 integerSubType""" n = len(p) if n == 2: p[0] = ('ApplicationSyntax', p[1]) elif n == 3: p[0] = ('ApplicationSyntax', p[1], p[2]) # NETWORKADDRESS added for SEQUENCE syntax @staticmethod def p_sequenceApplicationSyntax(self, p): """sequenceApplicationSyntax : IPADDRESS anySubType | NETWORKADDRESS anySubType | COUNTER32 anySubType | GAUGE32 anySubType | UNSIGNED32 anySubType | TIMETICKS anySubType | OPAQUE | COUNTER64 anySubType""" n = len(p) if n == 2: p[0] = p[1] elif n == 3: p[0] = p[1] # XXX not supporting subtypes here # noinspection PyIncorrectDocstring class SupportIndex(object): # SMIv1 IndexTypes added @staticmethod def p_Index(self, p): """Index : ObjectName | typeSMIv1""" # libsmi: TODO: use the SYNTAX value of the correspondent # OBJECT-TYPE invocation p[0] = isinstance(p[1], tuple) and p[1][1][0] or p[1] # for Index rule @staticmethod def p_typeSMIv1(self, p): """typeSMIv1 : INTEGER | OCTET STRING | IPADDRESS | NETWORKADDRESS""" n = len(p) indextype = n == 3 and p[1] + ' ' + p[2] or p[1] p[0] = indextype # # Some changes in grammar to handle common mistakes in MIBs # # noinspection PyIncorrectDocstring class CommaInImport(object): # comma at the end of import list @staticmethod def p_importIdentifiers(self, p): """importIdentifiers : importIdentifiers ',' importIdentifier | importIdentifier | importIdentifiers ','""" n = len(p) if n == 4: p[0] = p[1] + [p[3]] elif n == 2: p[0] = [p[1]] elif n == 3: # excessive comma case p[0] = p[1] # noinspection PyIncorrectDocstring class CommaInSequence(object): # comma at the end of sequence list @staticmethod def p_sequenceItems(self, p): """sequenceItems : sequenceItems ',' sequenceItem | sequenceItem | sequenceItems ','""" # libsmi: TODO: might this list be emtpy? n = len(p) if n == 4: p[0] = p[1] + [p[3]] elif n == 2: p[0] = [p[1]] elif n == 3: # excessive comma case p[0] = p[1] # noinspection PyIncorrectDocstring class CommaAndSpaces(object): # common typos handled (mix of commas and spaces) @staticmethod def p_enumItems(self, p): """enumItems : enumItems ',' enumItem | enumItem | enumItems enumItem | enumItems ','""" n = len(p) if n == 4: p[0] = p[1] + [p[3]] elif n == 2: p[0] = [p[1]] elif n == 3: # typo case if p[2] == ',': p[0] = p[1] else: p[0] = p[1] + [p[2]] # noinspection PyIncorrectDocstring class UppercaseIdentifier(object): # common mistake - using UPPERCASE_IDENTIFIER @staticmethod def p_enumItem(self, p): """enumItem : LOWERCASE_IDENTIFIER '(' enumNumber ')' | UPPERCASE_IDENTIFIER '(' enumNumber ')'""" p[0] = (p[1], p[3]) # noinspection PyIncorrectDocstring class LowcaseIdentifier(object): # common mistake - LOWERCASE_IDENTIFIER in symbol's name @staticmethod def p_notificationTypeClause(self, p): """notificationTypeClause : fuzzy_lowercase_identifier NOTIFICATION_TYPE NotificationObjectsPart STATUS Status DESCRIPTION Text ReferPart COLON_COLON_EQUAL '{' NotificationName '}'""" # some MIBs have uppercase and/or lowercase id p[0] = ('notificationTypeClause', p[1], # id # p[2], # NOTIFICATION_TYPE p[3], # NotificationObjectsPart p[5], # status (p[6], p[7]), # description p[8], # Reference p[11]) # NotificationName aka objectIdentifier # noinspection PyIncorrectDocstring,PyIncorrectDocstring class CurlyBracesInEnterprises(object): # common mistake - curly brackets around enterprise symbol @staticmethod def p_trapTypeClause(self, p): """trapTypeClause : fuzzy_lowercase_identifier TRAP_TYPE EnterprisePart VarPart DescrPart ReferPart COLON_COLON_EQUAL NUMBER""" # libsmi: TODO: range of number? p[0] = ('trapTypeClause', p[1], # fuzzy_lowercase_identifier # p[2], # TRAP_TYPE p[3], # EnterprisePart (objectIdentifier) p[4], # VarPart p[5], # description p[6], # reference p[8]) # NUMBER @staticmethod def p_EnterprisePart(self, p): """EnterprisePart : ENTERPRISE objectIdentifier | ENTERPRISE '{' objectIdentifier '}'""" n = len(p) if n == 3: p[0] = p[2] elif n == 5: # common mistake case p[0] = p[3] # noinspection PyIncorrectDocstring class NoCells(object): # common mistake - no Cells @staticmethod def p_CreationPart(self, p): """CreationPart : CREATION_REQUIRES '{' Cells '}' | CREATION_REQUIRES '{' '}' | empty""" n = len(p) if n == 5: p[0] = (p[1], p[3]) relaxedGrammar = { 'supportSmiV1Keywords': [ SupportSmiV1Keywords.p_importedKeyword, SupportSmiV1Keywords.p_typeSMIandSPPI, SupportSmiV1Keywords.p_ApplicationSyntax, SupportSmiV1Keywords.p_sequenceApplicationSyntax ], 'supportIndex': [ SupportIndex.p_Index, SupportIndex.p_typeSMIv1 ], 'commaAtTheEndOfImport': [CommaInImport.p_importIdentifiers], 'commaAtTheEndOfSequence': [CommaInSequence.p_sequenceItems], 'mixOfCommasAndSpaces': [CommaAndSpaces.p_enumItems], 'uppercaseIdentifier': [UppercaseIdentifier.p_enumItem], 'lowcaseIdentifier': [LowcaseIdentifier.p_notificationTypeClause], 'curlyBracesAroundEnterpriseInTrap': [ CurlyBracesInEnterprises.p_trapTypeClause, CurlyBracesInEnterprises.p_EnterprisePart ], 'noCells': [NoCells.p_CreationPart] } def parserFactory(**grammarOptions): """Factory function producing custom specializations of base *SmiV2Parser* class. Keyword Args: grammarOptions: a list of (bool) typed optional keyword parameters enabling particular set of SMIv2 grammar relaxations. Returns: Specialized copy of *SmiV2Parser* class. Notes: The following SMIv2 grammar relaxation parameters are defined: * supportSmiV1Keywords - parses SMIv1 grammar * supportIndex - tolerates ASN.1 types in INDEX clause * commaAtTheEndOfImport - tolerates stray comma at the end of IMPORT section * commaAtTheEndOfSequence - tolerates stray comma at the end of sequence of elements in MIB * mixOfCommasAndSpaces - tolerate a mix of comma and spaces in MIB enumerations * uppercaseIdentifier - tolerate uppercased MIB identifiers * lowcaseIdentifier - tolerate lowercase MIB identifiers * curlyBracesAroundEnterpriseInTrap - tolerate curly braces around enterprise ID in TRAP MACRO * noCells - tolerate missing cells (XXX) Examples: >>> from pysmi.parser import smi >>> SmiV1Parser = smi.parserFactory(supportSmiV1Keywords=True, supportIndex=True) """ classAttr = {} for option in grammarOptions: if grammarOptions[option]: if option not in relaxedGrammar: raise error.PySmiError('Unknown parser relaxation option: %s' % option) for func in relaxedGrammar[option]: if sys.version_info[0] > 2: classAttr[func.__name__] = func else: classAttr[func.func_name] = func classAttr['defaultLexer'] = lexerFactory(**grammarOptions) return type('SmiParser', (SmiV2Parser,), classAttr) pysmi-0.3.4/pysmi/parser/smiv1.py0000664006321400632140000000045013411726453020374 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.parser.smi import parserFactory from pysmi.parser.dialect import smiV1 # compatibility stub SmiV1Parser = parserFactory(**smiV1) pysmi-0.3.4/pysmi/parser/smiv1compat.py0000664006321400632140000000053613411726453021605 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.parser.smi import parserFactory from pysmi.parser.dialect import smiV1Relaxed # compatibility stub SmiV1CompatParser = parserFactory(**smiV1Relaxed) SmiStarParser = SmiV1CompatParser pysmi-0.3.4/pysmi/parser/smiv2.py0000664006321400632140000000045013411726453020375 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.parser.smi import parserFactory from pysmi.parser.dialect import smiV2 # compatibility stub SmiV2Parser = parserFactory(**smiV2) pysmi-0.3.4/pysmi/reader/0000775006321400632140000000000013454602625016733 5ustar ietingofietingof00000000000000pysmi-0.3.4/pysmi/reader/__init__.py0000664006321400632140000000066313411726453021050 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.reader.callback import CallbackReader from pysmi.reader.ftpclient import FtpReader from pysmi.reader.httpclient import HttpReader from pysmi.reader.zipreader import ZipReader from pysmi.reader.localfile import FileReader from pysmi.reader.url import getReadersFromUrls pysmi-0.3.4/pysmi/reader/base.py0000664006321400632140000000302013454602500020202 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os class AbstractReader(object): maxMibSize = 10000000 # MIBs can't be that large fuzzyMatching = True # try different file names while searching for MIB originalMatching = uppercaseMatching = lowcaseMatching = True exts = ['', os.path.extsep + 'txt', os.path.extsep + 'mib', os.path.extsep + 'my'] exts.extend([x.upper() for x in exts if x]) def setOptions(self, **kwargs): for k in kwargs: setattr(self, k, kwargs[k]) return self def getMibVariants(self, mibname, **options): filenames = [] if self.originalMatching: filenames.append(mibname) if self.uppercaseMatching: filenames.append(mibname.upper()) if self.lowcaseMatching: filenames.append(mibname.lower()) if self.fuzzyMatching: part = filenames[-1].find('-mib') if part != -1: filenames.extend( [x[:part] for x in filenames] ) else: suffixed = mibname + '-mib' filenames.append(suffixed.upper()) filenames.append(suffixed.lower()) return ((x, x + y) for x in filenames for y in options.get('exts', self.exts)) def getData(self, filename, **options): raise NotImplementedError() pysmi-0.3.4/pysmi/reader/callback.py0000664006321400632140000000275413454602500021041 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import time from pysmi.reader.base import AbstractReader from pysmi.mibinfo import MibInfo from pysmi import error from pysmi import debug class CallbackReader(AbstractReader): """Fetch ASN.1 MIB text by name by calling user-defined callable. *CallbackReader* class instance tries to retrieve ASN.1 MIB files by name and return their contents to caller. """ def __init__(self, cbFun, cbCtx=None): """Create an instance of *CallbackReader* bound to specific URL. Args: cbFun (callable): user callable accepting *MIB name* and *cbCtx* objects Keyword Args: cbCtx (object): user object that can be used to communicate state information between user-scope code and the *cbFun* callable scope """ self._cbFun = cbFun self._cbCtx = cbCtx def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._cbFun) def getData(self, mibname, **options): debug.logger & debug.flagReader and debug.logger('calling user callback %s for MIB %s' % (self._cbFun, mibname)) res = self._cbFun(mibname, self._cbCtx) if res: return MibInfo(path='file:///dev/stdin', file='', name=mibname, mtime=time.time()), res raise error.PySmiReaderFileNotFoundError(mibname=mibname, reader=self) pysmi-0.3.4/pysmi/reader/ftpclient.py0000664006321400632140000001113313454602500021264 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys import time import ftplib from pysmi.reader.base import AbstractReader from pysmi.mibinfo import MibInfo from pysmi.compat import decode from pysmi import error from pysmi import debug class FtpReader(AbstractReader): """Fetch ASN.1 MIB text by name from FTP server. *FtpReader* class instance tries to download ASN.1 MIB files by name and return their contents to caller. """ def __init__(self, host, locationTemplate, timeout=5, ssl=False, port=21, user='anonymous', password='anonymous@'): """Create an instance of *FtpReader* bound to specific FTP server directory. Args: host (str): domain name or IP address of web server locationTemplate (str): location part of the directory containing @mib@ magic placeholder to be replaced with MIB name fetch. Keyword Args: timeout (int): response timeout ssl (bool): access HTTPS web site port (int): TCP port web server is listening user (str): username at FTP server password (str): password for *username* at FTP server """ self._host = host self._locationTemplate = locationTemplate self._timeout = timeout self._ssl = ssl self._port = port self._user = user self._password = password if '@mib@' not in locationTemplate: raise error.PySmiError('@mib@ placeholder not specified in location at %s' % self) def __str__(self): return '%s{"ftp://%s%s"}' % (self.__class__.__name__, self._host, self._locationTemplate) def getData(self, mibname, **options): if self._ssl: conn = ftplib.FTP_TLS() else: conn = ftplib.FTP() try: conn.connect(self._host, self._port, self._timeout) except ftplib.all_errors: raise error.PySmiReaderFileNotFoundError( 'failed to connect to FTP server %s:%s: %s' % (self._host, self._port, sys.exc_info()[1]), reader=self) try: conn.login(self._user, self._password) except ftplib.all_errors: conn.close() raise error.PySmiReaderFileNotFoundError('failed to log in to FTP server %s:%s as %s/%s: %s' % (self._host, self._port, self._user, self._password, sys.exc_info()[1]), reader=self) mibname = decode(mibname) debug.logger & debug.flagReader and debug.logger('looking for MIB %s' % mibname) for mibalias, mibfile in self.getMibVariants(mibname, **options): location = self._locationTemplate.replace('@mib@', mibfile) mtime = time.time() debug.logger & debug.flagReader and debug.logger( 'trying to fetch MIB %s from %s:%s' % (location, self._host, self._port)) data = [] try: try: response = conn.sendcmd('MDTM %s' % location) except ftplib.all_errors: debug.logger & debug.flagReader and debug.logger( 'server %s:%s does not support MDTM command, fetching file %s' % ( self._host, self._port, location)) else: debug.logger & debug.flagReader and debug.logger( 'server %s:%s MDTM response is %s' % (self._host, self._port, response)) if response[:3] == 213: mtime = time.mktime(time.strptime(response[4:], "%Y%m%d%H%M%S")) debug.logger & debug.flagReader and debug.logger('fetching source MIB %s, mtime %s' % (location, time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(mtime)))) conn.retrlines('RETR %s' % location, lambda x, y=data: y.append(x)) except ftplib.all_errors: debug.logger & debug.flagReader and debug.logger( 'failed to fetch MIB %s from %s:%s: %s' % (location, self._host, self._port, sys.exc_info()[1])) continue data = decode('\n'.join(data)) debug.logger & debug.flagReader and debug.logger('fetched %s bytes in %s' % (len(data), location)) conn.close() return MibInfo(path='ftp://%s%s' % (self._host, location), file=mibfile, name=mibalias, mtime=mtime), data conn.close() raise error.PySmiReaderFileNotFoundError('source MIB %s not found' % mibname, reader=self) pysmi-0.3.4/pysmi/reader/httpclient.py0000664006321400632140000000747513454602500021470 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import socket import sys import time try: # noinspection PyUnresolvedReferences from urllib2 import Request, urlopen except ImportError: # noinspection PyUnresolvedReferences from urllib.request import Request from urllib.request import urlopen from pysmi.reader.base import AbstractReader from pysmi.mibinfo import MibInfo from pysmi.compat import decode from pysmi import __version__ as pysmi_version from pysmi import error from pysmi import debug class HttpReader(AbstractReader): """Fetch ASN.1 MIB text by name from a web site. *HttpReader* class instance tries to download ASN.1 MIB files by name and return their contents to caller. """ MIB_MAGIC = '@mib@' def __init__(self, host, port, locationTemplate, timeout=5, ssl=False): """Create an instance of *HttpReader* bound to specific URL. Note: The `http_proxy` and `https_proxy` environment variables are respected by the underlying `urllib` stdlib module. Args: host (str): domain name or IP address of web server port (int): TCP port web server is listening locationTemplate (str): location part of the URL optionally containing @mib@ magic placeholder to be replaced with MIB name. If @mib@ magic is not present, MIB name is appended to `locationTemplate` Keyword Args: timeout (int): response timeout ssl (bool): access HTTPS web site """ self._url = '%s://%s:%d%s' % (ssl and 'https' or 'http', host, port, decode(locationTemplate)) socket.setdefaulttimeout(timeout) self._user_agent = 'pysmi-%s; python-%s.%s.%s; %s' % ( pysmi_version, sys.version_info[0], sys.version_info[1], sys.version_info[2], sys.platform ) def __str__(self): return self._url def getData(self, mibname, **options): headers = { 'Accept': 'text/plain', 'User-Agent': self._user_agent } mibname = decode(mibname) debug.logger & debug.flagReader and debug.logger('looking for MIB %s' % mibname) for mibalias, mibfile in self.getMibVariants(mibname, **options): if self.MIB_MAGIC in self._url: url = self._url.replace(self.MIB_MAGIC, mibfile) else: url = self._url + mibfile debug.logger & debug.flagReader and debug.logger('trying to fetch MIB from %s' % url) try: req = Request(url, headers=headers) response = urlopen(req) except Exception: debug.logger & debug.flagReader and debug.logger('failed to fetch MIB from %s: %s' % (url, sys.exc_info()[1])) continue debug.logger & debug.flagReader and debug.logger('HTTP response %s' % response.code) if response.code == 200: try: mtime = time.mktime(time.strptime(response.getheader('Last-Modified'), "%a, %d %b %Y %H:%M:%S %Z")) except Exception: debug.logger & debug.flagReader and debug.logger('malformed HTTP headers: %s' % sys.exc_info()[1]) mtime = time.time() debug.logger & debug.flagReader and debug.logger( 'fetching source MIB %s, mtime %s' % (url, response.getheader('Last-Modified'))) return MibInfo(path=url, file=mibfile, name=mibalias, mtime=mtime), decode(response.read(self.maxMibSize)) raise error.PySmiReaderFileNotFoundError('source MIB %s not found' % mibname, reader=self) pysmi-0.3.4/pysmi/reader/localfile.py0000664006321400632140000001151113454602500021226 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os import sys import time from pysmi.reader.base import AbstractReader from pysmi.mibinfo import MibInfo from pysmi.compat import decode from pysmi import debug from pysmi import error class FileReader(AbstractReader): """Fetch ASN.1 MIB text by name from local file. *FileReader* class instance tries to locate ASN.1 MIB files by name, fetch and return their contents to caller. """ useIndexFile = True # optional .index file mapping MIB to file name indexFile = '.index' def __init__(self, path, recursive=True, ignoreErrors=True): """Create an instance of *FileReader* serving a directory. Args: path (str): directory to search MIB files Keyword Args: recursive (bool): whether to include subdirectories ignoreErrors (bool): ignore filesystem access errors """ self._path = os.path.normpath(path) self._recursive = recursive self._ignoreErrors = ignoreErrors self._indexLoaded = False self._mibIndex = None def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._path) def getSubdirs(self, path, recursive=True, ignoreErrors=True): if not recursive: return [path] dirs = [path] try: subdirs = os.listdir(path) except OSError: if ignoreErrors: return dirs else: raise error.PySmiError('directory %s access error: %s' % (path, sys.exc_info()[1])) for d in subdirs: d = os.path.join(decode(path), decode(d)) if os.path.isdir(d): dirs.extend(self.getSubdirs(d, recursive)) return dirs @staticmethod def loadIndex(indexFile): mibIndex = {} if os.path.exists(indexFile): try: f = open(indexFile) mibIndex = dict( [x.split()[:2] for x in f.readlines()] ) f.close() debug.logger & debug.flagReader and debug.logger( 'loaded MIB index map from %s file, %s entries' % (indexFile, len(mibIndex))) except IOError: pass return mibIndex def getMibVariants(self, mibname, **options): if self.useIndexFile: if not self._indexLoaded: self._mibIndex = self.loadIndex( os.path.join(self._path, self.indexFile) ) self._indexLoaded = True if mibname in self._mibIndex: debug.logger & debug.flagReader and debug.logger( 'found %s in MIB index: %s' % (mibname, self._mibIndex[mibname])) return [(mibname, self._mibIndex[mibname])] return super(FileReader, self).getMibVariants(mibname, **options) def getData(self, mibname, **options): debug.logger & debug.flagReader and debug.logger( '%slooking for MIB %s' % (self._recursive and 'recursively ' or '', mibname)) for path in self.getSubdirs(self._path, self._recursive, self._ignoreErrors): for mibalias, mibfile in self.getMibVariants(mibname, **options): f = os.path.join(decode(path), decode(mibfile)) debug.logger & debug.flagReader and debug.logger('trying MIB %s' % f) if os.path.exists(f) and os.path.isfile(f): try: mtime = os.stat(f)[8] debug.logger & debug.flagReader and debug.logger( 'source MIB %s mtime is %s, fetching data...' % ( f, time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(mtime)))) fp = open(f, mode='rb') mibData = fp.read(self.maxMibSize) fp.close() if len(mibData) == self.maxMibSize: raise IOError('MIB %s too large' % f) return MibInfo(path='file://%s' % f, file=mibfile, name=mibalias, mtime=mtime), decode(mibData) except (OSError, IOError): debug.logger & debug.flagReader and debug.logger( 'source file %s open failure: %s' % (f, sys.exc_info()[1])) if not self._ignoreErrors: raise error.PySmiError('file %s access error: %s' % (f, sys.exc_info()[1])) raise error.PySmiReaderFileNotModifiedError('source MIB %s is older than needed' % f, reader=self) raise error.PySmiReaderFileNotFoundError('source MIB %s not found' % mibname, reader=self) pysmi-0.3.4/pysmi/reader/url.py0000664006321400632140000000510013411726453020102 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: # noinspection PyUnresolvedReferences import urlparse except ImportError: # noinspection PyUnresolvedReferences from urllib import parse as urlparse from pysmi.reader.localfile import FileReader from pysmi.reader.zipreader import ZipReader from pysmi.reader.httpclient import HttpReader from pysmi.reader.ftpclient import FtpReader from pysmi import error def getReadersFromUrls(*sourceUrls, **options): readers = [] for sourceUrl in sourceUrls: mibSource = urlparse.urlparse(sourceUrl) if sys.version_info[0:2] < (2, 5): class ParseResult(tuple): pass mibSource = ParseResult(mibSource) for k, v in zip(('scheme', 'netloc', 'path', 'params', 'query', 'fragment', 'username', 'password', 'hostname', 'port'), mibSource + ('', '', '', None)): if k == 'scheme': if not mibSource[0] or mibSource[0] == 'file': if mibSource[2].endswith('.zip') or mibSource[2].endswith('.ZIP'): v = 'zip' setattr(mibSource, k, v) if mibSource.scheme in ('', 'file', 'zip'): scheme = mibSource.scheme if scheme != 'file' and (mibSource.path.endswith('.zip') or mibSource.path.endswith('.ZIP')): scheme = 'zip' else: scheme = 'file' if scheme == 'file': readers.append(FileReader(mibSource.path).setOptions(**options)) else: readers.append(ZipReader(mibSource.path).setOptions(**options)) elif mibSource.scheme in ('http', 'https'): readers.append(HttpReader(mibSource.hostname or mibSource.netloc, mibSource.port or 80, mibSource.path, ssl=mibSource.scheme == 'https').setOptions(**options)) elif mibSource.scheme in ('ftp', 'sftp'): readers.append( FtpReader(mibSource.hostname or mibSource.netloc, mibSource.path, ssl=mibSource.scheme == 'sftp', port=mibSource.port or 21, user=mibSource.username or 'anonymous', password=mibSource.password or 'anonymous@').setOptions(**options)) else: raise error.PySmiError('Unsupported URL scheme %s' % sourceUrl) return readers pysmi-0.3.4/pysmi/reader/zipreader.py0000664006321400632140000001300313454602500021257 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os import sys import time import datetime import zipfile from pysmi.reader.base import AbstractReader from pysmi.mibinfo import MibInfo from pysmi.compat import decode from pysmi import debug from pysmi import error class FileLike(object): """Stripped down, binary file mock to work with ZipFile""" def __init__(self, buf, name): self.name = name self.buf = buf self.null = buf[:0] self.len = len(buf) self.buflist = [] self.pos = 0 self.closed = False self.softspace = 0 def close(self): if not self.closed: self.closed = True self.buf = self.null self.pos = 0 def seek(self, pos, mode = 0): if self.buflist: self.buf += self.null.join(self.buflist) self.buflist = [] if mode == 1: pos += self.pos elif mode == 2: pos += self.len self.pos = max(0, pos) def tell(self): return self.pos def read(self, n=-1): if self.buflist: self.buf += self.null.join(self.buflist) self.buflist = [] if n < 0: newpos = self.len else: newpos = min(self.pos + n, self.len) r = self.buf[self.pos:newpos] self.pos = newpos return r class ZipReader(AbstractReader): """Fetch ASN.1 MIB text by name from a ZIP archive. *ZipReader* class instance tries to locate ASN.1 MIB files by name, fetch and return their contents to caller. """ useIndexFile = False def __init__(self, path, ignoreErrors=True): """Create an instance of *ZipReader* serving a ZIP archive. Args: path (str): path to ZIP archive containing MIB files Keyword Args: ignoreErrors (bool): ignore ZIP archive access errors """ self._name = path self._members = {} self._pendingError = None try: self._members = self._readZipDirectory(fileObj=open(path, 'rb')) except Exception: debug.logger & debug.flagReader and debug.logger( 'ZIP file %s open failure: %s' % (self._name, sys.exc_info()[1])) if not ignoreErrors: self._pendingError = error.PySmiError('file %s access error: %s' % (self._name, sys.exc_info()[1])) def _readZipDirectory(self, fileObj): archive = zipfile.ZipFile(fileObj) if isinstance(fileObj, FileLike): fileObj = None members = {} for member in archive.infolist(): filename = os.path.basename(member.filename) if not filename: continue if (member.filename.endswith('.zip') or member.filename.endswith('.ZIP')): innerZipBlob = archive.read(member.filename) innerMembers = self._readZipDirectory(FileLike(innerZipBlob, member.filename)) for innerFilename, ref in innerMembers.items(): while innerFilename in members: innerFilename += '+' members[innerFilename] = [[fileObj, member.filename, None]] members[innerFilename].extend(ref) else: mtime = time.mktime(datetime.datetime(*member.date_time[:6]).timetuple()) members[filename] = [[fileObj, member.filename, mtime]] return members def _readZipFile(self, refs): for fileObj, filename, mtime in refs: if not fileObj: fileObj = FileLike(dataObj, name=self._name) archive = zipfile.ZipFile(fileObj) try: dataObj = archive.read(filename) except Exception: debug.logger & debug.flagReader and debug.logger('ZIP read component %s read error: %s' % (fileObj.name, sys.exc_info()[1])) return '', 0 return dataObj, mtime def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._name) def getData(self, mibname, **options): debug.logger & debug.flagReader and debug.logger('looking for MIB %s at %s' % (mibname, self._name)) if self._pendingError: raise self._pendingError if not self._members: raise error.PySmiReaderFileNotFoundError('source MIB %s not found' % mibname, reader=self) for mibalias, mibfile in self.getMibVariants(mibname, **options): debug.logger & debug.flagReader and debug.logger('trying MIB %s' % mibfile) try: refs = self._members[mibfile] except KeyError: continue mibData, mtime = self._readZipFile(refs) if not mibData: continue debug.logger & debug.flagReader and debug.logger( 'source MIB %s, mtime %s, read from %s/%s' % (mibfile, time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(mtime)), self._name, mibfile) ) if len(mibData) == self.maxMibSize: raise IOError('MIB %s/%s too large' % (self._name, mibfile)) return MibInfo(path='zip://%s/%s' % (self._name, mibfile), file=mibfile, name=mibalias, mtime=mtime), decode(mibData) raise error.PySmiReaderFileNotFoundError('source MIB %s not found' % mibname, reader=self) pysmi-0.3.4/pysmi/searcher/0000775006321400632140000000000013454602625017265 5ustar ietingofietingof00000000000000pysmi-0.3.4/pysmi/searcher/__init__.py0000664006321400632140000000054313411726453021377 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.searcher.pyfile import PyFileSearcher from pysmi.searcher.pypackage import PyPackageSearcher from pysmi.searcher.stub import StubSearcher from pysmi.searcher.anyfile import AnyFileSearcher pysmi-0.3.4/pysmi/searcher/anyfile.py0000664006321400632140000000362113411726453021267 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os import sys import time from pysmi.searcher.base import AbstractSearcher from pysmi.compat import decode from pysmi import debug from pysmi import error class AnyFileSearcher(AbstractSearcher): """Figures out if given file exists at given location. """ exts = [] def __init__(self, path): """Create an instance of *AnyFileSearcher* bound to specific directory. Args: path (str): path to local directory """ self._path = os.path.normpath(decode(path)) def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._path) def fileExists(self, mibname, mtime, rebuild=False): if rebuild: debug.logger & debug.flagSearcher and debug.logger('pretend %s is very old' % mibname) return mibname = decode(mibname) basename = os.path.join(self._path, mibname) for sfx in self.exts: f = basename + sfx if not os.path.exists(f) or not os.path.isfile(f): debug.logger & debug.flagSearcher and debug.logger('%s not present or not a file' % f) continue try: fileTime = os.stat(f)[8] except OSError: raise error.PySmiSearcherError('failure opening compiled file %s: %s' % (f, sys.exc_info()[1]), searcher=self) debug.logger & debug.flagSearcher and debug.logger( 'found %s, mtime %s' % (f, time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(fileTime)))) if fileTime >= mtime: raise error.PySmiFileNotModifiedError() raise error.PySmiFileNotFoundError('no compiled file %s found' % mibname, searcher=self) pysmi-0.3.4/pysmi/searcher/base.py0000664006321400632140000000062513411726453020553 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # class AbstractSearcher(object): def setOptions(self, **kwargs): for k in kwargs: setattr(self, k, kwargs[k]) return self def fileExists(self, mibname, mtime, rebuild=False): raise NotImplementedError() pysmi-0.3.4/pysmi/searcher/pyfile.py0000664006321400632140000000716613454602500021131 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os import sys import time import struct try: import importlib try: SOURCE_SUFFIXES = importlib.machinery.SOURCE_SUFFIXES BYTECODE_SUFFIXES = importlib.machinery.BYTECODE_SUFFIXES except Exception: raise ImportError() except ImportError: import imp SOURCE_SUFFIXES = [s[0] for s in imp.get_suffixes() if s[2] == imp.PY_SOURCE] BYTECODE_SUFFIXES = [s[0] for s in imp.get_suffixes() if s[2] == imp.PY_COMPILED] from pysmi.searcher.base import AbstractSearcher from pysmi.compat import decode from pysmi import debug from pysmi import error class PyFileSearcher(AbstractSearcher): """Figures out if given Python file (source or bytecode) exists at given location. """ def __init__(self, path): """Create an instance of *PyFileSearcher* bound to specific directory. Args: path (str): path to local directory """ self._path = os.path.normpath(decode(path)) def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._path) def fileExists(self, mibname, mtime, rebuild=False): if rebuild: debug.logger & debug.flagSearcher and debug.logger('pretend %s is very old' % mibname) return mibname = decode(mibname) pyfile = os.path.join(self._path, mibname) for pySfx in BYTECODE_SUFFIXES: f = pyfile + pySfx if not os.path.exists(f) or not os.path.isfile(f): debug.logger & debug.flagSearcher and debug.logger('%s not present or not a file' % f) continue try: fp = open(f, 'rb') pyData = fp.read(8) fp.close() except IOError: raise error.PySmiSearcherError('failure opening compiled file %s: %s' % (f, sys.exc_info()[1]), searcher=self) if pyData[:4] == imp.get_magic(): pyData = pyData[4:] pyTime = struct.unpack('= mtime: raise error.PySmiFileNotModifiedError() else: raise error.PySmiFileNotFoundError('older file %s exists' % mibname, searcher=self) else: debug.logger & debug.flagSearcher and debug.logger('bad magic in %s' % f) continue for pySfx in SOURCE_SUFFIXES: f = pyfile + pySfx if not os.path.exists(f) or not os.path.isfile(f): debug.logger & debug.flagSearcher and debug.logger('%s not present or not a file' % f) continue try: pyTime = os.stat(f)[8] except OSError: raise error.PySmiSearcherError('failure opening compiled file %s: %s' % (f, sys.exc_info()[1]), searcher=self) debug.logger & debug.flagSearcher and debug.logger( 'found %s, mtime %s' % (f, time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(pyTime)))) if pyTime >= mtime: raise error.PySmiFileNotModifiedError() raise error.PySmiFileNotFoundError('no compiled file %s found' % mibname, searcher=self) pysmi-0.3.4/pysmi/searcher/pypackage.py0000664006321400632140000001210513454602500021572 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os import time import struct try: import importlib try: PY_MAGIC_NUMBER = importlib.util.MAGIC_NUMBER SOURCE_SUFFIXES = importlib.machinery.SOURCE_SUFFIXES BYTECODE_SUFFIXES = importlib.machinery.BYTECODE_SUFFIXES except Exception: raise ImportError() except ImportError: import imp PY_MAGIC_NUMBER = imp.get_magic() SOURCE_SUFFIXES = [s[0] for s in imp.get_suffixes() if s[2] == imp.PY_SOURCE] BYTECODE_SUFFIXES = [s[0] for s in imp.get_suffixes() if s[2] == imp.PY_COMPILED] from pysmi.searcher.base import AbstractSearcher from pysmi.searcher.pyfile import PyFileSearcher from pysmi.compat import decode from pysmi import debug from pysmi import error class PyPackageSearcher(AbstractSearcher): """Figures out if given Python module (source or bytecode) exists in given Python package. Python package must be importable. """ def __init__(self, package): """Create an instance of *PyPackageSearcher* bound to specific Python package. Args: package (str): name of the Python package to look up Python modules at. """ self._package = package self.__loader = None def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._package) @staticmethod def _parseDosTime(dosdate, dostime): t = (((dosdate >> 9) & 0x7f) + 1980, # year ((dosdate >> 5) & 0x0f), # month dosdate & 0x1f, # mday (dostime >> 11) & 0x1f, # hour (dostime >> 5) & 0x3f, # min (dostime & 0x1f) * 2, # sec -1, # wday -1, # yday -1) # dst return time.mktime(t) def fileExists(self, mibname, mtime, rebuild=False): if rebuild: debug.logger & debug.flagSearcher and debug.logger('pretend %s is very old' % mibname) return mibname = decode(mibname) try: p = __import__(self._package, globals(), locals(), ['__init__']) if hasattr(p, '__loader__') and hasattr(p.__loader__, '_files'): self.__loader = p.__loader__ self._package = self._package.replace('.', os.sep) debug.logger & debug.flagSearcher and debug.logger( '%s is an importable egg at %s' % (self._package, os.path.split(p.__file__)[0])) elif hasattr(p, '__file__'): debug.logger & debug.flagSearcher and debug.logger( '%s is not an egg, trying it as a package directory' % self._package) return PyFileSearcher(os.path.split(p.__file__)[0]).fileExists(mibname, mtime, rebuild=rebuild) else: raise error.PySmiFileNotFoundError('%s is neither importable nor a file' % self._package, searcher=self) except ImportError: raise error.PySmiFileNotFoundError('%s is not importable, trying as a path' % self._package, searcher=self) for pySfx in BYTECODE_SUFFIXES: f = os.path.join(self._package, mibname.upper()) + pySfx if f not in self.__loader._files: debug.logger & debug.flagSearcher and debug.logger('%s is not in %s' % (f, self._package)) continue pyData = self.__loader.get_data(f) if pyData[:4] == PY_MAGIC_NUMBER: pyData = pyData[4:] pyTime = struct.unpack('= mtime: raise error.PySmiFileNotModifiedError() else: raise error.PySmiFileNotFoundError('older file %s exists' % mibname, searcher=self) else: debug.logger & debug.flagSearcher and debug.logger('bad magic in %s' % f) continue for pySfx in SOURCE_SUFFIXES: f = os.path.join(self._package, mibname.upper()) + pySfx if f not in self.__loader._files: debug.logger & debug.flagSearcher and debug.logger('%s is not in %s' % (f, self._package)) continue pyTime = self._parseDosTime( self.__loader._files[f][6], self.__loader._files[f][5] ) debug.logger & debug.flagSearcher and debug.logger( 'found %s, mtime %s' % (f, time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(pyTime)))) if pyTime >= mtime: raise error.PySmiFileNotModifiedError() else: raise error.PySmiFileNotFoundError('older file %s exists' % mibname, searcher=self) raise error.PySmiFileNotFoundError('no file %s found' % mibname, searcher=self) pysmi-0.3.4/pysmi/searcher/stub.py0000664006321400632140000000241413411726453020614 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.searcher.base import AbstractSearcher from pysmi import debug from pysmi import error class StubSearcher(AbstractSearcher): """Figures out if given MIB module is present in a fixed list of modules. """ def __init__(self, *mibnames): """Create an instance of *StubSearcher* initialized with a fixed list or MIB modules names. Args: mibnames (str): blacklisted MIB names """ self._mibnames = mibnames def __str__(self): return '%s' % self.__class__.__name__ def fileExists(self, mibname, mtime, rebuild=False): if mibname in self._mibnames: debug.logger & debug.flagSearcher and debug.logger('pretend compiled %s exists and is very new' % mibname) raise error.PySmiFileNotModifiedError('compiled file %s is among %s' % (mibname, ', '.join(self._mibnames)), searcher=self) raise error.PySmiFileNotFoundError('no compiled file %s found among %s' % (mibname, ', '.join(self._mibnames)), searcher=self) pysmi-0.3.4/pysmi/writer/0000775006321400632140000000000013454602625017005 5ustar ietingofietingof00000000000000pysmi-0.3.4/pysmi/writer/__init__.py0000664006321400632140000000044713411726453021122 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # from pysmi.writer.localfile import FileWriter from pysmi.writer.pyfile import PyFileWriter from pysmi.writer.callback import CallbackWriter pysmi-0.3.4/pysmi/writer/base.py0000664006321400632140000000073713411726453020277 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # class AbstractWriter(object): def setOptions(self, **kwargs): for k in kwargs: setattr(self, k, kwargs[k]) return self def putData(self, mibname, data, comments=(), dryRun=False): raise NotImplementedError() def getData(self, filename): raise NotImplementedError() pysmi-0.3.4/pysmi/writer/callback.py0000664006321400632140000000276113411726453021120 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys from pysmi.writer.base import AbstractWriter from pysmi import debug from pysmi import error class CallbackWriter(AbstractWriter): """Invokes user-specified callable and passes transformed MIB module to it. Note: user callable object signature must be as follows .. function:: cbFun(mibname, contents, cbCtx) """ def __init__(self, cbFun, cbCtx=None): """Creates an instance of *CallbackWriter* class. Args: cbFun (callable): user-supplied callable Keyword Args: cbCtx: user-supplied object passed intact to user callback """ self._cbFun = cbFun self._cbCtx = cbCtx def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._cbFun) def putData(self, mibname, data, comments=(), dryRun=False): if dryRun: debug.logger & debug.flagWriter and debug.logger('dry run mode') return try: self._cbFun(mibname, data, self._cbCtx) except Exception: raise error.PySmiWriterError( 'user callback %s failure writing %s: %s' % (self._cbFun, mibname, sys.exc_info()[1]), writer=self) debug.logger & debug.flagWriter and debug.logger('user callback for %s succeeded' % mibname) def getData(self, filename): return '' pysmi-0.3.4/pysmi/writer/localfile.py0000664006321400632140000000504513411726453021314 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os import sys import tempfile from pysmi.writer.base import AbstractWriter from pysmi.compat import encode, decode from pysmi import debug from pysmi import error class FileWriter(AbstractWriter): """Stores transformed MIB modules in files at specified location. User is expected to pass *FileReader* class instance to *MibCompiler* on instantiation. The rest is internal to *MibCompiler*. """ suffix = '' def __init__(self, path): """Creates an instance of *FileReader* class. Args: path: writable directory to store created files """ self._path = decode(os.path.normpath(path)) def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._path) def getData(self, mibname, dryRun=False): filename = os.path.join(self._path, decode(mibname)) + self.suffix f = None try: f = open(filename) data = f.read() f.close() return data except (OSError, IOError, UnicodeEncodeError): if f: f.close() return '' def putData(self, mibname, data, comments=(), dryRun=False): if dryRun: debug.logger & debug.flagWriter and debug.logger('dry run mode') return if not os.path.exists(self._path): try: os.makedirs(self._path) except OSError: raise error.PySmiWriterError( 'failure creating destination directory %s: %s' % (self._path, sys.exc_info()[1]), writer=self) if comments: data = '#\n' + ''.join(['# %s\n' % x for x in comments]) + '#\n' + data filename = os.path.join(self._path, decode(mibname)) + self.suffix tfile = None try: fd, tfile = tempfile.mkstemp(dir=self._path) os.write(fd, encode(data)) os.close(fd) os.rename(tfile, filename) except (OSError, IOError, UnicodeEncodeError): exc = sys.exc_info() if tfile: try: os.unlink(tfile) except OSError: pass raise error.PySmiWriterError('failure writing file %s: %s' % (filename, exc[1]), file=filename, writer=self) debug.logger & debug.flagWriter and debug.logger('%s stored in %s' % (mibname, filename)) pysmi-0.3.4/pysmi/writer/pyfile.py0000664006321400632140000000650513454602500020645 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import os import sys import tempfile import py_compile try: import importlib try: SOURCE_SUFFIXES = importlib.machinery.SOURCE_SUFFIXES except Exception: raise ImportError() except ImportError: import imp SOURCE_SUFFIXES = [s[0] for s in imp.get_suffixes() if s[2] == imp.PY_SOURCE] from pysmi.writer.base import AbstractWriter from pysmi.compat import encode, decode from pysmi import debug from pysmi import error class PyFileWriter(AbstractWriter): """Stores transformed MIB modules as Python files at specified location. User is expected to pass *PyFileWriter* class instance to *MibCompiler* on instantiation. The rest is internal to *MibCompiler*. """ pyCompile = True pyOptimizationLevel = -1 def __init__(self, path): """Creates an instance of *PyFileWriter* class. Args: path: writable directory to store Python modules """ self._path = decode(os.path.normpath(path)) def __str__(self): return '%s{"%s"}' % (self.__class__.__name__, self._path) def putData(self, mibname, data, comments=(), dryRun=False): if dryRun: debug.logger & debug.flagWriter and debug.logger('dry run mode') return if not os.path.exists(self._path): try: os.makedirs(self._path) except OSError: raise error.PySmiWriterError( 'failure creating destination directory %s: %s' % (self._path, sys.exc_info()[1]), writer=self) if comments: data = '#\n' + ''.join(['# %s\n' % x for x in comments]) + '#\n' + data pyfile = os.path.join(self._path, decode(mibname)) pyfile += SOURCE_SUFFIXES[0] tfile = None try: fd, tfile = tempfile.mkstemp(dir=self._path) os.write(fd, encode(data)) os.close(fd) os.rename(tfile, pyfile) except (OSError, IOError, UnicodeEncodeError): exc = sys.exc_info() if tfile: try: os.unlink(tfile) except OSError: pass raise error.PySmiWriterError('failure writing file %s: %s' % (pyfile, exc[1]), file=pyfile, writer=self) debug.logger & debug.flagWriter and debug.logger('created file %s' % pyfile) if self.pyCompile: try: if sys.version_info[0:2] > (3, 1): # noinspection PyArgumentList py_compile.compile(pyfile, doraise=True, optimize=self.pyOptimizationLevel) else: py_compile.compile(pyfile, doraise=True) except (SyntaxError, py_compile.PyCompileError): pass # XXX except: try: os.unlink(pyfile) except Exception: pass raise error.PySmiWriterError('failure compiling %s: %s' % (pyfile, sys.exc_info()[1]), file=mibname, writer=self) debug.logger & debug.flagWriter and debug.logger('%s stored' % mibname) def getData(self, filename): return '' pysmi-0.3.4/pysmi.egg-info/0000775006321400632140000000000013454602625017163 5ustar ietingofietingof00000000000000pysmi-0.3.4/pysmi.egg-info/PKG-INFO0000664006321400632140000000313413454602625020261 0ustar ietingofietingof00000000000000Metadata-Version: 1.2 Name: pysmi Version: 0.3.4 Summary: SNMP SMI/MIB Parser Home-page: https://github.com/etingof/pysmi Author: Ilya Etingof Author-email: etingof@gmail.com Maintainer: Ilya Etingof License: BSD Description: A pure-Python implementation of SNMP/SMI MIB parsing and conversion library. Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Education Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Communications Classifier: Topic :: System :: Monitoring Classifier: Topic :: System :: Networking :: Monitoring Classifier: Topic :: Software Development :: Libraries :: Python Modules pysmi-0.3.4/pysmi.egg-info/SOURCES.txt0000664006321400632140000001000013454602625021036 0ustar ietingofietingof00000000000000CHANGES.rst LICENSE.rst MANIFEST.in README.md THANKS.txt TODO.txt devel-requirements.txt requirements.txt setup.cfg setup.py test-requirements.txt docs/Makefile docs/README.txt docs/source/changelog.rst docs/source/conf.py docs/source/contents.rst docs/source/documentation.rst docs/source/download.rst docs/source/library-reference.rst docs/source/license.rst docs/source/mibcopy.rst docs/source/mibdump.rst docs/source/.static/logo.svg docs/source/examples/always-borrow-precompiled-pysnmp-files.rst docs/source/examples/borrow-precompiled-pysnmp-files-on-failure.rst docs/source/examples/compile-smistar-mibs-into-pysnmp-files-if-needed.rst docs/source/examples/compile-smiv2-mibs-from-text-into-pysnmp-code.rst docs/source/examples/download-and-compile-smistar-mibs-into-json.rst docs/source/examples/download-and-compile-smistar-mibs-into-pysnmp-files.rst docs/source/pysmi/borrower/anyfile/anyfileborrower.rst docs/source/pysmi/borrower/pyfile/pyfileborrower.rst docs/source/pysmi/codegen/jsondoc/jsoncodegen.rst docs/source/pysmi/codegen/null/nullcodegen.rst docs/source/pysmi/codegen/pysnmp/pysnmpcodegen.rst docs/source/pysmi/compiler/mibcompiler.rst docs/source/pysmi/compiler/mibstatus.rst docs/source/pysmi/parser/smi/dialect.rst docs/source/pysmi/parser/smi/parserfactory.rst docs/source/pysmi/reader/callback/callbackreader.rst docs/source/pysmi/reader/ftpclient/ftpreader.rst docs/source/pysmi/reader/httpclient/httpreader.rst docs/source/pysmi/reader/localfile/filereader.rst docs/source/pysmi/reader/zipreader/zipreader.rst docs/source/pysmi/searcher/pyfile/pyfilesearcher.rst docs/source/pysmi/searcher/pypackage/pypackagesearcher.rst docs/source/pysmi/searcher/stub/stubsearcher.rst docs/source/pysmi/writer/callback/callbackwriter.rst docs/source/pysmi/writer/localfile/filewriter.rst docs/source/pysmi/writer/pyfile/pyfilewriter.rst examples/always-borrow-precompiled-pysnmp-files.py examples/borrow-precompiled-pysnmp-files-on-failure.py examples/compile-smistar-mibs-into-pysnmp-files-if-needed.py examples/compile-smiv2-mibs-from-text-into-pysnmp-code.py examples/download-and-compile-smistar-mibs-into-json.py examples/download-and-compile-smistar-mibs-into-pysnmp-files.py pysmi/__init__.py pysmi/compat.py pysmi/compiler.py pysmi/debug.py pysmi/error.py pysmi/mibinfo.py pysmi.egg-info/PKG-INFO pysmi.egg-info/SOURCES.txt pysmi.egg-info/dependency_links.txt pysmi.egg-info/requires.txt pysmi.egg-info/top_level.txt pysmi.egg-info/zip-safe pysmi/borrower/__init__.py pysmi/borrower/anyfile.py pysmi/borrower/base.py pysmi/borrower/pyfile.py pysmi/codegen/__init__.py pysmi/codegen/base.py pysmi/codegen/jsondoc.py pysmi/codegen/null.py pysmi/codegen/pysnmp.py pysmi/codegen/symtable.py pysmi/lexer/__init__.py pysmi/lexer/base.py pysmi/lexer/smi.py pysmi/parser/__init__.py pysmi/parser/base.py pysmi/parser/dialect.py pysmi/parser/null.py pysmi/parser/smi.py pysmi/parser/smiv1.py pysmi/parser/smiv1compat.py pysmi/parser/smiv2.py pysmi/reader/__init__.py pysmi/reader/base.py pysmi/reader/callback.py pysmi/reader/ftpclient.py pysmi/reader/httpclient.py pysmi/reader/localfile.py pysmi/reader/url.py pysmi/reader/zipreader.py pysmi/searcher/__init__.py pysmi/searcher/anyfile.py pysmi/searcher/base.py pysmi/searcher/pyfile.py pysmi/searcher/pypackage.py pysmi/searcher/stub.py pysmi/writer/__init__.py pysmi/writer/base.py pysmi/writer/callback.py pysmi/writer/localfile.py pysmi/writer/pyfile.py scripts/mibcopy.py scripts/mibdump.py tests/__init__.py tests/__main__.py tests/test_agentcapabilities_smiv2_pysnmp.py tests/test_imports_smiv2_pysnmp.py tests/test_modulecompliance_smiv2_pysnmp.py tests/test_moduleidentity_smiv2_pysnmp.py tests/test_notificationgroup_smiv2_pysnmp.py tests/test_notificationtype_smiv2_pysnmp.py tests/test_objectgroup_smiv2_pysnmp.py tests/test_objectidentity_smiv2_pysnmp.py tests/test_objecttype_smiv2_pysnmp.py tests/test_smiv1_smiv2_pysnmp.py tests/test_traptype_smiv2_pysnmp.py tests/test_typedeclaration_smiv1_pysnmp.py tests/test_typedeclaration_smiv2_pysnmp.py tests/test_valuedeclaration_smiv2_pysnmp.py tests/test_zipreader.pypysmi-0.3.4/pysmi.egg-info/dependency_links.txt0000664006321400632140000000000113454602625023231 0ustar ietingofietingof00000000000000 pysmi-0.3.4/pysmi.egg-info/requires.txt0000664006321400632140000000000413454602625021555 0ustar ietingofietingof00000000000000ply pysmi-0.3.4/pysmi.egg-info/top_level.txt0000664006321400632140000000000613454602625021711 0ustar ietingofietingof00000000000000pysmi pysmi-0.3.4/pysmi.egg-info/zip-safe0000664006321400632140000000000113026564037020612 0ustar ietingofietingof00000000000000 pysmi-0.3.4/requirements.txt0000664006321400632140000000020513454602510017602 0ustar ietingofietingof00000000000000ply==3.4; python_version < '2.6' ply; python_version >= '2.6' ordereddict; python_version < '2.7' simplejson; python_version < '2.6' pysmi-0.3.4/scripts/0000775006321400632140000000000013454602625016017 5ustar ietingofietingof00000000000000pysmi-0.3.4/scripts/mibcopy.py0000664006321400632140000002060713411726453020037 0ustar ietingofietingof00000000000000#!/usr/bin/env python # # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # # SNMP SMI/MIB copying tool # import os import sys import getopt import shutil from datetime import datetime from pysmi.reader import FileReader, getReadersFromUrls from pysmi.writer import CallbackWriter from pysmi.parser import SmiV1CompatParser from pysmi.codegen import JsonCodeGen from pysmi.compiler import MibCompiler from pysmi import debug from pysmi import error # sysexits.h EX_OK = 0 EX_USAGE = 64 EX_SOFTWARE = 70 # Defaults quietFlag = False verboseFlag = False mibSources = [] dstDirectory = None cacheDirectory = '' dryrunFlag = False ignoreErrorsFlag = False helpMessage = """\ Usage: %s [--help] [--version] [--verbose] [--quiet] [--debug=<%s>] [--mib-source=] [--cache-directory=] [--ignore-errors] [--dry-run] Where: URI - file, zip, http, https, ftp, sftp schemes are supported. Use @mib@ placeholder token in URI to refer directly to the required MIB module when source does not support directory listing (e.g. HTTP). """ % ( sys.argv[0], '|'.join([x for x in sorted(debug.flagMap)]) ) # TODO(etingof): add the option to copy MIBs into enterprise-indexed subdirs try: opts, inputMibs = getopt.getopt( sys.argv[1:], 'hv', ['help', 'version', 'verbose', 'quiet', 'debug=', 'mib-source=', 'mib-stub=', 'cache-directory=', 'ignore-errors', 'dry-run'] ) except getopt.GetoptError: sys.exit(EX_USAGE) for opt in opts: if opt[0] == '-h' or opt[0] == '--help': sys.stderr.write("""\ Synopsis: SNMP SMI/MIB files copying tool. When given MIB file(s) or directory(ies) on input and a destination directory, the tool parses MIBs to figure out their canonical MIB module name and the latest revision date, then copies MIB module on input into the destination directory under its MIB module name *if* there is no such file already or its revision date is older. Documentation: http://snmplabs.com/pysmi %s """ % helpMessage) sys.exit(EX_OK) if opt[0] == '-v' or opt[0] == '--version': from pysmi import __version__ sys.stderr.write("""\ SNMP SMI/MIB library version %s, written by Ilya Etingof Python interpreter: %s Software documentation and support at http://snmplabs.com/pysmi %s """ % (__version__, sys.version, helpMessage)) sys.exit(EX_OK) if opt[0] == '--quiet': quietFlag = True if opt[0] == '--verbose': verboseFlag = True if opt[0] == '--debug': debug.setLogger(debug.Debug(*opt[1].split(','))) if opt[0] == '--mib-source': mibSources.append(opt[1]) if opt[0] == '--cache-directory': cacheDirectory = opt[1] if opt[0] == '--ignore-errors': ignoreErrorsFlag = True if not mibSources: mibSources = ['file:///usr/share/snmp/mibs', 'http://mibs.snmplabs.com/asn1/@mib@'] if len(inputMibs) < 2: sys.stderr.write('ERROR: MIB source and/or destination arguments not given\r\n%s\r\n' % helpMessage) sys.exit(EX_USAGE) dstDirectory = inputMibs.pop() if os.path.exists(dstDirectory) and not os.path.isdir(dstDirectory): sys.stderr.write('ERROR: given destination is not a directory\r\n%s\r\n' % helpMessage) sys.exit(EX_USAGE) try: os.makedirs(dstDirectory, mode=0o755) except OSError: pass # Compiler infrastructure codeGenerator = JsonCodeGen() mibParser = SmiV1CompatParser(tempdir=cacheDirectory) fileWriter = CallbackWriter(lambda *x: None) def getMibRevision(mibDir, mibFile): mibCompiler = MibCompiler( mibParser, codeGenerator, fileWriter ) mibCompiler.addSources( FileReader(mibDir, recursive=False, ignoreErrors=ignoreErrorsFlag), *getReadersFromUrls(*mibSources) ) try: processed = mibCompiler.compile( mibFile, **dict(noDeps=True, rebuild=True, fuzzyMatching=False, ignoreErrors=ignoreErrorsFlag) ) except error.PySmiError: sys.stderr.write('ERROR: %s\r\n' % sys.exc_info()[1]) sys.exit(EX_SOFTWARE) for canonicalMibName in processed: if (processed[canonicalMibName] == 'compiled' and processed[canonicalMibName].path == 'file://' + os.path.join(mibDir, mibFile)): try: revision = datetime.strptime(processed[canonicalMibName].revision, '%Y-%m-%d %H:%M') except Exception: revision = datetime.fromtimestamp(0) return canonicalMibName, revision raise error.PySmiError('Can\'t read or parse MIB "%s"' % os.path.join(mibDir, mibFile)) def shortenPath(path, maxLength=45): if len(path) > maxLength: return '...' + path[-maxLength:] else: return path mibsSeen = mibsCopied = mibsFailed = 0 mibsRevisions = {} for srcDirectory in inputMibs: if verboseFlag: sys.stderr.write('Reading "%s"...\r\n' % srcDirectory) if os.path.isfile(srcDirectory): mibFiles = [(os.path.abspath(os.path.dirname(srcDirectory)), os.path.basename(srcDirectory))] else: mibFiles = [(os.path.abspath(dirName), mibFile) for dirName, _, mibFiles in os.walk(srcDirectory) for mibFile in mibFiles] for srcDirectory, mibFile in mibFiles: mibsSeen += 1 # TODO(etingof): also check module OID to make sure there is no name collision try: mibName, srcMibRevision = getMibRevision(srcDirectory, mibFile) except error.PySmiError as ex: if verboseFlag: sys.stderr.write('Failed to read source MIB "%s": %s\r\n' % (os.path.join(srcDirectory, mibFile), ex)) if not quietFlag: sys.stderr.write('FAILED %s\r\n' % shortenPath(os.path.join(srcDirectory, mibFile))) mibsFailed +=1 continue if mibName in mibsRevisions: dstMibRevision = mibsRevisions[mibName] else: try: _, dstMibRevision = getMibRevision(dstDirectory, mibName) except error.PySmiError as ex: if verboseFlag: sys.stderr.write('MIB "%s" is not available at the ' 'destination directory "%s": %s\r\n' % (os.path.join(srcDirectory, mibFile), dstDirectory, ex)) dstMibRevision = datetime.fromtimestamp(0) mibsRevisions[mibName] = dstMibRevision if dstMibRevision >= srcMibRevision: if verboseFlag: sys.stderr.write('Destination MIB "%s" has the same or newer revision as the ' 'source MIB "%s"\r\n' % (os.path.join(dstDirectory, mibName), os.path.join(srcDirectory, mibFile))) if not quietFlag: sys.stderr.write('NOT COPIED %s (%s)\r\n' % ( shortenPath(os.path.join(srcDirectory, mibFile)), mibName)) continue mibsRevisions[mibName] = srcMibRevision if verboseFlag: sys.stderr.write('Copying "%s" (revision "%s") -> "%s" (revision "%s")\r\n' % ( os.path.join(srcDirectory, mibFile), srcMibRevision, os.path.join(dstDirectory, mibName), dstMibRevision)) try: shutil.copy(os.path.join(srcDirectory, mibFile), os.path.join(dstDirectory, mibName)) except Exception as ex: if verboseFlag: sys.stderr.write('Failed to copy MIB "%s" -> "%s" (%s): "%s"\r\n' % ( os.path.join(srcDirectory, mibFile), os.path.join(dstDirectory, mibName), mibName, ex)) if not quietFlag: sys.stderr.write('FAILED %s (%s)\r\n' % ( shortenPath(os.path.join(srcDirectory, mibFile)), mibName)) mibsFailed += 1 else: if not quietFlag: sys.stderr.write('COPIED %s (%s)\r\n' % ( shortenPath(os.path.join(srcDirectory, mibFile)), mibName)) mibsCopied +=1 if not quietFlag: sys.stderr.write("MIBs seen: %d, copied: %d, failed: %d\r\n" % (mibsSeen, mibsCopied, mibsFailed)) sys.exit(EX_OK) pysmi-0.3.4/scripts/mibdump.py0000664006321400632140000003021313454602510020016 0ustar ietingofietingof00000000000000#!/usr/bin/env python # # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # # SNMP SMI/MIB data management tool # import os import sys import getopt from pysmi.reader import getReadersFromUrls from pysmi.searcher import AnyFileSearcher, PyFileSearcher, PyPackageSearcher, StubSearcher from pysmi.borrower import AnyFileBorrower, PyFileBorrower from pysmi.writer import PyFileWriter, FileWriter, CallbackWriter from pysmi.parser import SmiV1CompatParser from pysmi.codegen import PySnmpCodeGen, JsonCodeGen, NullCodeGen from pysmi.compiler import MibCompiler from pysmi import debug from pysmi import error # sysexits.h EX_OK = 0 EX_USAGE = 64 EX_SOFTWARE = 70 EX_MIB_MISSING = 79 EX_MIB_FAILED = 79 # Defaults verboseFlag = True mibSources = [] doFuzzyMatchingFlag = True mibSearchers = [] mibStubs = [] mibBorrowers = [] dstFormat = None dstDirectory = None cacheDirectory = '' nodepsFlag = False rebuildFlag = False dryrunFlag = False genMibTextsFlag = False keepTextsLayout = False pyCompileFlag = True pyOptimizationLevel = 0 ignoreErrorsFlag = False buildIndexFlag = False writeMibsFlag = True helpMessage = """\ Usage: %s [--help] [--version] [--quiet] [--debug=<%s>] [--mib-source=] [--mib-searcher=] [--mib-stub=] [--mib-borrower=] [--destination-format=] [--destination-directory=] [--cache-directory=] [--disable-fuzzy-source] [--no-dependencies] [--no-python-compile] [--python-optimization-level] [--ignore-errors] [--build-index] [--rebuild] [--dry-run] [--no-mib-writes] [--generate-mib-texts] [--keep-texts-layout] [MIB-NAME [...]]] Where: URI - file, zip, http, https, ftp, sftp schemes are supported. Use @mib@ placeholder token in URI to refer directly to the required MIB module when source does not support directory listing (e.g. HTTP). FORMAT - pysnmp, json, null""" % ( sys.argv[0], '|'.join([x for x in sorted(debug.flagMap)]) ) try: opts, inputMibs = getopt.getopt( sys.argv[1:], 'hv', ['help', 'version', 'quiet', 'debug=', 'mib-source=', 'mib-searcher=', 'mib-stub=', 'mib-borrower=', 'destination-format=', 'destination-directory=', 'cache-directory=', 'no-dependencies', 'no-python-compile', 'python-optimization-level=', 'ignore-errors', 'build-index', 'rebuild', 'dry-run', 'no-mib-writes', 'generate-mib-texts', 'disable-fuzzy-source', 'keep-texts-layout'] ) except getopt.GetoptError: if verboseFlag: sys.stderr.write('ERROR: %s\r\n%s\r\n' % (sys.exc_info()[1], helpMessage)) sys.exit(EX_USAGE) for opt in opts: if opt[0] == '-h' or opt[0] == '--help': sys.stderr.write("""\ Synopsis: SNMP SMI/MIB files conversion tool Documentation: http://snmplabs.com/pysmi %s """ % helpMessage) sys.exit(EX_OK) if opt[0] == '-v' or opt[0] == '--version': from pysmi import __version__ sys.stderr.write("""\ SNMP SMI/MIB library version %s, written by Ilya Etingof Python interpreter: %s Software documentation and support at http://snmplabs.com/pysmi %s """ % (__version__, sys.version, helpMessage)) sys.exit(EX_OK) if opt[0] == '--quiet': verboseFlag = False if opt[0] == '--debug': debug.setLogger(debug.Debug(*opt[1].split(','))) if opt[0] == '--mib-source': mibSources.append(opt[1]) if opt[0] == '--mib-searcher': mibSearchers.append(opt[1]) if opt[0] == '--mib-stub': mibStubs.append(opt[1]) if opt[0] == '--mib-borrower': mibBorrowers.append((opt[1], genMibTextsFlag)) if opt[0] == '--destination-format': dstFormat = opt[1] if opt[0] == '--destination-directory': dstDirectory = opt[1] if opt[0] == '--cache-directory': cacheDirectory = opt[1] if opt[0] == '--no-dependencies': nodepsFlag = True if opt[0] == '--no-python-compile': pyCompileFlag = False if opt[0] == '--python-optimization-level': try: pyOptimizationLevel = int(opt[1]) except ValueError: sys.stderr.write('ERROR: known Python optimization levels: -1, 0, 1, 2\r\n%s\r\n' % helpMessage) sys.exit(EX_USAGE) if opt[0] == '--ignore-errors': ignoreErrorsFlag = True if opt[0] == '--build-index': buildIndexFlag = True if opt[0] == '--rebuild': rebuildFlag = True if opt[0] == '--dry-run': dryrunFlag = True if opt[0] == '--no-mib-writes': writeMibsFlag = False if opt[0] == '--generate-mib-texts': genMibTextsFlag = True if opt[0] == '--disable-fuzzy-source': doFuzzyMatchingFlag = False if opt[0] == '--keep-texts-layout': keepTextsLayout = True if not mibSources: mibSources = ['file:///usr/share/snmp/mibs', 'http://mibs.snmplabs.com/asn1/@mib@'] if inputMibs: mibSources = sorted( set([os.path.abspath(os.path.dirname(x)) for x in inputMibs if os.path.sep in x]) ) + mibSources inputMibs = [os.path.basename(os.path.splitext(x)[0]) for x in inputMibs] if not inputMibs: sys.stderr.write('ERROR: MIB modules names not specified\r\n%s\r\n' % helpMessage) sys.exit(EX_USAGE) if not dstFormat: dstFormat = 'pysnmp' if dstFormat == 'pysnmp': if not mibSearchers: mibSearchers = PySnmpCodeGen.defaultMibPackages if not mibStubs: mibStubs = [x for x in PySnmpCodeGen.baseMibs if x not in PySnmpCodeGen.fakeMibs] if not mibBorrowers: mibBorrowers = [('http://mibs.snmplabs.com/pysnmp/notexts/@mib@', False), ('http://mibs.snmplabs.com/pysnmp/fulltexts/@mib@', True)] if not dstDirectory: dstDirectory = os.path.expanduser("~") if sys.platform[:3] == 'win': dstDirectory = os.path.join(dstDirectory, 'PySNMP Configuration', 'mibs') else: dstDirectory = os.path.join(dstDirectory, '.pysnmp', 'mibs') # Compiler infrastructure borrowers = [PyFileBorrower(x[1], genTexts=mibBorrowers[x[0]][1]) for x in enumerate(getReadersFromUrls(*[m[0] for m in mibBorrowers], **dict(lowcaseMatching=False)))] searchers = [PyFileSearcher(dstDirectory)] for mibSearcher in mibSearchers: searchers.append(PyPackageSearcher(mibSearcher)) searchers.append(StubSearcher(*mibStubs)) codeGenerator = PySnmpCodeGen() fileWriter = PyFileWriter(dstDirectory).setOptions(pyCompile=pyCompileFlag, pyOptimizationLevel=pyOptimizationLevel) elif dstFormat == 'json': if not mibStubs: mibStubs = JsonCodeGen.baseMibs if not mibBorrowers: mibBorrowers = [('http://mibs.snmplabs.com/json/notexts/@mib@', False), ('http://mibs.snmplabs.com/json/fulltexts/@mib@', True)] if not dstDirectory: dstDirectory = os.path.join('.') # Compiler infrastructure borrowers = [AnyFileBorrower(x[1], genTexts=mibBorrowers[x[0]][1]).setOptions(exts=['.json']) for x in enumerate(getReadersFromUrls(*[m[0] for m in mibBorrowers], **dict(lowcaseMatching=False)))] searchers = [AnyFileSearcher(dstDirectory).setOptions(exts=['.json']), StubSearcher(*mibStubs)] codeGenerator = JsonCodeGen() fileWriter = FileWriter(dstDirectory).setOptions(suffix='.json') elif dstFormat == 'null': if not mibStubs: mibStubs = NullCodeGen.baseMibs if not mibBorrowers: mibBorrowers = [('http://mibs.snmplabs.com/null/notexts/@mib@', False), ('http://mibs.snmplabs.com/null/fulltexts/@mib@', True)] if not dstDirectory: dstDirectory = '' # Compiler infrastructure codeGenerator = NullCodeGen() searchers = [StubSearcher(*mibStubs)] borrowers = [AnyFileBorrower(x[1], genTexts=mibBorrowers[x[0]][1]) for x in enumerate(getReadersFromUrls(*[m[0] for m in mibBorrowers], **dict(lowcaseMatching=False)))] fileWriter = CallbackWriter(lambda *x: None) else: sys.stderr.write('ERROR: unknown destination format: %s\r\n%s\r\n' % (dstFormat, helpMessage)) sys.exit(EX_USAGE) if verboseFlag: sys.stderr.write("""Source MIB repositories: %s Borrow missing/failed MIBs from: %s Existing/compiled MIB locations: %s Compiled MIBs destination directory: %s MIBs excluded from code generation: %s MIBs to compile: %s Destination format: %s Parser grammar cache directory: %s Also compile all relevant MIBs: %s Rebuild MIBs regardless of age: %s Dry run mode: %s Create/update MIBs: %s Byte-compile Python modules: %s (optimization level %s) Ignore compilation errors: %s Generate OID->MIB index: %s Generate texts in MIBs: %s Keep original texts layout: %s Try various file names while searching for MIB module: %s """ % (', '.join(mibSources), ', '.join([x[0] for x in mibBorrowers if x[1] == genMibTextsFlag]), ', '.join(mibSearchers), dstDirectory, ', '.join(sorted(mibStubs)), ', '.join(inputMibs), dstFormat, cacheDirectory or 'not used', nodepsFlag and 'no' or 'yes', rebuildFlag and 'yes' or 'no', dryrunFlag and 'yes' or 'no', writeMibsFlag and 'yes' or 'no', dstFormat == 'pysnmp' and pyCompileFlag and 'yes' or 'no', dstFormat == 'pysnmp' and pyOptimizationLevel and 'yes' or 'no', ignoreErrorsFlag and 'yes' or 'no', buildIndexFlag and 'yes' or 'no', genMibTextsFlag and 'yes' or 'no', keepTextsLayout and 'yes' or 'no', doFuzzyMatchingFlag and 'yes' or 'no')) # Initialize compiler infrastructure mibCompiler = MibCompiler( SmiV1CompatParser(tempdir=cacheDirectory), codeGenerator, fileWriter ) try: mibCompiler.addSources( *getReadersFromUrls( *mibSources, **dict(fuzzyMatching=doFuzzyMatchingFlag) ) ) mibCompiler.addSearchers(*searchers) mibCompiler.addBorrowers(*borrowers) processed = mibCompiler.compile( *inputMibs, **dict(noDeps=nodepsFlag, rebuild=rebuildFlag, dryRun=dryrunFlag, genTexts=genMibTextsFlag, textFilter=keepTextsLayout and (lambda symbol, text: text) or None, writeMibs=writeMibsFlag, ignoreErrors=ignoreErrorsFlag) ) if buildIndexFlag: mibCompiler.buildIndex( processed, dryRun=dryrunFlag, ignoreErrors=ignoreErrorsFlag ) except error.PySmiError: sys.stderr.write('ERROR: %s\r\n' % sys.exc_info()[1]) sys.exit(EX_SOFTWARE) else: if verboseFlag: sys.stderr.write('%sreated/updated MIBs: %s\r\n' % (dryrunFlag and 'Would be c' or 'C', ', '.join( ['%s%s' % (x, x != processed[x].alias and ' (%s)' % processed[x].alias or '') for x in sorted(processed) if processed[x] == 'compiled']))) sys.stderr.write('Pre-compiled MIBs %sborrowed: %s\r\n' % (dryrunFlag and 'Would be ' or '', ', '.join( ['%s (%s)' % (x, processed[x].path) for x in sorted(processed) if processed[x] == 'borrowed']))) sys.stderr.write( 'Up to date MIBs: %s\r\n' % ', '.join(['%s' % x for x in sorted(processed) if processed[x] == 'untouched'])) sys.stderr.write('Missing source MIBs: %s\r\n' % ', '.join( ['%s' % x for x in sorted(processed) if processed[x] == 'missing'])) sys.stderr.write( 'Ignored MIBs: %s\r\n' % ', '.join(['%s' % x for x in sorted(processed) if processed[x] == 'unprocessed'])) sys.stderr.write('Failed MIBs: %s\r\n' % ', '.join( ['%s (%s)' % (x, processed[x].error) for x in sorted(processed) if processed[x] == 'failed'])) exitCode = EX_OK if any(x for x in processed.values() if x == 'missing'): exitCode = EX_MIB_MISSING if any(x for x in processed.values() if x == 'failed'): exitCode = EX_MIB_FAILED sys.exit(exitCode) pysmi-0.3.4/setup.cfg0000664006321400632140000000015213454602625016147 0ustar ietingofietingof00000000000000[bdist_wheel] universal = 1 [metadata] license_file = LICENSE.rst [egg_info] tag_build = tag_date = 0 pysmi-0.3.4/setup.py0000664006321400632140000000764613411726453016056 0ustar ietingofietingof00000000000000#!/usr/bin/env python # # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # """SNMP SMI/MIB Parser A pure-Python implementation of SNMP/SMI MIB parsing and conversion library. """ import os import sys classifiers = """\ Development Status :: 5 - Production/Stable Environment :: Console Intended Audience :: Developers Intended Audience :: Education Intended Audience :: Information Technology Intended Audience :: System Administrators Intended Audience :: Telecommunications Industry License :: OSI Approved :: BSD License Natural Language :: English Operating System :: OS Independent Programming Language :: Python :: 2 Programming Language :: Python :: 2.4 Programming Language :: Python :: 2.5 Programming Language :: Python :: 2.6 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.2 Programming Language :: Python :: 3.3 Programming Language :: Python :: 3.4 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Topic :: Communications Topic :: System :: Monitoring Topic :: System :: Networking :: Monitoring Topic :: Software Development :: Libraries :: Python Modules """ def howto_install_setuptools(): print(""" Error: You need setuptools Python package! It's very easy to install it, just type: wget https://bootstrap.pypa.io/ez_setup.py python ez_setup.py Then you could make eggs from this package. """) if sys.version_info[:2] < (2, 4): print("ERROR: this package requires Python 2.4 or later!") sys.exit(1) try: from setuptools import setup, Command params = {'zip_safe': True} except ImportError: for arg in sys.argv: if 'egg' in arg: howto_install_setuptools() sys.exit(1) from distutils.core import setup, Command params = {} if sys.version_info[:2] < (2, 6): params['requires'] = ['ply(==3.4)', 'simplejson(==2.1)'] else: params['requires'] = ['ply'] if sys.version_info[:2] < (2, 7): params['requires'].append('ordereddict') else: if sys.version_info[:2] < (2, 6): params['install_requires'] = ['ply==3.4', 'simplejson==2.1'] else: params['install_requires'] = ['ply'] if sys.version_info[:2] < (2, 7): params['install_requires'].append('ordereddict') doclines = [x.strip() for x in (__doc__ or '').split('\n') if x] params.update({ 'name': 'pysmi', 'version': open(os.path.join('pysmi', '__init__.py')).read().split('\'')[1], 'description': doclines[0], 'long_description': ' '.join(doclines[1:]), 'maintainer': 'Ilya Etingof ', 'author': 'Ilya Etingof', 'author_email': 'etingof@gmail.com', 'url': 'https://github.com/etingof/pysmi', 'platforms': ['any'], 'classifiers': [x for x in classifiers.split('\n') if x], 'license': 'BSD', 'packages': ['pysmi', 'pysmi.reader', 'pysmi.searcher', 'pysmi.lexer', 'pysmi.parser', 'pysmi.codegen', 'pysmi.borrower', 'pysmi.writer'], 'scripts': [os.path.join('scripts', 'mibdump.py'), os.path.join('scripts', 'mibcopy.py')] }) # handle unittest discovery feature if sys.version_info[0:2] < (2, 7) or \ sys.version_info[0:2] in ((3, 0), (3, 1)): try: import unittest2 as unittest except ImportError: unittest = None else: import unittest if unittest: class PyTest(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): suite = unittest.defaultTestLoader.discover('tests') unittest.TextTestRunner(verbosity=2).run(suite) params['cmdclass'] = {'test': PyTest} setup(**params) pysmi-0.3.4/test-requirements.txt0000664006321400632140000000001713307233506020562 0ustar ietingofietingof00000000000000pysnmp>=4.3.10 pysmi-0.3.4/tests/0000775006321400632140000000000013454602625015472 5ustar ietingofietingof00000000000000pysmi-0.3.4/tests/__init__.py0000664006321400632140000000007313065461076017604 0ustar ietingofietingof00000000000000# This file is necessary to make this directory a package. pysmi-0.3.4/tests/__main__.py0000664006321400632140000000166613411726453017574 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # try: import unittest2 as unittest except ImportError: import unittest suite = unittest.TestLoader().loadTestsFromNames( ['test_zipreader', 'test_agentcapabilities_smiv2_pysnmp', 'test_imports_smiv2_pysnmp', 'test_modulecompliance_smiv2_pysnmp', 'test_moduleidentity_smiv2_pysnmp', 'test_notificationgroup_smiv2_pysnmp', 'test_notificationtype_smiv2_pysnmp', 'test_objectgroup_smiv2_pysnmp', 'test_objectidentity_smiv2_pysnmp', 'test_objecttype_smiv2_pysnmp', 'test_smiv1_smiv2_pysnmp', 'test_traptype_smiv2_pysnmp', 'test_typedeclaration_smiv1_pysnmp', 'test_typedeclaration_smiv2_pysnmp', 'test_valuedeclaration_smiv2_pysnmp'] ) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_agentcapabilities_smiv2_pysnmp.py0000664006321400632140000000513113454602510025272 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class AgentCapabilitiesTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY FROM SNMPv2-SMI AGENT-CAPABILITIES FROM SNMPv2-CONF; testCapability AGENT-CAPABILITIES PRODUCT-RELEASE "Test produce" STATUS current DESCRIPTION "test capabilities" SUPPORTS TEST-MIB INCLUDES { testSystemGroup, testNotificationObjectGroup, testNotificationGroup } VARIATION testSysLevelType ACCESS read-only DESCRIPTION "Not supported." VARIATION testSysLevelType ACCESS read-only DESCRIPTION "Supported." ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testAgentCapabilitiesSymbol(self): self.assertTrue( 'testCapability' in self.ctx, 'symbol not present' ) def testAgentCapabilitiesName(self): self.assertEqual( self.ctx['testCapability'].getName(), (1, 3), 'bad name' ) def testAgentCapabilitiesDescription(self): self.assertEqual( self.ctx['testCapability'].getDescription(), 'test capabilities', 'bad DESCRIPTION' ) # XXX SUPPORTS/INCLUDES/VARIATION/ACCESS not supported by pysnmp def testAgentCapabilitiesClass(self): self.assertEqual( self.ctx['testCapability'].__class__.__name__, 'AgentCapabilities', 'bad SYNTAX class' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_imports_smiv2_pysnmp.py0000664006321400632140000000311713411726453023327 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class ImportClauseTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY, OBJECT-TYPE, Unsigned32, mib-2 FROM SNMPv2-SMI SnmpAdminString FROM SNMP-FRAMEWORK-MIB; END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testModuleImportsRequiredMibs(self): self.assertEqual( self.mibInfo.imported, ('SNMP-FRAMEWORK-MIB', 'SNMPv2-CONF', 'SNMPv2-SMI', 'SNMPv2-TC'), 'imported MIBs not reported' ) def testModuleCheckImportedSymbol(self): self.assertTrue( 'SnmpAdminString' in self.ctx, 'imported symbol not present' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_modulecompliance_smiv2_pysnmp.py0000664006321400632140000000434113454602510025144 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class ModuleComplianceTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-COMPLIANCE FROM SNMPv2-CONF; testCompliance MODULE-COMPLIANCE STATUS current DESCRIPTION "This is the MIB compliance statement" MODULE MANDATORY-GROUPS { testComplianceInfoGroup, testNotificationInfoGroup } GROUP testNotificationGroup DESCRIPTION "Support for these notifications is optional." ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testModuleComplianceSymbol(self): self.assertTrue( 'testCompliance' in self.ctx, 'symbol not present' ) def testModuleComplianceName(self): self.assertEqual( self.ctx['testCompliance'].getName(), (1, 3), 'bad name' ) def testModuleComplianceDescription(self): self.assertEqual( self.ctx['testCompliance'].getDescription(), 'This is the MIB compliance statement', 'bad DESCRIPTION' ) def testModuleComplianceClass(self): self.assertEqual( self.ctx['testCompliance'].__class__.__name__, 'ModuleCompliance', 'bad SYNTAX class' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_moduleidentity_smiv2_pysnmp.py0000664006321400632140000000640713454602510024670 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class ModuleIdentityTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY FROM SNMPv2-SMI; testModule MODULE-IDENTITY LAST-UPDATED "200001100000Z" -- Midnight 10 January 2000 ORGANIZATION "AgentX Working Group" CONTACT-INFO "WG-email: agentx@dorothy.bmc.com" DESCRIPTION "This is the MIB module for the SNMP" REVISION "200001100000Z" -- Midnight 10 January 2000 DESCRIPTION "Initial version published as RFC 2742." ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testModuleIdentitySymbol(self): self.assertTrue( 'testModule' in self.ctx, 'symbol not present' ) def testModuleIdentityName(self): self.assertEqual( self.ctx['testModule'].getName(), (1, 3), 'bad name' ) def testModuleIdentityLastUpdated(self): self.assertEqual( self.ctx['testModule'].getLastUpdated(), '200001100000Z', 'bad LAST-UPDATED' ) def testModuleIdentityOrganization(self): self.assertEqual( self.ctx['testModule'].getOrganization(), 'AgentX Working Group', 'bad ORGANIZATION' ) def testModuleIdentityRevisions(self): self.assertEqual( self.ctx['testModule'].getRevisions(), ('2000-01-10 00:00',), 'bad REVISIONS' ) # TODO: pysnmp does not implement .getRevisionsDescriptions() # self.assertEqual( # self.ctx['testModule'].getRevisionsDescriptions(), # ('Initial version published as RFC 2742.',), # 'bad REVISIONS' # ) def testModuleIdentityContactInfo(self): self.assertEqual( self.ctx['testModule'].getContactInfo(), 'WG-email: agentx@dorothy.bmc.com', 'bad CONTACT-INFO' ) def testModuleIdentityDescription(self): self.assertEqual( self.ctx['testModule'].getDescription(), 'This is the MIB module for the SNMP', 'bad DESCRIPTION' ) def testModuleIdentityClass(self): self.assertEqual( self.ctx['testModule'].__class__.__name__, 'ModuleIdentity', 'bad SYNTAX class' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_notificationgroup_smiv2_pysnmp.py0000664006321400632140000000442413454602510025371 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class NotificationGroupTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS NOTIFICATION-GROUP FROM SNMPv2-CONF; testNotificationGroup NOTIFICATION-GROUP NOTIFICATIONS { testStatusChangeNotify, testClassEventNotify, testThresholdBelowNotify } STATUS current DESCRIPTION "A collection of test notifications." ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testNotificationGroupSymbol(self): self.assertTrue( 'testNotificationGroup' in self.ctx, 'symbol not present' ) def testNotificationGroupName(self): self.assertEqual( self.ctx['testNotificationGroup'].getName(), (1, 3), 'bad name' ) def testNotificationGroupDescription(self): self.assertEqual( self.ctx['testNotificationGroup'].getDescription(), 'A collection of test notifications.', 'bad DESCRIPTION' ) def testNotificationGroupClass(self): self.assertEqual( self.ctx['testNotificationGroup'].__class__.__name__, 'NotificationGroup', 'bad SYNTAX class' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_notificationtype_smiv2_pysnmp.py0000664006321400632140000000433413454602510025216 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class NotificationTypeTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS NOTIFICATION-TYPE FROM SNMPv2-SMI; testNotificationType NOTIFICATION-TYPE OBJECTS { testChangeConfigType, testChangeConfigValue } STATUS current DESCRIPTION "A collection of test notification types." ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testNotificationTypeSymbol(self): self.assertTrue( 'testNotificationType' in self.ctx, 'symbol not present' ) def testNotificationTypeName(self): self.assertEqual( self.ctx['testNotificationType'].getName(), (1, 3), 'bad name' ) def testNotificationTypeDescription(self): self.assertEqual( self.ctx['testNotificationType'].getDescription(), 'A collection of test notification types.', 'bad DESCRIPTION' ) def testNotificationTypeClass(self): self.assertEqual( self.ctx['testNotificationType'].__class__.__name__, 'NotificationType', 'bad SYNTAX class' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_objectgroup_smiv2_pysnmp.py0000664006321400632140000000462213454602510024151 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.parser.dialect import smiV2 from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class ObjectGroupTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-GROUP FROM SNMPv2-CONF; testObjectGroup OBJECT-GROUP OBJECTS { testStorageType, testRowStatus } STATUS current DESCRIPTION "A collection of test objects." ::= { 1 3 } END """ def setUp(self): ast = parserFactory(**smiV2)().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testObjectGroupSymbol(self): self.assertTrue( 'testObjectGroup' in self.ctx, 'symbol not present' ) def testObjectGroupName(self): self.assertEqual( self.ctx['testObjectGroup'].getName(), (1, 3), 'bad name' ) def testObjectGroupDescription(self): self.assertEqual( self.ctx['testObjectGroup'].getDescription(), 'A collection of test objects.', 'bad DESCRIPTION' ) def testObjectGroupObjects(self): self.assertEqual( self.ctx['testObjectGroup'].getObjects(), (('TEST-MIB', 'testStorageType'), ('TEST-MIB', 'testRowStatus')), 'bad OBJECTS' ) def testObjectGroupClass(self): self.assertEqual( self.ctx['testObjectGroup'].__class__.__name__, 'ObjectGroup', 'bad SYNTAX class' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_objectidentity_smiv2_pysnmp.py0000664006321400632140000000425113454602510024644 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class ObjectIdentityTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-IDENTITY FROM SNMPv2-SMI; testObject OBJECT-IDENTITY STATUS current DESCRIPTION "Initial version" REFERENCE "ABC" ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testObjectIdentitySymbol(self): self.assertTrue( 'testObject' in self.ctx, 'symbol not present' ) def testObjectIdentityName(self): self.assertEqual( self.ctx['testObject'].getName(), (1, 3), 'bad name' ) def testObjectIdentityDescription(self): self.assertEqual( self.ctx['testObject'].getDescription(), 'Initial version', 'bad DESCRIPTION' ) def testObjectIdentityReference(self): self.assertEqual( self.ctx['testObject'].getReference(), 'ABC', 'bad REFERENCE' ) def testObjectIdentityClass(self): self.assertEqual( self.ctx['testObject'].__class__.__name__, 'ObjectIdentity', 'bad SYNTAX class' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_objecttype_smiv2_pysnmp.py0000664006321400632140000004134113454602510023775 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pyasn1.compat.octets import str2octs from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class ObjectTypeBasicTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; testObjectType OBJECT-TYPE SYNTAX Integer32 UNITS "seconds" MAX-ACCESS accessible-for-notify STATUS current DESCRIPTION "Test object" REFERENCE "ABC" ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testObjectTypeSymbol(self): self.assertTrue( 'testObjectType' in self.ctx, 'symbol not present' ) def testObjectTypeName(self): self.assertEqual( self.ctx['testObjectType'].getName(), (1, 3), 'bad name' ) def testObjectTypeDescription(self): self.assertEqual( self.ctx['testObjectType'].getDescription(), 'Test object', 'bad DESCRIPTION' ) def testObjectTypeStatus(self): self.assertEqual( self.ctx['testObjectType'].getStatus(), 'current', 'bad STATUS' ) # TODO:revisit # def testObjectTypeReference(self): # self.assertEqual( # self.ctx['testObjectType'].getReference(), str2octs('ABC'), # 'bad REFERENCE' # ) def testObjectTypeMaxAccess(self): self.assertEqual( self.ctx['testObjectType'].getMaxAccess(), 'accessiblefornotify', 'bad MAX-ACCESS' ) def testObjectTypeUnits(self): self.assertEqual( self.ctx['testObjectType'].getUnits(), 'seconds', 'bad UNITS' ) def testObjectTypeSyntax(self): self.assertEqual( self.ctx['testObjectType'].getSyntax().clone(123), 123, 'bad SYNTAX' ) def testObjectTypeClass(self): self.assertEqual( self.ctx['testObjectType'].__class__.__name__, 'MibScalar', 'bad SYNTAX' ) class ObjectTypeIntegerDefaultTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE, Integer32 FROM SNMPv2-SMI; testObjectType OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" DEFVAL { 123456 } ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeSyntax(self): self.assertEqual( self.ctx['testObjectType'].getSyntax(), 123456, 'bad DEFVAL' ) class ObjectTypeEnumDefaultTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; testObjectType OBJECT-TYPE SYNTAX INTEGER { enable(1), disable(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" DEFVAL { enable } ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeSyntax(self): self.assertEqual( self.ctx['testObjectType'].getSyntax(), 1, 'bad DEFVAL' ) class ObjectTypeStringDefaultTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; testObjectType OBJECT-TYPE SYNTAX OCTET STRING MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" DEFVAL { "test value" } ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeSyntax(self): self.assertEqual( self.ctx['testObjectType'].getSyntax(), str2octs('test value'), 'bad DEFVAL' ) class ObjectTypeWithIntegerConstraintTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE, Unsigned32 FROM SNMPv2-SMI; testObjectType OBJECT-TYPE SYNTAX Unsigned32 (0..4294967295) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" DEFVAL { 0 } ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeSyntax(self): self.assertEqual( self.ctx['testObjectType'].getSyntax().clone(123), 123, 'bad integer range constrained SYNTAX' ) class ObjectTypeWithIntegerSetConstraintTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE, Unsigned32 FROM SNMPv2-SMI; testObjectType OBJECT-TYPE SYNTAX Unsigned32 (0|2|44) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeSyntax(self): self.assertEqual( self.ctx['testObjectType'].getSyntax().clone(44), 44, 'bad multiple integer constrained SYNTAX' ) class ObjectTypeWithStringSizeConstraintTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE, Unsigned32 FROM SNMPv2-SMI; testObjectType OBJECT-TYPE SYNTAX OCTET STRING (SIZE (0..512)) MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeSyntax(self): self.assertEqual( self.ctx['testObjectType'].getSyntax().clone(''), str2octs(''), 'bad size constrained SYNTAX' ) class ObjectTypeBitsTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE, Unsigned32 FROM SNMPv2-SMI; testObjectType OBJECT-TYPE SYNTAX BITS { notification(0), set(1) } MAX-ACCESS read-only STATUS current DESCRIPTION "Test object" ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeSyntax(self): self.assertEqual( self.ctx['testObjectType'].getSyntax().clone(('set',)), str2octs('@'), 'bad BITS SYNTAX' ) class ObjectTypeMibTableTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; testTable OBJECT-TYPE SYNTAX SEQUENCE OF TestEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test table" ::= { 1 3 } testEntry OBJECT-TYPE SYNTAX TestEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test row" INDEX { testIndex } ::= { testTable 1 } TestEntry ::= SEQUENCE { testIndex INTEGER, testValue OCTET STRING } testIndex OBJECT-TYPE SYNTAX INTEGER MAX-ACCESS read-create STATUS current DESCRIPTION "Test column" ::= { testEntry 1 } testValue OBJECT-TYPE SYNTAX OCTET STRING MAX-ACCESS read-create STATUS current DESCRIPTION "Test column" ::= { testEntry 2 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeTableClass(self): self.assertEqual( self.ctx['testTable'].__class__.__name__, 'MibTable', 'bad table class' ) def testObjectTypeTableRowClass(self): self.assertEqual( self.ctx['testEntry'].__class__.__name__, 'MibTableRow', 'bad table row class' ) def testObjectTypeTableColumnClass(self): self.assertEqual( self.ctx['testIndex'].__class__.__name__, 'MibTableColumn', 'bad table column class' ) def testObjectTypeTableRowIndex(self): self.assertEqual( self.ctx['testEntry'].getIndexNames(), ((0, 'TEST-MIB', 'testIndex'),), 'bad table index' ) class ObjectTypeMibTableImpliedIndexTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; testTable OBJECT-TYPE SYNTAX SEQUENCE OF TestEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test table" ::= { 1 3 } testEntry OBJECT-TYPE SYNTAX TestEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test row" INDEX { IMPLIED testIndex } ::= { testTable 3 } TestEntry ::= SEQUENCE { testIndex INTEGER } testIndex OBJECT-TYPE SYNTAX INTEGER MAX-ACCESS read-create STATUS current DESCRIPTION "Test column" ::= { testEntry 1 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeTableRowIndex(self): self.assertEqual( self.ctx['testEntry'].getIndexNames(), ((1, 'TEST-MIB', 'testIndex'),), 'bad IMPLIED table index' ) class ObjectTypeMibTableMultipleIndicesTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; testTable OBJECT-TYPE SYNTAX SEQUENCE OF TestEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test table" ::= { 1 3 } testEntry OBJECT-TYPE SYNTAX TestEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test row" INDEX { testIndex, testValue } ::= { testTable 3 } TestEntry ::= SEQUENCE { testIndex INTEGER, testValue OCTET STRING } testIndex OBJECT-TYPE SYNTAX INTEGER MAX-ACCESS read-create STATUS current DESCRIPTION "Test column" ::= { testEntry 1 } testValue OBJECT-TYPE SYNTAX OCTET STRING MAX-ACCESS read-create STATUS current DESCRIPTION "Test column" ::= { testEntry 2 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeTableRowIndex(self): self.assertEqual( self.ctx['testEntry'].getIndexNames(), ((0, 'TEST-MIB', 'testIndex'), (0, 'TEST-MIB', 'testValue')), 'bad multiple table indices' ) class ObjectTypeAurmentingMibTableTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; testTable OBJECT-TYPE SYNTAX SEQUENCE OF TestEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test table" ::= { 1 3 } testEntry OBJECT-TYPE SYNTAX TestEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test row" INDEX { testIndex } ::= { testTable 3 } TestEntry ::= SEQUENCE { testIndex INTEGER } testIndex OBJECT-TYPE SYNTAX INTEGER MAX-ACCESS read-create STATUS current DESCRIPTION "Test column" ::= { testEntry 1 } testTableExt OBJECT-TYPE SYNTAX SEQUENCE OF TestEntryExt MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test table" ::= { 1 4 } testEntryExt OBJECT-TYPE SYNTAX TestEntryExt MAX-ACCESS not-accessible STATUS current DESCRIPTION "Test row" AUGMENTS { testEntry } ::= { testTableExt 3 } TestEntryExt ::= SEQUENCE { testIndexExt INTEGER } testIndexExt OBJECT-TYPE SYNTAX INTEGER MAX-ACCESS read-create STATUS current DESCRIPTION "Test column" ::= { testEntryExt 1 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') self.ctx = {'mibBuilder': MibBuilder()} exec(codeobj, self.ctx, self.ctx) def testObjectTypeTableRowAugmention(self): # XXX provide getAugmentation() method self.assertEqual( list(self.ctx['testEntry'].augmentingRows.keys())[0], ('TEST-MIB', 'testEntryExt'), 'bad AUGMENTS table clause' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_smiv1_smiv2_pysnmp.py0000664006321400632140000000446713454602510022674 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class SmiV1TestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS Counter, IpAddress, TimeTicks FROM RFC1155-SMI DisplayString, mib-2 FROM RFC1213-MIB OBJECT-TYPE FROM RFC-1212 NOTIFICATION-GROUP FROM SNMPv2-CONF; testSmiV1 NOTIFICATION-GROUP NOTIFICATIONS { testStatusChangeNotify, testClassEventNotify, testThresholdBelowNotify } STATUS current DESCRIPTION "A collection of test notifications." ::= { 1 3 } END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testSmiV1Symbol(self): self.assertTrue( 'testSmiV1' in self.ctx, 'symbol not present' ) def testSmiV1Name(self): self.assertEqual( self.ctx['testSmiV1'].getName(), (1, 3), 'bad name' ) def testSmiV1Description(self): self.assertEqual( self.ctx['testSmiV1'].getDescription(), 'A collection of test notifications.', 'bad DESCRIPTION' ) def testSmiV1Class(self): self.assertEqual( self.ctx['testSmiV1'].__class__.__name__, 'NotificationGroup', 'bad SYNTAX class' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_traptype_smiv2_pysnmp.py0000664006321400632140000000430613454602510023475 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class TrapTypeTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS TRAP-TYPE FROM RFC-1215 OBJECT-TYPE FROM RFC1155-SMI; testId OBJECT IDENTIFIER ::= { 1 3 } testObject OBJECT-TYPE SYNTAX INTEGER MAX-ACCESS accessible-for-notify STATUS current DESCRIPTION "Test object" ::= { 1 3 } testTrap TRAP-TYPE ENTERPRISE testId VARIABLES { testObject } DESCRIPTION "Test trap" ::= 1 END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testTrapTypeSymbol(self): self.assertTrue( 'testTrap' in self.ctx, 'symbol not present' ) def testTrapTypeName(self): self.assertEqual( self.ctx['testTrap'].getName(), (1, 3, 0, 1), 'bad name' ) def testTrapTypeDescription(self): self.assertEqual( self.ctx['testTrap'].getDescription(), 'Test trap', 'bad DESCRIPTION' ) def testTrapTypeClass(self): self.assertEqual( self.ctx['testTrap'].__class__.__name__, 'NotificationType', 'bad SYNTAX class' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_typedeclaration_smiv1_pysnmp.py0000664006321400632140000000560513411726453025024 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.parser.dialect import smiV1Relaxed from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class TypeDeclarationTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS NetworkAddress, IpAddress, Counter, Gauge, TimeTicks, Opaque FROM RFC1155-SMI; -- simple types TestTypeInteger ::= INTEGER TestTypeOctetString ::= OCTET STRING TestTypeObjectIdentifier ::= OBJECT IDENTIFIER -- application types TestTypeNetworkAddress::= NetworkAddress TestTypeIpAddress ::= IpAddress TestTypeCounter ::= Counter TestTypeGauge ::= Gauge TestTypeTimeTicks ::= TimeTicks TestTypeOpaque ::= Opaque END """ def setUp(self): ast = parserFactory(**smiV1Relaxed)().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def protoTestSymbol(self, symbol, klass): self.assertTrue( symbol in self.ctx, 'symbol %s not present' % symbol ) def protoTestClass(self, symbol, klass): self.assertEqual( self.ctx[symbol].__bases__[0].__name__, klass, 'expected class %s, got %s at %s' % (klass, self.ctx[symbol].__bases__[0].__name__, symbol) ) # populate test case class with per-type methods typesMap = ( ('TestTypeInteger', 'Integer32'), ('TestTypeOctetString', 'OctetString'), ('TestTypeObjectIdentifier', 'ObjectIdentifier'), ('TestTypeNetworkAddress', 'IpAddress'), ('TestTypeIpAddress', 'IpAddress'), ('TestTypeCounter', 'Counter32'), ('TestTypeGauge', 'Gauge32'), ('TestTypeTimeTicks', 'TimeTicks'), ('TestTypeOpaque', 'Opaque') ) def decor(func, symbol, klass): def inner(self): func(self, symbol, klass) return inner for s, k in typesMap: setattr(TypeDeclarationTestCase, 'testTypeDeclaration' + k + 'SymbolTestCase', decor(TypeDeclarationTestCase.protoTestSymbol, s, k)) setattr(TypeDeclarationTestCase, 'testTypeDeclaration' + k + 'ClassTestCase', decor(TypeDeclarationTestCase.protoTestClass, s, k)) # XXX constraints flavor not checked suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_typedeclaration_smiv2_pysnmp.py0000664006321400632140000001241113454602510025010 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class TypeDeclarationTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS IpAddress, Counter32, Gauge32, TimeTicks, Opaque, Integer32, Unsigned32, Counter64 FROM SNMPv2-SMI TEXTUAL-CONVENTION FROM SNMPv2-TC; -- simple types TestTypeInteger ::= INTEGER TestTypeOctetString ::= OCTET STRING TestTypeObjectIdentifier ::= OBJECT IDENTIFIER -- application types TestTypeIpAddress ::= IpAddress TestTypeInteger32 ::= Integer32 TestTypeCounter32 ::= Counter32 TestTypeGauge32 ::= Gauge32 TestTypeTimeTicks ::= TimeTicks TestTypeOpaque ::= Opaque TestTypeCounter64 ::= Counter64 TestTypeUnsigned32 ::= Unsigned32 -- constrained subtypes TestTypeEnum ::= INTEGER { noResponse(-1), noError(0), tooBig(1) } TestTypeSizeRangeConstraint ::= OCTET STRING (SIZE (0..255)) TestTypeSizeConstraint ::= OCTET STRING (SIZE (8 | 11)) TestTypeRangeConstraint ::= INTEGER (0..2) TestTypeSingleValueConstraint ::= INTEGER (0|2|4) TestTypeBits ::= BITS { sunday(0), monday(1), tuesday(2), wednesday(3), thursday(4), friday(5), saturday(6) } TestTextualConvention ::= TEXTUAL-CONVENTION DISPLAY-HINT "1x:" STATUS current DESCRIPTION "Test TC" REFERENCE "Test reference" SYNTAX OCTET STRING END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def protoTestSymbol(self, symbol, klass): self.assertTrue( symbol in self.ctx, 'symbol %s not present' % symbol ) def protoTestClass(self, symbol, klass): self.assertEqual( self.ctx[symbol].__bases__[0].__name__, klass, 'expected class %s, got %s at %s' % (klass, self.ctx[symbol].__bases__[0].__name__, symbol) ) def TestTextualConventionSymbol(self): self.assertTrue( 'TestTextualConvention' in self.ctx, 'symbol not present' ) def TestTextualConventionDisplayHint(self): self.assertEqual( self.ctx['TestTextualConvention'].getDisplayHint(), '1x:', 'bad DISPLAY-HINT' ) def TestTextualConventionStatus(self): self.assertEqual( self.ctx['TestTextualConvention'].getStatus(), 'current', 'bad STATUS' ) def TestTextualConventionDescription(self): self.assertEqual( self.ctx['TestTextualConvention'].getDescription(), 'Test TC', 'bad DESCRIPTION' ) def TestTextualConventionReference(self): self.assertEqual( self.ctx['TestTextualConvention'].getReference(), 'Test reference', 'bad REFERENCE' ) def TestTextualConventionClass(self): self.assertEqual( self.ctx['TestTextualConvention'].__class__.__name__, 'TextualConvention', 'bad SYNTAX class' ) # populate test case class with per-type methods typesMap = ( # TODO: Integer/Integer32? ('TestTypeInteger', 'Integer32'), ('TestTypeOctetString', 'OctetString'), ('TestTypeObjectIdentifier', 'ObjectIdentifier'), ('TestTypeIpAddress', 'IpAddress'), ('TestTypeInteger32', 'Integer32'), ('TestTypeCounter32', 'Counter32'), ('TestTypeGauge32', 'Gauge32'), ('TestTypeTimeTicks', 'TimeTicks'), ('TestTypeOpaque', 'Opaque'), ('TestTypeCounter64', 'Counter64'), ('TestTypeUnsigned32', 'Unsigned32'), ('TestTypeTestTypeEnum', 'Integer32'), ('TestTypeSizeRangeConstraint', 'OctetString'), ('TestTypeSizeConstraint', 'OctetString'), ('TestTypeRangeConstraint', 'Integer32'), ('TestTypeSingleValueConstraint', 'Integer32') ) def decor(func, symbol, klass): def inner(self): func(self, symbol, klass) return inner for s, k in typesMap: setattr(TypeDeclarationTestCase, 'testTypeDeclaration' + k + 'SymbolTestCase', decor(TypeDeclarationTestCase.protoTestSymbol, s, k)) setattr(TypeDeclarationTestCase, 'testTypeDeclaration' + k + 'ClassTestCase', decor(TypeDeclarationTestCase.protoTestClass, s, k)) # XXX constraints flavor not checked suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_valuedeclaration_smiv2_pysnmp.py0000664006321400632140000000515413411726453025157 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys try: import unittest2 as unittest except ImportError: import unittest from pysmi.parser.smi import parserFactory from pysmi.codegen.pysnmp import PySnmpCodeGen from pysmi.codegen.symtable import SymtableCodeGen from pysnmp.smi.builder import MibBuilder class ValueDeclarationTestCase(unittest.TestCase): """ TEST-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI; -- simple values testValue1 OBJECT IDENTIFIER ::= { 1 } testValue2 OBJECT IDENTIFIER ::= { testValue1 3 } testValue3 OBJECT IDENTIFIER ::= { 1 3 6 1 2 } -- testValue01 INTEGER ::= 123 -- testValue02 INTEGER ::= -123 -- testValue04 OCTET STRING ::= h'test string' -- testValue05 INTEGER ::= testValue01 -- testValue06 OCTET STRING ::= "test string" -- testValue07 OCTET STRING ::= b'010101' -- application syntax -- testValue03 Integer32 ::= 123 -- testValue03 Counter32 ::= 123 -- testValue03 Gauge32 ::= 123 -- testValue03 Unsigned32 ::= 123 -- testValue03 TimeTicks ::= 123 -- testValue03 Opaque ::= "0123" -- testValue03 Counter64 ::= 123456789123456789 -- testValue03 IpAddress ::= "127.0.0.1" END """ def setUp(self): ast = parserFactory()().parse(self.__class__.__doc__)[0] mibInfo, symtable = SymtableCodeGen().genCode(ast, {}, genTexts=True) self.mibInfo, pycode = PySnmpCodeGen().genCode(ast, {mibInfo.name: symtable}, genTexts=True) codeobj = compile(pycode, 'test', 'exec') mibBuilder = MibBuilder() mibBuilder.loadTexts = True self.ctx = {'mibBuilder': mibBuilder} exec(codeobj, self.ctx, self.ctx) def testValueDeclarationSymbol(self): self.assertTrue( 'testValue1' in self.ctx and 'testValue2' in self.ctx and 'testValue3' in self.ctx, 'symbol not present' ) def testValueDeclarationName1(self): self.assertEqual( self.ctx['testValue1'].getName(), (1,), 'bad value' ) def testValueDeclarationName2(self): self.assertEqual( self.ctx['testValue2'].getName(), (1, 3), 'bad value' ) def testValueDeclarationName3(self): self.assertEqual( self.ctx['testValue3'].getName(), (1, 3, 6, 1, 2), 'bad value' ) suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite) pysmi-0.3.4/tests/test_zipreader.py0000664006321400632140000003171613411726453021077 0ustar ietingofietingof00000000000000# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys import os import tempfile try: import unittest2 as unittest except ImportError: import unittest try: import StringIO except ImportError: from io import StringIO from pysmi.reader.zipreader import ZipReader class ZipReaderTestCase(unittest.TestCase): zipArchive = [ 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 8, 135, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 28, 0, 116, 101, 115, 116, 47, 85, 84, 9, 0, 3, 16, 211, 195, 89, 25, 211, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 230, 134, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 28, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 85, 84, 9, 0, 3, 207, 210, 195, 89, 3, 211, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 230, 134, 53, 75, 102, 214, 67, 99, 2, 0, 0, 0, 2, 0, 0, 0, 17, 0, 28, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 116, 101, 115, 116, 65, 85, 84, 9, 0, 3, 207, 210, 195, 89, 3, 211, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 66, 10, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 2, 135, 53, 75, 162, 170, 2, 92, 138, 7, 0, 0, 138, 7, 0, 0, 13, 0, 28, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 46, 122, 105, 112, 85, 84, 9, 0, 3, 3, 211, 195, 89, 3, 211, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 253, 134, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 28, 0, 116, 101, 115, 116, 47, 85, 84, 9, 0, 3, 253, 210, 195, 89, 3, 211, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 230, 134, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 28, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 85, 84, 9, 0, 3, 207, 210, 195, 89, 3, 211, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 130, 131, 53, 75, 227, 250, 30, 37, 12, 0, 0, 0, 12, 0, 0, 0, 21, 0, 28, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 116, 101, 115, 116, 65, 46, 116, 120, 116, 85, 84, 9, 0, 3, 116, 204, 195, 89, 134, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 115, 117, 98, 100, 105, 114, 116, 101, 115, 116, 65, 10, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 109, 131, 53, 75, 237, 78, 102, 83, 6, 0, 0, 0, 6, 0, 0, 0, 14, 0, 28, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 65, 46, 116, 120, 116, 85, 84, 9, 0, 3, 78, 204, 195, 89, 134, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 116, 101, 115, 116, 65, 10, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 144, 131, 53, 75, 204, 176, 61, 249, 144, 2, 0, 0, 144, 2, 0, 0, 13, 0, 28, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 46, 122, 105, 112, 85, 84, 9, 0, 3, 143, 204, 195, 89, 143, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 117, 131, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 28, 0, 116, 101, 115, 116, 47, 85, 84, 9, 0, 3, 94, 204, 195, 89, 98, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 130, 131, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 28, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 85, 84, 9, 0, 3, 116, 204, 195, 89, 134, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 130, 131, 53, 75, 227, 250, 30, 37, 12, 0, 0, 0, 12, 0, 0, 0, 21, 0, 28, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 116, 101, 115, 116, 65, 46, 116, 120, 116, 85, 84, 9, 0, 3, 116, 204, 195, 89, 116, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 115, 117, 98, 100, 105, 114, 116, 101, 115, 116, 65, 10, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 109, 131, 53, 75, 237, 78, 102, 83, 6, 0, 0, 0, 6, 0, 0, 0, 14, 0, 28, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 65, 46, 116, 120, 116, 85, 84, 9, 0, 3, 78, 204, 195, 89, 78, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 116, 101, 115, 116, 65, 10, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 117, 131, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 24, 0, 0, 0, 0, 0, 0, 0, 16, 0, 253, 65, 0, 0, 0, 0, 116, 101, 115, 116, 47, 85, 84, 5, 0, 3, 94, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 130, 131, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 24, 0, 0, 0, 0, 0, 0, 0, 16, 0, 253, 65, 63, 0, 0, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 85, 84, 5, 0, 3, 116, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 130, 131, 53, 75, 227, 250, 30, 37, 12, 0, 0, 0, 12, 0, 0, 0, 21, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 180, 129, 133, 0, 0, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 116, 101, 115, 116, 65, 46, 116, 120, 116, 85, 84, 5, 0, 3, 116, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 109, 131, 53, 75, 237, 78, 102, 83, 6, 0, 0, 0, 6, 0, 0, 0, 14, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 180, 129, 224, 0, 0, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 65, 46, 116, 120, 116, 85, 84, 5, 0, 3, 78, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 5, 6, 0, 0, 0, 0, 4, 0, 4, 0, 76, 1, 0, 0, 46, 1, 0, 0, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 230, 134, 53, 75, 102, 214, 67, 99, 2, 0, 0, 0, 2, 0, 0, 0, 17, 0, 28, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 116, 101, 115, 116, 65, 85, 84, 9, 0, 3, 207, 210, 195, 89, 207, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 66, 10, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 253, 134, 53, 75, 39, 231, 88, 122, 2, 0, 0, 0, 2, 0, 0, 0, 10, 0, 28, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 67, 85, 84, 9, 0, 3, 253, 210, 195, 89, 253, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 67, 10, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 211, 134, 53, 75, 165, 133, 110, 72, 2, 0, 0, 0, 2, 0, 0, 0, 10, 0, 28, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 65, 85, 84, 9, 0, 3, 173, 210, 195, 89, 173, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 65, 10, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 253, 134, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 24, 0, 0, 0, 0, 0, 0, 0, 16, 0, 253, 65, 0, 0, 0, 0, 116, 101, 115, 116, 47, 85, 84, 5, 0, 3, 253, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 230, 134, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 24, 0, 0, 0, 0, 0, 0, 0, 16, 0, 253, 65, 63, 0, 0, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 85, 84, 5, 0, 3, 207, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 130, 131, 53, 75, 227, 250, 30, 37, 12, 0, 0, 0, 12, 0, 0, 0, 21, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 180, 129, 133, 0, 0, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 116, 101, 115, 116, 65, 46, 116, 120, 116, 85, 84, 5, 0, 3, 116, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 109, 131, 53, 75, 237, 78, 102, 83, 6, 0, 0, 0, 6, 0, 0, 0, 14, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 180, 129, 224, 0, 0, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 65, 46, 116, 120, 116, 85, 84, 5, 0, 3, 78, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 144, 131, 53, 75, 204, 176, 61, 249, 144, 2, 0, 0, 144, 2, 0, 0, 13, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 129, 46, 1, 0, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 46, 122, 105, 112, 85, 84, 5, 0, 3, 143, 204, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 230, 134, 53, 75, 102, 214, 67, 99, 2, 0, 0, 0, 2, 0, 0, 0, 17, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 180, 129, 5, 4, 0, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 116, 101, 115, 116, 65, 85, 84, 5, 0, 3, 207, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 253, 134, 53, 75, 39, 231, 88, 122, 2, 0, 0, 0, 2, 0, 0, 0, 10, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 180, 129, 82, 4, 0, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 67, 85, 84, 5, 0, 3, 253, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 211, 134, 53, 75, 165, 133, 110, 72, 2, 0, 0, 0, 2, 0, 0, 0, 10, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 180, 129, 152, 4, 0, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 65, 85, 84, 5, 0, 3, 173, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 5, 6, 0, 0, 0, 0, 8, 0, 8, 0, 150, 2, 0, 0, 222, 4, 0, 0, 0, 0, 80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 211, 134, 53, 75, 165, 133, 110, 72, 2, 0, 0, 0, 2, 0, 0, 0, 10, 0, 28, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 65, 85, 84, 9, 0, 3, 173, 210, 195, 89, 3, 211, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 65, 10, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 8, 135, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 24, 0, 0, 0, 0, 0, 0, 0, 16, 0, 253, 65, 0, 0, 0, 0, 116, 101, 115, 116, 47, 85, 84, 5, 0, 3, 16, 211, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 230, 134, 53, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 24, 0, 0, 0, 0, 0, 0, 0, 16, 0, 253, 65, 63, 0, 0, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 85, 84, 5, 0, 3, 207, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 230, 134, 53, 75, 102, 214, 67, 99, 2, 0, 0, 0, 2, 0, 0, 0, 17, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 180, 129, 133, 0, 0, 0, 116, 101, 115, 116, 47, 115, 117, 98, 100, 105, 114, 47, 116, 101, 115, 116, 65, 85, 84, 5, 0, 3, 207, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 2, 135, 53, 75, 162, 170, 2, 92, 138, 7, 0, 0, 138, 7, 0, 0, 13, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 129, 210, 0, 0, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 46, 122, 105, 112, 85, 84, 5, 0, 3, 3, 211, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 1, 2, 30, 3, 10, 0, 0, 0, 0, 0, 211, 134, 53, 75, 165, 133, 110, 72, 2, 0, 0, 0, 2, 0, 0, 0, 10, 0, 24, 0, 0, 0, 0, 0, 1, 0, 0, 0, 180, 129, 163, 8, 0, 0, 116, 101, 115, 116, 47, 116, 101, 115, 116, 65, 85, 84, 5, 0, 3, 173, 210, 195, 89, 117, 120, 11, 0, 1, 4, 140, 102, 0, 0, 4, 140, 102, 0, 0, 80, 75, 5, 6, 0, 0, 0, 0, 5, 0, 5, 0, 151, 1, 0, 0, 233, 8, 0, 0, 0, 0] if sys.version_info[0] < 3: zipContents = ''.join([chr(x) for x in zipArchive]) else: zipContents = bytes(zipArchive) def testGetDataFromFile(self): filename = None try: fd, filename = tempfile.mkstemp() os.write(fd, self.zipContents) os.close(fd) zipReader = ZipReader(filename) mibinfo, data = zipReader.getData('testA') assert data == 'A\n' except Exception: pass if filename: try: os.remove(filename) except Exception: pass def testGetInnerZipData(self): filename = None try: fd, filename = tempfile.mkstemp() os.write(fd, self.zipContents) os.close(fd) zipReader = ZipReader(filename) mibinfo, data = zipReader.getData('testC') assert data == 'C\n' except Exception: pass if filename: try: os.remove(filename) except Exception: pass suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite)