源码阅读 howdoi

Author Avatar
kdwycz 1月 20, 2017
  • 在其它设备中阅读本文章

柿子跳软的捏(然而感受到来自自己的弱者气息)

howdoi是一个命令行中查询编程问题的工具,使用stackoverflow和google检索出最适合问题的答案并显示其中的代码部分

虽说是个200多行的小工具,还是能学到一些东西的。比如CLI工具的写法,选取网页中的元素(爬虫基础),如何打包发布一个工具等等

流程

command_line_runner 入口函数,调用 get_parser处理了传入的参数,并对显示版本号,清除缓存做单独处理。有传入查询的话调用howdoi处理,否则返回帮助文档。

howdoi把查询拼成了一个字符串,并且去掉了问号。(_get_instructions)然后进行查询:_get_links返回google搜索到的stackoverflow链接;get_answer用来获取链接中的问题答案:如果命令需要返回链接就直接返回,否则开始解析网页中的回答部分。如果回答部分包括代码就_format_output来输出,普通文本直接输出。完成查询流程

调用的库

argparse

Python标准库中用来解析参数的工具。我之前使用过看起来更优雅的click。但是在对外发布包的话。没有第三方依赖也是很好的选择

glob

In [1]: import glob

In [2]: glob.glob('/Users/kdwycz/M*')
Out[2]: ['/Users/kdwycz/Movies', '/Users/kdwycz/Music']

看起来是一个查找路径的库,比更为人熟知的os.listdir()再过滤要优雅太多。还有一个glob.iglob方法返回的是一个迭代器,适合文件数量很大的情况

requests-cache

一个神奇的给网络查询加缓存的包。我很诧异它在没有影响requests正常使用的情况下怎么加缓存的。就去看了下源代码。原来是通过hook来实现

pyquery

是一个用jQuery语法对xml进行操作的库。用法非常简洁

pygments

代码高亮工具(不知道怎么演示的路过)

In [1]: from pygments import highlight

In [2]: from pygments.lexers import PythonLexer

In [3]: from pygments.formatters.terminal import TerminalFormatter

In [4]: code = "def _format_output(code, args):\n    if not args['color']:\n        return code\n    lexer = None\n    # try to find a lexer using the StackOverflow tags\n    # or the query arguments\n    for
   ...:  keyword in args['query'].split() + args['tags']:\n        try:\n            lexer = get_lexer_by_name(keyword)\n            break\n        except ClassNotFound:\n            pass\n\n    # no lexer fo
   ...: und above, use the guesser\n    if not lexer:\n        try:\n            lexer = guess_lexer(code)\n        except ClassNotFound:\n            return code\n    return highlight(code,\n
   ...:      lexer,\n                     TerminalFormatter(bg='dark'))"

In [5]: print(highlight(code, PythonLexer(), TerminalFormatter()))
def _format_output(code, args):
    if not args['color']:
        return code
    lexer = None
    # try to find a lexer using the StackOverflow tags
    # or the query arguments
    for keyword in args['query'].split() + args['tags']:
        try:
            lexer = get_lexer_by_name(keyword)
            break
        except ClassNotFound:
            pass

    # no lexer found above, use the guesser
    if not lexer:
        try:
            lexer = guess_lexer(code)
        except ClassNotFound:
            return code
    return highlight(code,
                     lexer,
                     TerminalFormatter(bg='dark'))

其他

Python版本兼容

作者使用了sys模块中的version来判定版本。我以前见到的代码大多是try下面import看是否异常。

  # Handle imports for Python 2 and 3
  if sys.version < '3':
      import codecs
      from urllib import quote as url_quote
      from urllib import getproxies

      # Handling Unicode: http://stackoverflow.com/a/6633040/305414
      def u(x):
          return codecs.unicode_escape_decode(x)[0]
  else:
      from urllib.request import getproxies
      from urllib.parse import quote as url_quote

      def u(x):
          return x

requests-cache/compat.py 做的更进一步了些,判断了Python小版本,系统环境和解释器

后记

虽然很早就想看源代码总结,但是直接促使我写这篇文章的确是看到别人对这个项目的阅读博文……写的时候并没有参考(写完看看也没有他写的好T_T)一开始还想把流程画成图,尝试了hexo的绘图插件和手绘后放弃,其实还是不晓得如何梳理结构。好在这个项目逻辑非常简单。给我更多的帮助是发现了些以前没用过的库

扩展资料

Github gleitz/howdoi

六系小白 阅读源代码之开篇Howdoi

Python爬虫利器六之PyQuery的用法

Comparing Python Command-Line Parsing Libraries - Argparse, Docopt, and Click

本站所有原创内容均以 署名-非商业性使用-相同方式共享 4.0 (CC BY-NC-SA 4.0) 协议授权
本文链接:https://blog.kdwycz.com/archives/code001/