Skip to content

Commit

Permalink
v3.0.0. Command-line options changed.
Browse files Browse the repository at this point in the history
  • Loading branch information
kyan001 committed Aug 6, 2021
1 parent a1bc23a commit d80e14d
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 40 deletions.
58 changes: 35 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)

Expand All @@ -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.")
```

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down
13 changes: 11 additions & 2 deletions UPDATES.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
4 changes: 2 additions & 2 deletions ping3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down
13 changes: 7 additions & 6 deletions ping3/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__":
Expand Down
19 changes: 14 additions & 5 deletions tests/test_command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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'])
Expand All @@ -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__":
Expand Down
4 changes: 2 additions & 2 deletions tests/test_ping3.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,15 @@ 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.
dest_addr = my_ip # only localhost can send and receive from 127.0.0.1 (or 127.0.1.1 on Ubuntu).
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"
Expand Down

0 comments on commit d80e14d

Please sign in to comment.