将列表作为 url 值传递给 urlopen



Motivation

受此问题的启发 - OP 正在使用urlopen(),并且不小心传递了一个sys.argv列表而不是字符串作为url。抛出此错误消息:

属性

错误:"列表"对象没有属性"超时">

由于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这样的静态代码分析工具,或者像类型注释这样的语言功能来静态捕获这种错误。

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

  • 对于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)
    

问题

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

您可以使用 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的类型,因为它在其存根文件中的定义。现在typeshed仍然缺少一些标准库模块,因此您必须贡献它们或忽略相关的错误,直到它们被添加:-)。


什么时候运行mypy?

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

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

首先,您需要检查网址类型是否为字符串,如果是字符串,则检查 ValueError 异常(有效网址)

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)

最新更新