blob: 6c16b1ce151852da1a54e7aedb515c0e5c898290 [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#!/usr/bin/env python3
Georg Brandl56897312005-08-24 18:32:30 +00002
3"""List all those Python files that require a coding directive
4
Éric Araujo1e794f62011-05-05 20:18:16 +02005Usage: findnocoding.py dir1 [dir2...]
Georg Brandl56897312005-08-24 18:32:30 +00006"""
7
Thomas Wouters89f507f2006-12-13 04:49:30 +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 Petersonc0747cf2008-11-03 20:31:38 +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
Collin Winter6afaeb72007-08-03 17:06:41 +000031 print("The pysource module is not available; "
32 "no sophisticated Python source file search will be done.", file=sys.stderr)
Georg Brandl56897312005-08-24 18:32:30 +000033
34
Serhiy Storchakae431d3c2016-03-20 23:36:29 +020035decl_re = re.compile(rb'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)')
Serhiy Storchaka768c16c2014-01-09 18:36:09 +020036blank_re = re.compile(rb'^[ \t\f]*(?:[#\r\n]|$)')
Georg Brandl56897312005-08-24 18:32:30 +000037
38def get_declaration(line):
Serhiy Storchakadafea852013-09-16 23:51:56 +030039 match = decl_re.match(line)
Georg Brandl56897312005-08-24 18:32:30 +000040 if match:
41 return match.group(1)
Serhiy Storchakadafea852013-09-16 23:51:56 +030042 return b''
Georg Brandl56897312005-08-24 18:32:30 +000043
44def has_correct_encoding(text, codec):
45 try:
Georg Brandl8efadf52008-05-16 15:23:30 +000046 str(text, codec)
Georg Brandl56897312005-08-24 18:32:30 +000047 except UnicodeDecodeError:
48 return False
49 else:
50 return True
51
52def needs_declaration(fullpath):
53 try:
Victor Stinner98516a62012-08-01 20:12:51 +020054 infile = open(fullpath, 'rb')
Georg Brandl56897312005-08-24 18:32:30 +000055 except IOError: # Oops, the file was removed - ignore it
56 return None
57
Victor Stinner98516a62012-08-01 20:12:51 +020058 with infile:
59 line1 = infile.readline()
60 line2 = infile.readline()
Tim Peters9e34c042005-08-26 15:20:46 +000061
Serhiy Storchaka768c16c2014-01-09 18:36:09 +020062 if (get_declaration(line1) or
63 blank_re.match(line1) and get_declaration(line2)):
Victor Stinner98516a62012-08-01 20:12:51 +020064 # the file does have an encoding declaration, so trust it
Victor Stinner98516a62012-08-01 20:12:51 +020065 return False
Tim Peters9e34c042005-08-26 15:20:46 +000066
Victor Stinner98516a62012-08-01 20:12:51 +020067 # check the whole file for non utf-8 characters
68 rest = infile.read()
Tim Peters9e34c042005-08-26 15:20:46 +000069
Benjamin Petersoncff882c2008-10-25 23:43:00 +000070 if has_correct_encoding(line1+line2+rest, "utf-8"):
Georg Brandl56897312005-08-24 18:32:30 +000071 return False
Tim Peters9e34c042005-08-26 15:20:46 +000072
Georg Brandl56897312005-08-24 18:32:30 +000073 return True
74
75
76usage = """Usage: %s [-cd] paths...
77 -c: recognize Python source files trying to compile them
78 -d: debug output""" % sys.argv[0]
79
R David Murray54ac8322012-04-04 21:28:14 -040080if __name__ == '__main__':
Georg Brandl56897312005-08-24 18:32:30 +000081
R David Murray54ac8322012-04-04 21:28:14 -040082 try:
83 opts, args = getopt.getopt(sys.argv[1:], 'cd')
84 except getopt.error as msg:
85 print(msg, file=sys.stderr)
86 print(usage, file=sys.stderr)
87 sys.exit(1)
Georg Brandl56897312005-08-24 18:32:30 +000088
R David Murray54ac8322012-04-04 21:28:14 -040089 is_python = pysource.looks_like_python
90 debug = False
Georg Brandl56897312005-08-24 18:32:30 +000091
R David Murray54ac8322012-04-04 21:28:14 -040092 for o, a in opts:
93 if o == '-c':
94 is_python = pysource.can_be_compiled
95 elif o == '-d':
96 debug = True
Georg Brandl56897312005-08-24 18:32:30 +000097
R David Murray54ac8322012-04-04 21:28:14 -040098 if not args:
99 print(usage, file=sys.stderr)
100 sys.exit(1)
101
102 for fullpath in pysource.walk_python_files(args, is_python):
103 if debug:
104 print("Testing for coding: %s" % fullpath)
105 result = needs_declaration(fullpath)
106 if result:
107 print(fullpath)