From 00610aa53372116375ceb304c9f48406dbf63753 Mon Sep 17 00:00:00 2001 From: Guilherme Martins Crocetti <24530683+gmcrocetti@users.noreply.github.com> Date: Wed, 22 Apr 2026 09:42:57 -0300 Subject: [PATCH] gh-113093: add parameter 'mode' in shelve.open, letting users control file's type and access permissions --- Doc/library/shelve.rst | 14 +++++++++----- Doc/whatsnew/3.15.rst | 3 +++ Lib/shelve.py | 12 +++++++----- Lib/test/test_shelve.py | 7 +++++++ .../2026-04-17-10-42-00.gh-issue-113093.KzsNvW.rst | 2 ++ 5 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-17-10-42-00.gh-issue-113093.KzsNvW.rst diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst index bd3d56f6af595a..5b49d86ea452e6 100644 --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -18,7 +18,7 @@ lots of shared sub-objects. The keys are ordinary strings. .. function:: open(filename, flag='c', protocol=None, writeback=False, *, \ - serializer=None, deserializer=None) + mode=0o666, serializer=None, deserializer=None) Open a persistent dictionary. The filename specified is the base filename for the underlying database. As a side-effect, an extension may be added to the @@ -42,6 +42,9 @@ lots of shared sub-objects. The keys are ordinary strings. determine which accessed entries are mutable, nor which ones were actually mutated). + The optional *mode* parameter controls the file mode (permissions) when creating + a new shelf. It has the same interpretation as the *mode* parameter of :func:`dbm.open`. + By default, :mod:`!shelve` uses :func:`pickle.dumps` and :func:`pickle.loads` for serializing and deserializing. This can be changed by supplying *serializer* and *deserializer*, respectively. @@ -66,7 +69,8 @@ lots of shared sub-objects. The keys are ordinary strings. .. versionchanged:: 3.15 Accepts custom *serializer* and *deserializer* functions in place of - :func:`pickle.dumps` and :func:`pickle.loads`. + :func:`pickle.dumps` and :func:`pickle.loads`. Accepts *mode* to + control file mode, behavior is the same as in :func:`dbm.open`. .. note:: @@ -209,19 +213,19 @@ Restrictions .. class:: DbfilenameShelf(filename, flag='c', protocol=None, \ - writeback=False, *, serializer=None, \ + writeback=False, *, mode=0o666, serializer=None \ deserializer=None) A subclass of :class:`Shelf` which accepts a *filename* instead of a dict-like object. The underlying file will be opened using :func:`dbm.open`. By default, the file will be created and opened for both read and write. The optional *flag* parameter has the same interpretation as for the - :func:`.open` function. The optional *protocol*, *writeback*, *serializer* + :func:`.open` function. The optional *mode*, *protocol*, *writeback*, *serializer* and *deserializer* parameters have the same interpretation as in :func:`~shelve.open`. .. versionchanged:: 3.15 - Added the *serializer* and *deserializer* parameters. + Added the *mode*, *serializer* and *deserializer* parameters. .. _shelve-example: diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index c4dac339be66af..f4a27dc67c5be0 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1014,6 +1014,9 @@ shelve in the :mod:`shelve` module. (Contributed by Furkan Onder in :gh:`99631`.) +* Add suport for custom mode in :func:`shelve.open`. + (Contributed by Guilherme Crocetti in :gh:`113093`.) + socket ------ diff --git a/Lib/shelve.py b/Lib/shelve.py index 9f6296667fdb6b..ad0c5574fd9a1c 100644 --- a/Lib/shelve.py +++ b/Lib/shelve.py @@ -236,9 +236,9 @@ class DbfilenameShelf(Shelf): """ def __init__(self, filename, flag='c', protocol=None, writeback=False, *, - serializer=None, deserializer=None): + mode=0o666, serializer=None, deserializer=None): import dbm - Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback, + Shelf.__init__(self, dbm.open(filename, flag, mode), protocol, writeback, serializer=serializer, deserializer=deserializer) def clear(self): @@ -249,7 +249,7 @@ def clear(self): self.dict.clear() def open(filename, flag='c', protocol=None, writeback=False, *, - serializer=None, deserializer=None): + mode=0o666, serializer=None, deserializer=None): """Open a persistent dictionary for reading and writing. The filename parameter is the base filename for the underlying @@ -257,10 +257,12 @@ def open(filename, flag='c', protocol=None, writeback=False, *, filename and more than one file may be created. The optional flag parameter has the same interpretation as the flag parameter of dbm.open(). The optional protocol parameter specifies the - version of the pickle protocol. + version of the pickle protocol. The optional mode parameter is + passed to dbm.open() and controls the file mode when creating a + new shelf, set to 0666 by default. See the module's __doc__ string for an overview of the interface. """ - return DbfilenameShelf(filename, flag, protocol, writeback, + return DbfilenameShelf(filename, flag, protocol, writeback, mode=mode, serializer=serializer, deserializer=deserializer) diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py index 5f6a030e018f96..5f65c9d33e8308 100644 --- a/Lib/test/test_shelve.py +++ b/Lib/test/test_shelve.py @@ -5,6 +5,7 @@ import pickle import os +from unittest import mock from test.support import import_helper, os_helper, subTests from collections.abc import MutableMapping from test.test_dbm import dbm_iterator @@ -47,6 +48,12 @@ class TestCase(unittest.TestCase): dirname = os_helper.TESTFN fn = os.path.join(os_helper.TESTFN, "shelftemp.db") + @mock.patch("dbm.open", autospec=True) + def test_open_calls_dbm_as_expected(self, dbm_open): + shelf_open_mode = 0o433 + shelve.open(filename=self.fn, mode=shelf_open_mode) + dbm_open.assert_called_once_with(self.fn, 'c', shelf_open_mode) + def test_close(self): d1 = {} s = shelve.Shelf(d1, protocol=2, writeback=False) diff --git a/Misc/NEWS.d/next/Library/2026-04-17-10-42-00.gh-issue-113093.KzsNvW.rst b/Misc/NEWS.d/next/Library/2026-04-17-10-42-00.gh-issue-113093.KzsNvW.rst new file mode 100644 index 00000000000000..f479ac89497a3c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-17-10-42-00.gh-issue-113093.KzsNvW.rst @@ -0,0 +1,2 @@ +Add parameter *mode* in :func:`shelve.open`. +Patch by Guilherme Crocetti.