From f67dc1f269ddb5af258af86601fd04d74137e23d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Aug 2026 19:27:41 +0300 Subject: [PATCH 1/2] gh-155043: Support copy.replace() for argparse.Namespace Co-Authored-By: Claude Opus 5 (1M context) --- Doc/library/argparse.rst | 6 ++++++ Lib/argparse.py | 6 ++++++ Lib/test/test_argparse.py | 14 ++++++++++++++ .../2026-08-01-19-04-00.gh-issue-155043.Ar1Nsp.rst | 1 + 4 files changed, 27 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-08-01-19-04-00.gh-issue-155043.Ar1Nsp.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index e4a5f4d109b499..d57467c2759a48 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1679,6 +1679,12 @@ The Namespace object Simple class used by default by :meth:`~ArgumentParser.parse_args` to create an object holding attributes and return it. + :class:`!Namespace` objects support :func:`copy.replace`, + which returns a copy of the object with the specified attributes replaced. + + .. versionchanged:: next + Added support of :func:`copy.replace`. + This class is deliberately simple, just an :class:`object` subclass with a readable string representation. If you prefer to have dict-like view of the attributes, you can use the standard Python idiom, :func:`vars`:: diff --git a/Lib/argparse.py b/Lib/argparse.py index 0840c4c45cffaa..d792fcb9266e2d 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1545,6 +1545,12 @@ def __eq__(self, other): def __contains__(self, key): return key in self.__dict__ + def __replace__(self, /, **changes): + new = self.__class__() + new.__dict__.update(self.__dict__) + new.__dict__.update(changes) + return new + class _ActionsContainer(object): diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 287fcb7a084a49..11a62000558252 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2,6 +2,7 @@ import _colorize import contextlib +import copy import functools import io import operator @@ -6267,6 +6268,19 @@ def test_equality_returns_notimplemented(self): self.assertIs(ns.__eq__(None), NotImplemented) self.assertIs(ns.__ne__(None), NotImplemented) + def test_replace(self): + ns = argparse.Namespace(a=1, b=2) + new = copy.replace(ns, b=3, c=4) + self.assertIsInstance(new, argparse.Namespace) + self.assertEqual(new, argparse.Namespace(a=1, b=3, c=4)) + self.assertEqual(ns, argparse.Namespace(a=1, b=2)) + + class MyNamespace(argparse.Namespace): + pass + new = copy.replace(MyNamespace(a=1), a=2) + self.assertIsInstance(new, MyNamespace) + self.assertEqual(new.a, 2) + # =================== # File encoding tests diff --git a/Misc/NEWS.d/next/Library/2026-08-01-19-04-00.gh-issue-155043.Ar1Nsp.rst b/Misc/NEWS.d/next/Library/2026-08-01-19-04-00.gh-issue-155043.Ar1Nsp.rst new file mode 100644 index 00000000000000..715b0a1783730e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-01-19-04-00.gh-issue-155043.Ar1Nsp.rst @@ -0,0 +1 @@ +:class:`argparse.Namespace` objects now support :func:`copy.replace`. From af234285c67d7e75d9006389157b62bf6a11bc03 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 1 Aug 2026 21:48:09 +0300 Subject: [PATCH 2/2] Say "support for" instead of "support of" Co-Authored-By: Claude Opus 5 (1M context) --- Doc/library/argparse.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index d57467c2759a48..8ae96311026f33 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -1683,7 +1683,7 @@ The Namespace object which returns a copy of the object with the specified attributes replaced. .. versionchanged:: next - Added support of :func:`copy.replace`. + Added support for :func:`copy.replace`. This class is deliberately simple, just an :class:`object` subclass with a readable string representation. If you prefer to have dict-like view of the