#!/usr/bin/env python
# encoding: utf-8

"""
.. codeauthor:: Tsuyoshi Hombashi <tsuyoshi.hombashi@gmail.com>
"""

from __future__ import print_function

import argparse
import json
import multiprocessing
import os
import sys

import logbook
import pingparsing
from subprocrunner import CommandError


DEFAULT_COUNT = 10
QUIET_LOG_LEVEL = logbook.NOTSET


def parse_option():
    parser = argparse.ArgumentParser(
        epilog="Issue tracker: https://github.com/thombashi/pingparsing/issues")

    if is_use_stdin():
        parser.add_argument(
            "destination_or_file", nargs="+",
            help="")

    parser.add_argument(
        "--max-workers", type=int,
        help="""a number of threads for when multiple destination/file
        specified. defaults to equals to two times number of cores.
        """)
    parser.add_argument(
        "--indent", type=int, default=4,
        help="""JSON output will be pretty-printed with the indent level.
        (default= %(default)s)
        """)
    parser.add_argument(
        "--icmp-reply", action="store_true", default=False,
        help="print icmp packet replies.")

    loglevel_dest = "log_level"
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        "--debug", dest=loglevel_dest, action="store_const",
        const=logbook.DEBUG, default=logbook.INFO,
        help="for debug print.")
    group.add_argument(
        "--quiet", dest=loglevel_dest, action="store_const",
        const=logbook.NOTSET, default=logbook.INFO,
        help="suppress execution log messages.")

    group = parser.add_argument_group("Ping Options")
    group.add_argument(
        "-c", "--count", type=int,
        help="""stop after sending the count.
        see also ping(8) [-c count] option description.
        """)
    group.add_argument(
        "-w", "--deadline", type=float,
        help="""timeout in seconds.
        see also ping(8) [-w deadline] option description.
        """)
    group.add_argument(
        "-I", "--interface", dest="interface",
        help="network interface")

    return parser.parse_args()


def initialize_log_handler(log_level):
    debug_format_str = (
        "[{record.level_name}] {record.channel} {record.func_name} "
        "({record.lineno}): {record.message}")
    if log_level == logbook.DEBUG:
        info_format_str = debug_format_str
    else:
        info_format_str = "[{record.level_name}] {record.channel}: {record.message}"

    logbook.StderrHandler(
        level=logbook.DEBUG, format_string=debug_format_str
    ).push_application()
    logbook.StderrHandler(
        level=logbook.INFO, format_string=info_format_str
    ).push_application()


def is_use_stdin():
    return sys.stdin.isatty() or len(sys.argv) > 1


def parse_ping(logger, dest_or_file, interface, count, deadline, is_parse_icmp_reply):
    if os.path.isfile(dest_or_file):
        with open(dest_or_file) as f:
            ping_result_text = f.read()
    else:
        transmitter = pingparsing.PingTransmitter()
        transmitter.destination_host = dest_or_file
        transmitter.interface = interface
        transmitter.count = count
        transmitter.deadline = deadline
        transmitter.is_quiet = not is_parse_icmp_reply

        try:
            result = transmitter.ping()
        except CommandError as e:
            logger.error(e)
            sys.exit(e.errno)

        ping_result_text = result.stdout
        if result.returncode != 0:
            logger.error(result.stderr)

    ping_parser = pingparsing.PingParsing()
    stats = ping_parser.parse(ping_result_text)
    output = stats.as_dict()
    if is_parse_icmp_reply:
        output["icmp_reply"] = stats.icmp_reply_list

    return (dest_or_file, output)


def get_ping_param(options):
    count = options.count
    deadline = options.deadline

    if not options.count and not options.deadline:
        count = DEFAULT_COUNT

    return (count, deadline)


def main():
    options = parse_option()

    initialize_log_handler(options.log_level)

    logger = logbook.Logger("pingparsing cli")
    logger.level = options.log_level
    pingparsing.set_log_level(options.log_level)

    output = {}
    if is_use_stdin():
        from concurrent import futures

        pingparsing.set_log_level(options.log_level)

        max_workers = (multiprocessing.cpu_count() * 2
                       if options.max_workers is None else options.max_workers)
        count, deadline = get_ping_param(options)
        logger.debug("max-workers={}, count={}, deadline={}".format(
            max_workers, count, deadline))

        try:
            with futures.ProcessPoolExecutor(max_workers) as executor:
                future_list = []
                for dest_or_file in options.destination_or_file:
                    logger.debug("start {}".format(dest_or_file))
                    future_list.append(executor.submit(
                        parse_ping, logger, dest_or_file, options.interface,
                        count, deadline, options.icmp_reply))

                for future in futures.as_completed(future_list):
                    key, ping_data = future.result()
                    output[key] = ping_data
        finally:
            logger.debug("shutdown ProcessPoolExecutor")
            executor.shutdown()
    else:
        ping_result_text = sys.stdin.read()
        ping_parser = pingparsing.PingParsing()
        stats = ping_parser.parse(ping_result_text)
        output = stats.as_dict()
        if options.icmp_reply:
            output["icmp_reply"] = stats.icmp_reply_list

    if options.indent <= 0:
        print(json.dumps(output))
    else:
        print(json.dumps(output, indent=options.indent))

    return 0


if __name__ == "__main__":
    sys.exit(main())

@@ -2155,24 +2155,30 @@
 :%0A    debug_
+level_
 format_str =
@@ -2336,32 +2336,38 @@
 G:%0A        info_
+level_
 format_str = deb
@@ -2365,24 +2365,30 @@
 str = debug_
+level_
 format_str%0A 
@@ -2405,24 +2405,30 @@
        info_
+level_
 format_str =
@@ -2564,16 +2564,22 @@
 g=debug_
+level_
 format_s
@@ -2572,37 +2572,32 @@
 level_format_str
-%0A    
 ).push_applicati
@@ -2675,16 +2675,22 @@
 ng=info_
+level_
 format_s
@@ -2691,21 +2691,16 @@
 rmat_str
-%0A    
 ).push_a

Rename variables