Home | History | Annotate | Download | only in scripts
      1 #!/usr/bin/env python

      2 
      3 """List all those Python files that require a coding directive
      4 
      5 Usage: nocoding.py dir1 [dir2...]
      6 """
      7 
      8 __author__ = "Oleg Broytmann, Georg Brandl"
      9 
     10 import sys, os, re, getopt
     11 
     12 # our pysource module finds Python source files

     13 try:
     14     import pysource
     15 except ImportError:
     16     # emulate the module with a simple os.walk

     17     class pysource:
     18         has_python_ext = looks_like_python = can_be_compiled = None
     19         def walk_python_files(self, paths, *args, **kwargs):
     20             for path in paths:
     21                 if os.path.isfile(path):
     22                     yield path.endswith(".py")
     23                 elif os.path.isdir(path):
     24                     for root, dirs, files in os.walk(path):
     25                         for filename in files:
     26                             if filename.endswith(".py"):
     27                                 yield os.path.join(root, filename)
     28     pysource = pysource()
     29 
     30 
     31     print >>sys.stderr, ("The pysource module is not available; "
     32                          "no sophisticated Python source file search will be done.")
     33 
     34 
     35 decl_re = re.compile(r"coding[=:]\s*([-\w.]+)")
     36 
     37 def get_declaration(line):
     38     match = decl_re.search(line)
     39     if match:
     40         return match.group(1)
     41     return ''
     42 
     43 def has_correct_encoding(text, codec):
     44     try:
     45         unicode(text, codec)
     46     except UnicodeDecodeError:
     47         return False
     48     else:
     49         return True
     50 
     51 def needs_declaration(fullpath):
     52     try:
     53         infile = open(fullpath, 'rU')
     54     except IOError: # Oops, the file was removed - ignore it

     55         return None
     56 
     57     line1 = infile.readline()
     58     line2 = infile.readline()
     59 
     60     if get_declaration(line1) or get_declaration(line2):
     61         # the file does have an encoding declaration, so trust it

     62         infile.close()
     63         return False
     64 
     65     # check the whole file for non-ASCII characters

     66     rest = infile.read()
     67     infile.close()
     68 
     69     if has_correct_encoding(line1+line2+rest, "ascii"):
     70         return False
     71 
     72     return True
     73 
     74 
     75 usage = """Usage: %s [-cd] paths...
     76     -c: recognize Python source files trying to compile them
     77     -d: debug output""" % sys.argv[0]
     78 
     79 try:
     80     opts, args = getopt.getopt(sys.argv[1:], 'cd')
     81 except getopt.error, msg:
     82     print >>sys.stderr, msg
     83     print >>sys.stderr, usage
     84     sys.exit(1)
     85 
     86 is_python = pysource.looks_like_python
     87 debug = False
     88 
     89 for o, a in opts:
     90     if o == '-c':
     91         is_python = pysource.can_be_compiled
     92     elif o == '-d':
     93         debug = True
     94 
     95 if not args:
     96     print >>sys.stderr, usage
     97     sys.exit(1)
     98 
     99 for fullpath in pysource.walk_python_files(args, is_python):
    100     if debug:
    101         print "Testing for coding: %s" % fullpath
    102     result = needs_declaration(fullpath)
    103     if result:
    104         print fullpath
    105