{"action":"created","comment":{"url":"https://api.github.com/repos/spyder-ide/spyder/pulls/comments/244660529","pull_request_review_id":188582873,"id":244660529,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI0NDY2MDUyOQ==","diff_hunk":"@@ -0,0 +1,223 @@\n+# -*- coding: utf-8 -*-\n+#\n+# Copyright © Spyder Project Contributors\n+# Licensed under the terms of the MIT License\n+# (see spyder/__init__.py for details)\n+\n+\"\"\"Autosave components for the Editor plugin and the EditorStack widget\"\"\"\n+\n+# Standard library imports\n+import logging\n+import os\n+import os.path as osp\n+\n+# Third party imports\n+from qtpy.QtCore import QTimer\n+\n+# Local imports\n+from spyder.config.base import get_conf_path\n+from spyder.config.main import CONF\n+from spyder.plugins.editor.widgets.recover import RecoveryDialog\n+\n+\n+logger = logging.getLogger(__name__)\n+\n+\n+class AutosaveForPlugin(object):\n+    \"\"\"Component of editor plugin implementing autosave functionality.\"\"\"\n+\n+    # Interval (in ms) between two autosaves\n+    DEFAULT_AUTOSAVE_INTERVAL = 60 * 1000\n+\n+    def __init__(self, editor):\n+        \"\"\"\n+        Constructor.\n+\n+        Autosave is disabled after construction and needs to be enabled\n+        explicitly if required.\n+\n+        Args:\n+            editor (Editor): editor plugin.\n+        \"\"\"\n+        self.editor = editor\n+        self.timer = QTimer(self.editor)\n+        self.timer.setSingleShot(True)\n+        self.timer.timeout.connect(self.do_autosave)\n+        self._enabled = False  # Can't use setter here\n+        self._interval = self.DEFAULT_AUTOSAVE_INTERVAL\n+\n+    @property\n+    def enabled(self):\n+        \"\"\"\n+        Get or set whether autosave component is enabled.\n+\n+        The setter will start or stop the autosave component if appropriate.\n+        \"\"\"\n+        return self._enabled\n+\n+    @enabled.setter\n+    def enabled(self, new_enabled):\n+        if new_enabled == self.enabled:\n+            return\n+        self.stop_autosave_timer()\n+        self._enabled = new_enabled\n+        self.start_autosave_timer()\n+\n+    @property\n+    def interval(self):\n+        \"\"\"\n+        Interval between two autosaves, in milliseconds.\n+\n+        The setter will perform an autosave if the interval is changed and\n+        autosave is enabled.\n+        \"\"\"\n+        return self._interval\n+\n+    @interval.setter\n+    def interval(self, new_interval):\n+        if new_interval == self.interval:\n+            return\n+        self.stop_autosave_timer()\n+        self._interval = new_interval\n+        if self.enabled:\n+            self.do_autosave()\n+\n+    def start_autosave_timer(self):\n+        \"\"\"\n+        Start a timer which calls do_autosave() after `self.interval`.\n+\n+        The autosave timer is only started if autosave is enabled.\n+        \"\"\"\n+        if self.enabled:\n+            self.timer.start(self.interval)\n+\n+    def stop_autosave_timer(self):\n+        \"\"\"Stop the autosave timer.\"\"\"\n+        self.timer.stop()\n+\n+    def do_autosave(self):\n+        \"\"\"Instruct current editorstack to autosave files where necessary.\"\"\"\n+        logger.debug('Autosave triggered')\n+        stack = self.editor.get_current_editorstack()\n+        stack.autosave.autosave_all()\n+        self.start_autosave_timer()\n+\n+    def try_recover_from_autosave(self):\n+        \"\"\"Offer to recover files from autosave.\"\"\"\n+        autosave_dir = get_conf_path('autosave')\n+        autosave_mapping = CONF.get('editor', 'autosave_mapping', {})\n+        dialog = RecoveryDialog(autosave_dir, autosave_mapping,\n+                                parent=self.editor)\n+        dialog.exec_if_nonempty()\n+        self.recover_files_to_open = dialog.files_to_open[:]\n+\n+\n+class AutosaveForStack(object):\n+    \"\"\"\n+    Component of EditorStack implementing autosave functionality.\n+\n+    Attributes:\n+        stack (EditorStack): editor stack this component belongs to.\n+        name_mapping (dict): map between names of opened and autosave files.\n+    \"\"\"\n+\n+    def __init__(self, editorstack):\n+        \"\"\"\n+        Constructor.\n+\n+        Args:\n+            editorstack (EditorStack): editor stack this component belongs to.\n+        \"\"\"\n+        self.stack = editorstack\n+        self.name_mapping = {}\n+\n+    def create_unique_autosave_filename(self, filename, autosave_dir):\n+        \"\"\"\n+        Create unique autosave file name for specified file name.\n+\n+        Args:\n+            filename (str): original file name\n+            autosave_dir (str): directory in which autosave files are stored\n+        \"\"\"\n+        basename = osp.basename(filename)\n+        autosave_filename = osp.join(autosave_dir, basename)\n+        if autosave_filename in self.name_mapping.values():\n+            counter = 0\n+            root, ext = osp.splitext(basename)\n+            while autosave_filename in self.name_mapping.values():\n+                counter += 1\n+                autosave_basename = '{}-{}{}'.format(root, counter, ext)\n+                autosave_filename = osp.join(autosave_dir, autosave_basename)\n+        return autosave_filename\n+\n+    def remove_autosave_file(self, fileinfo):\n+        \"\"\"\n+        Remove autosave file for specified file.\n+\n+        This function also updates `self.autosave_mapping` and clears the\n+        `changed_since_autosave` flag.\n+        \"\"\"\n+        filename = fileinfo.filename\n+        if filename not in self.name_mapping:\n+            return\n+        autosave_filename = self.name_mapping[filename]\n+        os.remove(autosave_filename)","path":"spyder/plugins/editor/utils/autosave.py","position":164,"original_position":164,"commit_id":"d3b5639c22228c2a6d99f620b872aa20d31b4d06","original_commit_id":"d3b5639c22228c2a6d99f620b872aa20d31b4d06","user":{"login":"jitseniesen","id":7941918,"node_id":"MDQ6VXNlcjc5NDE5MTg=","avatar_url":"https://avatars3.githubusercontent.com/u/7941918?v=4","gravatar_id":"","url":"https://api.github.com/users/jitseniesen","html_url":"https://github.com/jitseniesen","followers_url":"https://api.github.com/users/jitseniesen/followers","following_url":"https://api.github.com/users/jitseniesen/following{/other_user}","gists_url":"https://api.github.com/users/jitseniesen/gists{/gist_id}","starred_url":"https://api.github.com/users/jitseniesen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jitseniesen/subscriptions","organizations_url":"https://api.github.com/users/jitseniesen/orgs","repos_url":"https://api.github.com/users/jitseniesen/repos","events_url":"https://api.github.com/users/jitseniesen/events{/privacy}","received_events_url":"https://api.github.com/users/jitseniesen/received_events","type":"User","site_admin":false},"body":"Errors when removing autosave files are now ignored. Regarding errors when autosave itself fails, see the discussion of ` spyder/plugins/editor/widgets/tests/test_editor.py ` line 702 below.","created_at":"2019-01-02T04:09:15Z","updated_at":"2019-01-02T04:09:15Z","html_url":"https://github.com/spyder-ide/spyder/pull/7660#discussion_r244660529","pull_request_url":"https://api.github.com/repos/spyder-ide/spyder/pulls/7660","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/spyder-ide/spyder/pulls/comments/244660529"},"html":{"href":"https://github.com/spyder-ide/spyder/pull/7660#discussion_r244660529"},"pull_request":{"href":"https://api.github.com/repos/spyder-ide/spyder/pulls/7660"}},"in_reply_to_id":236764220},"pull_request":{"url":"https://api.github.com/repos/spyder-ide/spyder/pulls/7660","id":207241045,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA3MjQxMDQ1","html_url":"https://github.com/spyder-ide/spyder/pull/7660","diff_url":"https://github.com/spyder-ide/spyder/pull/7660.diff","patch_url":"https://github.com/spyder-ide/spyder/pull/7660.patch","issue_url":"https://api.github.com/repos/spyder-ide/spyder/issues/7660","number":7660,"state":"open","locked":false,"title":"PR: Implement autosave in editor","user":{"login":"jitseniesen","id":7941918,"node_id":"MDQ6VXNlcjc5NDE5MTg=","avatar_url":"https://avatars3.githubusercontent.com/u/7941918?v=4","gravatar_id":"","url":"https://api.github.com/users/jitseniesen","html_url":"https://github.com/jitseniesen","followers_url":"https://api.github.com/users/jitseniesen/followers","following_url":"https://api.github.com/users/jitseniesen/following{/other_user}","gists_url":"https://api.github.com/users/jitseniesen/gists{/gist_id}","starred_url":"https://api.github.com/users/jitseniesen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jitseniesen/subscriptions","organizations_url":"https://api.github.com/users/jitseniesen/orgs","repos_url":"https://api.github.com/users/jitseniesen/repos","events_url":"https://api.github.com/users/jitseniesen/events{/privacy}","received_events_url":"https://api.github.com/users/jitseniesen/received_events","type":"User","site_admin":false},"body":"### Pull Request Checklist\r\n\r\n* [x] Read and followed this repo's [Contributing Guidelines](https://github.com/spyder-ide/spyder/blob/master/CONTRIBUTING.md)\r\n* [x] Based your PR on the latest version of the correct branch (master or 3.x)\r\n* [x] Followed [PEP8](https://www.python.org/dev/peps/pep-0008/) for code style\r\n* [x] Ensured your pull request hasn't eliminated unrelated blank lines/spaces,\r\n      modified the ``spyder/defaults`` directory, or added new icons/assets\r\n* [x] Wrote at least one-line docstrings for any new functions\r\n* [x] Added at least one unit test covering the changes, if at all possible\r\n* [x] Described your changes and the motivation for them below\r\n* [x] Noted what issue(s) this pull request resolves, creating one if needed\r\n* [x] Included a screenshot, if this PR makes any visible changes to the UI\r\n\r\n### To do\r\n* [x] Editor reloading file because it changed on disk should not trigger an autosave\r\n\r\nFollowing CAM Gerlach's review:\r\n* [x] Shorten text at top of recovery dialog and use tooltips on buttons instead\r\n* [x] Reformat list of files in recovery dialog, maybe using table widget or rules\r\n* [x] Try making `Size:` and `Last modified:` italics\r\n* [x] Use `localtime` and `'%Y-%m-%d %H:%M:%S'` format when listing time\r\n* [x] Add preferences for turning autosave off and specifying autosave interval\r\n* [x] Format docstring of `recovery_data_key_function`\r\n* [x] Format docstrings of test functions to comply with relevant PEP standard\r\n* [x] Include a test for a graceful handling of when the autosave is unsuccessful\r\n* [x] Further tweak to text in recovery dialog window\r\n\r\n## Description of Changes\r\n\r\nEvery minute, save a copy of every file in the editor with unsaved changes in a new autosave directory, which lives under the spyder config directory. This autosave file is removed when it is no longer needed (e.g. when the user saves the file manually). On startup, check the autosave directory and offer to recover any files which are found there. This should enable the user to recover most of their work in the case of a crash.\r\n\r\nI will write a more complete description in the comment below.\r\n\r\n### Issue(s) Resolved\r\n\r\nFixes #2111\r\n","created_at":"2018-08-09T08:40:39Z","updated_at":"2019-01-02T04:09:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f8c6dddaa387cc25183c16310a12702511291a4e","assignee":{"login":"jitseniesen","id":7941918,"node_id":"MDQ6VXNlcjc5NDE5MTg=","avatar_url":"https://avatars3.githubusercontent.com/u/7941918?v=4","gravatar_id":"","url":"https://api.github.com/users/jitseniesen","html_url":"https://github.com/jitseniesen","followers_url":"https://api.github.com/users/jitseniesen/followers","following_url":"https://api.github.com/users/jitseniesen/following{/other_user}","gists_url":"https://api.github.com/users/jitseniesen/gists{/gist_id}","starred_url":"https://api.github.com/users/jitseniesen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jitseniesen/subscriptions","organizations_url":"https://api.github.com/users/jitseniesen/orgs","repos_url":"https://api.github.com/users/jitseniesen/repos","events_url":"https://api.github.com/users/jitseniesen/events{/privacy}","received_events_url":"https://api.github.com/users/jitseniesen/received_events","type":"User","site_admin":false},"assignees":[{"login":"jitseniesen","id":7941918,"node_id":"MDQ6VXNlcjc5NDE5MTg=","avatar_url":"https://avatars3.githubusercontent.com/u/7941918?v=4","gravatar_id":"","url":"https://api.github.com/users/jitseniesen","html_url":"https://github.com/jitseniesen","followers_url":"https://api.github.com/users/jitseniesen/followers","following_url":"https://api.github.com/users/jitseniesen/following{/other_user}","gists_url":"https://api.github.com/users/jitseniesen/gists{/gist_id}","starred_url":"https://api.github.com/users/jitseniesen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jitseniesen/subscriptions","organizations_url":"https://api.github.com/users/jitseniesen/orgs","repos_url":"https://api.github.com/users/jitseniesen/repos","events_url":"https://api.github.com/users/jitseniesen/events{/privacy}","received_events_url":"https://api.github.com/users/jitseniesen/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":177786063,"node_id":"MDU6TGFiZWwxNzc3ODYwNjM=","url":"https://api.github.com/repos/spyder-ide/spyder/labels/component:Editor","name":"component:Editor","color":"d4c5f9","default":false},{"id":821131168,"node_id":"MDU6TGFiZWw4MjExMzExNjg=","url":"https://api.github.com/repos/spyder-ide/spyder/labels/status:Ready%20For%20Review","name":"status:Ready For Review","color":"0e8a16","default":false},{"id":517492141,"node_id":"MDU6TGFiZWw1MTc0OTIxNDE=","url":"https://api.github.com/repos/spyder-ide/spyder/labels/type:Feature","name":"type:Feature","color":"e99695","default":false}],"milestone":{"url":"https://api.github.com/repos/spyder-ide/spyder/milestones/44","html_url":"https://github.com/spyder-ide/spyder/milestone/44","labels_url":"https://api.github.com/repos/spyder-ide/spyder/milestones/44/labels","id":2322046,"node_id":"MDk6TWlsZXN0b25lMjMyMjA0Ng==","number":44,"title":"v4.0beta2","description":"","creator":{"login":"ccordoba12","id":365293,"node_id":"MDQ6VXNlcjM2NTI5Mw==","avatar_url":"https://avatars3.githubusercontent.com/u/365293?v=4","gravatar_id":"","url":"https://api.github.com/users/ccordoba12","html_url":"https://github.com/ccordoba12","followers_url":"https://api.github.com/users/ccordoba12/followers","following_url":"https://api.github.com/users/ccordoba12/following{/other_user}","gists_url":"https://api.github.com/users/ccordoba12/gists{/gist_id}","starred_url":"https://api.github.com/users/ccordoba12/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ccordoba12/subscriptions","organizations_url":"https://api.github.com/users/ccordoba12/orgs","repos_url":"https://api.github.com/users/ccordoba12/repos","events_url":"https://api.github.com/users/ccordoba12/events{/privacy}","received_events_url":"https://api.github.com/users/ccordoba12/received_events","type":"User","site_admin":false},"open_issues":11,"closed_issues":198,"state":"open","created_at":"2017-02-14T15:29:33Z","updated_at":"2019-01-02T03:46:40Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/spyder-ide/spyder/pulls/7660/commits","review_comments_url":"https://api.github.com/repos/spyder-ide/spyder/pulls/7660/comments","review_comment_url":"https://api.github.com/repos/spyder-ide/spyder/pulls/comments{/number}","comments_url":"https://api.github.com/repos/spyder-ide/spyder/issues/7660/comments","statuses_url":"https://api.github.com/repos/spyder-ide/spyder/statuses/d3b5639c22228c2a6d99f620b872aa20d31b4d06","head":{"label":"jitseniesen:autosave-v2","ref":"autosave-v2","sha":"d3b5639c22228c2a6d99f620b872aa20d31b4d06","user":{"login":"jitseniesen","id":7941918,"node_id":"MDQ6VXNlcjc5NDE5MTg=","avatar_url":"https://avatars3.githubusercontent.com/u/7941918?v=4","gravatar_id":"","url":"https://api.github.com/users/jitseniesen","html_url":"https://github.com/jitseniesen","followers_url":"https://api.github.com/users/jitseniesen/followers","following_url":"https://api.github.com/users/jitseniesen/following{/other_user}","gists_url":"https://api.github.com/users/jitseniesen/gists{/gist_id}","starred_url":"https://api.github.com/users/jitseniesen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jitseniesen/subscriptions","organizations_url":"https://api.github.com/users/jitseniesen/orgs","repos_url":"https://api.github.com/users/jitseniesen/repos","events_url":"https://api.github.com/users/jitseniesen/events{/privacy}","received_events_url":"https://api.github.com/users/jitseniesen/received_events","type":"User","site_admin":false},"repo":{"id":49170417,"node_id":"MDEwOlJlcG9zaXRvcnk0OTE3MDQxNw==","name":"spyder","full_name":"jitseniesen/spyder","private":false,"owner":{"login":"jitseniesen","id":7941918,"node_id":"MDQ6VXNlcjc5NDE5MTg=","avatar_url":"https://avatars3.githubusercontent.com/u/7941918?v=4","gravatar_id":"","url":"https://api.github.com/users/jitseniesen","html_url":"https://github.com/jitseniesen","followers_url":"https://api.github.com/users/jitseniesen/followers","following_url":"https://api.github.com/users/jitseniesen/following{/other_user}","gists_url":"https://api.github.com/users/jitseniesen/gists{/gist_id}","starred_url":"https://api.github.com/users/jitseniesen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jitseniesen/subscriptions","organizations_url":"https://api.github.com/users/jitseniesen/orgs","repos_url":"https://api.github.com/users/jitseniesen/repos","events_url":"https://api.github.com/users/jitseniesen/events{/privacy}","received_events_url":"https://api.github.com/users/jitseniesen/received_events","type":"User","site_admin":false},"html_url":"https://github.com/jitseniesen/spyder","description":"Jitse Niesen's repository for Spyder - The Scientific PYthon Development EnviRonment","fork":true,"url":"https://api.github.com/repos/jitseniesen/spyder","forks_url":"https://api.github.com/repos/jitseniesen/spyder/forks","keys_url":"https://api.github.com/repos/jitseniesen/spyder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jitseniesen/spyder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jitseniesen/spyder/teams","hooks_url":"https://api.github.com/repos/jitseniesen/spyder/hooks","issue_events_url":"https://api.github.com/repos/jitseniesen/spyder/issues/events{/number}","events_url":"https://api.github.com/repos/jitseniesen/spyder/events","assignees_url":"https://api.github.com/repos/jitseniesen/spyder/assignees{/user}","branches_url":"https://api.github.com/repos/jitseniesen/spyder/branches{/branch}","tags_url":"https://api.github.com/repos/jitseniesen/spyder/tags","blobs_url":"https://api.github.com/repos/jitseniesen/spyder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jitseniesen/spyder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jitseniesen/spyder/git/refs{/sha}","trees_url":"https://api.github.com/repos/jitseniesen/spyder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jitseniesen/spyder/statuses/{sha}","languages_url":"https://api.github.com/repos/jitseniesen/spyder/languages","stargazers_url":"https://api.github.com/repos/jitseniesen/spyder/stargazers","contributors_url":"https://api.github.com/repos/jitseniesen/spyder/contributors","subscribers_url":"https://api.github.com/repos/jitseniesen/spyder/subscribers","subscription_url":"https://api.github.com/repos/jitseniesen/spyder/subscription","commits_url":"https://api.github.com/repos/jitseniesen/spyder/commits{/sha}","git_commits_url":"https://api.github.com/repos/jitseniesen/spyder/git/commits{/sha}","comments_url":"https://api.github.com/repos/jitseniesen/spyder/comments{/number}","issue_comment_url":"https://api.github.com/repos/jitseniesen/spyder/issues/comments{/number}","contents_url":"https://api.github.com/repos/jitseniesen/spyder/contents/{+path}","compare_url":"https://api.github.com/repos/jitseniesen/spyder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jitseniesen/spyder/merges","archive_url":"https://api.github.com/repos/jitseniesen/spyder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jitseniesen/spyder/downloads","issues_url":"https://api.github.com/repos/jitseniesen/spyder/issues{/number}","pulls_url":"https://api.github.com/repos/jitseniesen/spyder/pulls{/number}","milestones_url":"https://api.github.com/repos/jitseniesen/spyder/milestones{/number}","notifications_url":"https://api.github.com/repos/jitseniesen/spyder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jitseniesen/spyder/labels{/name}","releases_url":"https://api.github.com/repos/jitseniesen/spyder/releases{/id}","deployments_url":"https://api.github.com/repos/jitseniesen/spyder/deployments","created_at":"2016-01-07T00:30:26Z","updated_at":"2018-09-03T13:23:21Z","pushed_at":"2018-11-25T17:56:01Z","git_url":"git://github.com/jitseniesen/spyder.git","ssh_url":"git@github.com:jitseniesen/spyder.git","clone_url":"https://github.com/jitseniesen/spyder.git","svn_url":"https://github.com/jitseniesen/spyder","homepage":"","size":47600,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"spyder-ide:master","ref":"master","sha":"bc6d741d5d85087b8a6d7d068e7fc91773879fce","user":{"login":"spyder-ide","id":1284937,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEyODQ5Mzc=","avatar_url":"https://avatars1.githubusercontent.com/u/1284937?v=4","gravatar_id":"","url":"https://api.github.com/users/spyder-ide","html_url":"https://github.com/spyder-ide","followers_url":"https://api.github.com/users/spyder-ide/followers","following_url":"https://api.github.com/users/spyder-ide/following{/other_user}","gists_url":"https://api.github.com/users/spyder-ide/gists{/gist_id}","starred_url":"https://api.github.com/users/spyder-ide/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spyder-ide/subscriptions","organizations_url":"https://api.github.com/users/spyder-ide/orgs","repos_url":"https://api.github.com/users/spyder-ide/repos","events_url":"https://api.github.com/users/spyder-ide/events{/privacy}","received_events_url":"https://api.github.com/users/spyder-ide/received_events","type":"Organization","site_admin":false},"repo":{"id":30892477,"node_id":"MDEwOlJlcG9zaXRvcnkzMDg5MjQ3Nw==","name":"spyder","full_name":"spyder-ide/spyder","private":false,"owner":{"login":"spyder-ide","id":1284937,"node_id":"MDEyOk9yZ2FuaXphdGlvbjEyODQ5Mzc=","avatar_url":"https://avatars1.githubusercontent.com/u/1284937?v=4","gravatar_id":"","url":"https://api.github.com/users/spyder-ide","html_url":"https://github.com/spyder-ide","followers_url":"https://api.github.com/users/spyder-ide/followers","following_url":"https://api.github.com/users/spyder-ide/following{/other_user}","gists_url":"https://api.github.com/users/spyder-ide/gists{/gist_id}","starred_url":"https://api.github.com/users/spyder-ide/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spyder-ide/subscriptions","organizations_url":"https://api.github.com/users/spyder-ide/orgs","repos_url":"https://api.github.com/users/spyder-ide/repos","events_url":"https://api.github.com/users/spyder-ide/events{/privacy}","received_events_url":"https://api.github.com/users/spyder-ide/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/spyder-ide/spyder","description":"Official repository for Spyder - The Scientific Python Development Environment","fork":false,"url":"https://api.github.com/repos/spyder-ide/spyder","forks_url":"https://api.github.com/repos/spyder-ide/spyder/forks","keys_url":"https://api.github.com/repos/spyder-ide/spyder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/spyder-ide/spyder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/spyder-ide/spyder/teams","hooks_url":"https://api.github.com/repos/spyder-ide/spyder/hooks","issue_events_url":"https://api.github.com/repos/spyder-ide/spyder/issues/events{/number}","events_url":"https://api.github.com/repos/spyder-ide/spyder/events","assignees_url":"https://api.github.com/repos/spyder-ide/spyder/assignees{/user}","branches_url":"https://api.github.com/repos/spyder-ide/spyder/branches{/branch}","tags_url":"https://api.github.com/repos/spyder-ide/spyder/tags","blobs_url":"https://api.github.com/repos/spyder-ide/spyder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/spyder-ide/spyder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/spyder-ide/spyder/git/refs{/sha}","trees_url":"https://api.github.com/repos/spyder-ide/spyder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/spyder-ide/spyder/statuses/{sha}","languages_url":"https://api.github.com/repos/spyder-ide/spyder/languages","stargazers_url":"https://api.github.com/repos/spyder-ide/spyder/stargazers","contributors_url":"https://api.github.com/repos/spyder-ide/spyder/contributors","subscribers_url":"https://api.github.com/repos/spyder-ide/spyder/subscribers","subscription_url":"https://api.github.com/repos/spyder-ide/spyder/subscription","commits_url":"https://api.github.com/repos/spyder-ide/spyder/commits{/sha}","git_commits_url":"https://api.github.com/repos/spyder-ide/spyder/git/commits{/sha}","comments_url":"https://api.github.com/repos/spyder-ide/spyder/comments{/number}","issue_comment_url":"https://api.github.com/repos/spyder-ide/spyder/issues/comments{/number}","contents_url":"https://api.github.com/repos/spyder-ide/spyder/contents/{+path}","compare_url":"https://api.github.com/repos/spyder-ide/spyder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/spyder-ide/spyder/merges","archive_url":"https://api.github.com/repos/spyder-ide/spyder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/spyder-ide/spyder/downloads","issues_url":"https://api.github.com/repos/spyder-ide/spyder/issues{/number}","pulls_url":"https://api.github.com/repos/spyder-ide/spyder/pulls{/number}","milestones_url":"https://api.github.com/repos/spyder-ide/spyder/milestones{/number}","notifications_url":"https://api.github.com/repos/spyder-ide/spyder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/spyder-ide/spyder/labels{/name}","releases_url":"https://api.github.com/repos/spyder-ide/spyder/releases{/id}","deployments_url":"https://api.github.com/repos/spyder-ide/spyder/deployments","created_at":"2015-02-16T22:49:48Z","updated_at":"2019-01-02T03:46:45Z","pushed_at":"2019-01-02T03:46:41Z","git_url":"git://github.com/spyder-ide/spyder.git","ssh_url":"git@github.com:spyder-ide/spyder.git","clone_url":"https://github.com/spyder-ide/spyder.git","svn_url":"https://github.com/spyder-ide/spyder","homepage":"https://www.spyder-ide.org/","size":47866,"stargazers_count":3970,"watchers_count":3970,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":808,"mirror_url":null,"archived":false,"open_issues_count":710,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":808,"open_issues":710,"watchers":3970,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/spyder-ide/spyder/pulls/7660"},"html":{"href":"https://github.com/spyder-ide/spyder/pull/7660"},"issue":{"href":"https://api.github.com/repos/spyder-ide/spyder/issues/7660"},"comments":{"href":"https://api.github.com/repos/spyder-ide/spyder/issues/7660/comments"},"review_comments":{"href":"https://api.github.com/repos/spyder-ide/spyder/pulls/7660/comments"},"review_comment":{"href":"https://api.github.com/repos/spyder-ide/spyder/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/spyder-ide/spyder/pulls/7660/commits"},"statuses":{"href":"https://api.github.com/repos/spyder-ide/spyder/statuses/d3b5639c22228c2a6d99f620b872aa20d31b4d06"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"jitseniesen"}}