blob: 70b1a666133e75490b7c73c76a8385cf92af8a88 [file] [log] [blame]
Georg Brandl56897312005-08-24 18:32:30 +00001#!/usr/bin/env python
2
3"""List all those Python files that require a coding directive
4
5Usage: nocoding.py dir1 [dir2...]
6"""
7
Georg Brandl0750b1f2006-10-06 12:46:08 +00008__author__ = "Oleg Broytmann, Georg Brandl"
Georg Brandl56897312005-08-24 18:32:30 +00009
10import sys, os, re, getopt
11
12# our pysource module finds Python source files
13try:
14 import pysource
Benjamin Petersonadc93b92008-10-25 23:27:07 +000015except ImportError:
Georg Brandl56897312005-08-24 18:32:30 +000016 # 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()
Tim Peters9e34c042005-08-26 15:20:46 +000029
30
Georg Brandl56897312005-08-24 18:32:30 +000031 print >>sys.stderr, ("The pysource module is not available; "
32 "no sophisticated Python source file search will be done.")
33
34
Serhiy Storchakae4818f62013-09-17 10:09:08 +030035decl_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)')
Serhiy Storchaka3eb554f2014-09-05 10:22:05 +030036blank_re = re.compile(r'^[ \t\f]*(?:[#\r\n]|$)')
Georg Brandl56897312005-08-24 18:32:30 +000037
38def get_declaration(line):
Serhiy Storchakae787bce2013-09-17 00:00:46 +030039 match = decl_re.match(line)
Georg Brandl56897312005-08-24 18:32:30 +000040 if match:
41 return match.group(1)
Serhiy Storchakae787bce2013-09-17 00:00:46 +030042 return b''
Georg Brandl56897312005-08-24 18:32:30 +000043
44def has_correct_encoding(text, codec):
45 try:
46 unicode(text, codec)
47 except UnicodeDecodeError:
48 return False
49 else:
50 return True
51
52def needs_declaration(fullpath):
53 try:
54 infile = open(fullpath, 'rU')
55 except IOError: # Oops, the file was removed - ignore it
56 return None
57
58 line1 = infile.readline()
59 line2 = infile.readline()
Tim Peters9e34c042005-08-26 15:20:46 +000060
Serhiy Storchaka3eb554f2014-09-05 10:22:05 +030061 if (get_declaration(line1) or
62 blank_re.match(line1) and get_declaration(line2)):
Georg Brandl56897312005-08-24 18:32:30 +000063 # the file does have an encoding declaration, so trust it
64 infile.close()
65 return False
Tim Peters9e34c042005-08-26 15:20:46 +000066
Georg Brandl56897312005-08-24 18:32:30 +000067 # check the whole file for non-ASCII characters
68 rest = infile.read()
69 infile.close()
Tim Peters9e34c042005-08-26 15:20:46 +000070
Georg Brandl56897312005-08-24 18:32:30 +000071 if has_correct_encoding(line1+line2+rest, "ascii"):
72 return False
Tim Peters9e34c042005-08-26 15:20:46 +000073
Georg Brandl56897312005-08-24 18:32:30 +000074 return True
75
76
77usage = """Usage: %s [-cd] paths...
78 -c: recognize Python source files trying to compile them
79 -d: debug output""" % sys.argv[0]
80
81try:
82 opts, args = getopt.getopt(sys.argv[1:], 'cd')
83except getopt.error, msg:
84 print >>sys.stderr, msg
85 print >>sys.stderr, usage
86 sys.exit(1)
87
88is_python = pysource.looks_like_python
89debug = False
90
91for o, a in opts:
92 if o == '-c':
93 is_python = pysource.can_be_compiled
94 elif o == '-d':
95 debug = True
96
97if not args:
98 print >>sys.stderr, usage
99 sys.exit(1)
100
101for fullpath in pysource.walk_python_files(args, is_python):
102 if debug:
103 print "Testing for coding: %s" % fullpath
104 result = needs_declaration(fullpath)
105 if result:
106 print fullpath