diff --git a/Tests/test_imageshow.py b/Tests/test_imageshow.py index 02edfdfa1f7..bf19a603362 100644 --- a/Tests/test_imageshow.py +++ b/Tests/test_imageshow.py @@ -85,11 +85,13 @@ def test_ipythonviewer(): not on_ci() or is_win32(), reason="Only run on CIs; hangs on Windows CIs", ) -def test_file_deprecated(): +def test_file_deprecated(tmp_path): + f = str(tmp_path / "temp.jpg") for viewer in ImageShow._viewers: + hopper().save(f) with pytest.warns(DeprecationWarning): try: - viewer.show_file(file="test.jpg") + viewer.show_file(file=f) except NotImplementedError: pass with pytest.raises(TypeError): diff --git a/src/PIL/ImageShow.py b/src/PIL/ImageShow.py index 2165da30732..f8829fc21e0 100644 --- a/src/PIL/ImageShow.py +++ b/src/PIL/ImageShow.py @@ -15,7 +15,6 @@ import shutil import subprocess import sys -import tempfile import warnings from shlex import quote @@ -127,6 +126,16 @@ def show_file(self, path=None, **options): os.system(self.get_command(path, **options)) return 1 + def _remove_path_after_delay(self, path): + subprocess.Popen( + [ + sys.executable, + "-c", + "import os, sys, time; time.sleep(20); os.remove(sys.argv[1])", + path, + ] + ) + # -------------------------------------------------------------------- @@ -180,16 +189,8 @@ def show_file(self, path=None, **options): path = options.pop("file") else: raise TypeError("Missing required argument: 'path'") - fd, temp_path = tempfile.mkstemp() - with os.fdopen(fd, "w") as f: - f.write(path) - with open(temp_path) as f: - subprocess.Popen( - ["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"], - shell=True, - stdin=f, - ) - os.remove(temp_path) + subprocess.call(["open", "-a", "Preview.app", path]) + self._remove_path_after_delay(path) return 1 @@ -205,6 +206,16 @@ def get_command(self, file, **options): command = self.get_command_ex(file, **options)[0] return f"({command} {quote(file)}; rm -f {quote(file)})&" + +class XDGViewer(UnixViewer): + """ + The freedesktop.org ``xdg-open`` command. + """ + + def get_command_ex(self, file, **options): + command = executable = "xdg-open" + return command, executable + def show_file(self, path=None, **options): """ Display given file. @@ -223,28 +234,11 @@ def show_file(self, path=None, **options): path = options.pop("file") else: raise TypeError("Missing required argument: 'path'") - fd, temp_path = tempfile.mkstemp() - with os.fdopen(fd, "w") as f: - f.write(path) - with open(temp_path) as f: - command = self.get_command_ex(path, **options)[0] - subprocess.Popen( - ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f - ) - os.remove(temp_path) + subprocess.Popen(["xdg-open", path]) + self._remove_path_after_delay(path) return 1 -class XDGViewer(UnixViewer): - """ - The freedesktop.org ``xdg-open`` command. - """ - - def get_command_ex(self, file, **options): - command = executable = "xdg-open" - return command, executable - - class DisplayViewer(UnixViewer): """ The ImageMagick ``display`` command. @@ -257,6 +251,32 @@ def get_command_ex(self, file, title=None, **options): command += f" -name {quote(title)}" return command, executable + def show_file(self, path=None, **options): + """ + Display given file. + + Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated, + and ``path`` should be used instead. + """ + if path is None: + if "file" in options: + warnings.warn( + "The 'file' argument is deprecated and will be removed in Pillow " + "10 (2023-07-01). Use 'path' instead.", + DeprecationWarning, + ) + path = options.pop("file") + else: + raise TypeError("Missing required argument: 'path'") + args = ["display"] + if "title" in options: + args += ["-name", options["title"]] + args.append(path) + + subprocess.Popen(args) + os.remove(path) + return 1 + class GmDisplayViewer(UnixViewer): """The GraphicsMagick ``gm display`` command.""" @@ -266,6 +286,27 @@ def get_command_ex(self, file, **options): command = "gm display" return command, executable + def show_file(self, path=None, **options): + """ + Display given file. + + Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated, + and ``path`` should be used instead. + """ + if path is None: + if "file" in options: + warnings.warn( + "The 'file' argument is deprecated and will be removed in Pillow " + "10 (2023-07-01). Use 'path' instead.", + DeprecationWarning, + ) + path = options.pop("file") + else: + raise TypeError("Missing required argument: 'path'") + subprocess.Popen(["gm", "display", path]) + os.remove(path) + return 1 + class EogViewer(UnixViewer): """The GNOME Image Viewer ``eog`` command.""" @@ -275,6 +316,27 @@ def get_command_ex(self, file, **options): command = "eog -n" return command, executable + def show_file(self, path=None, **options): + """ + Display given file. + + Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated, + and ``path`` should be used instead. + """ + if path is None: + if "file" in options: + warnings.warn( + "The 'file' argument is deprecated and will be removed in Pillow " + "10 (2023-07-01). Use 'path' instead.", + DeprecationWarning, + ) + path = options.pop("file") + else: + raise TypeError("Missing required argument: 'path'") + subprocess.Popen(["eog", "-n", path]) + os.remove(path) + return 1 + class XVViewer(UnixViewer): """ @@ -290,6 +352,32 @@ def get_command_ex(self, file, title=None, **options): command += f" -name {quote(title)}" return command, executable + def show_file(self, path=None, **options): + """ + Display given file. + + Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated, + and ``path`` should be used instead. + """ + if path is None: + if "file" in options: + warnings.warn( + "The 'file' argument is deprecated and will be removed in Pillow " + "10 (2023-07-01). Use 'path' instead.", + DeprecationWarning, + ) + path = options.pop("file") + else: + raise TypeError("Missing required argument: 'path'") + args = ["xv"] + if "title" in options: + args += ["-name", options["title"]] + args.append(path) + + subprocess.Popen(args) + os.remove(path) + return 1 + if sys.platform not in ("win32", "darwin"): # unixoids if shutil.which("xdg-open"):