Pylint插件:忽略Django的国际化代码调用报错
NOTICE:如果更新到Django1.4+以上版本后,就不会报类似Error级别的提示了。
用Django写Web开发类型的程序,经常会用到程序的国际化操作,例如,保存如下代码为example.py:
from django.utils.translation import ugettext_lazy as _
print _('damn it!')
如果项目中用到Pylint来检查代码,执行如下:
pylint -E example.py
这个时候会显示一个Error级别的提示,如下:
No config file found, using default configuration
************* Module example
E: 3,6: _ is not callable
熟悉Django的人,一定会觉得很奇怪,怎么可能函数不能被调用,这里就不具体展开说明原因了:
- 可以认为是Pylint不够智能
- 也可以认为Python本身太灵活,Django中调用的国际化模块,刚好用了一些动态语言的特性
怎么办?
- Pylint提供了灵活的配置设置,过了一遍配置,发现没有自定义设置可以忽略这个情况
- Google之,但很多是说直接忽略那条规则,这样虽然可以达到忽略的效果,但是同样也忽略了不应该忽略的检查,比如:a = 1; a()这种语法错误
- 看Pylint官方文档,发现Pylint扩展性还是不错的,提供自定义插件机制,-–load-plugin参数指定插件即可,那么就自己写个插件来处理这种情况吧!
- 继续Google,发现有人写过类似插件,虽然是处理别的问题,但很类似:http://www.logilab.org/blogentry/78354
写个插件!
代码很简单,原理就是写个假的函数调用,在Pylint执行该模块的函数检查时候,直接调用了假的函数,从而绕过该报错,但又不会影响这条规则检查其它代码时候报告Error级别信息。保存如下代码为astng_django.py
from logilab.astng import MANAGER
from logilab.astng.builder import ASTNGBuilder
def hashlib_transform(module):
if module.name == 'django.utils.translation':
fake = ASTNGBuilder(MANAGER).string_build('''
def ugettext_lazy(value):
return u''
def ugettext(value):
return u''
''')
for hashfunc in ('ugettext_lazy', 'ugettext'):
module.locals[hashfunc] = fake.locals[hashfunc]
def register(linter):
"""called when loaded by pylint --load-plugins, register our tranformation
function here
"""
MANAGER.register_transformer(hashlib_transform)
这个时候执行命令(需要PYTHONPATH能找到astng_django.py)
pylint -E example.py --load-plugins=astng_django
输出如下:
No config file found, using default configuration
就没有刚才的Error级别的提示了。
保存如下代码为error.py,再验证下报错的情况是否被忽略:
fake_function = 1
fake_function()
执行命令:
pylint -E error.py --load-plugins=astng_django
输出如下:
No config file found, using default configuration
************* Module error
E: 2,0: fake_function is not callable
这样就算初步解决这个问题了,即可以不让Django程序报干扰的Error级别信息,又不会忽略的确需要报的Error级别信息。
占个坑~
照例,GitHub上先占个坑:https://github.com/akun/pylint_plugin
后续TODO:
- 前面有说明必须指定PYTHONPATH,有点麻烦,但作为临时解决问题是够了。后续需要做个完整的Python库,然后发布到PyPI,然后作为正式的安装包,就更方便别人使用了。
- 另外,这个插件还是相对简单,其实Django中的国际化处理有好多函数,需要后续补充。
- 将上述的相关验证转化为对应的测试代码。