https://github.com/python/cpython/commit/c0d0b286bc0b24512b56c9087a4bcf8ffca50ab6
commit: c0d0b286bc0b24512b56c9087a4bcf8ffca50ab6
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-13T13:06:17+03:00
summary:

gh-155044: Support copy.replace() for optparse.Values (GH-155050)

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-08-01-19-05-00.gh-issue-155044.Op1Val.rst
M Doc/library/optparse.rst
M Lib/optparse.py
M Lib/test/test_optparse.py

diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst
index 905212965bd70f..09416f12ad45c2 100644
--- a/Doc/library/optparse.rst
+++ b/Doc/library/optparse.rst
@@ -1073,6 +1073,12 @@ As you can see, most actions involve storing or updating 
a value somewhere.
    and can be overridden by a custom subclass passed to the *values* argument 
of
    :meth:`OptionParser.parse_args` (as described in 
:ref:`optparse-parsing-arguments`).
 
+   :class:`!Values` objects support :func:`copy.replace`,
+   which returns a copy of the object with the specified attributes replaced.
+
+   .. versionchanged:: next
+      Added support for :func:`copy.replace`.
+
 Option
 arguments (and various other values) are stored as attributes of this object,
 according to the :attr:`~Option.dest` (destination) option attribute.
diff --git a/Lib/optparse.py b/Lib/optparse.py
index de1082442ef7f2..ae6737a3d13942 100644
--- a/Lib/optparse.py
+++ b/Lib/optparse.py
@@ -830,6 +830,12 @@ def __eq__(self, other):
         else:
             return NotImplemented
 
+    def __replace__(self, /, **changes):
+        new = self.__class__()
+        new.__dict__.update(self.__dict__)
+        new.__dict__.update(changes)
+        return new
+
     def _update_careful(self, dict):
         """
         Update the option values from an arbitrary dictionary, but only
diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py
index fc8ef9520b3c0f..9fca2dafd5c99e 100644
--- a/Lib/test/test_optparse.py
+++ b/Lib/test/test_optparse.py
@@ -434,6 +434,13 @@ def test_basics(self):
         self.assertNotEqual(values, "")
         self.assertNotEqual(values, [])
 
+    def test_replace(self):
+        values = Values(defaults={"foo": "bar", "baz": 42})
+        new = copy.replace(values, baz=43, spam="eggs")
+        self.assertIsInstance(new, Values)
+        self.assertEqual(vars(new), {"foo": "bar", "baz": 43, "spam": "eggs"})
+        self.assertEqual(vars(values), {"foo": "bar", "baz": 42})
+
 
 class TestTypeAliases(BaseTest):
     def setUp(self):
diff --git 
a/Misc/NEWS.d/next/Library/2026-08-01-19-05-00.gh-issue-155044.Op1Val.rst 
b/Misc/NEWS.d/next/Library/2026-08-01-19-05-00.gh-issue-155044.Op1Val.rst
new file mode 100644
index 00000000000000..10665f913ef5e6
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-08-01-19-05-00.gh-issue-155044.Op1Val.rst
@@ -0,0 +1 @@
+:class:`optparse.Values` objects now support :func:`copy.replace`.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to