I used to use perl -c programfile
to check the syntax of a Perl program and then exit without executing it. Is there an equivalent way to do this for a Python script?

- 7,883
- 2
- 25
- 41

- 142,882
- 41
- 325
- 378
9 Answers
You can check the syntax by compiling it:
python -m py_compile script.py

- 181,706
- 17
- 308
- 431

- 14,224
- 4
- 28
- 34
-
12`import script`, but all code must be in functions. Which is good practice anyway. I've even adopted this for shell scripts. From here it's a small step to unit testing. – Henk Langeveld Aug 10 '12 at 12:07
-
1won't work if you have an embedded engine with injected modules – n611x007 Feb 18 '13 at 13:41
-
73`python -m compileall` can also do directories recursively and has a better command line interface. – C2H5OH Feb 20 '13 at 09:19
-
9Great answer, but how can I prevent it for creating ".pyc" file? What's the use of ".pyc" file by the way? – pdubois Mar 18 '14 at 09:47
-
@MarkJohnson: So if `mycode.pyc` file exist the performance optimization is obtained even when we run `python mycode.py`, am I right? – pdubois Mar 19 '14 at 00:06
-
1Anyone can tell me how this command work? When I tried for this code: `print time.timezone` (without `import time`), there was no message at all after I run the command. – null Nov 27 '14 at 20:30
-
6For Python 2.7.9, when `-m py_compile` is present, I'm finding that neither `-B` nor `PYTHONDONTWRITEBYTECODE` suppresses creation of the **.pyc** file. – DavidRR Mar 25 '15 at 14:32
-
@C2H5OH: compileall ignores sources not ending with ".py" and I could not work it around. – proski Oct 02 '15 at 23:58
-
1It may be worth pointing out that using this method, python will return a non-zero exit status of the code compile fails. So you can incorporate this into a build script if you like. – Brian S. Oct 26 '16 at 15:59
-
I cursed python for *years* due to my script failing due to a syntax error in the exception handler print statement....this should be the second thing taught after teaching the interactive mode. – TCSGrad Jun 11 '19 at 02:20
-
1What's the output after running this command? I don't see any *.pyc files generated. If nothing is returned, does that mean my syntax is fine? – Victor Cui Jun 20 '19 at 23:14
-
2I run the script `python -m py_compile src/nike_run.py`, and it finished without error msg, but the code will crash in running time with a message 'TypeError: run_test_in_batch() missing 1 required positional argument: 'total_test_rownum'', seems it can not detect such error. Please correct me if wrong. – Ninja Apr 18 '20 at 16:35
-
1@Ninja Correct. Python is a dynamic language, so type errors are detected at runtime. – Jasper-M May 27 '20 at 07:27
-
Thank you @Jasper-M. Could you suggest one tool to check syntax? I know one of them is PyCharm, but it's too heavy for only syntax check. – Ninja May 27 '20 at 08:00
-
this answer is not correct, as it can lead to false positives: for example python3 compile successful with try catch block of a `StandardError` and that has been removed in python 3. So be cautious.... – Raffaello May 20 '21 at 13:24
-
@Ninja your main problem is that you shouldn't really do a static code analysis of a dynamic programming language (like Python) without having an engine that parses and/or executes the code, to provide you with a list of possible errors, which would occur at run-time. PyCharm doesn't just perform "only syntax check" but actually parses python code with an internal engine and that's why it's "too heavy". – Mladen B. Feb 07 '23 at 04:19

- 99
- 9

- 126,773
- 69
- 172
- 181
-
20All of these do much more than check the syntax. Really this isn't the answer. – Matt Joiner Dec 21 '11 at 01:57
-
41All of these check the syntax, so the answer is correct. Other checks are a (very useful) bonus. – johndodo Aug 27 '14 at 05:52
-
2PyChecker hasn't been updated since 2011 and does not support Python 3. – JPaget Feb 28 '22 at 18:50
-
1Pylint is very customizable. I used to add disable directives all over my code for Pylint, but lately I've been just setting up a pylintrc to turn off all the warnings I don't care about. With the right pylintrc, this may well be the best answer. – user1277476 Oct 10 '22 at 03:06
-
import sys
filename = sys.argv[1]
source = open(filename, 'r').read() + '\n'
compile(source, filename, 'exec')
Save this as checker.py and run python checker.py yourpyfile.py
.

- 20,755
- 11
- 51
- 73

- 20,355
- 6
- 41
- 43
-
1A little bit too heavy for a Makefile for a tiny script collection, but it does the job and doesn't produce any unwanted file. – proski Oct 03 '15 at 00:01
-
1It's an old answer, but something to notice is that this only checks the syntax, not if the script would successfully execute. – vallentin Mar 18 '16 at 03:10
-
2Thanks a lot. It works. Just one comment, there is no answer if the code is correct. Otherwise error messages with line numbers are shown. – musbach Jan 11 '18 at 16:12
Here's another solution, using the ast
module:
python -c "import ast; ast.parse(open('programfile').read())"
To do it cleanly from within a Python script:
import ast, traceback
filename = 'programfile'
with open(filename) as f:
source = f.read()
valid = True
try:
ast.parse(source)
except SyntaxError:
valid = False
traceback.print_exc() # Remove to silence any errros
print(valid)

- 12,125
- 9
- 63
- 94
-
3Awesome one-liner that does not require all of the imported libs or produce .pyc files. Thanks! – mmell Aug 16 '19 at 18:55
-
1Should be the accepted answer. Compiling these files (as the accepted answer suggests) is overkill, when one just wants to know if the syntax is valid. – Nils Lindemann Jul 30 '20 at 11:10
-
1Notice that `ast.parse(string)` is [equivalent to](https://github.com/python/cpython/blob/master/Lib/ast.py#L37) `compile(string, filename='
', mode='exec', flags=ast.PyCF_ONLY_AST)`. – Nils Lindemann Jul 30 '20 at 12:36 -
1
-
This also does not execute top-level code. Python actually executes modules when compiling or importing them; it's just that "executing a `def` statement" is how Python creates function objects, which then become attributes of the module object. – Karl Knechtel Jul 05 '22 at 03:34
Pyflakes does what you ask, it just checks the syntax. From the docs:
Pyflakes makes a simple promise: it will never complain about style, and it will try very, very hard to never emit false positives.
Pyflakes is also faster than Pylint or Pychecker. This is largely because Pyflakes only examines the syntax tree of each file individually.
To install and use:
$ pip install pyflakes
$ pyflakes yourPyFile.py

- 6,455
- 3
- 32
- 42
-
1This is better than most voted answer. It not only checks for syntax, but also shows all the unused and undefined variables. Very helpful especially when you are running time taking scripts. – Shashwat Mar 16 '21 at 09:07
python -m compileall -q .
Will compile everything under current directory recursively, and print only errors.
$ python -m compileall --help
usage: compileall.py [-h] [-l] [-r RECURSION] [-f] [-q] [-b] [-d DESTDIR] [-x REGEXP] [-i FILE] [-j WORKERS] [--invalidation-mode {checked-hash,timestamp,unchecked-hash}] [FILE|DIR [FILE|DIR ...]]
Utilities to support installing Python libraries.
positional arguments:
FILE|DIR zero or more file and directory names to compile; if no arguments given, defaults to the equivalent of -l sys.path
optional arguments:
-h, --help show this help message and exit
-l don't recurse into subdirectories
-r RECURSION control the maximum recursion level. if `-l` and `-r` options are specified, then `-r` takes precedence.
-f force rebuild even if timestamps are up to date
-q output only error messages; -qq will suppress the error messages as well.
-b use legacy (pre-PEP3147) compiled file locations
-d DESTDIR directory to prepend to file paths for use in compile-time tracebacks and in runtime tracebacks in cases where the source file is unavailable
-x REGEXP skip files matching the regular expression; the regexp is searched for in the full path of each file considered for compilation
-i FILE add all the files and directories listed in FILE to the list considered for compilation; if "-", names are read from stdin
-j WORKERS, --workers WORKERS
Run compileall concurrently
--invalidation-mode {checked-hash,timestamp,unchecked-hash}
set .pyc invalidation mode; defaults to "checked-hash" if the SOURCE_DATE_EPOCH environment variable is set, and "timestamp" otherwise.
Exit value is 1 when syntax errors have been found.
Thanks C2H5OH.

- 11,939
- 3
- 73
- 67
Thanks to the above answers @Rosh Oxymoron. I improved the script to scan all files in a dir that are python files. So for us lazy folks just give it the directory and it will scan all the files in that directory that are python. you can specify any file ext. you like.
import sys
import glob, os
os.chdir(sys.argv[1])
for file in glob.glob("*.py"):
source = open(file, 'r').read() + '\n'
compile(source, file, 'exec')
Save this as checker.py and run python checker.py ~/YOURDirectoryTOCHECK

- 1,059
- 10
- 17
for some reason ( I am a py newbie ... ) the -m call did not work ...
so here is a bash wrapper func ...
# ---------------------------------------------------------
# check the python synax for all the *.py files under the
# <<product_version_dir/sfw/python
# ---------------------------------------------------------
doCheckPythonSyntax(){
doLog "DEBUG START doCheckPythonSyntax"
test -z "$sleep_interval" || sleep "$sleep_interval"
cd $product_version_dir/sfw/python
# python3 -m compileall "$product_version_dir/sfw/python"
# foreach *.py file ...
while read -r f ; do \
py_name_ext=$(basename $f)
py_name=${py_name_ext%.*}
doLog "python3 -c \"import $py_name\""
# doLog "python3 -m py_compile $f"
python3 -c "import $py_name"
# python3 -m py_compile "$f"
test $! -ne 0 && sleep 5
done < <(find "$product_version_dir/sfw/python" -type f -name "*.py")
doLog "DEBUG STOP doCheckPythonSyntax"
}
# eof func doCheckPythonSyntax

- 5,114
- 1
- 56
- 53