Skip to content

Commit

Permalink
support pre.parse function to parase input params
Browse files Browse the repository at this point in the history
  • Loading branch information
Eastwu5788 committed May 26, 2020
1 parent 74b7ada commit 43b376b
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 35 deletions.
10 changes: 10 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
.. py:currentmodule:: pre_request
Version 2.1.2 (2020-06-01)
-------------------------------

Unreleased

- 开放 `pre.parse` 函数提供直接解析入参能力
- 详细说明文档进一步完善
- 修复使用过程中发现的问题


Version 2.1.1
-------------------------

Expand Down
24 changes: 24 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,30 @@ pre-request提供了非常方便的使用方法,也提供了灵活的扩展机
print(resp.get_data(as_text=True))
不使用装饰器
-------------

我们也支持不使用装饰器解析入参, 通过 `pre.parse()` 函数解析入参

.. code-block:: python
args = {
"params": Rule(email=True)
}
# 全局处理 pre-request 抛出的异常,进行格式化返回
@app.errorhandler(ParamsValueError)
def params_value_error(e):
return pre.fmt_resp(e)
@app.route("/index")
def example_handler():
rst = pre.parse(args)
return str(rst)
贡献代码
----------

Expand Down
20 changes: 20 additions & 0 deletions docs/source/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,23 @@ pre-request的过滤能力主要是通过`@pre.catch`装饰器来实现的
@pre.catch(get=get_field, post=post_field)
def all_handler(params):
return str(params)
`pre.parse` 解析函数介绍
---------------------------

如果您觉得使用 `@pre.cache` 装饰器模式对您的代码侵入性太高,我们也提供了 `pre.parse()` 函数来解析用户入参

.. code-block:: python
def get_handler():
params = pre.parse(get=req_params)
return str(params)
如果用户入参不符合规则要求,我们会抛出 `ParamsValueError` 异常,您可以在Flask框架中对所有此类型异常进行捕获并格式化返回

.. code-block:: python
@app.errorhandler(ParamsValueError)
def params_value_error(e):
return pre.fmt_resp(e)
4 changes: 2 additions & 2 deletions examples/example_filter/example_gt_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

# 指定gt_key, 禁止两个参数相等
gt_key_params = {
"p1": Rule(type=datetime, dest="P1"),
"p2": Rule(type=datetime, gt_key="P1", dest="P2")
"p1": Rule(type=datetime, fmt="%Y-%m-%d %H:%M:%S", dest="P1"),
"p2": Rule(type=datetime, fmt="%Y-%m-%d %H:%M:%S", gt_key="P1", dest="P2", required=False)
}


Expand Down
42 changes: 42 additions & 0 deletions examples/example_flask/example_parse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# !/usr/local/python/bin/python
# -*- coding: utf-8 -*-
# (C) Wu Dong, 2020
# All rights reserved
# @Author: 'Wu Dong <wudong@eastwu.cn>'
# @Time: '2020-05-26 10:50'
from flask import Flask
from pre_request import pre, Rule
from pre_request import ParamsValueError

app = Flask(__name__)
app.config["TESTING"] = True
client = app.test_client()


# 指定email=True,此时框架会自动判断用户入参是否符合email正则
params = {
"params": Rule(email=True)
}


@app.errorhandler(ParamsValueError)
def params_value_error(e):
return pre.fmt_resp(e)


@app.route("/email", methods=["GET", "POST"])
def example_email_handler():
return str(pre.parse(params))


def example_email_filter():
""" 演示邮箱验证
"""
resp = client.get("/email", data={
"params": "wudong@eastwu.cn"
})
print(resp.data)


if __name__ == "__main__":
example_email_filter()
7 changes: 4 additions & 3 deletions pre_request/filters/cross/equal_key_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ def fmt_error_message(self, code):
def filter_required(self):
""" 验证是否需要进行过滤
"""
if not self.rule.required and self.value is None:
return False

if self.rule.eq_key is not None or self.rule.neq_key is not None:
return True

Expand All @@ -71,6 +68,10 @@ def __call__(self, *args, **kwargs):
params = kwargs.get("params", dict())
value = get_deep_value(self.rule.key_map or self.key, params, None, deep=True)

# BUG: complex filter value will be None
if not self.rule.required and value is None:
return value

for r_key, r_code in self.support_rules.items():
rule = getattr(self.rule, r_key, None)

Expand Down
70 changes: 40 additions & 30 deletions pre_request/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,47 +282,57 @@ def _handler_complex_filter(self, k, r, rst):

filter_obj(params=rst)

def parse(self, rule=None, **options):
""" Parse input params
"""
fmt_rst = dict()

# invalid input
if not rule and not options:
return fmt_rst

# query rules with special method
from flask import request # pylint: disable=import-outside-toplevel
rules = options.get(request.method) or options.get(request.method.lower())

# common rule
if rules is None and rule is not None:
rules = rule

# ignore catch with empty rules
if not rules:
raise ValueError("request method '%s' with invalid filter rule" % request.method)

# use simple filter to handler params
for k, r in rules.items():
value = self._handler_simple_filter(k, r)
# simple filter handler
fmt_rst[r.key_map if isinstance(r, Rule) and r.key_map else k] = value

# use complex filter to handler params
for k, r in rules.items():
self._handler_complex_filter(k, r, fmt_rst)

return fmt_rst

def catch(self, rule=None, **options):
""" Catch request params
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
from flask import g, request # pylint: disable=import-outside-toplevel
fmt_rst = dict()

# ignore with empty rule
if not rule and not options:
return func(*args, **kwargs)

# query rules with special method
rules = options.get(request.method) or options.get(request.method.lower())

# common rule
if rules is None and rule is not None:
rules = rule

# ignore catch with empty rules
if not rules:
raise ValueError("request method '%s' with invalid filter rule" % request.method)

# use simple filter to handler params
for k, r in rules.items():
try:
value = self._handler_simple_filter(k, r)
# simple filter handler
fmt_rst[r.key_map if isinstance(r, Rule) and r.key_map else k] = value
except ParamsValueError as e:
return self._f_resp(e)

# use complex filter to handler params
for k, r in rules.items():
try:
self._handler_complex_filter(k, r, fmt_rst)
except ParamsValueError as e:
return self._f_resp(e)
# parse input params
try:
fmt_rst = self.parse(rule, **options)
except ParamsValueError as e:
return self.fmt_resp(e)

# assignment params to func args
from flask import g
setattr(g, self.store_key, fmt_rst)
if self.store_key in getfullargspec(func).args:
kwargs[self.store_key] = fmt_rst
Expand All @@ -331,7 +341,7 @@ def wrapper(*args, **kwargs):
return wrapper
return decorator

def _f_resp(self, error):
def fmt_resp(self, error):
""" Handler not formatted request error
:param error: ParamsValueError
Expand Down
53 changes: 53 additions & 0 deletions tests/test_flask/test_parse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# !/usr/local/python/bin/python
# -*- coding: utf-8 -*-
# (C) Wu Dong, 2020
# All rights reserved
# @Author: 'Wu Dong <wudong@eastwu.cn>'
# @Time: '2020-05-26 10:54'
import json
from flask import Flask, make_response
from pre_request import pre, Rule
from pre_request import ParamsValueError

app = Flask(__name__)
app.config["TESTING"] = True
client = app.test_client()


def json_resp(result):
result = json.dumps(result)
resp = make_response(result)
resp.headers['Content-Type'] = 'application/json'
return resp


# 指定email=True,此时框架会自动判断用户入参是否符合email正则
email_params = {
"params": Rule(email=True)
}


@app.errorhandler(ParamsValueError)
def params_value_error(e):
return pre.fmt_resp(e)


@app.route("/email", methods=["GET", "POST"])
def example_email_handler():
params = pre.parse(get=email_params)
return json_resp(params)


class TestParse:

def test_parse_smoke(self):
resp = app.test_client().get("/email", data={
"params": "wudong@eastwu.cn"
})
assert resp.json == {"params": "wudong@eastwu.cn"}

def test_parse_error(self):
resp = app.test_client().get("/email", data={
"params": "wudong@@eastwu.cn"
})
assert resp.json["respCode"] == 564

0 comments on commit 43b376b

Please sign in to comment.