Motivation
Motivated by this problem - the OP was using urlopen()
and accidentally passed a sys.argv
list instead of a string as a url
. This error message was thrown:
AttributeError: 'list' object has no attribute 'timeout'
Because of the way urlopen
was written, the error message itself and the traceback is not very informative and may be difficult to understand especially for a Python newcomer:
Traceback (most recent call last):
File "test.py", line 15, in <module>
get_category_links(sys.argv)
File "test.py", line 10, in get_category_links
response = urlopen(url)
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 154, in urlopen
return opener.open(url, data, timeout)
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 420, in open
req.timeout = timeout
AttributeError: 'list' object has no attribute 'timeout'
Problem
Here is the shortened code I'm working with:
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
import sys
def get_category_links(url):
response = urlopen(url)
# do smth with response
print(response)
get_category_links(sys.argv)
I'm trying to think whether this kind of an error can be caught statically with either smart IDEs like PyCharm, static code analysis tools like flake8
or pylint
, or with language features like type annotations.
But, I'm failing to detect the problem:
it is probably too specific for
flake8
andpylint
to catch - they don't warn about the problemPyCharm
does not warn aboutsys.argv
being passed intourlopen
, even though, if you "jump to source" ofsys.argv
it is defined as:argv = [] # real value of type <class 'list'> skipped
if I annotate the function parameter as a string and pass
sys.argv
, no warnings as well:def get_category_links(url: str) -> None: response = urlopen(url) # do smth with response get_category_links(sys.argv)
Question
Is it possible to catch this problem statically (without actually executing the code)?
error: Argument 1 to "get_category_links" has incompatible type List[str]; expected "str"
. See of there's an mypy extension available for PyCharm, else you can run mypy with your tests to catch such issues. When I passed a list tourlopen()
I got:error: Argument 1 to "urlopen" has incompatible type List[str]; expected "Union[str, Request]"
(github.com/python/typeshed/blob/master/stdlib/3/urllib/…). – Adventistmypy
catches the problem! I wonder what prevents PyCharm to determine thatsys.argv
is a list and what helpsmypy
to know that it is. Cause, if I do hardcode a list instead ofsys.argv
- PyCharm finally warns about the mistype. Thanks so much - it deserves to be an actual answer. – Metcalf