Skip to content

Instantly share code, notes, and snippets.

@kipanshi
Forked from Deepwalker/gist:2023370
Created March 12, 2012 20:20
Show Gist options
  • Save kipanshi/2024435 to your computer and use it in GitHub Desktop.
Save kipanshi/2024435 to your computer and use it in GitHub Desktop.
Trafaret Tutorial
def trafaret_tutorial():
"""
So, you have some structure from wild. Say this will be some JSON over API.
But you cant change this JSON structure.
"""
sample_data = {
'userNameFirst': 'Adam',
'userNameSecond': 'Smith',
'userPassword': 'supersecretpassword',
'userEmail': '[email protected]',
'userRoles': 'teacher, worker, admin',
}
"""
And you will not save this structure like this, actually you want something
like this
"""
import hashlib
desired_data = {
'name': 'Adam',
'second_name': 'Smith',
'password': hashlib.md5('supersecretpassword').hexdigest(),
'email': '[email protected]',
'roles': ['teacher', 'worker', 'admin'],
}
"""
Ok, so you need to convert it somehow. You will write it simple
"""
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'
"""
And then you will figure out that you can get much more fields
and decide to optimize your solution with DRY in mind
"""
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'
"""
Not so bad, if you have many fields it will save your time. But now you get
new information - 'userEmail' is optional field.
And specification added field 'userTitle',
that must be 'bachelor' if not provided'.
Lets solve it!
"""
desired_data['title'] = 'Bachelor' # Update our test to new reality
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'
"""
Hm, ok, so much code, uh oh.
I think first variant were more straightforward.
"""
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'
"""
Good old code without complicate smell, good, yeah.
But what if you will have more fields?
I mean much more, and what will you do?
It seems you are ready to make new cool library for this things.
But wait, I did!
"""
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,
# Bonus: validation with regexp!
t.Key('userNameSecond') >>
'second_name': t.String(regex=r'^[a-zA-Z]+$'),
# You can bind as many converters as you want
t.Key('userPassword') >> 'password': t.String >> hash_md5,
# Bonus: trafaret.Email validates that string is valid email
t.Key('userEmail', optional=True, to_name='email'): t.Email,
t.Key('userTitle', default='Bachelor', to_name='title'): t.String,
t.Key('userRoles', to_name='roles'): t.String >> comma_to_list,
})
assert converter.check(sample_data) == desired_data
sample_data['userNameSecond'] += '123' # this will raise validation error
try:
converter.check(sample_data)
raise Exception('Validation doesn\'t work!')
except t.DataError:
pass
"""
So go to the https://github.com/Deepwalker/trafaret and start using it!
"""
if __name__ == '__main__':
trafaret_tutorial()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment