Static code analysis tools (with multicasting chat sample)

In the modern world with the fast cycles of software development it is critical to develop applications with high quality but without long periods of testing and bug fixing. One of the key points for gaining such performance is using static code analysis tools. Let me provide some samples of such tools which can be useful for software development:
  • Clang Static Analyzer - open source source code analysis tool that finds bugs in C, C++, and Objective-C programs;
  • PyLint - a static code analyser for Python;
  • Perl-Critic - a static code analysis tool for Perl;
  • FxCop - static analysis for Microsoft .NET programs.
There are many other tools, a list of which you can find in wikipedia. Let's do static code analysis of a simple multicasting chat application:
#!/usr/bin/env python3
import socket
import struct
import sys
from threading import Thread
MADDX = '225.100.100.100'
PORT = 6543
is_listening = False
def listen_messages(is_listening):
print('Start listening...')
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', PORT))
mreq = struct.pack('4sl', socket.inet_aton(MADDX), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
sock.settimeout(1)
while is_listening():
try:
print(sock.recv(10240))
sys.stdout.flush()
except socket.timeout:
pass
print('Stop listening...')
name = input('Enter your name: ')
listening_thread = Thread(target=listen_messages, args=(lambda: is_listening,))
is_listening = True
listening_thread.start()
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
while is_listening:
try:
line = input()
msg = '%s: %s' % (name, line)
sock.sendto(msg.encode('utf-8'), (MADDX, PORT))
except (EOFError, KeyboardInterrupt):
is_listening = False
listening_thread.join()
except KeyboardInterrupt:
pass
view raw chat.py hosted with ❤ by GitHub

Run PyLint for this script. See results below:
<skipped>
C:  1, 0: Missing module docstring (missing-docstring)
C:  9, 0: Invalid constant name "is_listening" (invalid-name)
W: 12,20: Redefining name 'is_listening' from outer scope (line 9) (redefined-outer-name)
W: 14,61: Redefining name 'sock' from outer scope (line 35) (redefined-outer-name)
C: 12, 0: Missing function docstring (missing-docstring)
C: 28, 0: Invalid constant name "name" (invalid-name)
C: 30, 0: Invalid constant name "listening_thread" (invalid-name)
C: 31, 0: Invalid constant name "is_listening" (invalid-name)
C: 39,16: Invalid constant name "line" (invalid-name)
C: 40,16: Invalid constant name "msg" (invalid-name)
C: 43,16: Invalid constant name "is_listening" (invalid-name)
<skipped>
Your code has been rated at 7.18/10
Not so good rating. Let's try to fix all warning with the changes like these:
  1. Missing module docstring - Code should be readable - developers write code for humans not machines, and good documentation is a key point for better understanding of the code. Add docstring to the top of the script: """ Multicasting chat application """
  2. Invalid constant name "is_listening" (invalid-name) - All global variables should be marked with uppercase symbols. Global variables are evil, especially in Python (if a function uses global variable, developer should mark it with the GLOBAL keyword - an error widespread among developers who do not know or forget this requirement). That's why I use lambda to pass parameter to the listen_messages function - in other case I had to use the GLOBAL keyword. To fix this warning I moved the whole script to 'main' function.
New version of the application (after all the actions above):
#!/usr/bin/env python3
""" Multicasting chat application """
import socket
import struct
import sys
from threading import Thread
MADDX = '225.100.100.100'
PORT = 6543
def listen_messages(is_listening):
""" Socket listening thread """
print('Start listening...')
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', PORT))
ip_mreq = struct.pack('4sl', socket.inet_aton(MADDX), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, ip_mreq)
sock.settimeout(1)
while is_listening():
try:
print(sock.recv(10240))
sys.stdout.flush()
except socket.timeout:
pass
print('Stop listening...')
def main():
""" The program entry point """
is_listening = False
name = input('Enter your name: ')
listening_thread = Thread(target=listen_messages, args=(lambda: is_listening,))
is_listening = True
listening_thread.start()
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
while is_listening:
try:
line = input()
msg = '%s: %s' % (name, line)
sock.sendto(msg.encode('utf-8'), (MADDX, PORT))
except (EOFError, KeyboardInterrupt):
is_listening = False
listening_thread.join()
except KeyboardInterrupt:
pass
main()
view raw chat.py hosted with ❤ by GitHub

Surely those were the small issues, however PyLint support many more features:



And as a side effect, now you can enjoy chatting in your LAN without any servers and monstrous applications!

Comments

Popular posts from this blog

Web application framework comparison by memory consumption

Trac Ticket Workflow

Python vs JS vs PHP for embedded systems