It's not a syntax error. b=c is perfectly valid syntax, whether or not c exists. In fact, some other module could have done
import __builtin__
__builtin__.c = 3
in which case there would be a built-in c variable with value 3 available to all modules, and your code would run fine.
For a somewhat less pathological example, if the file contains a * import such as
from numpy import *
the import will dump a whole bunch of names into the module's global namespace, and there's no way to tell what those names are. Even without import *, though, Python can't be sure that a reference to an unknown name is an error at compile time.
If you want to detect semantic errors such as this, you'll need a more complex analysis of the program. Integrating with an existing linter like pylint, as suggested by NPE, is likely to be more productive than writing your own tool. If you really want to do it yourself, you can parse the code with ast.parse and examine the AST, going statement by statement to see what variables exist at what points. You'll still never catch all bugs, but you'll find quite a few.
pylint - Check python code for errors - Stack Overflow
How to check python code's syntax error before running it - Stack Overflow
compilation - How to check syntax of Python file/script without executing it? - Stack Overflow
Are there any good syntax or style checkers recommended?
Why are developers using SQL syntax validation tools?
What context-setting options are available in Workikโs AI for SQL syntax Validator?
How does Workik AI help with SQL syntax validation?
Videos
It's not a syntax error. b=c is perfectly valid syntax, whether or not c exists. In fact, some other module could have done
import __builtin__
__builtin__.c = 3
in which case there would be a built-in c variable with value 3 available to all modules, and your code would run fine.
For a somewhat less pathological example, if the file contains a * import such as
from numpy import *
the import will dump a whole bunch of names into the module's global namespace, and there's no way to tell what those names are. Even without import *, though, Python can't be sure that a reference to an unknown name is an error at compile time.
If you want to detect semantic errors such as this, you'll need a more complex analysis of the program. Integrating with an existing linter like pylint, as suggested by NPE, is likely to be more productive than writing your own tool. If you really want to do it yourself, you can parse the code with ast.parse and examine the AST, going statement by statement to see what variables exist at what points. You'll still never catch all bugs, but you'll find quite a few.
It's a tricky one, for many reasons.
It might not be a bad idea to try and integrate with pylint instead of trying to come up with your own.