为Flake8 2和3编写插件

插件已经存在 Flake8 2.x几年了。PyPI上已经有很多这样的东西了。但对我来说 Flake8 为了给它们提供一个向后兼容的垫片,我们决定尝试用最简单的方法来编写一个兼容两个版本的插件。

注解

如果你的插件没有注册选项,它 应该 能够工作。

这个 只有两个 突破性的变化 Flake8 3.0的事实是,我们不再检查选项解析器中要从配置文件解析的字符串列表,也不再修补pep8或pycodestyle的 stdin_get_value 功能。在 Flake8 2.x,以便从 Flake8 查找和分析您必须执行以下操作:

parser.add_option('-X', '--example-flag', type='string',
                  help='...')
parser.config_options.append('example-flag')

为了 Flake8 3.0,我们添加了 的参数 add_option() 方法,您将在收到的解析器上调用:

  • parse_from_config which expects True or False

    什么时候? TrueFlake8 将解析配置文件中的选项 Flake8 找到。

  • comma_separated_list which expects True or False

    什么时候? TrueFlake8 将智能地拆分字符串并处理额外的空白。将解析列表中的值。

  • normalize_paths which expects True or False

    什么时候? TrueFlake8 威尔:

    • 移除拖尾路径分隔符(即。, os.path.sep

    • 返回包含分隔符的值的绝对路径

所有这三个选项都可以组合使用或单独使用。

正在分析配置文件中的选项

示例来自 Flake8 2.x现在看起来像:

parser.add_option('-X', '--example-flag', type='string',
                  parse_from_config=True,
                  help='...')

分析逗号分隔列表

现在让我们想象一下,我们想要添加的选项是期望用户提供一个逗号分隔的值列表(例如。, --select E123,W503,F405Flake8 2.x经常强迫用户自己解析这些列表,因为pep8特殊处理了某些标志,而其他标志则由它们自己处理。 Flake8 3.0增加 comma_separated_list 所以parsed选项已经是插件作者的列表了。当与 parse_from_config 这意味着用户还可以执行以下操作:

example-flag =
    first,
    second,
    third,
    fourth,
    fifth

Flake8 只返回列表:

["first", "second", "third", "fourth", "fifth"]

规范化路径值

最后,假设我们的新选项需要一个路径或路径列表。以确保这些路径是半规范化的(方式 Flake8 2.x曾经工作过)我们只需要通过 normalize_paths=True . 如果您指定 comma_separated_list=True 然后,这将把值解析为已规范化的路径列表。否则,将把值解析为单个路径。

Flake8 2和3上的选件处理

为了缓和这种转变 Flake8 维修人员已经释放 flake8-polyfill . flake8-polyfill 提供了一个方便的功能,帮助用户在Flake8 2和3之间顺利过渡。例如,如果你的插件必须在Flake8 2.x和3.x上工作,但是你想利用一些新的选项 add_option ,你能做到的

from flake8_polyfill import options


class MyPlugin(object):
    @classmethod
    def add_options(cls, parser):
        options.register(
            parser,
            '--application-names', default='', type='string',
            help='Names of the applications to be checked.',
            parse_from_config=True,
            comma_separated_list=True,
        )
        options.register(
            parser,
            '--style-name', default='', type='string',
            help='The name of the style convention you want to use',
            parse_from_config=True,
        )
        options.register(
            parser,
            '--application-paths', default='', type='string',
            help='Locations of the application code',
            parse_from_config=True,
            comma_separated_list=True,
            normalize_paths=True,
        )

    @classmethod
    def parse_options(cls, parsed_options):
        cls.application_names = parsed_options.application_names
        cls.style_name = parsed_options.style_name
        cls.application_paths = parsed_options.application_paths

flake8-polyfill 将使用 回调 到选项分析器。该项目直接复制了 Flake8 用于提供相同的功能。这意味着无论您使用的是Flake8 2.x还是3.x,都应该对您接收到的值进行相同的解析。

处理Flake8的标准2.5、2.6和3

释放后 Flake8 2.6版本中的处理标准对于某些插件来说变得有点棘手。 Flake8 2.5和更早的版本已经开始修补pep8 stdin_get_value 功能。2.6改为pycodestyle,只有monkey修补了它。3.0有自己的内部实现并使用它,但是没有直接为使用pep8和pycodestyle的插件提供任何东西 stdin_get_value 功能。 flake8-polyfill 通过它的 flake8_polyfill.stdin 模块。

如果插件需要从stdin读取内容,它可以执行以下操作:

from flake8_polyfill import stdin

stdin.monkey_patch('pep8')  # To monkey-patch only pep8
stdin.monkey_patch('pycodestyle')  # To monkey-patch only pycodestyle
stdin.monkey_patch('all')  # To monkey-patch both pep8 and pycodestyle

此外,当使用 allflake8-polyfill 不需要同时安装这两个包,但会尝试对这两个包进行monkey-patch,并且会忽略没有安装pep8或pycodestyle的事实。