Locating a PID based on an IP address and port I wrote a simple Python app that is given an IP address and port and the app then finds the PID listening on that IP:PORT.

I would like to hear constructive criticism regarding the bellow code.

import argparse
import sys
import socket
import subprocess
import os


def is_legal_ip(address):
    ip = address.split(":")
    pieces = ip[0].split('.')
    if len(pieces) != 4: 
        return False
    try: 
        return all(0&lt;=int(p)&lt;256 for p in pieces)
    except ValueError: 
        return False

def parse_arguments():
    if len(sys.argv) &gt; 2 or len(sys.argv) == 1:
        print("Please provide a single argument.")
        exit(1)

    parser = argparse.ArgumentParser("Returns a PID listenning on IP:PORT")
    parser.add_argument('ip_port', metavar='IP:PORT', type=str, nargs=1, help='local address')
    args = parser.parse_args()

    if (is_legal_ip(args.ip_port[0]) == False):
        print("Invalid IP address.")
        exit(1)

    return(args.ip_port[0])

def address_to_pid(ip_port):
    devnull = open(os.devnull, 'w')
    output = subprocess.check_output("netstat -nptl".split(), stderr = devnull).splitlines()
    devnull.close()

    for line in output[2::]:
        raw_line = line.split()
        if raw_line[3] == ip_port:
            if raw_line[6] == "-": 
                return "No PID listening on address"
            else:
                return raw_line[6].split(r"/")[0]


def main():
    ip_port = parse_arguments()

    print address_to_pid(ip_port)



if __name__ == "__main__": main()
First off, a couple of quick tips:


Follow the PEP8 style guide
Instead of x == False, use not x, for example in if (is_legal_ip(args.ip_port[0]) == False)
Omit unnecessary imports (import socket in this example)
Use spaces around operators, for example all(0 &lt;= int(p) &lt; 256 for p in pieces)
Break lines after colons, for example in if __name__ == "__main__": main()


Leave the job of argument parsing to argparse

No need to work with sys.args yourself.
For example you can simply remove these lines:


if len(sys.argv) &gt; 2 or len(sys.argv) == 1:
    print("Please provide a single argument.")
    exit(1)



The way you specified the ip-port arguments with nargs=1,
argparse will take care of validating the number of command line arguments.

Simplify the argument parsing

You can omit nargs=1.
But in that case,
the value of args.ip_port will not be a list,
but a simple string.

You can also omit the type=str, as that's the default.

Your usage would become simpler:

parser.add_argument('ip_port', metavar='IP:PORT', help='local address')
args = parser.parse_args()

if not is_legal_ip(args.ip_port):
    parser.error("Invalid IP address.")

return args.ip_port


Use two arguments instead of one

It's awkward that use ip:port,
the splitting at multiple places is just noise.
It will be simpler and cleaner to use two arguments instead of one:

parser.add_argument('ip', help='local address')
parser.add_argument('port', type=int, help='local port')
args = parser.parse_args()

if not is_legal_ip(args.ip):
    parser.error("Invalid IP address.")

return args.ip, args.port


Notice that this way argparse can take care of validating the port number.

Then in your main function, you can get the ip address and port pair like this:

ip, port = parse_arguments()


Benefit from the error reporting features of argparse

Instead of this:


if not is_legal_ip(args.ip_port):
    print("Invalid IP address.")
    exit(1)



I suggest to use this way:

if not is_legal_ip(args.ip_port):
    parser.error("Invalid IP address.")


argparse will print a usage help along with the error message,
and also exit.

A subtlety here is that argparse will exit with code 2 in this case,
which is common in case of invalid parameters of UNIX commands.

Working with file handles

When working with files, use with:

with open(os.devnull, 'w') as devnull:
    output = subprocess.check_output("netstat -nl".split(), stderr=devnull).splitlines()


This makes devnull.close() unnecessary, Python will call it when exiting the block.