如何在Python中有效提供Web,CLI和API接口?

时间:2019-05-06 15:27:08

标签: python flask interface command-line-interface python-click

我的问题如下。我的库中有一些功能:

def some_func(arg1=1):
    pass

我想以三种方式使用:

在其他python脚本中使用import语句:

import my_library
my_library.some_func()

使用CLI界面单击即可暴露。

@click.group()
@click.option('--arg1', default=1)
def some_func(arg1):
    pass

通过Flask使用网络界面进行曝光。

@app.route('/endpoint', defaults={'arg1': 1})
def some_func(arg1):
    pass

但是如何在不重复太多代码的情况下有效地构造它?

是否可以合并所有三个?我尝试了以下操作(失败):

@click.group()
@click.option('--arg1', default=1)
@app.route('/endpoint', defaults={'arg1': 1})
def some_func(arg1=1):
    pass

还是我真的需要上面定义的3个不同的功能?

如果是的话,应该如何设置默认值?

是否在所有位置访问全局变量是执行此操作的最佳方法?

2 个答案:

答案 0 :(得分:1)

由于装饰器语法只是函数应用程序的快捷方式,因此从在库中定义函数开始。然后您的click示例变为:

import my_library

click.group()(click.option('--arg1', default=1)(my_library.some_func))

您的Flask示例变为

import library

app.route('/endpoint', defaults={'arg1': 1})(my_library.some_func)

(对于Flask,我知道装饰器的返回值并不重要;我假设对于click也是一样。)

这假定您不打算同时使用与命令行工具和Flask应用程序相同的脚本; IMO没什么意义。


就简化默认值而言,没有什么好想到的。 Click,Flask和您的函数有三种指示默认值的方法:唯一的共同点是该默认值的实际。您可能会做这样的事情。首先,在my_library.py中:

some_func_default = 1

def some_func(arg=None):  # Or some other sentinel
    if arg is None:
        arg = some_func_default

然后使用其他两个脚本:

click.group()(click.option('--arg1', default=my_library.some_func_default)(my_library.some_func))

app.route('/endpoint', defaults={'arg1': my_library.some_func_default})(my_library.some_func)

当然,您可以使用inspect模块从原始的some_func提取默认值,但这无助于Click和Flask为其设置默认值的方式有所不同入口点。

答案 1 :(得分:0)

您可以使用 hug 库,该库正是为此用例制作的。

示例:


"""An example of writing an API to scrape hacker news once, and then enabling usage everywhere"""
import hug
import requests


@hug.local()
@hug.cli()
@hug.get()
def top_post(section: hug.types.one_of(('news', 'newest', 'show'))='news'):
    """Returns the top post from the provided section"""
    content = requests.get('https://news.ycombinator.com/{0}'.format(section)).content
    text = content.decode('utf-8')
    return text.split('<tr class=\'athing\'>')[1].split("<a href")[1].split(">")[1].split("<")[0]