将列表作为url值传递给urlopen

时间:2017-06-19 15:54:36

标签: python pycharm static-analysis type-hinting urlopen

动机

this problem激励 - OP正在使用urlopen()并意外地将sys.argv列表而不是字符串作为url传递。抛出此错误消息:

  

AttributeError:'list'对象没有属性'timeout'

由于编写urlopen的方式,错误消息本身和回溯信息量不大,特别是对于Python新手来说可能很难理解:

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'

问题

以下是我正在使用的缩短代码:

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)

我正在考虑是否可以使用PyCharm等智能IDE,静态代码分析工具(如flake8pylint)静态捕获此类错误,或者使用 type annotations 等语言功能。

但是,我没有发现问题:

  • 对于flake8pylint而言可能过于具体 - 他们没有警告这个问题
  • PyCharm并未警告sys.argv被传递到urlopen,即使您“跳转到”来源sys.argv,它也被定义为:

    argv = [] # real value of type <class 'list'> skipped
    
  • 如果我将函数参数注释为字符串并传递sys.argv,则不会出现警告:

    def get_category_links(url: str) -> None:
        response = urlopen(url)
        # do smth with response
    
    
    get_category_links(sys.argv)
    

问题

是否可以静态捕获此问题(不实际执行代码)?

2 个答案:

答案 0 :(得分:5)

您可以使用mypy来分析代码,而不是保持编辑器的特定性。这样它就可以在所有开发环境中运行,而不仅仅是那些使用PyCharm的人。

from urllib.request import urlopen
import sys


def get_category_links(url: str) -> None:
    response = urlopen(url)
    # do smth with response


get_category_links(sys.argv)
response = urlopen(sys.argv)

mypy针对上述代码指出的问题:

error: Argument 1 to "get_category_links" has incompatible type List[str]; expected "str"
error: Argument 1 to "urlopen" has incompatible type List[str]; expected "Union[str, Request]"

这里的Mypy可以猜测sys.argv的类型,因为它在存根文件中的定义。现在,一些标准库模块仍然是missing from typeshed,因此您必须提供它们或忽略相关错误,直到它们被添加: - )。

何时运行mypy?

  1. 要捕获此类错误,您可以在CI工具中使用带有测试的注释对文件运行mypy。在项目中的所有文件上运行它可能需要一些时间,对于一个小项目,它是您的选择。

  2. 添加一个预先提交的钩子,在分段文件上运行mypy并立即指出问题(如果需要一段时间,可能会对开发者有点烦恼)。

答案 1 :(得分:0)

首先,您需要检查url类型是否为字符串,如果是string,则检查ValueError异常(Valid url)

import sys
from urllib2 import urlopen

def get_category_links(url):
  if type(url) != type(""):  #Check if url is string or not
      print "Please give string url"
      return
  try:
      response = urlopen(url)
      # do smth with response
      print(response)
  except ValueError:        #If url is string but invalid
      print "Bad URL"

get_category_links(sys.argv)