可能是因为蓝图名字和要调用函数模块方法名相同
不要用相同的名字命名模块、目录和蓝图。
基本上我们的代码有这种结构。子树使其更简单。
-- webcompat
|-- __init__.py
|-- form.py
|-- api
| |-- __init__.py
| |-- uploads.py
| |-- endpoints.py
…
|-- helpers.py
|-- views.py
所以在webcompat/__init__.py
from webcompat.api.endpoints import api
app = Flask(__name__, static_url_path='')
app.register_blueprint(api)
在webcompat/api/endpoints/__init__.py
from webcompat.helpers import cool_feature
api = Blueprint('api', __name__, url_prefix='/api')
@api.route('blah')
def somewhere(foo):
"""blablah"""
yeah = cool_feature()
那么这里发生了什么? 模块和蓝图共享相同的名称。所以如果在测试中我们需要模拟cool_feature:
with patch('webcompat.api.endpoints.cool_feature') as mock_cool:
我们需要记住,在模拟时,我们不会模拟已定义的功能(也称为 webcompat.helpers.cool_feature
),而是在其已导入的位置(又名 webcompat.api.endpoints.cool_feature
)模拟。在这种情况下我们将无法模拟,因为会有名称冲突。错误将是:
E AttributeError: 'Blueprint' object has no attribute 'endpoints'
因为命名的webcompat.api
蓝图没有属性endpoints
,而模块webcompat.api
有一个。