From b6fd2b538da79f2b83a5a0b151482e0a3f1feecb Mon Sep 17 00:00:00 2001 From: isidentical Date: Fri, 27 Dec 2019 19:45:24 +0300 Subject: [PATCH 1/2] Implement missing __class_getitem__ for subprocess classes --- Lib/subprocess.py | 6 ++++++ Lib/test/test_subprocess.py | 3 +++ .../next/Library/2019-12-10-21-03-34.bpo-39019.i8RpMZ.rst | 2 ++ 3 files changed, 11 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2019-12-10-21-03-34.bpo-39019.i8RpMZ.rst diff --git a/Lib/subprocess.py b/Lib/subprocess.py index ba6f1983a5a227..a25cc072e1dcd8 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -446,6 +446,9 @@ def __repr__(self): args.append('stderr={!r}'.format(self.stderr)) return "{}({})".format(type(self).__name__, ', '.join(args)) + def __class_getitem__(cls, type): + return cls + def check_returncode(self): """Raise CalledProcessError if the exit code is non-zero.""" if self.returncode: @@ -987,6 +990,9 @@ def __repr__(self): obj_repr = obj_repr[:76] + "...>" return obj_repr + def __class_getitem__(cls, type): + return cls + @property def universal_newlines(self): # universal_newlines as retained as an alias of text_mode for API diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index f806be817b55bd..c5d8ae13894dcd 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1437,6 +1437,9 @@ def test_file_not_found_with_bad_cwd(self): subprocess.Popen(['exit', '0'], cwd='/some/nonexistent/directory') self.assertEqual(c.exception.filename, '/some/nonexistent/directory') + def test_class_getitems(self): + self.assertIs(subprocess.Popen[bytes], subprocess.Popen) + self.assertIs(subprocess.CompletedProcess[str], subprocess.CompletedProcess) class RunFuncTestCase(BaseTestCase): def run_python(self, code, **kwargs): diff --git a/Misc/NEWS.d/next/Library/2019-12-10-21-03-34.bpo-39019.i8RpMZ.rst b/Misc/NEWS.d/next/Library/2019-12-10-21-03-34.bpo-39019.i8RpMZ.rst new file mode 100644 index 00000000000000..b64a56edc50c7e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-12-10-21-03-34.bpo-39019.i8RpMZ.rst @@ -0,0 +1,2 @@ +Implement dummy ``__class_getitem__`` for ``subprocess.Popen``, +``subprocess.CompletedProcess`` From 74162ecbf7dbc690b8934bd49d7e5e47d8a431e2 Mon Sep 17 00:00:00 2001 From: isidentical Date: Fri, 27 Dec 2019 21:08:54 +0300 Subject: [PATCH 2/2] clarify purpose of __class_getitems__ --- Lib/subprocess.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Lib/subprocess.py b/Lib/subprocess.py index a25cc072e1dcd8..30f0d1be154c40 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -447,8 +447,18 @@ def __repr__(self): return "{}({})".format(type(self).__name__, ', '.join(args)) def __class_getitem__(cls, type): + """Provide minimal support for using this class as generic + (for example in type annotations). + + See PEP 484 and PEP 560 for more details. For example, + `CompletedProcess[bytes]` is a valid expression at runtime + (type argument `bytes` indicates the type used for stdout). + Note, no type checking happens at runtime, but a static type + checker can be used. + """ return cls + def check_returncode(self): """Raise CalledProcessError if the exit code is non-zero.""" if self.returncode: @@ -991,6 +1001,14 @@ def __repr__(self): return obj_repr def __class_getitem__(cls, type): + """Provide minimal support for using this class as generic + (for example in type annotations). + + See PEP 484 and PEP 560 for more details. For example, `Popen[bytes]` + is a valid expression at runtime (type argument `bytes` indicates the + type used for stdout). Note, no type checking happens at runtime, but + a static type checker can be used. + """ return cls @property