Chapter 06 gf_gen

个人觉着,工作流的最大魅力在于将所有工作都组件化和流程化了,同时它也会造成代码样板化,而样板化意味着可能包含着重复的劳动,解决重复劳动的一种方案就是采用代码生成器。gf_gen就是这样的一种生成器,它能够依据设置好的模板来快速的生成代码。

通过运行gf_gen --help来查看它的选项,可以看到它只包含三个有效选项:

-t --template 要使用的代码模板
-p --path 生成代码的路径
--show-args 查看模板所支持的参数

只需要三个参数,因为主要的生成工作是由具体的代码模板来做的,gf_gen本身只是做了一点微小的工作:对这些模板进行包装执行。

使用workflow模板

我们会用到越来越多的插件,要记忆每个插件的参数是不可能的事情,因此我们需要一个脚手架来做这件事,girlfriend自带的workflow模板就是这样一个脚手架。

gf_gen -t :workflow --show-args

:workflow表示是从entry_point注册表中加载模板。workflow模板只有两个参数,一个是-f,用来指定生成文件的路径,可以不指定,默认会在当前目录生成一个workflow.py,一个是--no-highlight,用于取消代码展示时的高亮,当你的终端颜色配置与生成器代码高亮方案产生冲突时,可以用该选项。

直接运行gf_gen -t :workflow 会出现一个交互界面,通过在这个交互界面中输入指令来向代码中添加新的结构

查看所有的指令

输入help可以查看所有的指令。另外支持使用tab对指令来进行自动补全。

展示当前代码

使用show命令可以查看当前已经生成的代码结构。

(Cmd) show
#coding: utf-8

from girlfriend.workflow.gfworkflow import Job, Decision

logger = None
logger_level = "info"


def workflow(options):
    work_units = (

    )

    return work_units

添加插件类型的Job

plugin_job 单元名称 [插件名称] [参数函数名称]

通常只需要指定一个单元名称即可,插件名称默认与单元名称相同。如果你希望使用函数动态生成参数,那么可以指定一个生成参数的函数名称

(Cmd) plugin_job crawl crawl gen_crawl_args
(Cmd) show
# coding: utf-8

"""
Docs goes here
"""

from girlfriend.workflow.gfworkflow import Job, Decision


logger = None
logger_level = "info"


def workflow(options):
       work_units = (
       # crawl
       Job(
           name="crawl",
           plugin="crawl",
           args=gen_crawl_args
        ),

    )

    return work_units


def gen_crawl_args(context):
    pass

添加函数类型的Job

caller_job 单元名称 [调用函数名称]

(Cmd) caller_job hello_world greeting
(Cmd) show
# coding: utf-8

"""
Docs goes here
"""

from girlfriend.workflow.gfworkflow import Job, Decision


logger = None
logger_level = "info"


def workflow(options):
    work_units = (
        # hello_world
        Job(
            name="hello_world",
            caller=greeting,
        ),

    )

    return work_units


def greeting(context):
    pass

添加Decision单元

decision 单元名称 [决策函数]

(Cmd) decision need_write_excel
(Cmd) show
# coding: utf-8

"""
Docs goes here
"""

from girlfriend.workflow.gfworkflow import Job, Decision


logger = None
logger_level = "info"


def workflow(options):
    work_units = (
        # need_write_excel
        Decision(
            "need_write_excel",
            need_write_excel
        ),

    )

    return work_units


def need_write_excel(context):
    pass

移动单元

使用move命令对已经添加的工作单元进行移动

将工作单元A移动到第2个位置处:move A 1

将工作单元A移到工作单元B之前:move A before B

将工作单元B移到工作单元A之后 move B after A

删除工作单元

remove 工作单元名称

添加cmd_parser

如果你的工作流需要接收命令行参数,那么可以通过cmd_parser指令来添加解析器对象:

(Cmd) cmd_parser
(Cmd) show
# coding: utf-8

"""
Docs goes here
"""

from argparse import ArgumentParser
from girlfriend.workflow.gfworkflow import Job, Decision


cmd_parser = ArgumentParser(description=__doc__.decode("utf-8"))
cmd_parser.add_argument("--option", "-o", dest="option",
                        default="", action="store", help="")


logger = None
logger_level = "info"


def workflow(options):
    work_units = (

    )

    return work_units

(Cmd)

管理环境

gf_workflow的一大特色是允许开发者针对不同的执行环境使用不同的参数策略,workflow模板通过管理环境指令来更加方便这一功能:

添加环境:

(Cmd) env test
(Cmd) show
# coding: utf-8

"""
Docs goes here
"""

from girlfriend.workflow.gfworkflow import Job, Decision
from girlfriend.workflow.protocol import Env


logger = None
logger_level = "info"


def _test_env_args(options):
    return {}


def _test_env_config(options):
    return {}

env = (
    Env("test", _test_env_args, _test_env_config),
)


def workflow(options):
    work_units = (

    )

    return work_units

移除环境:

remove_env 环境名称

扩展workflow模板

workflow带有所有内置插件的代码模板,也许你会思考,如果自己编写的插件,能集成到workflow模板中吗?答案是肯定的,你只需要添加一个名为girlfriend.plugin_code_meta的entry_point即可,例如:

"girlfriend.plugin_code_meta": [
    (
        "builtin = "
        "girlfriend.tools.code_template.plugin_code_meta:all_meta"
    )
]

其中的all_meta对象是一个字典,结构如下:

from girlfriend.tools.code_template.workflow_template import PluginCodeMeta

all_meta = {

    # csv series
    "read_csv": PluginCodeMeta(
        plugin_name="read_csv",
        args_template="""[
                CSVR(
                  path="filepath",
                  record_handler=None,
                  record_filter=None,
                  result_wrapper=TableWrapper(
                        "table_name",
                        titles=[]
                  ),
                  dialect="excel",
                  variable=None
                ),
            ]""",
        auto_imports=[
            "from girlfriend.plugin.csv import CSVR",
            "from girlfriend.data.table import TableWrapper"
        ]
    ),

    ...
}

每个插件的代码模板用一个PluginCodeMeta对象来表示,args_template即参数模板,auto_imports为使用该插件时需要自动导入的包。

开发自己的模板

你可以根据自己的开发习惯来定制代码生成模板,gf_gen对代码模板只有一个约定,只要包含一个gen函数的模块即可,所有生成代码的逻辑均有开发者自己在gen函数中实现:

def gen(path, options):
    # path 为工程创建目录
    # options 为解析后的命令行参数
    WorkflowGenerator(options.file_name, options).cmdloop()

你可以通过源码文件直接运行一个模板:

gf_gen -t ./template.py

也可以使用entry_point来注册:

"girlfriend.code_template": [
    "mycodetemplate= girlfriend.tools.code_template.mycodetemplate",
],

这样就可以随处通过gf_gen -t :mycodetemplate来使用模板了。

results matching ""

    No results matching ""