diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst index 09416f12ad45c2..df0f2a4df4db45 100644 --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -16,15 +16,12 @@ Choosing an argument parsing library The standard library includes three argument parsing libraries: * :mod:`getopt`: a module that closely mirrors the procedural C ``getopt`` API. - Included in the standard library since before the initial Python 1.0 release. * :mod:`!optparse`: a declarative replacement for ``getopt`` that provides equivalent functionality without requiring each application - to implement its own procedural option parsing logic. Included - in the standard library since the Python 2.3 release. + to implement its own procedural option parsing logic. * :mod:`argparse`: a more opinionated alternative to ``optparse`` that provides more functionality by default, at the expense of reduced application - flexibility in controlling exactly how arguments are processed. Included in - the standard library since the Python 2.7 and Python 3.2 releases. + flexibility in controlling exactly how arguments are processed. In the absence of more specific argument parsing design constraints, :mod:`argparse` is the recommended choice for implementing command line applications, as it offers diff --git a/Lib/optparse.py b/Lib/optparse.py index ae6737a3d13942..70ca3b38b021a5 100644 --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -1,12 +1,5 @@ """A powerful, extensible, and easy-to-use option parser. -By Greg Ward - -Originally distributed as Optik. - -For support, use the optik-users@lists.sourceforge.net mailing list -(http://lists.sourceforge.net/lists/listinfo/optik-users). - Simple usage example: from optparse import OptionParser diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 205916579b5f49..dcb4eac1b77952 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -822,6 +822,18 @@ def test_decompress_unused_data(self): self.assertEqual(dco.unconsumed_tail, b'') self.assertEqual(dco.unused_data, remainder) + def test_decompress_unconsumed_tail_after_eof(self): + source = b'abcdefghijklmnopqrstuvwxyz' + remainder = b'0123456789' + dco = zlib.decompressobj() + data = dco.decompress(zlib.compress(source) + remainder, 1) + data += dco.decompress(dco.unconsumed_tail) + + self.assertTrue(dco.eof) + self.assertEqual(data, source) + self.assertEqual(dco.unconsumed_tail, b'') + self.assertEqual(dco.unused_data, remainder) + # issue27164 def test_decompress_raw_with_dictionary(self): zdict = b'abcdefghijklmnopqrstuvwxyz' diff --git a/Misc/NEWS.d/next/Library/2026-09-25-22-15-54.gh-issue-158169.ZlibTail.rst b/Misc/NEWS.d/next/Library/2026-09-25-22-15-54.gh-issue-158169.ZlibTail.rst new file mode 100644 index 00000000000000..7c965451c056a4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-25-22-15-54.gh-issue-158169.ZlibTail.rst @@ -0,0 +1,2 @@ +Fix :attr:`zlib.Decompress.unconsumed_tail` duplicating +:attr:`~zlib.Decompress.unused_data` after end of stream when *max_length* was used. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 56c119db7d10c0..31533fa047af0b 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -838,6 +838,7 @@ save_unconsumed_input(compobject *self, Py_buffer *data, int err) return -1; } Py_SETREF(self->unused_data, new_unused_data); + self->zst.next_in += left_size; self->zst.avail_in = 0; } }