|
1 | 1 | import copy |
2 | 2 | import pickle |
3 | 3 | import re |
| 4 | +import warnings |
4 | 5 |
|
5 | 6 | import pytest |
6 | 7 |
|
@@ -215,18 +216,22 @@ def test_deepcopy_default_name_preserves_singleton_identity(self) -> None: |
215 | 216 | self.assertEqual(dup.last, hn.last) |
216 | 217 |
|
217 | 218 | def test_comparison(self) -> None: |
| 219 | + # deprecated behavior (#223/#224), still supported until 2.0: |
| 220 | + # deprecated_call() asserts the warning fires while silencing it |
218 | 221 | hn1 = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") |
219 | 222 | hn2 = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") |
220 | | - self.assertTrue(hn1 == hn2) |
221 | | - self.assertIsNot(hn1, hn2) |
222 | | - self.assertTrue(hn1 == "Dr. John P. Doe-Ray CLU, CFP, LUTC") |
| 223 | + with pytest.deprecated_call(): |
| 224 | + self.assertTrue(hn1 == hn2) |
| 225 | + self.assertIsNot(hn1, hn2) |
| 226 | + self.assertTrue(hn1 == "Dr. John P. Doe-Ray CLU, CFP, LUTC") |
223 | 227 | hn1 = HumanName("Doe, Dr. John P., CLU, CFP, LUTC") |
224 | 228 | hn2 = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") |
225 | | - self.assertTrue(not hn1 == hn2) |
226 | | - self.assertTrue(not hn1 == 0) |
227 | | - self.assertTrue(not hn1 == "test") |
228 | | - self.assertTrue(not hn1 == ["test"]) |
229 | | - self.assertTrue(not hn1 == {"test": hn2}) |
| 229 | + with pytest.deprecated_call(): |
| 230 | + self.assertTrue(not hn1 == hn2) |
| 231 | + self.assertTrue(not hn1 == 0) |
| 232 | + self.assertTrue(not hn1 == "test") |
| 233 | + self.assertTrue(not hn1 == ["test"]) |
| 234 | + self.assertTrue(not hn1 == {"test": hn2}) |
230 | 235 |
|
231 | 236 | def test_assignment_to_full_name(self) -> None: |
232 | 237 | hn = HumanName("John A. Kenneth Doe, Jr.") |
@@ -275,30 +280,37 @@ def test_assign_list_to_attribute(self) -> None: |
275 | 280 | self.m(hn.suffix, "test", hn) |
276 | 281 |
|
277 | 282 | def test_comparison_case_insensitive(self) -> None: |
| 283 | + # deprecated behavior (#223/#224), still supported until 2.0 |
278 | 284 | hn1 = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") |
279 | 285 | hn2 = HumanName("dr. john p. doe-Ray, CLU, CFP, LUTC") |
280 | | - self.assertTrue(hn1 == hn2) |
281 | | - self.assertIsNot(hn1, hn2) |
282 | | - self.assertTrue(hn1 == "Dr. John P. Doe-ray clu, CFP, LUTC") |
| 286 | + with pytest.deprecated_call(): |
| 287 | + self.assertTrue(hn1 == hn2) |
| 288 | + self.assertIsNot(hn1, hn2) |
| 289 | + self.assertTrue(hn1 == "Dr. John P. Doe-ray clu, CFP, LUTC") |
283 | 290 |
|
284 | 291 | def test_hash_matches_case_insensitive_equality(self) -> None: |
| 292 | + # deprecated behavior (#223/#224), still supported until 2.0. |
285 | 293 | # __eq__ compares lowercased strings, so __hash__ must too: |
286 | 294 | # equal objects are required to have equal hashes. |
287 | 295 | hn1 = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") |
288 | 296 | hn2 = HumanName("dr. john p. doe-Ray, CLU, CFP, LUTC") |
289 | | - self.assertEqual(hn1, hn2) |
290 | | - self.assertEqual(hash(hn1), hash(hn2)) |
291 | | - self.assertEqual(len({hn1, hn2}), 1) |
292 | | - # __eq__ also accepts plain strings, so hashing str(self).lower() |
293 | | - # specifically (not e.g. an attribute tuple) is what lets strings and |
294 | | - # HumanName instances interoperate in sets and dicts |
295 | | - hn = HumanName("John Smith") |
296 | | - self.assertEqual(hash(hn), hash("john smith")) |
297 | | - self.assertIn("john smith", {hn}) |
| 297 | + with pytest.deprecated_call(): |
| 298 | + self.assertEqual(hn1, hn2) |
| 299 | + self.assertEqual(hash(hn1), hash(hn2)) |
| 300 | + self.assertEqual(len({hn1, hn2}), 1) |
| 301 | + # __eq__ also accepts plain strings, so hashing str(self).lower() |
| 302 | + # specifically (not e.g. an attribute tuple) is what lets strings |
| 303 | + # and HumanName instances interoperate in sets and dicts |
| 304 | + hn = HumanName("John Smith") |
| 305 | + self.assertEqual(hash(hn), hash("john smith")) |
| 306 | + self.assertIn("john smith", {hn}) |
298 | 307 |
|
299 | 308 | def test_not_equal_operator(self) -> None: |
300 | | - self.assertTrue(HumanName("John Smith") != HumanName("Jane Smith")) |
301 | | - self.assertFalse(HumanName("John Smith") != HumanName("john smith")) |
| 309 | + # deprecated behavior (#223/#224), still supported until 2.0; |
| 310 | + # != routes through __eq__, so it warns too |
| 311 | + with pytest.deprecated_call(): |
| 312 | + self.assertTrue(HumanName("John Smith") != HumanName("Jane Smith")) |
| 313 | + self.assertFalse(HumanName("John Smith") != HumanName("john smith")) |
302 | 314 |
|
303 | 315 | def test_comparison_key_components(self) -> None: |
304 | 316 | hn = HumanName("Dr. Juan Q. Xavier de la Vega III") |
@@ -359,6 +371,31 @@ def test_matches_rejects_other_types(self) -> None: |
359 | 371 | with pytest.raises(TypeError, match="str or HumanName"): |
360 | 372 | hn.matches(bad) # type: ignore[arg-type] |
361 | 373 |
|
| 374 | + def test_eq_emits_deprecation_warning(self) -> None: |
| 375 | + # behavior is unchanged until 2.0 (#223); 1.3.0 only warns |
| 376 | + hn1 = HumanName("John Smith") |
| 377 | + hn2 = HumanName("john smith") |
| 378 | + with pytest.deprecated_call(match="matches"): |
| 379 | + result = hn1 == hn2 |
| 380 | + self.assertTrue(result) |
| 381 | + |
| 382 | + def test_hash_emits_deprecation_warning(self) -> None: |
| 383 | + hn = HumanName("John Smith") |
| 384 | + with pytest.deprecated_call(match="comparison_key"): |
| 385 | + result = hash(hn) |
| 386 | + self.assertEqual(result, hash("john smith")) |
| 387 | + |
| 388 | + def test_new_comparison_api_does_not_warn(self) -> None: |
| 389 | + # the replacements must be adoptable before 2.0 without tripping |
| 390 | + # -W error test suites; matches(str) parses, so this also covers |
| 391 | + # the parse path |
| 392 | + hn = HumanName("John Smith") |
| 393 | + with warnings.catch_warnings(): |
| 394 | + warnings.simplefilter("error") |
| 395 | + hn.comparison_key() |
| 396 | + hn.matches("Smith, John") |
| 397 | + hn.matches(HumanName("John Smith")) |
| 398 | + |
362 | 399 | def test_unparsable_attribute_removed(self) -> None: |
363 | 400 | # Removed in 1.3.0: the guard that reported unparsable names was |
364 | 401 | # unreachable, so the attribute was always False after any parse. |
|
0 commit comments