mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
gh-108751: Add copy.replace() function (GH-108752)
It creates a modified copy of an object by calling the object's __replace__() method. It is a generalization of dataclasses.replace(), named tuple's _replace() method and replace() methods in various classes, and supports all these stdlib classes.
This commit is contained in:
parent
9f0c0a46f0
commit
6f3c138dfa
19 changed files with 311 additions and 68 deletions
|
@ -1,6 +1,7 @@
|
|||
import asyncio
|
||||
import builtins
|
||||
import collections
|
||||
import copy
|
||||
import datetime
|
||||
import functools
|
||||
import importlib
|
||||
|
@ -3830,6 +3831,28 @@ class TestSignatureObject(unittest.TestCase):
|
|||
P('bar', P.VAR_POSITIONAL)])),
|
||||
'(foo, /, *bar)')
|
||||
|
||||
def test_signature_replace_parameters(self):
|
||||
def test(a, b) -> 42:
|
||||
pass
|
||||
|
||||
sig = inspect.signature(test)
|
||||
parameters = sig.parameters
|
||||
sig = sig.replace(parameters=list(parameters.values())[1:])
|
||||
self.assertEqual(list(sig.parameters), ['b'])
|
||||
self.assertEqual(sig.parameters['b'], parameters['b'])
|
||||
self.assertEqual(sig.return_annotation, 42)
|
||||
sig = sig.replace(parameters=())
|
||||
self.assertEqual(dict(sig.parameters), {})
|
||||
|
||||
sig = inspect.signature(test)
|
||||
parameters = sig.parameters
|
||||
sig = copy.replace(sig, parameters=list(parameters.values())[1:])
|
||||
self.assertEqual(list(sig.parameters), ['b'])
|
||||
self.assertEqual(sig.parameters['b'], parameters['b'])
|
||||
self.assertEqual(sig.return_annotation, 42)
|
||||
sig = copy.replace(sig, parameters=())
|
||||
self.assertEqual(dict(sig.parameters), {})
|
||||
|
||||
def test_signature_replace_anno(self):
|
||||
def test() -> 42:
|
||||
pass
|
||||
|
@ -3843,6 +3866,15 @@ class TestSignatureObject(unittest.TestCase):
|
|||
self.assertEqual(sig.return_annotation, 42)
|
||||
self.assertEqual(sig, inspect.signature(test))
|
||||
|
||||
sig = inspect.signature(test)
|
||||
sig = copy.replace(sig, return_annotation=None)
|
||||
self.assertIs(sig.return_annotation, None)
|
||||
sig = copy.replace(sig, return_annotation=sig.empty)
|
||||
self.assertIs(sig.return_annotation, sig.empty)
|
||||
sig = copy.replace(sig, return_annotation=42)
|
||||
self.assertEqual(sig.return_annotation, 42)
|
||||
self.assertEqual(sig, inspect.signature(test))
|
||||
|
||||
def test_signature_replaced(self):
|
||||
def test():
|
||||
pass
|
||||
|
@ -4187,41 +4219,66 @@ class TestParameterObject(unittest.TestCase):
|
|||
p = inspect.Parameter('foo', default=42,
|
||||
kind=inspect.Parameter.KEYWORD_ONLY)
|
||||
|
||||
self.assertIsNot(p, p.replace())
|
||||
self.assertEqual(p, p.replace())
|
||||
self.assertIsNot(p.replace(), p)
|
||||
self.assertEqual(p.replace(), p)
|
||||
self.assertIsNot(copy.replace(p), p)
|
||||
self.assertEqual(copy.replace(p), p)
|
||||
|
||||
p2 = p.replace(annotation=1)
|
||||
self.assertEqual(p2.annotation, 1)
|
||||
p2 = p2.replace(annotation=p2.empty)
|
||||
self.assertEqual(p, p2)
|
||||
self.assertEqual(p2, p)
|
||||
p3 = copy.replace(p, annotation=1)
|
||||
self.assertEqual(p3.annotation, 1)
|
||||
p3 = copy.replace(p3, annotation=p3.empty)
|
||||
self.assertEqual(p3, p)
|
||||
|
||||
p2 = p2.replace(name='bar')
|
||||
self.assertEqual(p2.name, 'bar')
|
||||
self.assertNotEqual(p2, p)
|
||||
p3 = copy.replace(p3, name='bar')
|
||||
self.assertEqual(p3.name, 'bar')
|
||||
self.assertNotEqual(p3, p)
|
||||
|
||||
with self.assertRaisesRegex(ValueError,
|
||||
'name is a required attribute'):
|
||||
p2 = p2.replace(name=p2.empty)
|
||||
with self.assertRaisesRegex(ValueError,
|
||||
'name is a required attribute'):
|
||||
p3 = copy.replace(p3, name=p3.empty)
|
||||
|
||||
p2 = p2.replace(name='foo', default=None)
|
||||
self.assertIs(p2.default, None)
|
||||
self.assertNotEqual(p2, p)
|
||||
p3 = copy.replace(p3, name='foo', default=None)
|
||||
self.assertIs(p3.default, None)
|
||||
self.assertNotEqual(p3, p)
|
||||
|
||||
p2 = p2.replace(name='foo', default=p2.empty)
|
||||
self.assertIs(p2.default, p2.empty)
|
||||
|
||||
p3 = copy.replace(p3, name='foo', default=p3.empty)
|
||||
self.assertIs(p3.default, p3.empty)
|
||||
|
||||
p2 = p2.replace(default=42, kind=p2.POSITIONAL_OR_KEYWORD)
|
||||
self.assertEqual(p2.kind, p2.POSITIONAL_OR_KEYWORD)
|
||||
self.assertNotEqual(p2, p)
|
||||
p3 = copy.replace(p3, default=42, kind=p3.POSITIONAL_OR_KEYWORD)
|
||||
self.assertEqual(p3.kind, p3.POSITIONAL_OR_KEYWORD)
|
||||
self.assertNotEqual(p3, p)
|
||||
|
||||
with self.assertRaisesRegex(ValueError,
|
||||
"value <class 'inspect._empty'> "
|
||||
"is not a valid Parameter.kind"):
|
||||
p2 = p2.replace(kind=p2.empty)
|
||||
with self.assertRaisesRegex(ValueError,
|
||||
"value <class 'inspect._empty'> "
|
||||
"is not a valid Parameter.kind"):
|
||||
p3 = copy.replace(p3, kind=p3.empty)
|
||||
|
||||
p2 = p2.replace(kind=p2.KEYWORD_ONLY)
|
||||
self.assertEqual(p2, p)
|
||||
p3 = copy.replace(p3, kind=p3.KEYWORD_ONLY)
|
||||
self.assertEqual(p3, p)
|
||||
|
||||
def test_signature_parameter_positional_only(self):
|
||||
with self.assertRaisesRegex(TypeError, 'name must be a str'):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue