老坑,现在来填掉:)
之前做一个需求,是需要解析Flask里的URL Rule里的参数名字和类型,用来自动生成命令行内的Rest Client的参数。
Rule: /disks/<int:disk_id>
需要得到参数: disk (type int)
解铃还须系铃人,直接看Flask源码吧:),看看它是如何管理/解析用户在 route 内添加的URL Parttern的.
首先,一路跟踪下去找到源码里的函数吧~~
from flask import Flask
app.route()
从 app.py中,可以看到
url_rule_class = Rule()
搜索parse 关键字,可以找到 parse_rule 函数,让我们一起来看看parse_rule函数吧:)
为了将parse_rule和 flask解耦,我拆出了以下代码。
import re
_rule_re = re.compile(r'''
(?P<static>[^<]*) # static rule data
<
(?:
(?P<converter>[a-zA-Z_][a-zA-Z0-9_]*) # converter name
(?:\((?P<args>.*?)\))? # converter arguments
\: # variable delimiter
)?
(?P<variable>[a-zA-Z_][a-zA-Z0-9_]*) # variable name
>
''', re.VERBOSE)
def parse_rule(rule):
"""Parse a rule and return it as generator. Each iteration yields tuples
in the form ``(converter, arguments, variable)``. If the converter is
`None` it's a static url part, otherwise it's a dynamic one.
:internal:
"""
pos = 0
end = len(rule)
do_match = _rule_re.match
used_names = set()
while pos < end:
m = do_match(rule, pos)
if m is None:
break
data = m.groupdict()
if data['static']:
yield None, None, data['static']
variable = data['variable']
converter = data['converter'] or 'default'
if variable in used_names:
raise ValueError('variable name %r used twice.' % variable)
used_names.add(variable)
yield converter, data['args'] or None, variable
pos = m.end()
if pos < end:
remaining = rule[pos:]
if '>' in remaining or '<' in remaining:
raise ValueError('malformed url rule: %r' % rule)
yield None, None, remaining
可以看到,flask讲一个URL Rule,首先拆解为 “/” 分隔的一个个单元。
之后,每个单元被解析为 converter(转换器), arguments(参数),variable(变量)。
以 /api/<int:id>/create 为例,可以知道得到三个单元
(None, None, "/api/"),
("int", None, "id"),
(None, None, "/create"),
第一个单元里,converter是None,则这个参数是一个URL中的静态字符串;
第二个单元内,converter是int,意即参数“id”是一个整型的变量;
第三个单元同第一个单元相同,不做多解释了。
通过以上分析,我们就拿到了Flask的Url Rule中变量的类型和名字,就可以做CLI自动生成中的参数解析了:)
PS:最近越来越赞同GongZi提的,“你会多少其实不重要要,重要的是你解决新问题的能力”,这种“Meta Learning”的能力,才是核心竞争力啊。