From 369b498219be791ebec8233208f08f07621b8359 Mon Sep 17 00:00:00 2001 From: Yves Weissig Date: Fri, 18 Aug 2023 17:52:57 +0100 Subject: [PATCH] Fixed #34642 -- Added File.open() support for *args and **kwargs. --- AUTHORS | 1 + django/core/files/base.py | 4 ++-- docs/ref/files/file.txt | 9 +++++++-- docs/releases/5.0.txt | 3 ++- tests/files/tests.py | 15 +++++++++++++++ 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6593f0889f..1f51cff05c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1053,6 +1053,7 @@ answer newbie questions, and generally made Django that much better: Yoong Kang Lim Yury V. Zaytsev Yusuke Miyazaki + Yves Weissig yyyyyyyan Zac Hatfield-Dodds Zachary Voase diff --git a/django/core/files/base.py b/django/core/files/base.py index 3ca43ec254..9682467afa 100644 --- a/django/core/files/base.py +++ b/django/core/files/base.py @@ -105,11 +105,11 @@ class File(FileProxyMixin): def __exit__(self, exc_type, exc_value, tb): self.close() - def open(self, mode=None): + def open(self, mode=None, *args, **kwargs): if not self.closed: self.seek(0) elif self.name and os.path.exists(self.name): - self.file = open(self.name, mode or self.mode) + self.file = open(self.name, mode or self.mode, *args, **kwargs) else: raise ValueError("The file cannot be reopened.") return self diff --git a/docs/ref/files/file.txt b/docs/ref/files/file.txt index 650bbb7079..ea9bf0968e 100644 --- a/docs/ref/files/file.txt +++ b/docs/ref/files/file.txt @@ -46,11 +46,12 @@ The ``File`` class The read/write mode for the file. - .. method:: open(mode=None) + .. method:: open(mode=None, *args, **kwargs) Open or reopen the file (which also does ``File.seek(0)``). The ``mode`` argument allows the same values - as Python's built-in :func:`python:open()`. + as Python's built-in :func:`python:open()`. ``*args`` and ``**kwargs`` + are passed after ``mode`` to Python's built-in :func:`python:open`. When reopening a file, ``mode`` will override whatever mode the file was originally opened with; ``None`` means to reopen with the original @@ -58,6 +59,10 @@ The ``File`` class It can be used as a context manager, e.g. ``with file.open() as f:``. + .. versionchanged:: 5.0 + + Support for passing ``*args`` and ``**kwargs`` was added. + .. method:: __iter__() Iterate over the file yielding one line at a time. diff --git a/docs/releases/5.0.txt b/docs/releases/5.0.txt index b9a871c8e9..2e23e40cbf 100644 --- a/docs/releases/5.0.txt +++ b/docs/releases/5.0.txt @@ -352,7 +352,8 @@ Error Reporting File Storage ~~~~~~~~~~~~ -* ... +* :meth:`.File.open` now passes all positional (``*args``) and keyword + arguments (``**kwargs``) to Python's built-in :func:`python:open`. File Uploads ~~~~~~~~~~~~ diff --git a/tests/files/tests.py b/tests/files/tests.py index b3478d2732..7dc5c04668 100644 --- a/tests/files/tests.py +++ b/tests/files/tests.py @@ -200,6 +200,21 @@ class FileTests(unittest.TestCase): self.assertIs(locks.unlock(f1), True) self.assertIs(locks.unlock(f2), True) + def test_open_supports_full_signature(self): + called = False + + def opener(path, flags): + nonlocal called + called = True + return os.open(path, flags) + + file_path = Path(__file__).parent / "test.png" + with open(file_path) as f: + test_file = File(f) + + with test_file.open(opener=opener): + self.assertIs(called, True) + class NoNameFileTestCase(unittest.TestCase): """