рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдбреЗрдЯрд╛ - рдЖрдк рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕реЗрд╡рд╛ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдФрд░ рдЖрдкрдХреЛ рдкрддрд╛ рдЪрд▓реЗрдЧрд╛ рдХрд┐ рдЖрдк рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдмрд╛рд╣рд░ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗред
рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рдпрд╣ JSON рд╣реЛрдЧрд╛, рдпрд╣ рдЖрдк рдирд╣реАрдВ рд╣реИрдВ рдЬреЛ рдЗрд╕рдХреА рд╕рдВрд░рдЪрдирд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдпрд╣ рд╣реИ:
sample_data = { 'userNameFirst': 'Adam', 'userNameSecond': 'Smith', 'userPassword': 'supersecretpassword', 'userEmail': 'adam@smith.math.edu', 'userRoles': 'teacher, worker, admin', }
рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рдЕрдВрджрд░, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдореИрдВ рдЪрд╛рд╣реВрдВрдЧрд╛ рдХрд┐ рд╕рдВрд░рдЪрдирд╛ рдЕрд▓рдЧ рд╣реЛ:
import hashlib desired_data = { 'name': 'Adam', 'second_name': 'Smith', 'password': hashlib.md5('supersecretpassword').hexdigest(), 'email': 'adam@smith.math.edu', 'roles': ['teacher', 'worker', 'admin'], }
рд╕рдВрднрд╡рддрдГ рдЖрдВрддрд░рд┐рдХ рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдирд╛ рд╣реИ, рдпрд╣ рдкреНрд░рдпрд╛рд╕ рдХрд░реЗрдВ:
new_data = { 'name': sample_data['userNameFirst'], 'second_name': sample_data['userNameSecond'], 'password': hashlib.md5(sample_data['userPassword']).hexdigest(), 'email': sample_data['userEmail'], 'roles': [s.strip() for s in sample_data['userRoles'].split(',')] } assert new_data == desired_data, 'Uh oh'
рд▓реЗрдХрд┐рди рдпрд╣рд╛рдБ рд╕рдВрджреЗрд╣ рд╣реИ рдХрд┐ рднреЗрдЬреЗ рдЧрдП рдирдореВрдиреЗ рдореЗрдВ рд╕рднреА рд╕рдВрднрд╛рд╡рд┐рдд рдХреНрд╖реЗрддреНрд░ рд╢рд╛рдорд┐рд▓ рдирд╣реАрдВ рд╣реИрдВред рд╣рдо рдЗрд╕реЗ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦреЗрдВрдЧреЗ рдФрд░ рдЕрдзрд┐рдХ рд▓рдЪреАрд▓рд╛ рд╡рд┐рдХрд▓реНрдк рд▓рд┐рдЦреЗрдВрдЧреЗ:
FIELDS = { 'userNameFirst': 'name', 'userNameSecond': 'second_name', 'userEmail': 'email', } new_data = dict((n2, sample_data[n1]) for n1, n2 in FIELDS.items()) new_data['roles'] = [s.strip() for s in sample_data['userRoles'].split(',')] new_data['password'] = hashlib.md5(sample_data['userPassword']).hexdigest() assert new_data == desired_data, 'Uh oh'
рдЕрдЪреНрдЫреА, рд▓рдЪреАрд▓реА, рдЖрд╕рд╛рдиреА рд╕реЗ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЦреЗрддреЛрдВ рддрдХ рдлреИрд▓реА рд╣реБрдИ рд╣реИред рдЬреИрд╕реЗ рд╣реА рдкреВрд░реНрдг рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдЙрдкрд▓рдмреНрдз рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рдо рдЖрд╕рд╛рдиреА рд╕реЗ рдЕрдкрдиреЗ рдХреЛрдб рдХреЛ рдЗрд╕рдореЗрдВ рдмрдврд╝рд╛ рджреЗрдВрдЧреЗред
рдФрд░ рдлрд┐рд░ рдЕрдЪрд╛рдирдХ рдПрдХ рдЫреЛрдЯрд╛ рдЕрджреНрдпрддрди рдЖрддрд╛ рд╣реИ - 'userEmail' рдПрдХ рд╡реИрдХрд▓реНрдкрд┐рдХ рдХреНрд╖реЗрддреНрд░ рд╣реИред рд╕рд╛рде рд╣реА, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдЯрд╛рдЗрдЯ рдлрд╝реАрд▓реНрдб рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рдпрджрд┐ рдкрд╛рд╕ рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ, рддреЛ 'рдмреИрдЪрд▓рд░' рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
рд╣рдорд╛рд░реЗ рд╣рд╛рде рдКрдм рдХреЗ рд▓рд┐рдП рдирд╣реАрдВ рд╣реИрдВ, рдЬрдм рдкреВрд░реА рдЬрд╛рдирдХрд╛рд░реА рдЕрдВрдд рдореЗрдВ рдЖрдиреЗ рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рд╣рдо рд╡реИрдХрд▓реНрдкрд┐рдХ рдлрд╝реАрд▓реНрдб рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдорд╛рдиреЛрдВ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦреЗрдВрдЧреЗред
desired_data['title'] = 'Bachelor' # FIELDS = { 'userNameFirst': 'name', 'userNameSecond': 'second_name', 'userEmail': ('email', '__optional'), 'userTitle': ('title', 'Bachelor'), } new_data = {} for old, new in FIELDS.items(): if isinstance(new, tuple): new, default = new if old not in sample_data: if default == '__optional': continue new_data[new] = default else: new_data[new] = sample_data[old] new_data['roles'] = [s.strip() for s in sample_data['userRoles'].split(',')] new_data['password'] = hashlib.md5(sample_data['userPassword']).hexdigest() assert new_data == desired_data, 'Uh oh'
рдирд░рдХ, рдЗрддрдиреЗ рдХрдо рдХреНрд╖реЗрддреНрд░ рдФрд░ рдЗрддрдирд╛ рдХреЛрдбред рдпрд╣ рдЖрд╕рд╛рди рдерд╛, рд╣рдо рдорд╛рдереЗ рдореЗрдВ рдЕрдм рддрдХ рдмреЗрд╣рддрд░ рдирд┐рд░реНрдгрдп рд▓реЗрдВрдЧреЗред
new_data = { 'name': sample_data['userNameFirst'], 'second_name': sample_data['userNameSecond'], 'password': hashlib.md5(sample_data['userPassword']).hexdigest(), 'roles': [s.strip() for s in sample_data['userRoles'].split(',')] } if 'userEmail' in sample_data: new_data['email'] = sample_data['userEmail'] new_data['title'] = sample_data.get('userTitle', 'Bachelor') assert new_data == desired_data, 'Uh oh'
рдЖрд╣, рдЕрдиреБрдЪрд┐рдд рдЬрдЯрд┐рд▓рддрд╛ рдХреЗ рдмрд┐рдирд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рдкрд░рд┐рдЪрд┐рдд рдХреЛрдб, рдареАрдХ рд╣реИред рд▓реЗрдХрд┐рди рдЬрдм рдкреВрд░рд╛ рд╕реНрдкреЗрд╕рд┐рдлрд┐рдХреЗрд╢рди рдЖрдПрдЧрд╛ рддреЛ рдХреНрдпрд╛ рд╣реЛрдЧрд╛? рдЬрд╛рд╣рд┐рд░рд╛ рддреМрд░ рдкрд░ рд╣рдо рджреВрд╕рд░реЗ рд╡рд┐рдХрд▓реНрдк рдкрд░ рд▓реМрдЯреЗрдВрдЧреЗ, рдЗрд╕рдореЗрдВ рдбреЗрдЯрд╛ рд╕рддреНрдпрд╛рдкрди, рдЕрдЪреНрдЫреЗ рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдЬреЛрдбрд╝реЗрдВ, рдЗрд╕реЗ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдореЗрдВ рдкреИрдХ рдХрд░реЗрдВ рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред
рд╣рдореНрдо, рд▓реЗрдХрд┐рди рд╡рд╣рд╛рдБ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЗрд╕ рддрд░рд╣ рдХреЗ рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИ, рджреЗрдЦреЗрдВ:
import trafaret as t hash_md5 = lambda d: hashlib.md5(d).hexdigest() comma_to_list = lambda d: [s.strip() for s in d.split(',')] converter = t.Dict({ t.Key('userNameFirst') >> 'name': t.String, t.Key('userNameSecond') >> 'second_name': t.String, t.Key('userPassword') >> 'password': hash_md5, t.Key('userEmail', optional=True) >> 'email': t.Email, t.Key('userTitle', default='Bachelor') >> 'title': t.String, t.Key('userRoles') >> 'roles': comma_to_list, }) assert converter.check(sample_data) == desired_data
рдпрд╣рд╛рдБ рд▓реЗ рд▓реЛ
github.com/Deepwalker/trafaretрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдЗрд╕ рд╡рд┐рд╖рдп рдХрд╛ рдкреВрд░рд╛ рдХреЛрдб рдпрд╣рд╛рдБ рд╣реИ
gist.github.com/2023370рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП nimnull рдХреЗ рдЕрдиреБрд░реЛрдз рдкрд░ рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдЬреЛрдбрд╝редрдЬрд╡рд╛рдм рдореЗрдВ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдорд╛рдирд╡ рднрд╛рд╖рд╛ рдореЗрдВ рдкрдХрдбрд╝рд╛ рдФрд░ рд░рд┐рдкреЛрд░реНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЖрдорддреМрд░ рдкрд░, рдЕрдкрд╡рд╛рдж рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдХреЛрдИ рд╡реНрдпрдХреНрддрд┐ рддреНрд░реБрдЯрд┐ рдХреЛ рдареАрдХ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдЗрд╕рд▓рд┐рдП рдЖрдкрдХреЛ рдПрдХ рд╕рдВрджреЗрд╢ рд▓рд┐рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рддрд╛рдХрд┐ рдкрддреЗ рдХреЛ рд╕рдордЭ рд╕рдХреЗрдВред
рдЙрдкрд░реЛрдХреНрдд рдЙрджрд╛рд╣рд░рдгреЛрдВ рдореЗрдВ, рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдЖрдо рддреМрд░ рдкрд░ рдХреЗрд╡рд▓ рдмрд╛рдж рдХреЗ рджрд┐рдиреЛрдВ рдореЗрдВ рдЙрддреНрдкрдиреНрди рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдХреНрдпреЛрдВрдХрд┐ рдмрд╛рдХреА рдореЗрдВ рдореИрдВрдиреЗ рдХреЛрдб рдХреЛ рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рдХрд┐рдпрд╛ред рдореИрдВрдиреЗ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдХрд┐ рд╕рднреА рд╕рдорд╛рди рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╕рддреНрдпрд╛рдкрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИрдВ, рдФрд░ рдЯреНрд░реИрдлрд╝рд┐рдХ рдореЗрдВ рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рдбреЗрдЯрд╛рдмреЗрд╕ рд╣реИ, рдбреЗрдЯрд╛ рд░реВрдкрд╛рдВрддрд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЯреНрд░реИрдлрд╝реЗрдЯред
рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рд░реВрдк рд╕реЗ
github.com/barbuza/contract , рдЬрд┐рд╕рд╕реЗ рдЯреНрд░реИрдлрд╝реЗрдЯ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛, рдФрд░ рдпрд╣ рд╕рддреНрдпрд╛рдкрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдерд╛ рдФрд░ рдЗрд╕рд╕реЗ рдЕрдзрд┐рдХ рдХреБрдЫ рдирд╣реАрдВред рдПрдХ рдЕрдЪреНрдЫреА рдмрд╛рдд, рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдореЗрд░реЗ рдкрд╛рд╕ рдереЛрдбрд╝рд╛ рдЕрд▓рдЧ рдХрд╛рдо рдерд╛, рдФрд░ рдлрдВрдХрдкрд░реНрд╕реЗрд░реНрд▓рд┐рдм рд╕реЗ '>>' рдХреА рдЫрд╛рдк рдереАред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ funcparserlib '>>' рдореЗрдВ рд╕реНрдЯреИрдВрд╕рд┐рд▓ рдХреА рддрд░рд╣ рд╣реА рд╣реЛрддрд╛ рд╣реИ - рдпрд╣ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдПрдХрддреНрд░рд┐рдд рдбреЗрдЯрд╛ рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИред
рд╡рд╛рдкрд╕ рдЧрд▓рддрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдПред рд╕реНрдЯреИрдВрд╕рд┐рд▓ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдЯреНрд░реИрдлрд╝реЗрдХреНрдЯ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рд╣реИрдВред DataError рдкреНрд░рддреНрдпреЗрдХ DataError рдореЗрдВ рдПрдХ рддреНрд░реБрдЯрд┐ рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реИред рд╕рд░рд▓ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП, рдЬреИрд╕реЗ рдХрд┐ рдлреНрд▓реЛрдЯ, рдЗрдВрдЯ, рд╕реНрдЯреНрд░рд┐рдВрдЧ, рдЖрджрд┐, рдпрд╣ рдЕрдВрдЧреНрд░реЗрдЬреА рдореЗрдВ рддреНрд░реБрдЯрд┐ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИред рдбрд┐рдХреНрдЯ рдХреЗ рд▓рд┐рдП, рдореИрдкрд┐рдВрдЧ рдФрд░ рд╕реВрдЪреА рдПрдХ рд╢рдмреНрджрдХреЛрд╢ рд╣реИред рдбрд┐рдХреНрдЯ рдФрд░ рдореИрдкрд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реИ - рд╢рдмреНрджрдХреЛрд╢ рддрддреНрд╡ рдлрд╝реАрд▓реНрдб рдЪреЗрдХрд┐рдВрдЧ рд╕реЗ рдПрдХрддреНрд░ рдХреА рдЧрдИ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╣реИрдВред рд╕реВрдЪреА рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЪрд╛рдмрд┐рдпрд╛рдБ рд╕рдВрдЦреНрдпрд╛рдПрдВ рд╣реЛрдВрдЧреА - рддрддреНрд╡реЛрдВ рдХреА рд╕реНрдерд┐рддрд┐ рд╕рдВрдЦреНрдпрд╛ред рд╕рдВрдЧрдарди рдХреЗ рд▓рд┐рдП рдЕрдиреНрдп рд╡рд┐рдХрд▓реНрдк рдЕрдиреБрдЪрд┐рдд рд▓рдЧрддреЗ рд╣реИрдВред
рдпрд╣ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ:
>>> import trafaret as t >>> c = t.Dict({'a': t.List(t.Int)}) >>> c.check({'a': [4, 5]}) {'a': [4, 5]} >>> c.check({'a': [4, 'a', 6]}) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "trafaret/__init__.py", line 110, in check return self._convert(self._check_val(value)) File "trafaret/__init__.py", line 804, in _check_val raise DataError(error=errors) trafaret.DataError: {'a': DataError({1: DataError(value cant be converted to int)})}
рд╣рд╛рдВ, рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдЙрджрд╛рд╣рд░рдг рд╕реЗ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЖрдкрдХреЛ рддреНрд░реБрдЯрд┐ рдХреЛ рдкрдХрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдм рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдирд╣реАрдВ рд╣реИ - рд╣рдореЗрдВ рдиреЗрд╕реНрдЯреЗрдб рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдорд┐рд▓реА рд╣реИрдВ, рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж рд╣рдо рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХрд╣рд╛рдВ рдФрд░ рдХреНрдпрд╛ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╣реИрдВред
рддреНрд░реБрдЯрд┐ рдХреЛ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд░реВрдк рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╣рд╛рдпрдХ рд╣реИ:
>>> t.extract_error(c, {'a': [4, 'a', 6]}) {'a': {1: 'value cant be converted to int'}}
рдФрд░ рдХреБрдЫ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдФрд░ рднреА рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ:
>>> from trafaret.utils import unfold >>> unfold(t.extract_error(c, {'a': [4, 'a', 6]}), prefix='form') {'form__a__1': 'value cant be converted to int'}
рдЕрдВрддрд┐рдо рдЙрджрд╛рд╣рд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ - рдирд╣реАрдВ, рд░реВрдкреЛрдВ рдХреЗ рд╕рд╛рде рд╕реНрдЯреИрдВрд╕рд┐рд▓ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдпрд╣реА рд╣реИ, рдЗрд╕рдореЗрдВ рдПрдХ рднреА рд╡рд┐рдЬреЗрдЯ рдирд╣реАрдВ рд╣реИ, рдФрд░ рдХреАрдорд┐рдпрд╛ / рдЯреЗрдмрд▓ рдкрд░ рдХреАрдорд┐рдпрд╛ рдпрд╛ рдПрдХ рдЕрджреНрднреБрдд рд░реВрдк рдореЗрдВ рд░реВрдкреЛрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди HTML рдлреЙрд░реНрдо рдХреЗ рд╕рд╛рде рдЖрдП рдбреЗрдЯрд╛ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдирд╛ рдХрд╛рдлреА рд╕рдВрднрд╡ рд╣реИред
рд╢рд╛рдпрдж рдпрд╣реА рд╕рдм рд╣реИ, рдкреНрд░рд╢реНрди рдкреВрдЫреЗрдВ, рдореИрдВ рдЬреЛрдбрд╝ рд╕рдХрддрд╛ рд╣реВрдВред
рдирд┐рд╖реНрдХрд░реНрд╖ рдореЗрдВ, рдореИрдВ рдЙрдкрдпреЛрдЧ рдФрд░ рд▓рдЪреАрд▓реЗрдкрди рдХрд╛ рдПрдХ рдХрдЯреНрдЯрд░ рдЙрджрд╛рд╣рд░рдг рдлреЗрдВрдХ рджреВрдВрдЧрд╛:
>>> todt = lambda m: datetime(*[int(i) for i in m.groups()]) >>> (t.String(regex='^year=(\d+),month=(\d+),day=(\d+)$') >> todt).check('year=2011,month=07,day=23') datetime.datetime(2011, 7, 23, 0, 0)