How can I check the syntax of Python script without executing it?
Asked Answered
N

9

476

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?

Newman answered 26/11, 2010 at 10:12 Comment(0)
V
740

You can check the syntax by compiling it:

python -m py_compile script.py
Vehicle answered 8/12, 2011 at 20:57 Comment(17)
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.Caerleon
won't work if you have an embedded engine with injected modulesSuperfuse
python -m compileall can also do directories recursively and has a better command line interface.Chain
Great answer, but how can I prevent it for creating ".pyc" file? What's the use of ".pyc" file by the way?Castara
@MarkJohnson: So if mycode.pyc file exist the performance optimization is obtained even when we run python mycode.py, am I right?Castara
Anyone 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.Elevator
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.Graeae
@C2H5OH: compileall ignores sources not ending with ".py" and I could not work it around.Denny
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.Namangan
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.Grandfatherly
What'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?Shaker
I 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.Stygian
@Stygian Correct. Python is a dynamic language, so type errors are detected at runtime.Mullis
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.Stygian
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....Martino
@Stygian 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".Haskell
@Chain great answer. The CLI is really nice, too. +1Unwish
O
71

You can use these tools:

Overestimate answered 26/11, 2010 at 10:29 Comment(5)
All of these do much more than check the syntax. Really this isn't the answer.Houghton
All of these check the syntax, so the answer is correct. Other checks are a (very useful) bonus.Realism
PyChecker hasn't been updated since 2011 and does not support Python 3.Chee
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.Cystoid
Pyflakes was perfectFilagree
I
28
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.

Insist answered 26/11, 2010 at 10:39 Comment(3)
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.Denny
It's an old answer, but something to notice is that this only checks the syntax, not if the script would successfully execute.Ellon
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.Dysphasia
N
27

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)
Narvik answered 15/8, 2019 at 11:15 Comment(5)
Awesome one-liner that does not require all of the imported libs or produce .pyc files. Thanks!Douai
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.Amblyoscope
Notice that ast.parse(string) is equivalent to compile(string, filename='<unknown>', mode='exec', flags=ast.PyCF_ONLY_AST).Amblyoscope
Exactly what I wanted to do.Cleric
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.Chimpanzee
B
26

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
Battaglia answered 8/1, 2020 at 19:52 Comment(1)
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.Marishamariska
W
15
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.

Wyant answered 19/4, 2021 at 8:25 Comment(0)
R
2

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

Rovner answered 10/9, 2015 at 9:22 Comment(0)
A
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

Abstergent answered 10/9, 2020 at 20:19 Comment(0)
P
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
Pernambuco answered 27/12, 2016 at 11:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.