{"action":"created","comment":{"url":"https://api.github.com/repos/python/cpython/pulls/comments/150270313","pull_request_review_id":75799483,"id":150270313,"diff_hunk":"@@ -412,10 +426,53 @@ def run(*popenargs, input=None, timeout=None, check=False, **kwargs):\n             stdout, stderr = process.communicate()\n             raise TimeoutExpired(process.args, timeout, output=stdout,\n                                  stderr=stderr)\n-        except:\n-            process.kill()\n-            process.wait()\n-            raise\n+        except BaseException as ex:\n+            try:\n+                if cleanup_timeout is None:\n+                    # Choose a reasonable default\n+                    if timeout:\n+                        remaining_timeout = timeout - (_time() - start_time)\n+                        cleanup_timeout = max(0.0, remaining_timeout)\n+                    elif isinstance(ex, KeyboardInterrupt):\n+                        # KeyboardInterrupts are:\n+                        # 1. Typically automatically triggered in the child, too.\n+                        #    Therefore, the child is likely to be already cleaning up\n+                        #    (if we give it the chance).\n+                        # 2. Generated interactively by humans at a keyboard.\n+                        #    If the child is well-written (exits in response to SIGINT),\n+                        #    a 1 second timeout is usually enough time for it to clean up.\n+                        #    Othwerwise, 1 second seems like a tolerable delay in response to Ctrl+C,\n+                        #    and a resonable price to pay for correct behavior in the well-written case.\n+                        cleanup_timeout = 1.0\n+                    else:\n+                        # The above reasoning does not apply to arbitrary exceptions,\n+                        # so kill the child immediately.\n+                        cleanup_timeout = 0.0\n+\n+                if cleanup_timeout == 0.0:\n+                    raise # Skip cleanup\n+\n+                # Close streams to/from child\n+                streams = (process.stdin, process.stdout, process.stderr)\n+                for f in filter(None, streams):\n+                    try:\n+                        f.close()\n+                    except:\n+                        pass  # Ignore EBADF or other errors.\n+\n+                try:\n+                    process.wait(timeout=cleanup_timeout)\n+                except:\n+                    # Ignore cleanup errors;\n+                    # original exception is always re-raised below\n+                    pass\n+            finally:\n+                # Kill the child and re-raise original exception,\n+                # regardless of successful/failed cleanup\n+                process.kill()\n+                process.wait()\n+                raise ex\n+","path":"Lib/subprocess.py","position":125,"original_position":125,"commit_id":"220b40f5613377a908e9bfe863def6179f86a3ef","original_commit_id":"220b40f5613377a908e9bfe863def6179f86a3ef","user":{"login":"pilcrow","id":119866,"avatar_url":"https://avatars3.githubusercontent.com/u/119866?v=4","gravatar_id":"","url":"https://api.github.com/users/pilcrow","html_url":"https://github.com/pilcrow","followers_url":"https://api.github.com/users/pilcrow/followers","following_url":"https://api.github.com/users/pilcrow/following{/other_user}","gists_url":"https://api.github.com/users/pilcrow/gists{/gist_id}","starred_url":"https://api.github.com/users/pilcrow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pilcrow/subscriptions","organizations_url":"https://api.github.com/users/pilcrow/orgs","repos_url":"https://api.github.com/users/pilcrow/repos","events_url":"https://api.github.com/users/pilcrow/events{/privacy}","received_events_url":"https://api.github.com/users/pilcrow/received_events","type":"User","site_admin":false},"body":"From the perspective of the child process, a TERM is at worst equivalent to a KILL, and possibly much more polite, since it _can_ be caught.  So, if we are committed to killing the child process, I'd encourage a TERM first.\r\n\r\n(It's tempting to full-on generalize this and allow something like `timeout_handler=some_func_accepting_the_process_as_arg` or `err_kill=( (0.5, SIGTERM), (0.5, SIGQUIT), (1.0, SIGKILL) )`  Those args are just illustrative, but you get the idea.)","created_at":"2017-11-10T15:55:51Z","updated_at":"2017-11-10T15:55:51Z","html_url":"https://github.com/python/cpython/pull/4283#discussion_r150270313","pull_request_url":"https://api.github.com/repos/python/cpython/pulls/4283","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/python/cpython/pulls/comments/150270313"},"html":{"href":"https://github.com/python/cpython/pull/4283#discussion_r150270313"},"pull_request":{"href":"https://api.github.com/repos/python/cpython/pulls/4283"}},"in_reply_to_id":150115925},"pull_request":{"url":"https://api.github.com/repos/python/cpython/pulls/4283","id":150699553,"html_url":"https://github.com/python/cpython/pull/4283","diff_url":"https://github.com/python/cpython/pull/4283.diff","patch_url":"https://github.com/python/cpython/pull/4283.patch","issue_url":"https://api.github.com/repos/python/cpython/issues/4283","number":4283,"state":"open","locked":false,"title":"bpo-25942: Added new parameter to subprocess.run(): cleanup_timeout","user":{"login":"stuarteberg","id":1655821,"avatar_url":"https://avatars3.githubusercontent.com/u/1655821?v=4","gravatar_id":"","url":"https://api.github.com/users/stuarteberg","html_url":"https://github.com/stuarteberg","followers_url":"https://api.github.com/users/stuarteberg/followers","following_url":"https://api.github.com/users/stuarteberg/following{/other_user}","gists_url":"https://api.github.com/users/stuarteberg/gists{/gist_id}","starred_url":"https://api.github.com/users/stuarteberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stuarteberg/subscriptions","organizations_url":"https://api.github.com/users/stuarteberg/orgs","repos_url":"https://api.github.com/users/stuarteberg/repos","events_url":"https://api.github.com/users/stuarteberg/events{/privacy}","received_events_url":"https://api.github.com/users/stuarteberg/received_events","type":"User","site_admin":false},"body":"**Summary:**\r\n\r\n`subprocess.call()` (and now also `subprocess.run()`) behave badly in the event of `SIGINT`, i.e. a user hitting `Ctrl+C` while the subprocess is running.  This was first reported by @pilcrow in [bpo-25942][1].\r\n\r\n[1]: https://bugs.python.org/issue25942\r\n\r\nSeveral possible solutions were discussed (by @vadmium, @pilcrow, and @haypo), but no action was taken.  Among them was this suggestion from @haypo:\r\n\r\n>If you really want to give time to the child process, I suggest to add a *new* optional parameter . For example `ctrlc_timeout=5.0`\r\n\r\nIMHO, that is the best option, and certainly much better than the status quo.  I've implemented that solution in this PR. (It is also similar to a proposal by @vadmium in that thread.)\r\n\r\n**Background: POSIX behavior for Ctrl+C**\r\n\r\nIn general, when the user hits `Ctrl+C`, the OS [sends `SIGINT` to *all processes* in the foreground process group][2], including any child processes launched via `subprocess call()`.  That is, both Python and it's child will automatically see the `SIGINT`; there is no need to explicitly send a duplicate `SIGINT` to the child.\r\n\r\n[2]: https://unix.stackexchange.com/a/149756/109091\r\n\r\n**What this PR does:**\r\n\r\nUpon receiving the `SIGINT` in the form of a `KeyboardInterrupt`, `call()` will wait *again* for the child process, but with `cleanup_timeout`, giving the child process time to perform cleanup actions.  If that timeout expires, then the child process is killed.  (Alternatively, during this time, the user can hit `Ctrl+C` again to immediately stop waiting and kill the child process.)\r\n\r\n**What this PR does not do:**\r\n\r\nThis PR attempts to make `subprocess.call()` behave in a less surprising manner in the context of interactive terminal applications, in which the user is likely to expect `Ctrl+C` to work properly.  If the child process does not handle `SIGINT` properly, we make no attempt to kill it via alternative means, such as `SIGTERM`.  If the developer needs such control over how the child is to be killed in the event of a `KeyboardInterrupt`, she should use the `Popen` API directly instead of calling `subprocess.call()` or `run()`.\r\n\r\n**Open question 1:**\r\n\r\nIt is not entirely clear what the default value of `cleanup_timeout` should be.  Setting it to 0 by default seems to defeat the purpose and wouldn't help naïve users write code that \"just works\".\r\n\r\nOn the other hand, setting it to an arbitrary value like `5.0` seems... arbitrary.  If the cleanup takes a long time, then we'd be killing it too soon.  But if the child doesn't handle `SIGINT` anyway, then we'd be wasting 5 seconds for no reason (unless the user hits `Ctrl+C` a second time).\r\n\r\nFor now, I've set the default value as follows:\r\n - If `timeout` was specified, use that. The child cleanup time must be less than its total expected runtime.\r\n - If `timeout` was not specified, then use `1.0`.  If the child process handles `SIGINT`, this introduces no extra delay.  If it does not handle `SIGINT`, then 1 second seems like a reasonable delay for what is likely a rare event an interactive console application.\r\n\r\n**Open question 2:**\r\n\r\nAccording to the docs, `subprocess.call()` is equivalent to `subprocess.run().returncode`.  Yet, these are currently implemented as independent functions (and I left it that way).  Is there any objection to replacing `subprocess.call()` with the following?\r\n\r\n```python\r\ndef call(*popenargs, timeout=None, cleanup_timeout=None, **kwargs):\r\n    return run(*popenargs, timeout=timeout, cleanup_timeout=cleanup_timeout, **kwargs).returncode\r\n```\r\n\r\n(That would also allow me to remove the mostly duplicated test code in this PR.)\r\n\r\n<!-- issue-number: bpo-25942 -->\r\nhttps://bugs.python.org/issue25942\r\n<!-- /issue-number -->\r\n","created_at":"2017-11-04T23:24:23Z","updated_at":"2017-11-10T15:55:51Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c252b5e360558451aaf427f3789349e6536ae5b4","assignee":{"login":"gpshead","id":68491,"avatar_url":"https://avatars2.githubusercontent.com/u/68491?v=4","gravatar_id":"","url":"https://api.github.com/users/gpshead","html_url":"https://github.com/gpshead","followers_url":"https://api.github.com/users/gpshead/followers","following_url":"https://api.github.com/users/gpshead/following{/other_user}","gists_url":"https://api.github.com/users/gpshead/gists{/gist_id}","starred_url":"https://api.github.com/users/gpshead/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gpshead/subscriptions","organizations_url":"https://api.github.com/users/gpshead/orgs","repos_url":"https://api.github.com/users/gpshead/repos","events_url":"https://api.github.com/users/gpshead/events{/privacy}","received_events_url":"https://api.github.com/users/gpshead/received_events","type":"User","site_admin":false},"assignees":[{"login":"gpshead","id":68491,"avatar_url":"https://avatars2.githubusercontent.com/u/68491?v=4","gravatar_id":"","url":"https://api.github.com/users/gpshead","html_url":"https://github.com/gpshead","followers_url":"https://api.github.com/users/gpshead/followers","following_url":"https://api.github.com/users/gpshead/following{/other_user}","gists_url":"https://api.github.com/users/gpshead/gists{/gist_id}","starred_url":"https://api.github.com/users/gpshead/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gpshead/subscriptions","organizations_url":"https://api.github.com/users/gpshead/orgs","repos_url":"https://api.github.com/users/gpshead/repos","events_url":"https://api.github.com/users/gpshead/events{/privacy}","received_events_url":"https://api.github.com/users/gpshead/received_events","type":"User","site_admin":false}],"requested_reviewers":[{"login":"gpshead","id":68491,"avatar_url":"https://avatars2.githubusercontent.com/u/68491?v=4","gravatar_id":"","url":"https://api.github.com/users/gpshead","html_url":"https://github.com/gpshead","followers_url":"https://api.github.com/users/gpshead/followers","following_url":"https://api.github.com/users/gpshead/following{/other_user}","gists_url":"https://api.github.com/users/gpshead/gists{/gist_id}","starred_url":"https://api.github.com/users/gpshead/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gpshead/subscriptions","organizations_url":"https://api.github.com/users/gpshead/orgs","repos_url":"https://api.github.com/users/gpshead/repos","events_url":"https://api.github.com/users/gpshead/events{/privacy}","received_events_url":"https://api.github.com/users/gpshead/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/python/cpython/pulls/4283/commits","review_comments_url":"https://api.github.com/repos/python/cpython/pulls/4283/comments","review_comment_url":"https://api.github.com/repos/python/cpython/pulls/comments{/number}","comments_url":"https://api.github.com/repos/python/cpython/issues/4283/comments","statuses_url":"https://api.github.com/repos/python/cpython/statuses/220b40f5613377a908e9bfe863def6179f86a3ef","head":{"label":"stuarteberg:fix-bpo-25942-subprocess-call","ref":"fix-bpo-25942-subprocess-call","sha":"220b40f5613377a908e9bfe863def6179f86a3ef","user":{"login":"stuarteberg","id":1655821,"avatar_url":"https://avatars3.githubusercontent.com/u/1655821?v=4","gravatar_id":"","url":"https://api.github.com/users/stuarteberg","html_url":"https://github.com/stuarteberg","followers_url":"https://api.github.com/users/stuarteberg/followers","following_url":"https://api.github.com/users/stuarteberg/following{/other_user}","gists_url":"https://api.github.com/users/stuarteberg/gists{/gist_id}","starred_url":"https://api.github.com/users/stuarteberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stuarteberg/subscriptions","organizations_url":"https://api.github.com/users/stuarteberg/orgs","repos_url":"https://api.github.com/users/stuarteberg/repos","events_url":"https://api.github.com/users/stuarteberg/events{/privacy}","received_events_url":"https://api.github.com/users/stuarteberg/received_events","type":"User","site_admin":false},"repo":{"id":81639651,"name":"cpython","full_name":"stuarteberg/cpython","owner":{"login":"stuarteberg","id":1655821,"avatar_url":"https://avatars3.githubusercontent.com/u/1655821?v=4","gravatar_id":"","url":"https://api.github.com/users/stuarteberg","html_url":"https://github.com/stuarteberg","followers_url":"https://api.github.com/users/stuarteberg/followers","following_url":"https://api.github.com/users/stuarteberg/following{/other_user}","gists_url":"https://api.github.com/users/stuarteberg/gists{/gist_id}","starred_url":"https://api.github.com/users/stuarteberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stuarteberg/subscriptions","organizations_url":"https://api.github.com/users/stuarteberg/orgs","repos_url":"https://api.github.com/users/stuarteberg/repos","events_url":"https://api.github.com/users/stuarteberg/events{/privacy}","received_events_url":"https://api.github.com/users/stuarteberg/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/stuarteberg/cpython","description":"The Python programming language","fork":true,"url":"https://api.github.com/repos/stuarteberg/cpython","forks_url":"https://api.github.com/repos/stuarteberg/cpython/forks","keys_url":"https://api.github.com/repos/stuarteberg/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stuarteberg/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stuarteberg/cpython/teams","hooks_url":"https://api.github.com/repos/stuarteberg/cpython/hooks","issue_events_url":"https://api.github.com/repos/stuarteberg/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/stuarteberg/cpython/events","assignees_url":"https://api.github.com/repos/stuarteberg/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/stuarteberg/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/stuarteberg/cpython/tags","blobs_url":"https://api.github.com/repos/stuarteberg/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stuarteberg/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stuarteberg/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/stuarteberg/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stuarteberg/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/stuarteberg/cpython/languages","stargazers_url":"https://api.github.com/repos/stuarteberg/cpython/stargazers","contributors_url":"https://api.github.com/repos/stuarteberg/cpython/contributors","subscribers_url":"https://api.github.com/repos/stuarteberg/cpython/subscribers","subscription_url":"https://api.github.com/repos/stuarteberg/cpython/subscription","commits_url":"https://api.github.com/repos/stuarteberg/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/stuarteberg/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/stuarteberg/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/stuarteberg/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/stuarteberg/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/stuarteberg/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stuarteberg/cpython/merges","archive_url":"https://api.github.com/repos/stuarteberg/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stuarteberg/cpython/downloads","issues_url":"https://api.github.com/repos/stuarteberg/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/stuarteberg/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/stuarteberg/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/stuarteberg/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stuarteberg/cpython/labels{/name}","releases_url":"https://api.github.com/repos/stuarteberg/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/stuarteberg/cpython/deployments","created_at":"2017-02-11T08:04:59Z","updated_at":"2017-02-11T08:05:21Z","pushed_at":"2017-11-07T15:03:12Z","git_url":"git://github.com/stuarteberg/cpython.git","ssh_url":"git@github.com:stuarteberg/cpython.git","clone_url":"https://github.com/stuarteberg/cpython.git","svn_url":"https://github.com/stuarteberg/cpython","homepage":"https://www.python.org/","size":214061,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"python:master","ref":"master","sha":"39a156c505b7dc431a0a4cffcbefca577848db38","user":{"login":"python","id":1525981,"avatar_url":"https://avatars3.githubusercontent.com/u/1525981?v=4","gravatar_id":"","url":"https://api.github.com/users/python","html_url":"https://github.com/python","followers_url":"https://api.github.com/users/python/followers","following_url":"https://api.github.com/users/python/following{/other_user}","gists_url":"https://api.github.com/users/python/gists{/gist_id}","starred_url":"https://api.github.com/users/python/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/python/subscriptions","organizations_url":"https://api.github.com/users/python/orgs","repos_url":"https://api.github.com/users/python/repos","events_url":"https://api.github.com/users/python/events{/privacy}","received_events_url":"https://api.github.com/users/python/received_events","type":"Organization","site_admin":false},"repo":{"id":81598961,"name":"cpython","full_name":"python/cpython","owner":{"login":"python","id":1525981,"avatar_url":"https://avatars3.githubusercontent.com/u/1525981?v=4","gravatar_id":"","url":"https://api.github.com/users/python","html_url":"https://github.com/python","followers_url":"https://api.github.com/users/python/followers","following_url":"https://api.github.com/users/python/following{/other_user}","gists_url":"https://api.github.com/users/python/gists{/gist_id}","starred_url":"https://api.github.com/users/python/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/python/subscriptions","organizations_url":"https://api.github.com/users/python/orgs","repos_url":"https://api.github.com/users/python/repos","events_url":"https://api.github.com/users/python/events{/privacy}","received_events_url":"https://api.github.com/users/python/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/python/cpython","description":"The Python programming language","fork":false,"url":"https://api.github.com/repos/python/cpython","forks_url":"https://api.github.com/repos/python/cpython/forks","keys_url":"https://api.github.com/repos/python/cpython/keys{/key_id}","collaborators_url":"https://api.github.com/repos/python/cpython/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/python/cpython/teams","hooks_url":"https://api.github.com/repos/python/cpython/hooks","issue_events_url":"https://api.github.com/repos/python/cpython/issues/events{/number}","events_url":"https://api.github.com/repos/python/cpython/events","assignees_url":"https://api.github.com/repos/python/cpython/assignees{/user}","branches_url":"https://api.github.com/repos/python/cpython/branches{/branch}","tags_url":"https://api.github.com/repos/python/cpython/tags","blobs_url":"https://api.github.com/repos/python/cpython/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/python/cpython/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/python/cpython/git/refs{/sha}","trees_url":"https://api.github.com/repos/python/cpython/git/trees{/sha}","statuses_url":"https://api.github.com/repos/python/cpython/statuses/{sha}","languages_url":"https://api.github.com/repos/python/cpython/languages","stargazers_url":"https://api.github.com/repos/python/cpython/stargazers","contributors_url":"https://api.github.com/repos/python/cpython/contributors","subscribers_url":"https://api.github.com/repos/python/cpython/subscribers","subscription_url":"https://api.github.com/repos/python/cpython/subscription","commits_url":"https://api.github.com/repos/python/cpython/commits{/sha}","git_commits_url":"https://api.github.com/repos/python/cpython/git/commits{/sha}","comments_url":"https://api.github.com/repos/python/cpython/comments{/number}","issue_comment_url":"https://api.github.com/repos/python/cpython/issues/comments{/number}","contents_url":"https://api.github.com/repos/python/cpython/contents/{+path}","compare_url":"https://api.github.com/repos/python/cpython/compare/{base}...{head}","merges_url":"https://api.github.com/repos/python/cpython/merges","archive_url":"https://api.github.com/repos/python/cpython/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/python/cpython/downloads","issues_url":"https://api.github.com/repos/python/cpython/issues{/number}","pulls_url":"https://api.github.com/repos/python/cpython/pulls{/number}","milestones_url":"https://api.github.com/repos/python/cpython/milestones{/number}","notifications_url":"https://api.github.com/repos/python/cpython/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/python/cpython/labels{/name}","releases_url":"https://api.github.com/repos/python/cpython/releases{/id}","deployments_url":"https://api.github.com/repos/python/cpython/deployments","created_at":"2017-02-10T19:23:51Z","updated_at":"2017-11-10T14:37:44Z","pushed_at":"2017-11-10T15:35:12Z","git_url":"git://github.com/python/cpython.git","ssh_url":"git@github.com:python/cpython.git","clone_url":"https://github.com/python/cpython.git","svn_url":"https://github.com/python/cpython","homepage":"https://www.python.org/","size":223108,"stargazers_count":14146,"watchers_count":14146,"language":"Python","has_issues":false,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":3201,"mirror_url":null,"archived":false,"open_issues_count":484,"forks":3201,"open_issues":484,"watchers":14146,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/python/cpython/pulls/4283"},"html":{"href":"https://github.com/python/cpython/pull/4283"},"issue":{"href":"https://api.github.com/repos/python/cpython/issues/4283"},"comments":{"href":"https://api.github.com/repos/python/cpython/issues/4283/comments"},"review_comments":{"href":"https://api.github.com/repos/python/cpython/pulls/4283/comments"},"review_comment":{"href":"https://api.github.com/repos/python/cpython/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/python/cpython/pulls/4283/commits"},"statuses":{"href":"https://api.github.com/repos/python/cpython/statuses/220b40f5613377a908e9bfe863def6179f86a3ef"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"pilcrow"}}