Mercurial > public > mercurial-scm > hg
comparison contrib/check-code.py @ 41821:14e8d042993a
contrib: split pypats list in check-code.py
This is a part of preparation to apply checking with check-code.py on
code fragments embedded in *.t test scripts.
Ideally, all patterns in "pypats" before this patch should be applied
on not only normal *.py files but also code fragments embedded in *.t
test scripts. But fixing test scripts for some patterns requires
many changes, and has less profit than effort.
Therefore, this patch splits pypats list into two below:
- commonpypats, which are applied on all (= including code fragments
embedded in *.t test scripts) *.py files
- pypats, which are applied only on normal *.py
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Fri, 01 Mar 2019 02:53:05 +0900 |
parents | e2472b12c842 |
children | 55ae5cd31f76 |
comparison
equal
deleted
inserted
replaced
41820:9d38b4b52061 | 41821:14e8d042993a |
---|---|
229 utestfilters = [ | 229 utestfilters = [ |
230 (r"<<(\S+)((.|\n)*?\n > \1)", rephere), | 230 (r"<<(\S+)((.|\n)*?\n > \1)", rephere), |
231 (r"( +)(#([^!][^\n]*\S)?)", repcomment), | 231 (r"( +)(#([^!][^\n]*\S)?)", repcomment), |
232 ] | 232 ] |
233 | 233 |
234 pypats = [ | 234 # common patterns to check *.py |
235 commonpypats = [ | |
235 [ | 236 [ |
236 (r'\\$', 'Use () to wrap long lines in Python, not \\'), | 237 (r'\\$', 'Use () to wrap long lines in Python, not \\'), |
237 (r'^\s*def\s*\w+\s*\(.*,\s*\(', | 238 (r'^\s*def\s*\w+\s*\(.*,\s*\(', |
238 "tuple parameter unpacking not available in Python 3+"), | 239 "tuple parameter unpacking not available in Python 3+"), |
239 (r'lambda\s*\(.*,.*\)', | 240 (r'lambda\s*\(.*,.*\)', |
260 # more lines at the same indent level | 261 # more lines at the same indent level |
261 r'((?P=indent)[^\n]+\n)*' | 262 r'((?P=indent)[^\n]+\n)*' |
262 # a pass at the same indent level, which is bogus | 263 # a pass at the same indent level, which is bogus |
263 r'(?P=indent)pass[ \t\n#]' | 264 r'(?P=indent)pass[ \t\n#]' |
264 ), 'omit superfluous pass'), | 265 ), 'omit superfluous pass'), |
265 (r'.{81}', "line too long"), | |
266 (r'[^\n]\Z', "no trailing newline"), | 266 (r'[^\n]\Z', "no trailing newline"), |
267 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"), | 267 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"), |
268 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', | 268 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', |
269 # "don't use underbars in identifiers"), | 269 # "don't use underbars in identifiers"), |
270 (r'^\s+(self\.)?[A-Za-z][a-z0-9]+[A-Z]\w* = ', | 270 (r'^\s+(self\.)?[A-Za-z][a-z0-9]+[A-Z]\w* = ', |
298 "missing whitespace around operator"), | 298 "missing whitespace around operator"), |
299 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]', | 299 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]', |
300 "wrong whitespace around ="), | 300 "wrong whitespace around ="), |
301 (r'\([^()]*( =[^=]|[^<>!=]= )', | 301 (r'\([^()]*( =[^=]|[^<>!=]= )', |
302 "no whitespace around = for named parameters"), | 302 "no whitespace around = for named parameters"), |
303 (r'raise Exception', "don't raise generic exceptions"), | |
304 (r'raise [^,(]+, (\([^\)]+\)|[^,\(\)]+)$', | 303 (r'raise [^,(]+, (\([^\)]+\)|[^,\(\)]+)$', |
305 "don't use old-style two-argument raise, use Exception(message)"), | 304 "don't use old-style two-argument raise, use Exception(message)"), |
306 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"), | 305 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"), |
307 (r' [=!]=\s+(True|False|None)', | 306 (r' [=!]=\s+(True|False|None)', |
308 "comparison with singleton, use 'is' or 'is not' instead"), | 307 "comparison with singleton, use 'is' or 'is not' instead"), |
314 'instead', r'#.*hasattr-py3-only'), | 313 'instead', r'#.*hasattr-py3-only'), |
315 (r'opener\([^)]*\).read\(', | 314 (r'opener\([^)]*\).read\(', |
316 "use opener.read() instead"), | 315 "use opener.read() instead"), |
317 (r'opener\([^)]*\).write\(', | 316 (r'opener\([^)]*\).write\(', |
318 "use opener.write() instead"), | 317 "use opener.write() instead"), |
319 (r'[\s\(](open|file)\([^)]*\)\.read\(', | |
320 "use util.readfile() instead"), | |
321 (r'[\s\(](open|file)\([^)]*\)\.write\(', | |
322 "use util.writefile() instead"), | |
323 (r'^[\s\(]*(open(er)?|file)\([^)]*\)(?!\.close\(\))', | |
324 "always assign an opened file to a variable, and close it afterwards"), | |
325 (r'[\s\(](open|file)\([^)]*\)\.(?!close\(\))', | |
326 "always assign an opened file to a variable, and close it afterwards"), | |
327 (r'(?i)descend[e]nt', "the proper spelling is descendAnt"), | 318 (r'(?i)descend[e]nt', "the proper spelling is descendAnt"), |
328 (r'\.debug\(\_', "don't mark debug messages for translation"), | 319 (r'\.debug\(\_', "don't mark debug messages for translation"), |
329 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"), | 320 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"), |
330 (r'^\s*except\s*:', "naked except clause", r'#.*re-raises'), | 321 (r'^\s*except\s*:', "naked except clause", r'#.*re-raises'), |
331 (r'^\s*except\s([^\(,]+|\([^\)]+\))\s*,', | 322 (r'^\s*except\s([^\(,]+|\([^\)]+\))\s*,', |
332 'legacy exception syntax; use "as" instead of ","'), | 323 'legacy exception syntax; use "as" instead of ","'), |
333 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"), | |
334 (r'release\(.*wlock, .*lock\)', "wrong lock release order"), | 324 (r'release\(.*wlock, .*lock\)', "wrong lock release order"), |
335 (r'\bdef\s+__bool__\b', "__bool__ should be __nonzero__ in Python 2"), | 325 (r'\bdef\s+__bool__\b', "__bool__ should be __nonzero__ in Python 2"), |
336 (r'os\.path\.join\(.*, *(""|\'\')\)', | 326 (r'os\.path\.join\(.*, *(""|\'\')\)', |
337 "use pathutil.normasprefix(path) instead of os.path.join(path, '')"), | 327 "use pathutil.normasprefix(path) instead of os.path.join(path, '')"), |
338 (r'\s0[0-7]+\b', 'legacy octal syntax; use "0o" prefix instead of "0"'), | 328 (r'\s0[0-7]+\b', 'legacy octal syntax; use "0o" prefix instead of "0"'), |
339 # XXX only catch mutable arguments on the first line of the definition | 329 # XXX only catch mutable arguments on the first line of the definition |
340 (r'def.*[( ]\w+=\{\}', "don't use mutable default arguments"), | 330 (r'def.*[( ]\w+=\{\}', "don't use mutable default arguments"), |
341 (r'\butil\.Abort\b', "directly use error.Abort"), | 331 (r'\butil\.Abort\b', "directly use error.Abort"), |
342 (r'^@(\w*\.)?cachefunc', "module-level @cachefunc is risky, please avoid"), | 332 (r'^@(\w*\.)?cachefunc', "module-level @cachefunc is risky, please avoid"), |
343 (r'^import atexit', "don't use atexit, use ui.atexit"), | |
344 (r'^import Queue', "don't use Queue, use pycompat.queue.Queue + " | 333 (r'^import Queue', "don't use Queue, use pycompat.queue.Queue + " |
345 "pycompat.queue.Empty"), | 334 "pycompat.queue.Empty"), |
346 (r'^import cStringIO', "don't use cStringIO.StringIO, use util.stringio"), | 335 (r'^import cStringIO', "don't use cStringIO.StringIO, use util.stringio"), |
347 (r'^import urllib', "don't use urllib, use util.urlreq/util.urlerr"), | 336 (r'^import urllib', "don't use urllib, use util.urlreq/util.urlerr"), |
348 (r'^import SocketServer', "don't use SockerServer, use util.socketserver"), | 337 (r'^import SocketServer', "don't use SockerServer, use util.socketserver"), |
356 "use mercurial.policy.importmod instead"), | 345 "use mercurial.policy.importmod instead"), |
357 (r'\.next\(\)', "don't use .next(), use next(...)"), | 346 (r'\.next\(\)', "don't use .next(), use next(...)"), |
358 (r'([a-z]*).revision\(\1\.node\(', | 347 (r'([a-z]*).revision\(\1\.node\(', |
359 "don't convert rev to node before passing to revision(nodeorrev)"), | 348 "don't convert rev to node before passing to revision(nodeorrev)"), |
360 (r'platform\.system\(\)', "don't use platform.system(), use pycompat"), | 349 (r'platform\.system\(\)', "don't use platform.system(), use pycompat"), |
350 | |
351 ], | |
352 # warnings | |
353 [ | |
354 ] | |
355 ] | |
356 | |
357 # patterns to check normal *.py files | |
358 pypats = [ | |
359 [ | |
360 # Ideally, these should be placed in "commonpypats" for | |
361 # consistency of coding rules in Mercurial source tree. | |
362 # But on the other hand, these are not so seriously required for | |
363 # python code fragments embedded in test scripts. Fixing test | |
364 # scripts for these patterns requires many changes, and has less | |
365 # profit than effort. | |
366 (r'.{81}', "line too long"), | |
367 (r'raise Exception', "don't raise generic exceptions"), | |
368 (r'[\s\(](open|file)\([^)]*\)\.read\(', | |
369 "use util.readfile() instead"), | |
370 (r'[\s\(](open|file)\([^)]*\)\.write\(', | |
371 "use util.writefile() instead"), | |
372 (r'^[\s\(]*(open(er)?|file)\([^)]*\)(?!\.close\(\))', | |
373 "always assign an opened file to a variable, and close it afterwards"), | |
374 (r'[\s\(](open|file)\([^)]*\)\.(?!close\(\))', | |
375 "always assign an opened file to a variable, and close it afterwards"), | |
376 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"), | |
377 (r'^import atexit', "don't use atexit, use ui.atexit"), | |
361 | 378 |
362 # rules depending on implementation of repquote() | 379 # rules depending on implementation of repquote() |
363 (r' x+[xpqo%APM][\'"]\n\s+[\'"]x', | 380 (r' x+[xpqo%APM][\'"]\n\s+[\'"]x', |
364 'string join across lines with no space'), | 381 'string join across lines with no space'), |
365 (r'''(?x)ui\.(status|progress|write|note|warn)\( | 382 (r'''(?x)ui\.(status|progress|write|note|warn)\( |
375 ((%([ n]?[PM]?([np]+|A))?x)|%%|b[bnx]|[ \nnpqAPMo])*x | 392 ((%([ n]?[PM]?([np]+|A))?x)|%%|b[bnx]|[ \nnpqAPMo])*x |
376 (?# this regexp can't use [^...] style, | 393 (?# this regexp can't use [^...] style, |
377 # because _preparepats forcibly adds "\n" into [^...], | 394 # because _preparepats forcibly adds "\n" into [^...], |
378 # even though this regexp wants match it against "\n")''', | 395 # even though this regexp wants match it against "\n")''', |
379 "missing _() in ui message (use () to hide false-positives)"), | 396 "missing _() in ui message (use () to hide false-positives)"), |
380 ], | 397 ] + commonpypats[0], |
381 # warnings | 398 # warnings |
382 [ | 399 [ |
383 # rules depending on implementation of repquote() | 400 # rules depending on implementation of repquote() |
384 (r'(^| )pp +xxxxqq[ \n][^\n]', "add two newlines after '.. note::'"), | 401 (r'(^| )pp +xxxxqq[ \n][^\n]', "add two newlines after '.. note::'"), |
385 ] | 402 ] + commonpypats[1] |
386 ] | 403 ] |
387 | 404 |
388 pyfilters = [ | 405 # common filters to convert *.py |
406 commonpyfilters = [ | |
389 (r"""(?msx)(?P<comment>\#.*?$)| | 407 (r"""(?msx)(?P<comment>\#.*?$)| |
390 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!"))) | 408 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!"))) |
391 (?P<text>(([^\\]|\\.)*?)) | 409 (?P<text>(([^\\]|\\.)*?)) |
392 (?P=quote))""", reppython), | 410 (?P=quote))""", reppython), |
393 ] | 411 ] |
412 | |
413 # filters to convert normal *.py files | |
414 pyfilters = [ | |
415 ] + commonpyfilters | |
394 | 416 |
395 # non-filter patterns | 417 # non-filter patterns |
396 pynfpats = [ | 418 pynfpats = [ |
397 [ | 419 [ |
398 (r'pycompat\.osname\s*[=!]=\s*[\'"]nt[\'"]', "use pycompat.iswindows"), | 420 (r'pycompat\.osname\s*[=!]=\s*[\'"]nt[\'"]', "use pycompat.iswindows"), |