Esempio n. 1
0
def add_leaf_name_parameters(leaf_name, module):
    leaf_name.i_config = True
    leaf_name.i_default = None
    leaf_name.i_default_str = ""
    leaf_name.i_groupings = dict()
    leaf_name.i_is_key = True
    leaf_name.i_leafref = None
    leaf_name.i_leafref_expanded = False
    leaf_name.i_leafref_ptr = None
    leaf_name.i_module = module
    leaf_name.i_origin_module = module
    leaf_name.i_typedefs = dict()
    leaf_name.i_uniques = list()
    leaf_name.is_grammatically_valid = True

    leaf_name_type = statements.Statement(
        module, leaf_name, error.Position("Automatically inserted statement"),
        "type", "string")
    leaf_name_type.i_groupings = dict()
    leaf_name_type.i_is_derived = False
    leaf_name_type.i_is_validated = True
    leaf_name_type.i_lengths = list()
    leaf_name_type.i_module = module
    leaf_name_type.i_origin_module = module
    leaf_name_type.i_ranges = list()
    leaf_name_type.i_type_spec = types.StringTypeSpec()
    leaf_name_type.i_type_spec.base = None
    leaf_name_type.i_type_spec.definition = ""
    leaf_name_type.i_type_spec.name = "string"
    leaf_name_type.i_typedef = None
    leaf_name_type.i_typedefs = dict()
    leaf_name_type.i_uniques = list()
    leaf_name_type.is_grammatically_valid = True

    leaf_name_mandatory = statements.Statement(
        module, leaf_name, error.Position("Automatically inserted statement"),
        "mandatory", "true")
    leaf_name_mandatory.i_groupings = dict()
    leaf_name_mandatory.i_module = module
    leaf_name_mandatory.i_origin_module = module
    leaf_name_mandatory.i_typedefs = dict()
    leaf_name_mandatory.i_uniques = list()
    leaf_name_mandatory.is_grammatically_valid = True

    leaf_name_description = statements.Statement(
        module, leaf_name, error.Position("Automatically inserted statement"),
        "description", "Name of the {0} service".format(module.arg))
    leaf_name_description.i_groupings = dict()
    leaf_name_description.i_module = module
    leaf_name_description.i_origin_module = module
    leaf_name_description.i_typedefs = dict()
    leaf_name_description.i_uniques = list()
    leaf_name_description.is_grammatically_valid = True

    leaf_name.substmts.append(leaf_name_type)
    leaf_name.substmts.append(leaf_name_mandatory)
    leaf_name.substmts.append(leaf_name_description)
Esempio n. 2
0
    def check_module_rawtext(ctx, stmt):
        """Perform validation of a module"s raw text.

    Args:
      ctx: The pyang.Context for the current validation.
      stmt: The pyang.Statement for a module that we are parsing
        Function is called once per module to reduce the number of
        iterations through the module.
    """
        try:
            mod_filename = stmt.pos.ref.split("/")[-1]
            mod_filename = mod_filename.split(".")[0]
        except IndexError:
            err_add(ctx.errors, stmt.pos, "OC_LINTER_ERROR",
                    "Can't determine a module name for %s" % stmt.pos)

        handle = None
        for mod in ctx.repository.get_modules_and_revisions(ctx):
            # stmt.pos.ref gives the reference to the file that this
            # key statement was within
            if mod[0] == mod_filename:
                handle = mod
                break

        if handle is not None:
            try:
                module = ctx.repository.get_module_from_handle(handle[2])
            except (AttributeError, IndexError) as e:
                err_add(ctx.errors, stmt.pos, "OC_LINTER_ERROR",
                        "Can't find module %s: %s" % (stmt.pos.ref, e))
                return
        else:
            err_add(ctx.errors, stmt.pos, "OC_LINTER_ERROR",
                    "Couldn't open module %s" % stmt.pos.ref)
            return

        key_re = re.compile(
            r"^([ ]+)?key([ ]+)(?P<arg>[^\"][a-zA-Z0-9\-_]+);$")
        quoted_re = re.compile(r"^\".*\"$")

        ln_count = 0
        for ln in module[2].split("\n"):
            ln_count += 1

            # Remove the newline from the module
            ln = ln.rstrip("\n")
            if key_re.match(ln):
                key_arg = key_re.sub(r"\g<arg>", ln)
                if not quoted_re.match(key_arg):
                    # Need to create a fake position object for the
                    # key statement because of this pre-initialisation
                    # module parse.
                    pos = error.Position(stmt.pos.ref)
                    pos.line = ln_count

                    # Generate an error as the key argument is not
                    # quoted.
                    err_add(ctx.errors, pos, "OC_KEY_ARGUMENT_UNQUOTED",
                            key_arg)
            ln_count += 1
Esempio n. 3
0
def add_fake_list_at_beginning(module):
    top_list = statements.Statement(
        module, module, error.Position("Automatically inserted statement"),
        "list", module.arg)

    leaf_name = statements.Statement(
        module, top_list, error.Position("Automatically inserted statement"),
        "leaf", "name")

    add_leaf_name_parameters(leaf_name, module)

    top_list.i_config = True
    top_list.i_is_validated = True
    top_list.i_key = [leaf_name]
    top_list.i_module = module
    top_list.i_origin_module = module
    top_list.i_typedefs = dict()
    top_list.i_unique = list()
    top_list.i_uniques = list()
    top_list.is_grammatically_valid = True

    leaf_name_keyword = statements.Statement(
        module, top_list, error.Position("Automatically inserted statement"),
        "key", "name")
    leaf_name_keyword.i_groupings = dict()
    leaf_name_keyword.i_module = module
    leaf_name_keyword.i_origin_module = module
    leaf_name_keyword.i_typedefs = dict()
    leaf_name_keyword.i_uniques = list()
    leaf_name_keyword.is_grammatically_valid = True

    old_list = list(module.i_children)
    del module.i_children[:]

    top_list.i_children = [leaf_name]
    top_list.i_children.extend(old_list)

    top_list.substmts.append(leaf_name_keyword)
    top_list.substmts.append(leaf_name)
    top_list.substmts.extend(old_list)

    module.i_children.append(top_list)

    del module.substmts[-len(old_list):]
    module.substmts.append(top_list)
Esempio n. 4
0
    def v_chk_3gpp_format(self, ctx, stmt):
        if (not (stmt.arg.startswith("_3gpp"))):
            return
        filename = stmt.pos.ref
        try:
            fd = io.open(filename, "r", encoding="utf-8", newline='')
            pos = error.Position(stmt.pos.ref)
            pos.top = stmt
            lineno = 0
            for line in fd:
                lineno += 1
                pos.line = lineno
                #  no tabs
                if (line.find('\t') != -1):
                    err_add(ctx.errors, pos, '3GPP_TAB_IN_FILE', ())
                #  no whitespace after the line
                #  removed for now as there are just too many of these
                #    errors
                # if (re.search('.*\s+\n',line) != None ):
                #    err_add(ctx.errors, self.pos,
                #        '3GPP_WHITESPACE_AT_END_OF_LINE',())
                #  lines shorter then 80 char
                if (len(line) > 82):
                    err_add(ctx.errors, pos, '3GPP_LONG_LINE', ())
                #  EOL should be just NL no CR
                if (line.find('\r') != -1):
                    err_add(ctx.errors, pos, '3GPP_CR_IN_FILE', ())
                #  only us-ascii chars
                try:
                    line.encode('ascii')
                except UnicodeEncodeError:
                    err_add(ctx.errors, pos, '3GPP_NON_ASCII', ())

        except IOError as ex:
            sys.stderr.write("error %s: %s\n" % (filename, ex))
            sys.exit(1)
        except UnicodeDecodeError as ex:
            s = str(ex).replace('utf-8', 'utf8')
            sys.stderr.write("%s: unicode error: %s\n" % (filename, s))
            sys.exit(1)
Esempio n. 5
0
    def post_validate_ctx(self, ctx, modules):
        if not ctx.opts.threegpp:
            return
        """Remove some lint errors that 3GPP considers acceptable"""
        for ctx_error in ctx.errors[:]:
            if ((ctx_error[1] == "LINT_MISSING_REQUIRED_SUBSTMT"
                 or ctx_error[1] == "LINT_MISSING_RECOMMENDED_SUBSTMT")
                    and ctx_error[2][2] == 'description' and
                (ctx_error[2][1] == 'enum' or ctx_error[2][1] == 'bit' or
                 ctx_error[2][1] == 'choice' or ctx_error[2][1] == 'container'
                 or ctx_error[2][1] == 'leaf-list' or ctx_error[2][1] == 'leaf'
                 or ctx_error[2][1] == 'typedef' or ctx_error[2][1]
                 == 'grouping' or ctx_error[2][1] == 'augment')):
                # remove error from ctx
                ctx.errors.remove(ctx_error)

        # check 3gpp format:
        error.add_error_code(
            '3GPP_TAB_IN_FILE', 3,
            '3GPP: tab characters should not be used in YANG modules')

        error.add_error_code(
            '3GPP_WHITESPACE_AT_END_OF_LINE', 3,
            '3GPP: extra whitespace should not be added at the end of the line'
        )

        error.add_error_code('3GPP_LONG_LINE', 3,
                             '3GPP: line longer than 80 characters')

        error.add_error_code(
            '3GPP_CR_IN_FILE', 3,
            ('3GPP: Carriage-return characters should not be used. '
             'End-of-line should be just one LF character'))

        error.add_error_code(
            '3GPP_NON_ASCII', 4,
            '3GPP: the module should only use ASCII characters')

        for module in modules:
            filename = module.pos.ref
            try:
                fd = io.open(filename, "r", encoding="utf-8", newline='')
                lineno = 0
                for line in fd:
                    lineno += 1
                    self.pos = error.Position(module.pos.ref)
                    self.pos.line = lineno
                    #  no tabs
                    if (line.find('\t') != -1):
                        err_add(ctx.errors, self.pos, '3GPP_TAB_IN_FILE', ())
                    #  no whitespace after the line
                    #  removed for now as there are just too many of these
                    #    errors
                    # if (re.search('.*\s+\n',line) != None ):
                    #    err_add(ctx.errors, self.pos,
                    #        '3GPP_WHITESPACE_AT_END_OF_LINE',())
                    #  lines shorter then 80 char
                    if (len(line) > 82):
                        err_add(ctx.errors, self.pos, '3GPP_LONG_LINE', ())
                    #  EOL should be just NL no CR
                    if (line.find('\r') != -1):
                        err_add(ctx.errors, self.pos, '3GPP_CR_IN_FILE', ())
                    #  only us-ascii chars
                    try:
                        line.encode('ascii')
                    except UnicodeEncodeError:
                        err_add(ctx.errors, self.pos, '3GPP_NON_ASCII', ())

            except IOError as ex:
                sys.stderr.write("error %s: %s\n" % (filename, ex))
                sys.exit(1)
            except UnicodeDecodeError as ex:
                s = str(ex).replace('utf-8', 'utf8')
                sys.stderr.write("%s: unicode error: %s\n" % (filename, s))
                sys.exit(1)

        return
Esempio n. 6
0
def run(args=None, extra_plugin_dirs=None):
    """
    The main CLI entrypoint
    :param args: explicitly passed arguments for using pyayng from python
    :param extra_plugin_dirs: additional plugin dirs (from calling app)
    """

    usage = """%prog [options] [<filename>...]

Validates the YANG module in <filename> (or stdin), and all its dependencies."""

    plugindirs = extra_plugin_dirs or []
    # check for --plugindir
    idx = 1
    while '--plugindir' in sys.argv[idx:]:
        idx = idx + sys.argv[idx:].index('--plugindir')
        plugindirs.append(sys.argv[idx+1])
        idx = idx + 1
    plugin.init(plugindirs)

    fmts = {}
    xforms = {}
    for p in plugin.plugins:
        p.add_output_format(fmts)
        p.add_transform(xforms)

    optlist = [
        # use capitalized versions of std options help and version
        optparse.make_option("-h", "--help",
                             action="help",
                             help="Show this help message and exit"),
        optparse.make_option("-v", "--version",
                             action="version",
                             help="Show version number and exit"),
        optparse.make_option("-V", "--verbose",
                             action="store_true"),
        optparse.make_option("-e", "--list-errors",
                             dest="list_errors",
                             action="store_true",
                             help="Print a listing of all error and warning " \
                                 "codes and exit."),
        optparse.make_option("--print-error-code",
                             dest="print_error_code",
                             action="store_true",
                             help="On errors, print the error code instead " \
                             "of the error message."),
        optparse.make_option("--print-error-basename",
                             dest="print_error_basename",
                             action="store_true",
                             help="On errors, print the basename of files " \
                             "of the error message."),
        optparse.make_option("--msg-template",
                             dest="msg_template",
                             type="string",
                             help="Template used to display error messages. " \
                             "This is a python new-style format string used " \
                             "to format the message information with keys " \
                             "file, line, code, type and msg. " \
                             "Example: --msg-template='{file} || {line} || " \
                             "{code} || {type} || {level} || {msg}'"),
        optparse.make_option("-W",
                             dest="warnings",
                             action="append",
                             default=[],
                             metavar="WARNING",
                             help="If WARNING is 'error', treat all warnings " \
                                 "as errors, except any listed WARNING. " \
                                 "If WARNING is 'none', do not report any " \
                                 "warnings."),
        optparse.make_option("-E",
                             dest="errors",
                             action="append",
                             default=[],
                             metavar="WARNING",
                             help="Treat each WARNING as an error.  For a " \
                                 "list of warnings, use --list-errors."),
        optparse.make_option("--ignore-error",
                             dest="ignore_error_tags",
                             action="append",
                             default=[],
                             metavar="ERROR",
                             help="Ignore ERROR.  Use with care.  For a " \
                                 "list of errors, use --list-errors."),
        optparse.make_option("--ignore-errors",
                             dest="ignore_errors",
                             action="store_true",
                             help="Ignore all errors.  Use with care."),
        optparse.make_option("--canonical",
                             dest="canonical",
                             action="store_true",
                             help="Validate the module(s) according to the " \
                             "canonical YANG order."),
        optparse.make_option("--max-line-length",
                             type="int",
                             dest="max_line_len"),
        optparse.make_option("--max-identifier-length",
                             type="int",
                             dest="max_identifier_len"),
        optparse.make_option("-t", "--transform", dest="transforms",
                             default=[], action="append",
                             help="Apply transform TRANSFORM.  Supported " \
                                  "transforms are: " + ', '.join(xforms)),
        optparse.make_option("-f", "--format",
                             dest="format",
                             help="Convert to FORMAT.  Supported formats " \
                             "are: " +  ', '.join(fmts)),
        optparse.make_option("-o", "--output",
                             dest="outfile",
                             help="Write the output to OUTFILE instead " \
                             "of stdout."),
        optparse.make_option("-F", "--features",
                             metavar="FEATURES",
                             dest="features",
                             default=[],
                             action="append",
                             help="Features to support, default all. " \
                             "<modname>:[<feature>,]*"),
        optparse.make_option("", "--max-status",
                             metavar="MAXSTATUS",
                             dest="max_status",
                             help="Max status to support, one of: " \
                             "current, deprecated, obsolete"),
        optparse.make_option("", "--deviation-module",
                             metavar="DEVIATION",
                             dest="deviations",
                             default=[],
                             action="append",
                             help="Deviation module"),
        optparse.make_option("-p", "--path",
                             dest="path",
                             default=[],
                             action="append",
                             help=os.pathsep + "-separated search path for yin"
                             " and yang modules"),
        optparse.make_option("--plugindir",
                             dest="plugindir",
                             help="Load pyang plugins from PLUGINDIR"),
        optparse.make_option("--strict",
                             dest="strict",
                             action="store_true",
                             help="Force strict YANG compliance."),
        optparse.make_option("--lax-quote-checks",
                             dest="lax_quote_checks",
                             action="store_true",
                             help="Lax check of backslash in quoted strings."),
        optparse.make_option("--lax-xpath-checks",
                             dest="lax_xpath_checks",
                             action="store_true",
                             help="Lax check of XPath expressions."),
        optparse.make_option("--trim-yin",
                             dest="trim_yin",
                             action="store_true",
                             help="In YIN input modules, trim whitespace "
                             "in textual arguments."),
        optparse.make_option("-L", "--hello",
                             dest="hello",
                             action="store_true",
                             help="Filename of a server's hello message is "
                             "given instead of module filename(s)."),
        optparse.make_option("--implicit-hello-deviations",
                             dest="implicit_hello_deviations",
                             action="store_true",
                             help="Attempt to parse all deviations from hello "
                             "message regardless of declaration."),
        optparse.make_option("--keep-comments",
                             dest="keep_comments",
                             action="store_true",
                             help="Pyang will not discard comments; \
                                   has effect if the output plugin can \
                                   handle comments."),
        optparse.make_option("--no-path-recurse",
                             dest="no_path_recurse",
                             action="store_true",
                             help="Do not recurse into directories in the \
                                   yang path."),
        ]

    optparser = optparse.OptionParser(usage, add_help_option = False)
    optparser.version = '%prog ' + pyang.__version__
    optparser.add_options(optlist)

    for p in plugin.plugins:
        p.add_opts(optparser)

    (o, args) = optparser.parse_args(args)

    if o.outfile is not None and o.format is None:
        sys.stderr.write("no format specified\n")
        sys.exit(1)

    filenames = args

    # Parse hello if present
    if o.hello:
        if len(filenames) > 1:
            sys.stderr.write("multiple hello files given\n")
            sys.exit(1)
        if filenames:
            try:
                fd = open(filenames[0], "rb")
            except IOError as ex:
                sys.stderr.write("error %s: %s\n" % (filenames[0], ex))
                sys.exit(1)
        elif sys.version < "3":
            fd = sys.stdin
        else:
            fd = sys.stdin.buffer
        hel = hello.HelloParser().parse(fd)

    path = os.pathsep.join(o.path)

    # add standard search path
    if len(o.path) == 0:
        path = "."
    else:
        path += os.pathsep + "."

    repos = repository.FileRepository(path, no_path_recurse=o.no_path_recurse,
                                      verbose=o.verbose)

    ctx = context.Context(repos)

    ctx.opts = o
    ctx.canonical = o.canonical
    ctx.max_line_len = o.max_line_len
    ctx.max_identifier_len = o.max_identifier_len
    ctx.trim_yin = o.trim_yin
    ctx.lax_xpath_checks = o.lax_xpath_checks
    ctx.lax_quote_checks = o.lax_quote_checks
    ctx.strict = o.strict
    ctx.max_status = o.max_status

    # make a map of features to support, per module
    if o.hello:
        for mn, rev in hel.yang_modules():
            ctx.features[mn] = hel.get_features(mn)
    for f in ctx.opts.features:
        (modulename, features) = parse_features_string(f)
        ctx.features[modulename] = features

    for p in plugin.plugins:
        p.setup_ctx(ctx)

    if o.list_errors is True:
        for tag in error.error_codes:
            (level, fmt) = error.error_codes[tag]
            if error.is_warning(level):
                print("Warning: %s" % tag)
            elif error.allow_warning(level):
                print("Minor Error:   %s" % tag)
            else:
                print("Error:   %s" % tag)
            print("Message: %s" % fmt)
            print("")
        sys.exit(0)

    # patch the error spec so that -W errors are treated as warnings
    for w in o.warnings:
        if w in error.error_codes:
            (level, wstr) = error.error_codes[w]
            if error.allow_warning(level):
                error.error_codes[w] = (4, wstr)

    xform_objs = []
    for transform in o.transforms:
        if transform not in xforms:
            sys.stderr.write("unsupported transform '%s'\n" % transform)
        else:
            xform_obj = xforms[transform]
            xform_obj.setup_xform(ctx)
            xform_objs.append(xform_obj)
    if len(xform_objs) != len(o.transforms):
        sys.exit(1)

    if o.format is not None:
        if o.format not in fmts:
            sys.stderr.write("unsupported format '%s'\n" % o.format)
            sys.exit(1)
        emit_obj = fmts[o.format]
        if o.keep_comments and emit_obj.handle_comments:
            ctx.keep_comments = True
        emit_obj.setup_fmt(ctx)
    else:
        emit_obj = None

    xform_and_emit_objs = xform_objs[:]
    if emit_obj is not None:
        xform_and_emit_objs.append(emit_obj)

    for p in plugin.plugins:
        p.pre_load_modules(ctx)

    exit_code = 0
    modules = []

    if o.hello:
        ctx.capabilities = hel.registered_capabilities()
        modules_missing = False
        for mn, rev in hel.yang_modules():
            mod = ctx.search_module(error.Position(''), mn, rev)
            if mod is None:
                emarg = mn
                if rev:
                    emarg += "@" + rev
                sys.stderr.write(
                    "module '%s' specified in hello not found.\n" % emarg)
                modules_missing = True
            else:
                modules.append(mod)
        if modules_missing is True:
            sys.exit(1)
    else:
        if len(filenames) == 0:
            text = sys.stdin.read()
            module = ctx.add_module('<stdin>', text)
            if module is None:
                exit_code = 1
            else:
                modules.append(module)
        if (len(filenames) > 1 and
            emit_obj is not None and
            not emit_obj.multiple_modules):
            sys.stderr.write("too many files to convert\n")
            sys.exit(1)

        for filename in filenames:
            try:
                fd = io.open(filename, "r", encoding="utf-8")
                text = fd.read()
                if o.verbose:
                    util.report_file_read(filename, "(CL)")
            except IOError as ex:
                sys.stderr.write("error %s: %s\n" % (filename, ex))
                sys.exit(1)
            except UnicodeDecodeError as ex:
                s = str(ex).replace('utf-8', 'utf8')
                sys.stderr.write("%s: unicode error: %s\n" % (filename, s))
                sys.exit(1)
            m = syntax.re_filename.search(filename)
            ctx.yin_module_map = {}
            if m is not None:
                name, rev, in_format = m.groups()
                name = os.path.basename(name)
                module = ctx.add_module(filename, text, in_format, name, rev,
                                        expect_failure_error=False)
            else:
                module = ctx.add_module(filename, text)
            if module is None:
                exit_code = 1
            else:
                modules.append(module)

    modulenames = []
    for m in modules:
        modulenames.append(m.arg)
        for s in m.search('include'):
            modulenames.append(s.arg)

    # apply deviations
    for filename in ctx.opts.deviations:
        try:
            fd = io.open(filename, "r", encoding="utf-8")
            text = fd.read()
        except IOError as ex:
            sys.stderr.write("error %s: %s\n" % (filename, ex))
            sys.exit(1)
        except UnicodeDecodeError as ex:
            s = str(ex).replace('utf-8', 'utf8')
            sys.stderr.write("%s: unicode error: %s\n" % (filename, s))
            sys.exit(1)
        m = ctx.add_module(filename, text)
        if m is not None:
            ctx.deviation_modules.append(m)
    if o.hello and o.implicit_hello_deviations:
        for deviation_module in hel.yang_implicit_deviation_modules():
            m = ctx.search_module(error.Position(''), deviation_module)
            if m is not None:
                ctx.deviation_modules.append(m)

    for p in plugin.plugins:
        p.pre_validate_ctx(ctx, modules)

    if len(xform_and_emit_objs) > 0 and len(modules) > 0:
        for obj in xform_and_emit_objs:
            obj.pre_validate(ctx, modules)

    ctx.validate()

    for m in modules:
        m.prune()

    # transform modules
    if len(xform_objs) > 0 and len(modules) > 0:
        for xform_obj in xform_objs:
            try:
                if not xform_obj.transform(ctx, modules):
                    for module in modules:
                        module.i_is_validated = False
                        statements.validate_module(ctx, module)
            except error.TransformError as e:
                if e.msg != "":
                    sys.stderr.write(e.msg + '\n')
                sys.exit(e.exit_code)

    # verify the given features
    for m in modules:
        if m.arg in ctx.features:
            for f in ctx.features[m.arg]:
                if f not in m.i_features:
                    sys.stderr.write("unknown feature %s in module %s\n" %
                                     (f, m.arg))
                    sys.exit(1)

    if len(xform_and_emit_objs) > 0 and len(modules) > 0:
        for obj in xform_and_emit_objs:
            obj.post_validate(ctx, modules)

    for p in plugin.plugins:
        p.post_validate_ctx(ctx, modules)

    def keyfun(e):
        if e[0].ref == filenames[0]:
            return 0
        else:
            return 1

    ctx.errors.sort(key=lambda e: (e[0].ref, e[0].line))
    if len(filenames) > 0:
        # first print error for the first filename given
        ctx.errors.sort(key=keyfun)

    if o.ignore_errors:
        ctx.errors = []

    for epos, etag, eargs in ctx.errors:
        if etag in o.ignore_error_tags:
            continue
        if (ctx.implicit_errors is False and
            epos.top.arg not in modulenames and
            (not hasattr(epos.top, 'i_modulename') or
             epos.top.i_modulename not in modulenames) and
            epos.ref not in filenames):
            # this module was added implicitly (by import); skip this error
            # the code includes submodules
            continue
        elevel = error.err_level(etag)
        if error.is_warning(elevel) and etag not in o.errors:
            kind = "warning"
            if 'error' in o.warnings and etag not in o.warnings:
                kind = "error"
                exit_code = 1
            elif 'none' in o.warnings:
                continue
        else:
            kind = "error"
            exit_code = 1
        emsg = etag if o.print_error_code else error.err_to_str(etag, eargs)

        if o.msg_template is not None:
            try:
                sys.stderr.write(str(o.msg_template).format(
                    file=epos.ref, line=epos.line,
                    code=etag, type=kind,
                    msg=error.err_to_str(etag, eargs),
                    level=elevel) + '\n')
            except KeyError as error_msg:
                sys.stderr.write(
                    "unsupported key %s in msg-template\n" % error_msg)
                sys.exit(1)
        else:
            sys.stderr.write('%s: %s: %s\n' %
                             (epos.label(o.print_error_basename), kind, emsg))

    if emit_obj is not None and len(modules) > 0:
        tmpfile = None
        if o.outfile is None:
            if sys.version < '3':
                fd = codecs.getwriter('utf8')(sys.stdout)
            else:
                fd = sys.stdout
        else:
            tmpfile = o.outfile + ".tmp"
            if sys.version < '3':
                fd = codecs.open(tmpfile, "w+", encoding="utf-8")
            else:
                fd = io.open(tmpfile, "w+", encoding="utf-8")
        try:
            emit_obj.emit(ctx, modules, fd)
        except error.EmitError as e:
            if e.msg != "":
                sys.stderr.write(e.msg + '\n')
            if tmpfile is not None:
                fd.close()
                os.remove(tmpfile)
            sys.exit(e.exit_code)
        except:
            if tmpfile is not None:
                fd.close()
                os.remove(tmpfile)
            raise
        if tmpfile is not None:
            fd.close()
            os.rename(tmpfile, o.outfile)

    sys.exit(exit_code)