489

I used to use perl -c <filename> 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?

0

9 Answers 9

763

You can check the syntax by compiling it:

python -m py_compile script.py
Sign up to request clarification or add additional context in comments.

17 Comments

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.
python -m compileall can also do directories recursively and has a better command line interface.
Great answer, but how can I prevent it for creating ".pyc" file? What's the use of ".pyc" file by the way?
For Python 2.7.9, when -m py_compile is present, I'm finding that neither -B nor PYTHONDONTWRITEBYTECODE suppresses creation of the .pyc file.
It 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.
|
70

You can use these tools:

6 Comments

All of these do much more than check the syntax. Really this isn't the answer.
All of these check the syntax, so the answer is correct. Other checks are a (very useful) bonus.
PyChecker hasn't been updated since 2011 and does not support Python 3.
Pylint 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.
Pyflakes was perfect
|
30

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)

5 Comments

Awesome one-liner that does not require all of the imported libs or produce .pyc files. Thanks!
Should 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.
Notice that ast.parse(string) is equivalent to compile(string, filename='<unknown>', mode='exec', flags=ast.PyCF_ONLY_AST).
Exactly what I wanted to do.
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.
29
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.

3 Comments

A little bit too heavy for a Makefile for a tiny script collection, but it does the job and doesn't produce any unwanted file.
It's an old answer, but something to notice is that this only checks the syntax, not if the script would successfully execute.
Thanks a lot. It works. Just one comment, there is no answer if the code is correct. Otherwise error messages with line numbers are shown.
28

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

1 Comment

This 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.
17
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.

Comments

2

Perhaps useful online checker PEP8 : http://pep8online.com/

Comments

1

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

Comments

0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.