0001-csvdatasource-allow-normalized-search-for-unicode-va.patch
passerelle/apps/csvdatasource/lookups.py | ||
---|---|---|
1 | 1 |
DELIMITER = '__' |
2 | 2 | |
3 |
import unicodedata |
|
4 | ||
3 | 5 |
class InvalidOperatorError(Exception): |
4 | 6 |
pass |
5 | 7 | |
... | ... | |
13 | 15 |
except (ValueError, TypeError): |
14 | 16 |
return False |
15 | 17 | |
18 |
def normalize(value): |
|
19 |
return unicodedata.normalize('NFKD', value).encode('ascii', 'ignore') |
|
20 | ||
16 | 21 | |
17 | 22 |
class Lookup(object): |
18 | 23 | |
... | ... | |
22 | 27 |
def icontains(self, key, value): |
23 | 28 |
return lambda x: value.lower() in x[key].lower() |
24 | 29 | |
30 |
def normcontains(self, key, value): |
|
31 |
return lambda x: normalize(value) in normalize(x[key]) |
|
32 | ||
33 |
def inormcontains(self, key, value): |
|
34 |
return lambda x: normalize(value.lower()) in normalize(x[key].lower()) |
|
35 | ||
25 | 36 |
def gt(self, key, value): |
26 | 37 |
return lambda x: int(x[key]) > int(value) |
27 | 38 | |
... | ... | |
54 | 65 |
def ieq(self, key, value): |
55 | 66 |
return lambda x: value.lower() == x[key].lower() |
56 | 67 | |
68 |
def normeq(self, key, value): |
|
69 |
return lambda x: normalize(value) == normalize(x[key]) |
|
70 | ||
71 |
def inormeq(self, key, value): |
|
72 |
return lambda x: normalize(value.lower()) == normalize(x[key].lower()) |
|
73 | ||
57 | 74 |
def ne(self, key, value): |
58 | 75 |
if is_int(value): |
59 | 76 |
return lambda x: int(value) != int(x[key]) |
passerelle/apps/csvdatasource/views.py | ||
---|---|---|
38 | 38 |
params = request.GET |
39 | 39 | |
40 | 40 |
case_insensitive = 'case-insensitive' in params |
41 |
normalized = 'normalized' in params |
|
41 | 42 |
query = params.get('q', None) |
42 | 43 | |
44 |
if normalized: |
|
45 |
lookup = 'normcontains' |
|
46 |
else: |
|
47 |
lookup = 'contains' |
|
48 | ||
43 | 49 |
if query: |
44 | 50 |
if case_insensitive: |
45 |
filters['text__icontains'] = query.lower() |
|
46 |
else: |
|
47 |
filters['text__contains'] = query |
|
51 |
lookup = 'i' + lookup |
|
52 |
query = query.lower() |
|
53 | ||
54 |
filters['text__%s' % lookup] = query |
|
48 | 55 | |
49 | 56 |
# builds filters according to csv file header |
50 | 57 |
for column_title in [t.strip() for t in obj.columns_keynames.split(',') if t]: |
tests/test_csv_datasource.py | ||
---|---|---|
182 | 182 |
assert 'text' in item |
183 | 183 |
assert filter_criteria in item['text'] |
184 | 184 | |
185 |
# require normalized comparison |
|
186 |
filters['normalized'] = '' |
|
187 |
filters['text'] = 'Benoit' |
|
188 |
resp = client.get(url, filters) |
|
189 |
assert len(result) |
|
190 | ||
185 | 191 |
def test_unicode_case_insensitive_filter_data(client, setup, filetype): |
186 | 192 |
csvdata, url = setup(',id,,text,', filename=filetype, data=get_file_content(filetype)) |
187 | 193 |
filter_criteria = u'anaëlle' |
... | ... | |
194 | 200 |
assert 'text' in item |
195 | 201 |
assert filter_criteria.lower() in item['text'].lower() |
196 | 202 | |
203 |
# require normalized comparison |
|
204 |
filters['normalized'] = '' |
|
205 |
filters['text'] = 'anaelle' |
|
206 |
resp = client.get(url, filters) |
|
207 |
assert len(result) |
|
208 | ||
197 | 209 |
def test_data_bom(client, setup): |
198 | 210 |
csvdata, url = setup('fam,id,, text,sexe ', data=data_bom) |
199 | 211 |
filters = {'text':'Eliot'} |
... | ... | |
258 | 270 |
assert result[0]['id'] == '22' |
259 | 271 |
assert result[0]['lname'] == 'MARTIN' |
260 | 272 | |
273 |
def test_normalized_filters(client, setup, filetype): |
|
274 |
csvdata, url = setup(filename=filetype, data=get_file_content(filetype)) |
|
275 |
filters = { |
|
276 |
'fname__normcontains': 'aëlle' |
|
277 |
} |
|
278 |
resp = client.get(url, filters) |
|
279 |
result = parse_response(resp) |
|
280 |
assert len(result) == 1 |
|
281 |
assert result[0]['id'] == '46' |
|
282 |
assert result[0]['lname'] == 'WILSON-LUZAYADIO' |
|
283 | ||
284 |
filters = { |
|
285 |
'fname__inormcontains': 'ANAëllE' |
|
286 |
} |
|
287 |
resp = client.get(url, filters) |
|
288 |
result = parse_response(resp) |
|
289 |
assert len(result) == 1 |
|
290 |
assert result[0]['fname'] == u'Anaëlle' |
|
291 | ||
261 | 292 |
def test_unknown_operator(client, setup, filetype): |
262 | 293 |
csvdata, url = setup(filename=filetype, data=get_file_content(filetype)) |
263 | 294 |
filters = {'id__whatever': '25', 'fname__icontains':'Eliot'} |
264 |
- |