Python數(shù)據(jù)驗證庫(三)voluptuous

繼續(xù)記錄最近學習的python數(shù)據(jù)驗證工具生蚁。
voluptuousvalidator的使用比較相似,注意是validator,不是validators瘸洛。validatorvalidators是兩個不同的python數(shù)據(jù)驗證的庫。

Voluptuous的目標:
1次和、簡潔
2反肋、支持復雜的數(shù)據(jù)結構
3、提供有價值的錯誤信息

一踏施、安裝

$ pip install voluptuous

二石蔗、數(shù)據(jù)驗證

1、和validator類似畅形,為了驗證數(shù)據(jù)养距,我們需要先定義一個模式scheme.

>>> from voluptuous import Schema
>>> schema = Schema({
      'q': str,
      'per_page': int,
      'page': int,
})

這個模式要求待檢查的數(shù)據(jù),字段"q"需要時str類型日熬,字段"per_page"需要是int類型棍厌,字段"page"需要是int類型。

如果我們要驗證的數(shù)據(jù)是

data = { 
 "q": "hello world", 
 "per_page": 20,
 "page": 10
}

只需要

>>> schema(data)
{'q': 'hello world', 'per_page': 20, 'page': 10}

如果驗證通過竖席,則返回驗證的數(shù)據(jù)耘纱。那么,如果驗證的參數(shù)不能通過呢毕荐?我們來看一個驗證失敗的例子束析。

failure_data = { 
 "q": "hello world", 
 "per_page": "hi",
 "page": 10
}
>>> schema(failure_data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Python27\lib\site-packages\voluptuous\schema_builder.py", line 221, i
n __call__
    return self._compiled([], data)
  File "D:\Python27\lib\site-packages\voluptuous\schema_builder.py", line 538, i
n validate_dict
    return base_validate(path, iteritems(data), out)
  File "D:\Python27\lib\site-packages\voluptuous\schema_builder.py", line 370, i
n validate_mapping
    raise er.MultipleInvalid(errors)
voluptuous.error.MultipleInvalid: expected int for dictionary value @ data['per_
page']

這里字段 "per_page"的值是字符串,不是int類型憎亚,驗證失敗员寇,程序報錯弄慰。
但是有時在一個程序里,我們會做多個驗證蝶锋,我們只是希望得到每一個驗證的結果陆爽,成功or失敗,不希望因為一處失敗扳缕,而影響后面程序的執(zhí)行墓陈。這種情況下,我們可以在程序中捕獲異常第献,得到錯誤信息贡必。

demo.py

from voluptuous import Schema, MultipleInvalid

schema = Schema({
      'q': str,
      'per_page': int,
      'page': int,
})

failure_data = { 
 "q": "hello world", 
 "per_page": "hi",
 "page": 10
}

try:
    schema(failure_data)
except MultipleInvalid as e:
    print e.errors

>>> python demo.py
[TypeInvalid('expected int',)]

e.errors可以很清晰知道驗證時,發(fā)生了類型驗證錯誤庸毫。

2仔拟、在驗證的過程中,有時我們需要數(shù)據(jù)必須含有某一個字段飒赃,這時可以使用Required.
以上面的例子為例 :

schema = Schema({
      'q': str,
      'per_page': int,
      'page': int,
})

data = { 
 "q": "hello world", 
 "page": 10
}

>>> schema(data)
{'q': 'hello world', 'page': 10}

data中沒有'per_page'字段利花,驗證依然是成功的;如果我們需要data中必須含有'per_page'字段载佳,那么schema可以這樣定義:

from voluptuous import Required
schema = Schema({
      'q': str,
      Required('per_page'): int,
      'page': int,
})

data = { 
 "q": "hello world", 
 "page": 10
}

>>>schema(data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Python27\lib\site-packages\voluptuous\schema_builder.py", line 221, i
n __call__
    return self._compiled([], data)
  File "D:\Python27\lib\site-packages\voluptuous\schema_builder.py", line 538, i
n validate_dict
    return base_validate(path, iteritems(data), out)
  File "D:\Python27\lib\site-packages\voluptuous\schema_builder.py", line 370, i
n validate_mapping
    raise er.MultipleInvalid(errors)
voluptuous.error.MultipleInvalid: required key not provided @ data['per_page']

此時data中缺少'per_page'字段炒事,程序報錯。

3蔫慧、通常我們不僅需要判斷數(shù)據(jù)字段是否存在挠乳,類型是否正確,還會對字符串或列表長度進行驗證姑躲,對數(shù)據(jù)值的范圍進行驗證睡扬。我們可以將對一個字段的多項驗證用All封裝起來。

>>> from voluptuous import Required, All, Length, Range
>>> schema = Schema({
...   Required('q'): All(str, Length(min=1)),
...   Required('per_page', default=5): All(int, Range(min=1, max=20)),
...   'page': All(int, Range(min=0)),
... })

舉兩個驗證失敗的例子:
(1) 數(shù)據(jù)中必須含有'q'字段

>>> from voluptuous import MultipleInvalid
>>>try:
    schema({})
except MultipleInvalid as e:
    exc = e
>>> exc.errors
[RequiredFieldInvalid('required key not provided',)]

(2) 字段page的值必須是一個大于等于0的整數(shù)黍析。

try:
    schema({'q': '#topic', 'per_page': 'one'})
except MultipleInvalid as e:
    exc = e
>>> exc.errors
[TypeInvalid('expected int',)]

三卖怜、定義schemas

voluptuous的一個優(yōu)點是不僅僅可以驗證字典數(shù)據(jù),也可以驗證一些其他類型的數(shù)據(jù)阐枣。

1马靠、字面值(Literals)

僅僅匹配模式schema中定義的值與數(shù)據(jù)data中的值是否相等。

>>> schema = Schema(1)
>>> schema(1)
1
>>> schema(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Python27\lib\site-packages\voluptuous\schema_builder.py", line 225, i
n __call__
    raise er.MultipleInvalid([e])
voluptuous.error.MultipleInvalid: not a valid value
>>> schema = Schema('a string')
>>> schema('a string')
'a string'
2、類型(types)
>>> schema = Schema(int)
>>> schema(1)
1
>>> schema('one')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Python27\lib\site-packages\voluptuous\schema_builder.py", line 225, i
n __call__
    raise er.MultipleInvalid([e])
voluptuous.error.MultipleInvalid: expected int
3、URL’s
>>> from voluptuous import Url
>>> schema = Schema(Url())
>>> schema('http://w3.org')
'http://w3.org'
>>> try:
...   schema('one')
...   raise AssertionError('MultipleInvalid not raised')
... except MultipleInvalid as e:
...   exc = e
>>> str(exc) == "expected a URL"
True
4、列表(Lists)

模式列表中定義了一些合法的值,被檢查的數(shù)據(jù)列表中的每一個值都需要在模式列表中被定義兽掰。

>>> schema = Schema([1, 'a', 'string'])
>>> schema([1])
[1]
>>> schema([1, 1, 1])
[1, 1, 1]
>>> schema(['a', 1, 'string', 1, 'string'])
['a', 1, 'string', 1, 'string']

如果想要定義一個列表,可以包含所有python合法值谓苟,可以使用list

>>> schema = Schema(list)
>>> schema([])
[]
>>> schema([1, 2])
[1, 2]

注意不是使用[]

>>> schema = Schema([])
>>> try:
...   schema([1])
...   raise AssertionError('MultipleInvalid not raised')
... except MultipleInvalid as e:
...   exc = e
>>> str(exc) == "not a valid value"
True
>>> schema([])
[]
5、自定義函數(shù)
>>> from datetime import datetime
>>> def Date(fmt='%Y-%m-%d'):
...   return lambda v: datetime.strptime(v, fmt)
>>> schema = Schema(Date())
>>> schema('2013-03-03')
datetime.datetime(2013, 3, 3, 0, 0)
>>> try:
...   schema('2013-03')
...   raise AssertionError('MultipleInvalid not raised')
... except MultipleInvalid as e:
...   exc = e
>>> str(exc) == "not a valid value"
True
6彬祖、字典

待驗證的數(shù)據(jù)中每一個鍵值對需要在字典中已定義,否則品抽,驗證失敗储笑。

>>> schema = Schema({1: 'one', 2: 'two'})
>>> schema({1: 'one'})
{1: 'one'}

如果我們要驗證的數(shù)據(jù)中有額外的鍵值對,并且這種情況不認為是錯誤的圆恤,可以這樣設置突倍。

>>> from voluptuous import ALLOW_EXTRA
>>> schema = Schema({2: 3}, extra=ALLOW_EXTRA)
>>> schema({1: 2, 2: 3})
{1: 2, 2: 3}

如果想要移除額外的鍵,可以使用Schema(..., extra=REMOVE_EXTRA):

>>> from voluptuous import REMOVE_EXTRA
>>> schema = Schema({2: 3}, extra=REMOVE_EXTRA)
>>> schema({1: 2, 2: 3})
{2: 3}

默認情況下盆昙,在字典模式schema中定義的key-value對羽历,待驗證的數(shù)據(jù)中不需要完全覆蓋。

>>> schema = Schema({1: 2, 3: 4})
>>> schema({3: 4})
{3: 4}

如果我們希望完全覆蓋淡喜,可以設置參數(shù)required

>>> schema = Schema({1: 2, 3: 4}, required=True)
>>> try:
...   schema({3: 4})
...   raise AssertionError('MultipleInvalid not raised')
... except MultipleInvalid as e:
...   exc = e
>>> str(exc) == "required key not provided @ data[1]"
True

或者僅僅設置必須含有其中某一個鍵key

>>> schema = Schema({Required(1): 2, 3: 4})
>>> try:
...   schema({3: 4})
...   raise AssertionError('MultipleInvalid not raised')
... except MultipleInvalid as e:
...   exc = e
>>> str(exc) == "required key not provided @ data[1]"
True
>>> schema({1: 2})
{1: 2}

或者僅僅對某一個鍵設置可選擇屬性:

>>> from voluptuous import Optional
>>> schema = Schema({1: 2, Optional(3): 4}, required=True)
>>> try:
...   schema({})
...   raise AssertionError('MultipleInvalid not raised')
... except MultipleInvalid as e:
...   exc = e
>>> str(exc) == "required key not provided @ data[1]"
True
>>> schema({1: 2})
{1: 2}
>>> try:
...   schema({1: 2, 4: 5})
...   raise AssertionError('MultipleInvalid not raised')
... except MultipleInvalid as e:
...   exc = e
>>> str(exc) == "extra keys not allowed @ data[4]"
True
>>> schema({1: 2, 3: 4})
{1: 2, 3: 4}

上一篇:Python數(shù)據(jù)驗證庫(二)validator
http://www.reibang.com/p/eee56214af9c

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秕磷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子炼团,更是在濱河造成了極大的恐慌澎嚣,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瘟芝,死亡現(xiàn)場離奇詭異易桃,居然都是意外死亡,警方通過查閱死者的電腦和手機锌俱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門晤郑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贸宏,你說我怎么就攤上這事贩汉。” “怎么了锚赤?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵匹舞,是天一觀的道長。 經(jīng)常有香客問我线脚,道長赐稽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任浑侥,我火速辦了婚禮姊舵,結果婚禮上,老公的妹妹穿的比我還像新娘寓落。我一直安慰自己括丁,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布伶选。 她就那樣靜靜地躺著史飞,像睡著了一般尖昏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上构资,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天抽诉,我揣著相機與錄音,去河邊找鬼吐绵。 笑死迹淌,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的己单。 我是一名探鬼主播唉窃,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼纹笼!你這毒婦竟也來了句携?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤允乐,失蹤者是張志新(化名)和其女友劉穎矮嫉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牍疏,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蠢笋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鳞陨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昨寞。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖厦滤,靈堂內(nèi)的尸體忽然破棺而出援岩,到底是詐尸還是另有隱情,我是刑警寧澤掏导,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布享怀,位于F島的核電站,受9級特大地震影響趟咆,放射性物質(zhì)發(fā)生泄漏添瓷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一值纱、第九天 我趴在偏房一處隱蔽的房頂上張望鳞贷。 院中可真熱鬧,春花似錦虐唠、人聲如沸搀愧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咱筛。三九已至搓幌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眷蚓,已是汗流浹背鼻种。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工反番, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沙热,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓罢缸,卻偏偏與公主長得像篙贸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子枫疆,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容