Conditions | 51 |
Total Lines | 223 |
Code Lines | 128 |
Lines | 0 |
Ratio | 0 % |
Tests | 110 |
CRAP Score | 51 |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like abydos.fingerprint._synoname.SynonameToolcode.fingerprint() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | # -*- coding: utf-8 -*- |
||
270 | 1 | def fingerprint(self, lname, fname='', qual='', normalize=0): |
|
271 | """Build the Synoname toolcode. |
||
272 | |||
273 | Parameters |
||
274 | ---------- |
||
275 | lname : str |
||
276 | Last name |
||
277 | fname : str |
||
278 | First name (can be blank) |
||
279 | qual : str |
||
280 | Qualifier |
||
281 | normalize : int |
||
282 | Normalization mode (0, 1, or 2) |
||
283 | |||
284 | Returns |
||
285 | ------- |
||
286 | tuple |
||
287 | The transformed names and the synoname toolcode |
||
288 | |||
289 | Examples |
||
290 | -------- |
||
291 | >>> st = SynonameToolcode() |
||
292 | >>> st.fingerprint('hat') |
||
293 | ('hat', '', '0000000003$$h') |
||
294 | >>> st.fingerprint('niall') |
||
295 | ('niall', '', '0000000005$$n') |
||
296 | >>> st.fingerprint('colin') |
||
297 | ('colin', '', '0000000005$$c') |
||
298 | >>> st.fingerprint('atcg') |
||
299 | ('atcg', '', '0000000004$$a') |
||
300 | >>> st.fingerprint('entreatment') |
||
301 | ('entreatment', '', '0000000011$$e') |
||
302 | |||
303 | >>> st.fingerprint('Ste.-Marie', 'Count John II', normalize=2) |
||
304 | ('ste.-marie ii', 'count john', '0200491310$015b049a127c$smcji') |
||
305 | >>> st.fingerprint('Michelangelo IV', '', 'Workshop of') |
||
306 | ('michelangelo iv', '', '3000550015$055b$mi') |
||
307 | |||
308 | """ |
||
309 | 1 | lname = lname.lower() |
|
310 | 1 | fname = fname.lower() |
|
311 | 1 | qual = qual.lower() |
|
312 | |||
313 | # Start with the basic code |
||
314 | 1 | toolcode = ['0', '0', '0', '000', '00', '00', '$', '', '$', ''] |
|
315 | |||
316 | 1 | full_name = ' '.join((lname, fname)) |
|
317 | |||
318 | 1 | if qual in self._qual_3: |
|
319 | 1 | toolcode[0] = '3' |
|
320 | 1 | elif qual in self._qual_2: |
|
321 | 1 | toolcode[0] = '2' |
|
322 | 1 | elif qual in self._qual_1: |
|
323 | 1 | toolcode[0] = '1' |
|
324 | |||
325 | # Fill field 1 (punctuation) |
||
326 | 1 | if '.' in full_name: |
|
327 | 1 | toolcode[1] = '2' |
|
328 | else: |
||
329 | 1 | for punct in ',-/:;"&\'()!{|}?$%*+<=>[\\]^_`~': |
|
330 | 1 | if punct in full_name: |
|
331 | 1 | toolcode[1] = '1' |
|
332 | 1 | break |
|
333 | |||
334 | 1 | elderyounger = '' # save elder/younger for possible movement later |
|
335 | 1 | for gen in self._gen_1: |
|
336 | 1 | if gen in full_name: |
|
337 | 1 | toolcode[2] = '1' |
|
338 | 1 | elderyounger = gen |
|
339 | 1 | break |
|
340 | else: |
||
341 | 1 | for gen in self._gen_2: |
|
342 | 1 | if gen in full_name: |
|
343 | 1 | toolcode[2] = '2' |
|
344 | 1 | elderyounger = gen |
|
345 | 1 | break |
|
346 | |||
347 | # do comma flip |
||
348 | 1 | if normalize: |
|
349 | 1 | comma = lname.find(',') |
|
350 | 1 | if comma != -1: |
|
351 | 1 | lname_end = lname[comma + 1 :] |
|
352 | 1 | while lname_end[0] in {' ', ','}: |
|
353 | 1 | lname_end = lname_end[1:] |
|
354 | 1 | fname = lname_end + ' ' + fname |
|
355 | 1 | lname = lname[:comma].strip() |
|
356 | |||
357 | # do elder/younger move |
||
358 | 1 | if normalize == 2 and elderyounger: |
|
359 | 1 | elderyounger_loc = fname.find(elderyounger) |
|
360 | 1 | if elderyounger_loc != -1: |
|
361 | 1 | lname = ' '.join((lname, elderyounger.strip())) |
|
362 | 1 | fname = ' '.join( |
|
363 | ( |
||
364 | fname[:elderyounger_loc].strip(), |
||
365 | fname[elderyounger_loc + len(elderyounger) :], |
||
366 | ) |
||
367 | ).strip() |
||
368 | |||
369 | 1 | toolcode[4] = '{:02d}'.format(len(fname)) |
|
370 | 1 | toolcode[5] = '{:02d}'.format(len(lname)) |
|
371 | |||
372 | # strip punctuation |
||
373 | 1 | for char in ',/:;"&()!{|}?$%*+<=>[\\]^_`~': |
|
374 | 1 | full_name = full_name.replace(char, '') |
|
375 | 1 | for pos, char in enumerate(full_name): |
|
376 | 1 | if char == '-' and full_name[pos - 1 : pos + 2] != 'b-g': |
|
377 | 1 | full_name = full_name[:pos] + ' ' + full_name[pos + 1 :] |
|
378 | |||
379 | # Fill field 9 (search range) |
||
380 | 1 | for letter in [_[0] for _ in full_name.split()]: |
|
381 | 1 | if letter not in toolcode[9]: |
|
382 | 1 | toolcode[9] += letter |
|
383 | 1 | if len(toolcode[9]) == 15: |
|
384 | 1 | break |
|
385 | |||
386 | 1 | def roman_check(numeral, fname, lname): |
|
387 | """Move Roman numerals from first name to last. |
||
388 | |||
389 | Parameters |
||
390 | ---------- |
||
391 | numeral : str |
||
392 | Roman numeral |
||
393 | fname : str |
||
394 | First name |
||
395 | lname : str |
||
396 | Last name |
||
397 | |||
398 | Returns |
||
399 | ------- |
||
400 | tuple |
||
401 | First and last names with Roman numeral moved |
||
402 | |||
403 | """ |
||
404 | 1 | loc = fname.find(numeral) |
|
405 | 1 | if fname and ( |
|
406 | loc != -1 |
||
407 | and (len(fname[loc:]) == len(numeral)) |
||
408 | or fname[loc + len(numeral)] in {' ', ','} |
||
409 | ): |
||
410 | 1 | lname = ' '.join((lname, numeral)) |
|
411 | 1 | fname = ' '.join( |
|
412 | ( |
||
413 | fname[:loc].strip(), |
||
414 | fname[loc + len(numeral) :].lstrip(' ,'), |
||
415 | ) |
||
416 | ) |
||
417 | 1 | return fname.strip(), lname.strip() |
|
418 | |||
419 | # Fill fields 7 (specials) and 3 (roman numerals) |
||
420 | 1 | for num, special in enumerate(self._synoname_special_table): |
|
421 | 1 | roman, match, extra, method = special |
|
422 | 1 | if method & self._method_dict['end']: |
|
423 | 1 | match_context = ' ' + match |
|
424 | 1 | loc = full_name.find(match_context) |
|
425 | 1 | if (len(full_name) > len(match_context)) and ( |
|
426 | loc == len(full_name) - len(match_context) |
||
427 | ): |
||
428 | 1 | if roman: |
|
429 | 1 | if not any( |
|
430 | abbr in fname for abbr in ('i.', 'v.', 'x.') |
||
431 | ): |
||
432 | 1 | full_name = full_name[:loc] |
|
433 | 1 | toolcode[7] += '{:03d}'.format(num) + 'a' |
|
434 | 1 | if toolcode[3] == '000': |
|
435 | 1 | toolcode[3] = '{:03d}'.format(num) |
|
436 | 1 | if normalize == 2: |
|
437 | 1 | fname, lname = roman_check(match, fname, lname) |
|
438 | else: |
||
439 | 1 | full_name = full_name[:loc] |
|
440 | 1 | toolcode[7] += '{:03d}'.format(num) + 'a' |
|
441 | 1 | if method & self._method_dict['middle']: |
|
442 | 1 | match_context = ' ' + match + ' ' |
|
443 | 1 | loc = 0 |
|
444 | 1 | while loc != -1: |
|
445 | 1 | loc = full_name.find(match_context, loc + 1) |
|
446 | 1 | if loc > 0: |
|
447 | 1 | if roman: |
|
448 | 1 | if not any( |
|
449 | abbr in fname for abbr in ('i.', 'v.', 'x.') |
||
450 | ): |
||
451 | 1 | full_name = ( |
|
452 | full_name[:loc] |
||
453 | + full_name[loc + len(match) + 1 :] |
||
454 | ) |
||
455 | 1 | toolcode[7] += '{:03d}'.format(num) + 'b' |
|
456 | 1 | if toolcode[3] == '000': |
|
457 | 1 | toolcode[3] = '{:03d}'.format(num) |
|
458 | 1 | if normalize == 2: |
|
459 | 1 | fname, lname = roman_check( |
|
460 | match, fname, lname |
||
461 | ) |
||
462 | else: |
||
463 | 1 | full_name = ( |
|
464 | full_name[:loc] |
||
465 | + full_name[loc + len(match) + 1 :] |
||
466 | ) |
||
467 | 1 | toolcode[7] += '{:03d}'.format(num) + 'b' |
|
468 | 1 | if method & self._method_dict['beginning']: |
|
469 | 1 | match_context = match + ' ' |
|
470 | 1 | loc = full_name.find(match_context) |
|
471 | 1 | if loc == 0: |
|
472 | 1 | full_name = full_name[len(match) + 1 :] |
|
473 | 1 | toolcode[7] += '{:03d}'.format(num) + 'c' |
|
474 | 1 | if method & self._method_dict['beginning_no_space']: |
|
475 | 1 | loc = full_name.find(match) |
|
476 | 1 | if loc == 0: |
|
477 | 1 | toolcode[7] += '{:03d}'.format(num) + 'd' |
|
478 | 1 | if full_name[: len(match)] not in toolcode[9]: |
|
479 | 1 | toolcode[9] += full_name[: len(match)] |
|
480 | |||
481 | 1 | if extra: |
|
482 | 1 | loc = full_name.find(extra) |
|
483 | 1 | if loc != -1: |
|
484 | 1 | toolcode[7] += '{:03d}'.format(num) + 'X' |
|
485 | # Since extras are unique, we only look for each of them |
||
486 | # once, and they include otherwise impossible characters |
||
487 | # for this field, it's not possible for the following line |
||
488 | # to have ever been false. |
||
489 | # if full_name[loc:loc+len(extra)] not in toolcode[9]: |
||
490 | 1 | toolcode[9] += full_name[loc : loc + len(match)] |
|
491 | |||
492 | 1 | return lname, fname, ''.join(toolcode) |
|
493 | |||
542 |