|
10 | 10 | dill = False # type: ignore[assignment] |
11 | 11 |
|
12 | 12 | from nameparser import HumanName |
13 | | -from nameparser.config import Constants, TupleManager |
| 13 | +from nameparser.config import CONSTANTS, Constants, TupleManager |
14 | 14 |
|
15 | 15 | from tests.base import HumanNameTestBase |
16 | 16 |
|
@@ -92,11 +92,67 @@ def test_name_instance_deepcopy_isolates_instance_config(self) -> None: |
92 | 92 | self.assertIn('chancellor', dup.C.titles) |
93 | 93 | self.assertNotIn('marker', hn.C.titles) |
94 | 94 |
|
| 95 | + def test_pickle_default_name_preserves_singleton_identity(self) -> None: |
| 96 | + """A default HumanName must re-attach to CONSTANTS after a pickle round-trip. |
| 97 | +
|
| 98 | + Without __getstate__/__setstate__, pickle serializes .C by value, so the |
| 99 | + restored name gets a detached copy — has_own_config flips to True and |
| 100 | + every pickled default name carries a full Constants copy. |
| 101 | + """ |
| 102 | + hn = HumanName("John Doe") |
| 103 | + self.assertFalse(hn.has_own_config) |
| 104 | + self.assertIs(hn.C, CONSTANTS) |
| 105 | + |
| 106 | + # Safe: round-tripping an object we just built, not untrusted data. |
| 107 | + restored = pickle.loads(pickle.dumps(hn)) |
| 108 | + |
| 109 | + self.assertIs(restored.C, CONSTANTS) |
| 110 | + self.assertFalse(restored.has_own_config) |
| 111 | + self.assertEqual(str(restored), str(hn)) |
| 112 | + self.assertEqual(restored.first, hn.first) |
| 113 | + self.assertEqual(restored.last, hn.last) |
| 114 | + |
| 115 | + def test_pickle_instance_config_name_preserves_own_config(self) -> None: |
| 116 | + """A HumanName with its own Constants must not be collapsed onto CONSTANTS after pickle.""" |
| 117 | + hn = HumanName("Smith, Dr. John", None) |
| 118 | + hn.C.titles.add('chancellor') |
| 119 | + hn.parse_full_name() |
| 120 | + self.assertTrue(hn.has_own_config) |
| 121 | + self.assertIsNot(hn.C, CONSTANTS) |
| 122 | + |
| 123 | + # Safe: round-tripping a HumanName the test just built, not untrusted data. |
| 124 | + restored = pickle.loads(pickle.dumps(hn)) |
| 125 | + |
| 126 | + self.assertTrue(restored.has_own_config) |
| 127 | + self.assertIsNot(restored.C, CONSTANTS) |
| 128 | + self.assertIn('chancellor', restored.C.titles) |
| 129 | + |
| 130 | + def test_shallow_copy_default_name_preserves_singleton_identity(self) -> None: |
| 131 | + """copy.copy of a default HumanName shares the CONSTANTS reference without hooks.""" |
| 132 | + hn = HumanName("John Doe") |
| 133 | + |
| 134 | + sc = copy.copy(hn) |
| 135 | + |
| 136 | + self.assertIs(sc.C, CONSTANTS) |
| 137 | + self.assertFalse(sc.has_own_config) |
| 138 | + |
| 139 | + def test_deepcopy_default_name_preserves_singleton_identity(self) -> None: |
| 140 | + """copy.deepcopy of a default HumanName must re-attach to CONSTANTS.""" |
| 141 | + hn = HumanName("John Doe") |
| 142 | + |
| 143 | + dup = copy.deepcopy(hn) |
| 144 | + |
| 145 | + self.assertIs(dup.C, CONSTANTS) |
| 146 | + self.assertFalse(dup.has_own_config) |
| 147 | + self.assertEqual(str(dup), str(hn)) |
| 148 | + self.assertEqual(dup.first, hn.first) |
| 149 | + self.assertEqual(dup.last, hn.last) |
| 150 | + |
95 | 151 | def test_comparison(self) -> None: |
96 | 152 | hn1 = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") |
97 | 153 | hn2 = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") |
98 | 154 | self.assertTrue(hn1 == hn2) |
99 | | - self.assertTrue(hn1 is not hn2) |
| 155 | + self.assertIsNot(hn1, hn2) |
100 | 156 | self.assertTrue(hn1 == "Dr. John P. Doe-Ray CLU, CFP, LUTC") |
101 | 157 | hn1 = HumanName("Doe, Dr. John P., CLU, CFP, LUTC") |
102 | 158 | hn2 = HumanName("Dr. John P. Doe-Ray, CLU, CFP, LUTC") |
@@ -156,7 +212,7 @@ def test_comparison_case_insensitive(self) -> None: |
156 | 212 | hn1 = HumanName("Doe-Ray, Dr. John P., CLU, CFP, LUTC") |
157 | 213 | hn2 = HumanName("dr. john p. doe-Ray, CLU, CFP, LUTC") |
158 | 214 | self.assertTrue(hn1 == hn2) |
159 | | - self.assertTrue(hn1 is not hn2) |
| 215 | + self.assertIsNot(hn1, hn2) |
160 | 216 | self.assertTrue(hn1 == "Dr. John P. Doe-ray clu, CFP, LUTC") |
161 | 217 |
|
162 | 218 | def test_slice(self) -> None: |
@@ -222,7 +278,7 @@ def test_is_conjunction_with_list(self) -> None: |
222 | 278 | def test_override_constants(self) -> None: |
223 | 279 | C = Constants() |
224 | 280 | hn = HumanName(constants=C) |
225 | | - self.assertTrue(hn.C is C) |
| 281 | + self.assertIs(hn.C, C) |
226 | 282 |
|
227 | 283 | def test_override_regex(self) -> None: |
228 | 284 | var = TupleManager([("spaces", re.compile(r"\s+", re.U)),]) |
|
0 commit comments