|
| 1 | +import abc |
1 | 2 | import collections |
2 | 3 | from itertools import permutations |
3 | 4 | import pickle |
@@ -217,6 +218,120 @@ class TestPartialCSubclass(TestPartialC): |
217 | 218 | partial = PartialSubclass |
218 | 219 |
|
219 | 220 |
|
| 221 | +class TestPartialMethod(unittest.TestCase): |
| 222 | + |
| 223 | + class A(object): |
| 224 | + nothing = functools.partialmethod(capture) |
| 225 | + positional = functools.partialmethod(capture, 1) |
| 226 | + keywords = functools.partialmethod(capture, a=2) |
| 227 | + both = functools.partialmethod(capture, 3, b=4) |
| 228 | + |
| 229 | + nested = functools.partialmethod(positional, 5) |
| 230 | + |
| 231 | + over_partial = functools.partialmethod(functools.partial(capture, c=6), 7) |
| 232 | + |
| 233 | + static = functools.partialmethod(staticmethod(capture), 8) |
| 234 | + cls = functools.partialmethod(classmethod(capture), d=9) |
| 235 | + |
| 236 | + a = A() |
| 237 | + |
| 238 | + def test_arg_combinations(self): |
| 239 | + self.assertEqual(self.a.nothing(), ((self.a,), {})) |
| 240 | + self.assertEqual(self.a.nothing(5), ((self.a, 5), {})) |
| 241 | + self.assertEqual(self.a.nothing(c=6), ((self.a,), {'c': 6})) |
| 242 | + self.assertEqual(self.a.nothing(5, c=6), ((self.a, 5), {'c': 6})) |
| 243 | + |
| 244 | + self.assertEqual(self.a.positional(), ((self.a, 1), {})) |
| 245 | + self.assertEqual(self.a.positional(5), ((self.a, 1, 5), {})) |
| 246 | + self.assertEqual(self.a.positional(c=6), ((self.a, 1), {'c': 6})) |
| 247 | + self.assertEqual(self.a.positional(5, c=6), ((self.a, 1, 5), {'c': 6})) |
| 248 | + |
| 249 | + self.assertEqual(self.a.keywords(), ((self.a,), {'a': 2})) |
| 250 | + self.assertEqual(self.a.keywords(5), ((self.a, 5), {'a': 2})) |
| 251 | + self.assertEqual(self.a.keywords(c=6), ((self.a,), {'a': 2, 'c': 6})) |
| 252 | + self.assertEqual(self.a.keywords(5, c=6), ((self.a, 5), {'a': 2, 'c': 6})) |
| 253 | + |
| 254 | + self.assertEqual(self.a.both(), ((self.a, 3), {'b': 4})) |
| 255 | + self.assertEqual(self.a.both(5), ((self.a, 3, 5), {'b': 4})) |
| 256 | + self.assertEqual(self.a.both(c=6), ((self.a, 3), {'b': 4, 'c': 6})) |
| 257 | + self.assertEqual(self.a.both(5, c=6), ((self.a, 3, 5), {'b': 4, 'c': 6})) |
| 258 | + |
| 259 | + self.assertEqual(self.A.both(self.a, 5, c=6), ((self.a, 3, 5), {'b': 4, 'c': 6})) |
| 260 | + |
| 261 | + def test_nested(self): |
| 262 | + self.assertEqual(self.a.nested(), ((self.a, 1, 5), {})) |
| 263 | + self.assertEqual(self.a.nested(6), ((self.a, 1, 5, 6), {})) |
| 264 | + self.assertEqual(self.a.nested(d=7), ((self.a, 1, 5), {'d': 7})) |
| 265 | + self.assertEqual(self.a.nested(6, d=7), ((self.a, 1, 5, 6), {'d': 7})) |
| 266 | + |
| 267 | + self.assertEqual(self.A.nested(self.a, 6, d=7), ((self.a, 1, 5, 6), {'d': 7})) |
| 268 | + |
| 269 | + def test_over_partial(self): |
| 270 | + self.assertEqual(self.a.over_partial(), ((self.a, 7), {'c': 6})) |
| 271 | + self.assertEqual(self.a.over_partial(5), ((self.a, 7, 5), {'c': 6})) |
| 272 | + self.assertEqual(self.a.over_partial(d=8), ((self.a, 7), {'c': 6, 'd': 8})) |
| 273 | + self.assertEqual(self.a.over_partial(5, d=8), ((self.a, 7, 5), {'c': 6, 'd': 8})) |
| 274 | + |
| 275 | + self.assertEqual(self.A.over_partial(self.a, 5, d=8), ((self.a, 7, 5), {'c': 6, 'd': 8})) |
| 276 | + |
| 277 | + def test_bound_method_introspection(self): |
| 278 | + obj = self.a |
| 279 | + self.assertIs(obj.both.__self__, obj) |
| 280 | + self.assertIs(obj.nested.__self__, obj) |
| 281 | + self.assertIs(obj.over_partial.__self__, obj) |
| 282 | + self.assertIs(obj.cls.__self__, self.A) |
| 283 | + self.assertIs(self.A.cls.__self__, self.A) |
| 284 | + |
| 285 | + def test_unbound_method_retrieval(self): |
| 286 | + obj = self.A |
| 287 | + self.assertFalse(hasattr(obj.both, "__self__")) |
| 288 | + self.assertFalse(hasattr(obj.nested, "__self__")) |
| 289 | + self.assertFalse(hasattr(obj.over_partial, "__self__")) |
| 290 | + self.assertFalse(hasattr(obj.static, "__self__")) |
| 291 | + self.assertFalse(hasattr(self.a.static, "__self__")) |
| 292 | + |
| 293 | + def test_descriptors(self): |
| 294 | + for obj in [self.A, self.a]: |
| 295 | + with self.subTest(obj=obj): |
| 296 | + self.assertEqual(obj.static(), ((8,), {})) |
| 297 | + self.assertEqual(obj.static(5), ((8, 5), {})) |
| 298 | + self.assertEqual(obj.static(d=8), ((8,), {'d': 8})) |
| 299 | + self.assertEqual(obj.static(5, d=8), ((8, 5), {'d': 8})) |
| 300 | + |
| 301 | + self.assertEqual(obj.cls(), ((self.A,), {'d': 9})) |
| 302 | + self.assertEqual(obj.cls(5), ((self.A, 5), {'d': 9})) |
| 303 | + self.assertEqual(obj.cls(c=8), ((self.A,), {'c': 8, 'd': 9})) |
| 304 | + self.assertEqual(obj.cls(5, c=8), ((self.A, 5), {'c': 8, 'd': 9})) |
| 305 | + |
| 306 | + def test_overriding_keywords(self): |
| 307 | + self.assertEqual(self.a.keywords(a=3), ((self.a,), {'a': 3})) |
| 308 | + self.assertEqual(self.A.keywords(self.a, a=3), ((self.a,), {'a': 3})) |
| 309 | + |
| 310 | + def test_invalid_args(self): |
| 311 | + with self.assertRaises(TypeError): |
| 312 | + class B(object): |
| 313 | + method = functools.partialmethod(None, 1) |
| 314 | + |
| 315 | + def test_repr(self): |
| 316 | + self.assertEqual(repr(vars(self.A)['both']), |
| 317 | + 'functools.partialmethod({}, 3, b=4)'.format(capture)) |
| 318 | + |
| 319 | + def test_abstract(self): |
| 320 | + class Abstract(abc.ABCMeta): |
| 321 | + |
| 322 | + @abc.abstractmethod |
| 323 | + def add(self, x, y): |
| 324 | + pass |
| 325 | + |
| 326 | + add5 = functools.partialmethod(add, 5) |
| 327 | + |
| 328 | + self.assertTrue(Abstract.add.__isabstractmethod__) |
| 329 | + self.assertTrue(Abstract.add5.__isabstractmethod__) |
| 330 | + |
| 331 | + for func in [self.A.static, self.A.cls, self.A.over_partial, self.A.nested, self.A.both]: |
| 332 | + self.assertFalse(getattr(func, '__isabstractmethod__', False)) |
| 333 | + |
| 334 | + |
220 | 335 | class TestUpdateWrapper(unittest.TestCase): |
221 | 336 |
|
222 | 337 | def check_wrapper(self, wrapper, wrapped, |
@@ -1433,6 +1548,7 @@ def test_main(verbose=None): |
1433 | 1548 | TestPartialC, |
1434 | 1549 | TestPartialPy, |
1435 | 1550 | TestPartialCSubclass, |
| 1551 | + TestPartialMethod, |
1436 | 1552 | TestUpdateWrapper, |
1437 | 1553 | TestTotalOrdering, |
1438 | 1554 | TestCmpToKeyC, |
|
0 commit comments