将列表作为 url 值传递给 urlopen

Passing a list as a url value to urlopen

动机

启发 - OP 使用 urlopen() 并意外传递了 sys.argv 列表而不是字符串作为 url。抛出此错误消息:

AttributeError: 'list' object has no attribute '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、[=19] 等静态代码分析工具静态捕获此类错误 =] 或 pylint,或具有 类型注释 等语言功能。

但是,我未能检测到问题:

问题

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

您可以使用 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. 添加一个预提交挂钩 运行s mypy on staged files 并立即指出问题(如果需要一段时间,开发人员可能会有点烦)。

首先,你需要检查 url 类型是否为字符串,如果是字符串则检查 ValueError exception(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)