2317780a23be15cb02367c3bede5507ce10b2d73
[librarian.git] / src / librarian / meta / types / person.py
1 from functools import total_ordering
2 from .base import MetaValue
3
4
5 @total_ordering
6 class Person(MetaValue):
7     """Single person with last name and a list of first names."""
8     def __init__(self, last_name, *first_names):
9         self.last_name = last_name
10         self.first_names = first_names
11
12     @classmethod
13     def from_text(cls, text):
14         parts = [token.strip() for token in text.split(',')]
15         if len(parts) == 1:
16             surname = parts[0]
17             names = []
18         elif len(parts) != 2:
19             raise ValueError(
20                 "Invalid person name. "
21                 "There should be at most one comma: \"%s\"."
22                 % text.encode('utf-8')
23             )
24         else:
25             surname = parts[0]
26             if len(parts[1]) == 0:
27                 # there is no non-whitespace data after the comma
28                 raise ValueError(
29                     "Found a comma, but no names given: \"%s\" -> %r."
30                     % (text, parts)
31                 )
32             names = parts[1].split()
33         return cls(surname, *names)
34
35     def readable(self):
36         return u" ".join(self.first_names + (self.last_name,))
37
38     def __eq__(self, right):
39         return (self.last_name == right.last_name
40                 and self.first_names == right.first_names)
41
42     def __lt__(self, other):
43         return ((self.last_name, self.first_names)
44                 < (other.last_name, other.first_names))
45
46     def __hash__(self):
47         return hash((self.last_name, self.first_names))
48
49     def __str__(self):
50         if len(self.first_names) > 0:
51             return '%s, %s' % (self.last_name, ' '.join(self.first_names))
52         else:
53             return self.last_name
54
55     def __repr__(self):
56         return 'Person(last_name=%r, first_names=*%r)' % (
57             self.last_name, self.first_names
58         )