diff --git a/README.md b/README.md index 7083090..d5d1868 100644 --- a/README.md +++ b/README.md @@ -52,28 +52,28 @@ pip uninstall ping3 # uninstall ping3 >>> ping('example.com') # Returns delay in seconds. 0.215697261510079666 ->>> ping('not.exist.com') # if host unknown (cannot resolve), returns False +>>> ping('not.exist.com') # If host unknown (cannot resolve), returns False. False ->>> ping("224.0.0.0") # If timed out (no reply), returns None +>>> ping("224.0.0.0") # If timed out (no reply), returns None. None ->>> ping('example.com', timeout=10) # Set timeout to 10 seconds. Default timeout=4 for 4 seconds. +>>> ping('example.com', timeout=10) # Set timeout to 10 seconds. Default timeout is 4 for 4 seconds. 0.215697261510079666 ->>> ping('example.com', unit='ms') # Returns delay in milliseconds. Default unit='s' for seconds. +>>> ping('example.com', unit='ms') # Returns delay in milliseconds. Default unit is 's' for seconds. 215.9627876281738 ->>> ping('example.com', src_addr='192.168.1.15') # WINDOWS ONLY. Set source ip address for multiple interfaces. Default src_addr=None for no binding. +>>> ping('example.com', src_addr='192.168.1.15') # Set source ip address for multiple interfaces. Default src_addr is None for no binding. 0.215697261510079666 ->>> ping('example.com', interface='eth0') # LINUX ONLY. Set source interface for multiple network interfaces. Default interface=None for no binding. +>>> ping('example.com', interface='eth0') # LINUX ONLY. Set source interface for multiple network interfaces. Default interface is None for no binding. 0.215697261510079666 ->>> ping('example.com', ttl=5) # Set packet Time-To-Live to 5. The packet is discarded if it does not reach the target host after 5 jumps. Default ttl=64. +>>> ping('example.com', ttl=5) # Set packet Time-To-Live to 5. The packet is discarded if it does not reach the target host after 5 jumps. Default ttl is 64. None ->>> ping('example.com', size=56) # Set ICMP packet payload to 56 bytes. The total ICMP packet size is 8 (header) + 56 (payload) = 64 bytes. Default size=56. +>>> ping('example.com', size=56) # Set ICMP packet payload to 56 bytes. The total ICMP packet size is 8 (header) + 56 (payload) = 64 bytes. Default size is 56. 0.215697261510079666 >>> verbose_ping('example.com') # Ping 4 times in a row. @@ -82,13 +82,13 @@ ping 'example.com' ... 216ms ping 'example.com' ... 219ms ping 'example.com' ... 217ms ->>> verbose_ping('example.com', timeout=10) # Set timeout to 10 seconds. Default timeout=4 for 4 seconds. +>>> verbose_ping('example.com', timeout=10) # Set timeout to 10 seconds. Default timeout is 4 for 4 seconds. ping 'example.com' ... 215ms ping 'example.com' ... 216ms ping 'example.com' ... 219ms ping 'example.com' ... 217ms ->>> verbose_ping('example.com', count=6) # Ping 6 times. Default count=4. +>>> verbose_ping('example.com', count=6) # Ping 6 times. Default count is 4. ping 'example.com' ... 215ms ping 'example.com' ... 216ms ping 'example.com' ... 219ms @@ -100,19 +100,19 @@ ping 'example.com' ... 216ms ping 'example.com' ... 215ms ... ->>> verbose_ping('example.com', src_addr='192.168.1.15') # WINDOWS ONLY. Ping from source IP address. Default src_addr=None +>>> verbose_ping('example.com', src_addr='192.168.1.15') # Ping from source IP address for multiple interfaces. Default src_addr is None. ping 'example.com' from '192.168.1.15' ... 215ms ping 'example.com' from '192.168.1.15' ... 216ms ping 'example.com' from '192.168.1.15' ... 219ms ping 'example.com' from '192.168.1.15' ... 217ms ->>> verbose_ping('example.com', interface='wifi0') # LINUX ONLY. Ping from network interface 'wifi0'. Default interface=None +>>> verbose_ping('example.com', interface='wifi0') # LINUX ONLY. Ping from network interface 'wifi0'. Default interface is None. ping 'example.com' from '192.168.1.15' ... 215ms ping 'example.com' from '192.168.1.15' ... 216ms ping 'example.com' from '192.168.1.15' ... 219ms ping 'example.com' from '192.168.1.15' ... 217ms ->>> verbose_ping('example.com', unit='s') # Displays delay in seconds. Default unit="ms" for milliseconds. +>>> verbose_ping('example.com', unit='s') # Displays delay in seconds. Default unit is "ms" for milliseconds. ping 'example.com' ... 1s ping 'example.com' ... 2s ping 'example.com' ... 1s @@ -130,7 +130,7 @@ ping 'example.com' ... 216ms # wait 5 secs ping 'example.com' ... 219ms # wait 5 secs ping 'example.com' ... 217ms ->>> verbose_ping('example.com', size=56) # Set ICMP payload to 56 bytes. Default size=56. +>>> verbose_ping('example.com', size=56) # Set ICMP payload to 56 bytes. Default size is 56. ping 'example.com' ... 215ms ping 'example.com' ... 216ms ping 'example.com' ... 219ms @@ -171,7 +171,7 @@ Raise exceptions when there are errors instead of return None >>> import ping3 >>> ping3.EXCEPTIONS = True # Default is False. ->>> ping3.ping("example.com", timeout=0.0001) # All Exceptions are subclasses of PingError +>>> ping3.ping("example.com", timeout=0.0001) [... Traceback ...] ping3.errors.Timeout: Request timeout for ICMP packet. (Timeout = 0.0001s) @@ -192,9 +192,9 @@ ping3.EXCEPTIONS = True try: ping3.ping("not.exist.com") -except ping3.errors.HostUnknown: # catch only host unknown error +except ping3.errors.HostUnknown: # Specific error is catched. print("Host unknown error raised.") -except ping3.errors.PingError: # catch all ping errors +except ping3.errors.PingError: # All ping3 errors are subclasses of `PingError`. print("A ping error raised.") ``` @@ -205,7 +205,7 @@ Note: On some platforms, `ping3` needs root privilege to send/receive packets. Y ```sh $ ping3 --help # -h/--help. Command-line help message. -$ python -m ping3 --help # Same as 'ping3'. 'ping3' is an alias for 'python -m ping3' +$ python -m ping3 --help # Same as `ping3`. `ping3` is an alias for `python -m ping3`. $ ping3 -v # -v/--version. Show ping3 version number. 2.2.2 @@ -233,19 +233,19 @@ $ ping3 -c 0 example.com # Ping endlessly (0 means infinite loops). Using `ctrl ping 'example.com' ... 215ms ... -$ ping3 -w 10 example.com # -w/--wait. Set timeout to 10 seconds. Default is 4. +$ ping3 -t 10 example.com # -t/--timeout. Set timeout to 10 seconds. Default is 4. ping 'example.com' ... 215ms ping 'example.com' ... 216ms ping 'example.com' ... 219ms ping 'example.com' ... 217ms -$ ping3 -t 5 example.com # -t/--ttl. # Set TTL to 5. Default is 64. +$ ping3 -T 5 example.com # -T/--ttl. # Set TTL to 5. Default is 64. ping 'example.com' ... Timeout ping 'example.com' ... Timeout ping 'example.com' ... Timeout ping 'example.com' ... Timeout -$ ping3 -l 56 example.com # -l/--load. Set ICMP packet payload to 56 bytes. Default is 56. +$ ping3 -s 56 example.com # -s/--size. Set ICMP packet payload to 56 bytes. Default is 56. ping 'example.com' ... 215ms ping 'example.com' ... 216ms ping 'example.com' ... 219ms @@ -257,11 +257,23 @@ ping 'example.com' ... 216ms # wait 5 secs ping 'example.com' ... 219ms # wait 5 secs ping 'example.com' ... 217ms -$ ping3 --exceptions --wait 0.001 example.com # EXCPETIONS mode is on when --exceptions shows up. +$ ping3 -I eth0 example.com # -I/--interface. LINUX ONLY. The gateway network interface to ping from. Default is None. +ping 'example.com' ... 215ms +ping 'example.com' ... 216ms +ping 'example.com' ... 219ms +ping 'example.com' ... 217ms + +$ ping3 -S 192.168.1.15 example.com # -S/--src. Ping from source IP address for multiple network interfaces. Default is None. +ping 'example.com' ... 215ms +ping 'example.com' ... 216ms +ping 'example.com' ... 219ms +ping 'example.com' ... 217ms + +$ ping3 -E --timeout 0.001 example.com # -E/--exceptions. EXCPETIONS mode is on when this shows up. [... Traceback ...] ping3.errors.Timeout: Request timeout for ICMP packet. (Timeout = 0.0001s) -$ ping3 --debug --wait 0.001 example.com # DEBUG mode is on when --debug shows up. +$ ping3 -D --timeout 0.001 example.com # -D/--debug. DEBUG mode is on when this shows up. [DEBUG] Request timeout for ICMP packet. (Timeout = 0.001s) ping 'example.com' ... Timeout > 0.001s [DEBUG] Request timeout for ICMP packet. (Timeout = 0.001s) diff --git a/UPDATES.md b/UPDATES.md index 5510cfe..7ae97f6 100644 --- a/UPDATES.md +++ b/UPDATES.md @@ -1,8 +1,17 @@ # UPDATES +* 3.0.0: + * Backward Compatibility: Only Command-line options changed, now the options is more like `ping` on macOS and Linux. + * `-w`/`--wait` -> `-t`/`--timeout`. + * `-t`/`--ttl` -> `-T`/`--ttl`. + * `-l`/`--load` -> `-s`/`--size`. + * Improvement: 2 command-line options now have short forms. + * `-D` is added as the short form of `--debug`. + * `-E` is added as the short form of `--exceptions`. + * Feature: Use new command-line option `-S`/`--src` to set source address `src_addr`. * 2.9.3: - * Set packet receive buffer size to 1500. ( #40 ) + * Bug Fix: Set packet receive buffer size to 1500. ( #40 ) * 2.9.2: - * Converted to a proper package. ( #38 #39 ) + * Improvement: Converted to a proper package. ( #38 #39 ) * 2.9.1: * Bug Fix: macOS is not treated as Linux now. * 2.9.0: diff --git a/ping3/__init__.py b/ping3/__init__.py index 13fbeb7..2588199 100644 --- a/ping3/__init__.py +++ b/ping3/__init__.py @@ -15,7 +15,7 @@ from . import errors from .enums import ICMP_DEFAULT_CODE, IcmpType, IcmpTimeExceededCode, IcmpDestinationUnreachableCode -__version__ = "2.9.3" +__version__ = "3.0.0" DEBUG = False # DEBUG: Show debug info for developers. (default False) EXCEPTIONS = False # EXCEPTIONS: Raise exception when delay is not available. LOGGER = None # LOGGER: Record logs into console or file. @@ -258,7 +258,7 @@ def ping(dest_addr: str, timeout: int = 4, unit: str = "s", src_addr: str = None dest_addr: The destination address, can be an IP address or a domain name. Ex. "192.168.1.1"/"example.com" timeout: Time to wait for a response, in seconds. Default is 4s, same as Windows CMD. (default 4) unit: The unit of returned value. "s" for seconds, "ms" for milliseconds. (default "s") - src_addr: WINDOWS ONLY. The IP address to ping from. This is for multiple network interfaces. Ex. "192.168.1.20". (default None) + src_addr: The IP address to ping from. This is for multiple network interfaces. Ex. "192.168.1.20". (default None) interface: LINUX ONLY. The gateway network interface to ping from. Ex. "wlan0". (default None) ttl: The Time-To-Live of the outgoing packet. Default is None, which means using OS default ttl -- 64 onLinux and macOS, and 128 on Windows. (default None) seq: ICMP packet sequence, usually increases from 0 in the same process. (default 0) diff --git a/ping3/command_line.py b/ping3/command_line.py index fb6df8e..c3be794 100644 --- a/ping3/command_line.py +++ b/ping3/command_line.py @@ -17,19 +17,20 @@ def main(assigned_args: list = None): parser.add_argument("-v", "--version", action="version", version=ping3.__version__) parser.add_argument(dest="dest_addr", metavar="DEST_ADDR", nargs="*", default=("example.com", "8.8.8.8"), help="The destination address, can be an IP address or a domain name. Ex. 192.168.1.1/example.com.") parser.add_argument("-c", "--count", dest="count", metavar="COUNT", type=int, default=4, help="How many pings should be sent. Default is 4.") - parser.add_argument("-w", "--wait", dest="timeout", metavar="TIMEOUT", type=float, default=4, help="Time to wait for a response, in seconds. Default is 4.") + parser.add_argument("-t", "--timeout", dest="timeout", metavar="TIMEOUT", type=float, default=4, help="Time to wait for a response, in seconds. Default is 4.") parser.add_argument("-i", "--interval", dest="interval", metavar="INTERVAL", type=float, default=0, help="Time to wait between each packet, in seconds. Default is 0.") parser.add_argument("-I", "--interface", dest="interface", metavar="INTERFACE", default="", help="LINUX ONLY. The gateway network interface to ping from. Default is None.") - parser.add_argument("-t", "--ttl", dest="ttl", metavar="TTL", type=int, default=64, help="The Time-To-Live of the outgoing packet. Default is 64.") - parser.add_argument("-l", "--load", dest="size", metavar="SIZE", type=int, default=56, help="The ICMP packet payload size in bytes. Default is 56.") - parser.add_argument("--debug", action="store_true", dest="debug", help="Turn on DEBUG mode.") - parser.add_argument("--exceptions", action="store_true", dest="exceptions", help="Turn on EXCEPTIONS mode.") + parser.add_argument("-S", "--src", dest="src_addr", metavar="SRC_ADDR", default="", help="The IP address to ping from. This is for multiple network interfaces. Default is None") + parser.add_argument("-T", "--ttl", dest="ttl", metavar="TTL", type=int, default=64, help="The Time-To-Live of the outgoing packet. Default is 64.") + parser.add_argument("-s", "--size", dest="size", metavar="SIZE", type=int, default=56, help="The ICMP packet payload size in bytes. Default is 56.") + parser.add_argument("-D", "--debug", action="store_true", dest="debug", help="Turn on DEBUG mode.") + parser.add_argument("-E", "--exceptions", action="store_true", dest="exceptions", help="Turn on EXCEPTIONS mode.") args = parser.parse_args(assigned_args) ping3.DEBUG = args.debug ping3.EXCEPTIONS = args.exceptions for addr in args.dest_addr: - ping3.verbose_ping(addr, count=args.count, ttl=args.ttl, timeout=args.timeout, size=args.size, interval=args.interval, interface=args.interface) + ping3.verbose_ping(addr, count=args.count, ttl=args.ttl, timeout=args.timeout, size=args.size, interval=args.interval, interface=args.interface, src_addr=args.src_addr) if __name__ == "__main__": diff --git a/tests/test_command_line.py b/tests/test_command_line.py index 48bd53c..737b7eb 100644 --- a/tests/test_command_line.py +++ b/tests/test_command_line.py @@ -43,20 +43,20 @@ def test_count(self): def test_timeout(self): with patch("sys.stdout", new=io.StringIO()) as fake_out: - command_line.main(['-w', '0.0001', 'example.com']) + command_line.main(['-t', '0.0001', 'example.com']) self.assertRegex(fake_out.getvalue(), r".*Timeout \> [0-9\.]+s.*") def test_ttl(self): with patch("sys.stdout", new=io.StringIO()) as fake_out: - command_line.main(['-t', '1', 'example.com']) + command_line.main(['-T', '1', 'example.com']) self.assertRegex(fake_out.getvalue(), r".*Timeout.*") def test_size(self): with patch("sys.stdout", new=io.StringIO()) as fake_out: - command_line.main(['-l', '100', 'example.com']) + command_line.main(['-s', '100', 'example.com']) self.assertRegex(fake_out.getvalue(), r".*[0-9]+ms.*") with self.assertRaises(OSError): - command_line.main(['-l', '99999', 'example.com']) + command_line.main(['-s', '99999', 'example.com']) def test_interval(self): with patch("sys.stdout", new=io.StringIO()) as fake_out: @@ -82,6 +82,15 @@ def test_interface(self): command_line.main(['-I', my_interface, 'example.com']) self.assertRegex(fake_out.getvalue(), r".*[0-9]+ms.*") + def test_src_addr(self): + with patch("sys.stdout", new=io.StringIO()) as fake_out: + my_ip = socket.gethostbyname(socket.gethostname()) + dest_addr = "example.com" + if my_ip == "127.0.0.1" or my_ip == "127.0.1.1": # This may caused by /etc/hosts settings. + dest_addr = my_ip # only localhost can send and receive from 127.0.0.1 (or 127.0.1.1 on Ubuntu). + command_line.main(['-S', my_ip, dest_addr]) + self.assertRegex(fake_out.getvalue(), r".*[0-9]+ms.*") + def test_debug(self): with patch("sys.stdout", new=io.StringIO()), patch("sys.stderr", new=io.StringIO()) as fake_err: command_line.main(['--debug', '-c', '1', 'example.com']) @@ -90,7 +99,7 @@ def test_debug(self): def test_exceptions(self): with patch("sys.stdout", new=io.StringIO()) as fake_out: with self.assertRaises(errors.Timeout): - command_line.main(['--exceptions', '-w', '0.0001', 'example.com']) + command_line.main(['--exceptions', '-t', '0.0001', 'example.com']) if __name__ == "__main__": diff --git a/tests/test_ping3.py b/tests/test_ping3.py index b9f648c..00c8162 100644 --- a/tests/test_ping3.py +++ b/tests/test_ping3.py @@ -112,7 +112,7 @@ def test_verbose_ping_interface(self): ping3.verbose_ping(dest_addr, interface=my_interface) self.assertRegex(fake_out.getvalue(), r".*[0-9]+ms.*") - def test_ping_bind(self): + def test_ping_src_addr(self): my_ip = socket.gethostbyname(socket.gethostname()) dest_addr = "example.com" if my_ip == "127.0.0.1" or my_ip == "127.0.1.1": # This may caused by /etc/hosts settings. @@ -120,7 +120,7 @@ def test_ping_bind(self): delay = ping3.ping(dest_addr, src_addr=my_ip) self.assertIsInstance(delay, float) - def test_verbose_ping_bind(self): + def test_verbose_ping_src_addr(self): with patch("sys.stdout", new=io.StringIO()) as fake_out: my_ip = socket.gethostbyname(socket.gethostname()) dest_addr = "example.com"