-
Notifications
You must be signed in to change notification settings - Fork 112
Expand file tree
/
Copy pathtest_initials.py
More file actions
219 lines (185 loc) · 10.1 KB
/
Copy pathtest_initials.py
File metadata and controls
219 lines (185 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
from nameparser import HumanName
from tests.base import HumanNameTestBase
class InitialsTestCase(HumanNameTestBase):
def test_initials(self) -> None:
hn = HumanName("Andrew Boris Petersen")
self.m(hn.initials(), "A. B. P.", hn)
def test_initials_simple_name(self) -> None:
hn = HumanName("John Doe")
self.m(hn.initials(), "J. D.", hn)
hn = HumanName("John Doe", initials_format="{first} {last}")
self.m(hn.initials(), "J. D.", hn)
hn = HumanName("John Doe", initials_format="{last}")
self.m(hn.initials(), "D.", hn)
hn = HumanName("John Doe", initials_format="{first}")
self.m(hn.initials(), "J.", hn)
hn = HumanName("John Doe", initials_format="{middle}")
self.m(hn.initials(), "", hn)
def test_initials_empty_part_with_none_default_not_literal_none(self) -> None:
# Regression: when empty_attribute_default is None, an empty name part
# used to be interpolated by str.format as the literal "None" (e.g.
# "John Doe" -> "J. None D."). Empty parts must render as ''.
hn = HumanName("John Doe", constants=None)
# empty_attribute_default has no explicit annotation (mypy infers str
# from the '' default), but None is documented/supported here -- see
# the doctest on the attribute's docstring in config/__init__.py. Not
# widened to str | None like string_format/suffix_delimiter because
# it cascades into ~8 public str-typed properties (title, first,
# middle, last, suffix, nickname, initials()).
hn.C.empty_attribute_default = None # type: ignore[assignment]
self.assertEqual(hn.initials(), "J. D.")
self.assertTrue("None" not in hn.initials())
def test_initials_all_empty_returns_empty_attribute_default(self) -> None:
# Regression: a fully-empty result must fall back to
# empty_attribute_default (here None), matching the first/last accessors,
# rather than rendering the literal "None None None".
hn = HumanName("", constants=None)
hn.C.empty_attribute_default = None # type: ignore[assignment] # see test above
self.assertEqual(hn.initials(), None)
def test_initials_middle_name_all_prefixes(self) -> None:
# "Vega, Juan de la" parses with middle name "de la", which contains
# no initialable words (both are prefixes). The part must be skipped
# entirely — not emit an empty initial ("J. . V.") and not crash when
# empty_attribute_default is None.
hn = HumanName("Vega, Juan de la")
self.m(hn.middle, "de la", hn)
self.assertEqual(hn.initials_list(), ["J", "V"])
self.assertEqual(hn.initials(), "J. V.")
def test_initials_complex_name(self) -> None:
hn = HumanName("Doe, John A. Kenneth, Jr.")
self.m(hn.initials(), "J. A. K. D.", hn)
def test_initials_format(self) -> None:
hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{first} {middle}")
self.m(hn.initials(), "J. A. K.", hn)
hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{first} {last}")
self.m(hn.initials(), "J. D.", hn)
hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{middle} {last}")
self.m(hn.initials(), "A. K. D.", hn)
hn = HumanName("Doe, John A. Kenneth, Jr.", initials_format="{first}, {last}")
self.m(hn.initials(), "J., D.", hn)
def test_initials_format_constants(self) -> None:
from nameparser.config import CONSTANTS
CONSTANTS.initials_format = "{first} {last}"
hn = HumanName("Doe, John A. Kenneth, Jr.")
self.m(hn.initials(), "J. D.", hn)
CONSTANTS.initials_format = "{first} {last}"
hn = HumanName("Doe, John A. Kenneth, Jr.")
self.m(hn.initials(), "J. D.", hn)
def test_initials_delimiter(self) -> None:
hn = HumanName("Doe, John A. Kenneth, Jr.", initials_delimiter=";")
self.m(hn.initials(), "J; A; K; D;", hn)
def test_initials_delimiter_constants(self) -> None:
from nameparser.config import CONSTANTS
CONSTANTS.initials_delimiter = ";"
hn = HumanName("Doe, John A. Kenneth, Jr.")
self.m(hn.initials(), "J; A; K; D;", hn)
def test_initials_list(self) -> None:
hn = HumanName("Andrew Boris Petersen")
self.m(hn.initials_list(), ["A", "B", "P"], hn)
def test_initials_list_complex_name(self) -> None:
hn = HumanName("Doe, John A. Kenneth, Jr.")
self.m(hn.initials_list(), ["J", "A", "K", "D"], hn)
def test_initials_with_prefix_firstname(self) -> None:
hn = HumanName("Van Jeremy Johnson")
self.m(hn.initials_list(), ["V", "J", "J"], hn)
def test_initials_with_prefix(self) -> None:
hn = HumanName("Alex van Johnson")
self.m(hn.initials_list(), ["A", "J"], hn)
def test_initials_delimiter_empty_string_kwarg(self) -> None:
# Regression: initials_delimiter='' was silently ignored due to `or` defaulting
hn = HumanName("Doe, John A.", initials_delimiter="")
self.m(hn.initials(), "J A D", hn)
def test_initials_format_empty_string_kwarg(self) -> None:
# Regression: initials_format='' was silently ignored due to `or` defaulting
hn = HumanName("Doe, John A.")
hn2 = HumanName("Doe, John A.", initials_format="")
self.assertNotEqual(hn.initials(), hn2.initials())
# "".format(...) returns ""; collapse_whitespace returns "" which falls through
# to empty_attribute_default (may be "" or None depending on config variant).
self.assertFalse(hn2.initials())
def test_initials_separator_kwarg(self) -> None:
# initials_separator="" with initials_format="{first}{middle}{last}" gives
# period-separated initials with no spaces — a common academic citation style
hn = HumanName(
"Doe, John A. Kenneth",
initials_separator="",
initials_format="{first}{middle}{last}",
)
self.m(hn.initials(), "J.A.K.D.", hn)
def test_initials_separator_custom_value(self) -> None:
# Non-empty custom separator exercising _process_initial on a multi-word
# token. "Van Berg" is a single name part whose two words produce two initials
# joined by initials_separator.
hn = HumanName("", initials_separator="-", initials_delimiter=".")
result = hn._process_initial("Van Berg", firstname=True)
self.assertEqual(result, "V-B")
def test_str_default_behavior_unchanged(self) -> None:
# Regression guard for the `or` → `is not None` change in __str__:
# the default path (no string_format kwarg) must still produce the expected string.
hn = HumanName("John Doe")
self.assertEqual(str(hn), "John Doe")
def test_initials_with_doubled_space_in_list_element(self) -> None:
# direct *_list assignment bypasses parse_pieces whitespace
# normalization, so initials must tolerate unnormalized elements
# instead of raising IndexError (#232)
hn = HumanName(first="John")
hn.middle_list = ["Q R"]
self.assertEqual(hn.initials_list(), ["J", "Q R"])
self.assertEqual(hn.initials(), "J. Q R.")
def test_constructor_first(self) -> None:
hn = HumanName(first="TheName")
self.m(hn.first, "TheName", hn)
def test_constructor_middle(self) -> None:
hn = HumanName(middle="TheName")
self.m(hn.middle, "TheName", hn)
def test_constructor_last(self) -> None:
hn = HumanName(last="TheName")
self.m(hn.last, "TheName", hn)
def test_constructor_title(self) -> None:
hn = HumanName(title="TheName")
self.m(hn.title, "TheName", hn)
def test_constructor_suffix(self) -> None:
hn = HumanName(suffix="TheName")
self.m(hn.suffix, "TheName", hn)
def test_constructor_nickname(self) -> None:
hn = HumanName(nickname="TheName")
self.m(hn.nickname, "TheName", hn)
def test_constructor_multiple(self) -> None:
hn = HumanName(first="TheName", last="lastname", title="mytitle", full_name="donotparse")
self.m(hn.first, "TheName", hn)
self.m(hn.last, "lastname", hn)
self.m(hn.title, "mytitle", hn)
def test_initials_separator_kwarg_multiword_part(self) -> None:
# Regression: initials_separator kwarg must flow into _process_initial
# for multi-word name parts, not just into the initials() join calls.
hn = HumanName("", initials_separator="")
result = hn._process_initial("Van Berg", firstname=True)
self.assertEqual(result, "VB")
def test_string_format_empty_string_kwarg(self) -> None:
# Regression: string_format='' was silently ignored due to `or` defaulting
hn = HumanName("John Doe", string_format="")
self.assertEqual(str(hn), "")
def test_initials_separator_empty_multi_part_middle(self) -> None:
# Full workflow from issue #152: empty delimiter + separator + compact format
# gives fully concatenated initials with no spaces or punctuation.
# Spaces between groups come from initials_format, so that must also be set.
hn = HumanName(
"Doe, John A. Kenneth",
initials_delimiter="",
initials_separator="",
initials_format="{first}{middle}{last}",
)
self.m(hn.initials(), "JAKD", hn)
def test_initials_separator_constants_multi_part_middle(self) -> None:
from nameparser.config import CONSTANTS
CONSTANTS.initials_delimiter = ""
CONSTANTS.initials_separator = ""
CONSTANTS.initials_format = "{first}{middle}{last}"
hn = HumanName("Doe, John A. Kenneth")
self.m(hn.initials(), "JAKD", hn)
def test_initials_separator_default_on_constants(self) -> None:
# Runs after test_initials_separator_constants_multi_part_middle so that,
# in file/definition order, it verifies the autouse fixture restored
# CONSTANTS.initials_separator rather than leaking the "" set above.
from nameparser.config import CONSTANTS
self.assertEqual(CONSTANTS.initials_separator, " ")