{"action":"created","comment":{"url":"https://api.github.com/repos/nipy/nipype/pulls/comments/141696545","pull_request_review_id":65952348,"id":141696545,"diff_hunk":"@@ -134,207 +114,190 @@ def __init__(self, plugin_args=None):\n         self._taskresult = {}\n         self._task_obj = {}\n         self._taskid = 0\n-        non_daemon = True\n-        self.plugin_args = plugin_args\n-        self.processors = cpu_count()\n-        self.memory_gb = get_system_total_memory_gb()*0.9 # 90% of system memory\n-\n-        self._timeout=2.0\n-        self._event = threading.Event()\n-\n-\n-\n-        # Check plugin args\n-        if self.plugin_args:\n-            if 'non_daemon' in self.plugin_args:\n-                non_daemon = plugin_args['non_daemon']\n-            if 'n_procs' in self.plugin_args:\n-                self.processors = self.plugin_args['n_procs']\n-            if 'memory_gb' in self.plugin_args:\n-                self.memory_gb = self.plugin_args['memory_gb']\n+        self._timeout = 2.0\n \n-        logger.debug(\"MultiProcPlugin starting %d threads in pool\"%(self.processors))\n+        # Read in options or set defaults.\n+        non_daemon = self.plugin_args.get('non_daemon', True)\n+        self.processors = self.plugin_args.get('n_procs', cpu_count())\n+        self.memory_gb = self.plugin_args.get('memory_gb',  # Allocate 90% of system memory\n+                                              get_system_total_memory_gb() * 0.9)\n+        self.raise_insufficient = self.plugin_args.get('raise_insufficient', True)\n \n         # Instantiate different thread pools for non-daemon processes\n-        if non_daemon:\n-            # run the execution using the non-daemon pool subclass\n-            self.pool = NonDaemonPool(processes=self.processors)\n-        else:\n-            self.pool = Pool(processes=self.processors)\n-\n-    def _wait(self):\n-        if len(self.pending_tasks) > 0:\n-            if self._config['execution']['poll_sleep_duration']:\n-                self._timeout = float(self._config['execution']['poll_sleep_duration'])\n-            sig_received=self._event.wait(self._timeout)\n-            if not sig_received:\n-                logger.debug('MultiProcPlugin timeout before signal received. Deadlock averted??')\n-            self._event.clear()\n+        logger.debug('MultiProcPlugin starting in \"%sdaemon\" mode (n_procs=%d, mem_gb=%0.2f)',\n+                     'non' if non_daemon else '', self.processors, self.memory_gb)\n+        self.pool = (NonDaemonPool if non_daemon else Pool)(processes=self.processors)\n \n     def _async_callback(self, args):\n-        self._taskresult[args['taskid']]=args\n-        self._event.set()\n+        self._taskresult[args['taskid']] = args\n \n     def _get_result(self, taskid):\n-        if taskid not in self._taskresult:\n-            result=None\n-        else:\n-            result=self._taskresult[taskid]\n-        return result\n-\n-    def _report_crash(self, node, result=None):\n-        if result and result['traceback']:\n-            node._result = result['result']\n-            node._traceback = result['traceback']\n-            return report_crash(node,\n-                                traceback=result['traceback'])\n-        else:\n-            return report_crash(node)\n+        return self._taskresult.get(taskid)\n \n     def _clear_task(self, taskid):\n         del self._task_obj[taskid]\n \n     def _submit_job(self, node, updatehash=False):\n         self._taskid += 1\n-        if hasattr(node.inputs, 'terminal_output'):\n-            if node.inputs.terminal_output == 'stream':\n-                node.inputs.terminal_output = 'allatonce'\n-\n-        self._task_obj[self._taskid] = \\\n-            self.pool.apply_async(run_node,\n-                                  (node, updatehash, self._taskid),\n-                                  callback=self._async_callback)\n+        if getattr(node.inputs, 'terminal_output', '') == 'stream':\n+            node.inputs.terminal_output = 'allatonce'\n+\n+        self._task_obj[self._taskid] = self.pool.apply_async(\n+            run_node, (node, updatehash, self._taskid),\n+            callback=self._async_callback)\n         return self._taskid\n \n     def _close(self):\n         self.pool.close()\n         return True\n \n+    def _prerun_check(self, graph):\n+        tasks_mem_gb = []\n+        tasks_num_th = []\n+        for node in graph.nodes():\n+            tasks_mem_gb.append(node.get_mem_gb())\n+            tasks_num_th.append(node.get_n_procs())\n+\n+        if np.any(np.array(tasks_mem_gb) > self.memory_gb):\n+            logger.warning(\n+                'Some nodes exceed the total amount of memory available '\n+                '(%0.2fGB).', self.memory_gb)\n+            if self.raise_insufficient:\n+                raise RuntimeError('Insufficient resources available for job')\n+\n+        if np.any(np.array(tasks_num_th) > self.processors):\n+            logger.warning(\n+                'Some nodes demand for more threads than available (%d).',\n+                self.processors)\n+            if self.raise_insufficient:\n+                raise RuntimeError('Insufficient resources available for job')\n+\n+    def _check_resources(self, running_tasks):\n+        \"\"\"\n+        Make sure there are resources available\n+        \"\"\"\n+        free_memory_gb = self.memory_gb\n+        free_processors = self.processors\n+        for _, jobid in running_tasks:\n+            free_memory_gb -= min(self.procs[jobid].get_mem_gb(), self.memory_gb)\n+            free_processors -= min(self.procs[jobid].get_n_procs(), self.processors)\n+\n+        return free_memory_gb, free_processors\n+\n     def _send_procs_to_workers(self, updatehash=False, graph=None):\n-        \"\"\" Sends jobs to workers when system resources are available.\n-            Check memory (gb) and cores usage before running jobs.\n         \"\"\"\n-        executing_now = []\n+        Sends jobs to workers when system resources are available.\n+        \"\"\"\n \n-        # Check to see if a job is available\n-        currently_running_jobids = np.flatnonzero((self.proc_pending == True) & \\\n-                                (self.depidx.sum(axis=0) == 0).__array__())\n+        # Check all jobs without dependency not run\n+        jobids = np.flatnonzero(\n+            ~self.proc_done & (self.depidx.sum(axis=0) == 0).__array__())\n \n         # Check available system resources by summing all threads and memory used\n-        busy_memory_gb = 0\n-        busy_processors = 0\n-        for jobid in currently_running_jobids:\n-            if self.procs[jobid]._interface.estimated_memory_gb <= self.memory_gb and \\\n-                            self.procs[jobid]._interface.num_threads <= self.processors:\n-\n-                busy_memory_gb += self.procs[jobid]._interface.estimated_memory_gb\n-                busy_processors += self.procs[jobid]._interface.num_threads\n+        free_memory_gb, free_processors = self._check_resources(self.pending_tasks)\n \n-            else:\n-                raise ValueError(\n-                    \"Resources required by jobid {0} ({3}GB, {4} threads) exceed what is \"\n-                    \"available on the system ({1}GB, {2} threads)\".format(\n-                        jobid, self.memory_gb, self.processors,\n-                        self.procs[jobid]._interface.estimated_memory_gb,\n-                        self.procs[jobid]._interface.num_threads))\n+        logger.info('Currently running %d tasks, and %d jobs ready. '\n+                     'Free memory (GB): %0.2f/%0.2f, Free processors: %d/%d',\n+                     len(self.pending_tasks), len(jobids),\n+                     free_memory_gb, self.memory_gb, free_processors, self.processors)\n \n-        free_memory_gb = self.memory_gb - busy_memory_gb\n-        free_processors = self.processors - busy_processors\n \n-        # Check all jobs without dependency not run\n-        jobids = np.flatnonzero((self.proc_done == False) & \\\n-                                (self.depidx.sum(axis=0) == 0).__array__())\n+        if (len(jobids) + len(self.pending_tasks)) == 0:\n+            logger.debug('No tasks are being run, and no jobs can '\n+                         'be submitted to the queue. Potential deadlock')\n+            return\n \n         # Sort jobs ready to run first by memory and then by number of threads\n         # The most resource consuming jobs run first\n-        jobids = sorted(jobids,\n-                        key=lambda item: (self.procs[item]._interface.estimated_memory_gb,\n-                                          self.procs[item]._interface.num_threads))\n-\n-        if str2bool(config.get('execution', 'profile_runtime')):\n-            logger.debug('Free memory (GB): %d, Free processors: %d',\n-                         free_memory_gb, free_processors)\n+        # jobids = sorted(jobids,\n+        #                 key=lambda item: (self.procs[item]._get_mem_gb(),\n+        #                                   self.procs[item]._get_n_procs()))","path":"nipype/pipeline/plugins/multiproc.py","position":305,"original_position":305,"commit_id":"983ac373d0ee64cd24f0780ee8b604cfa16b22d4","original_commit_id":"2fcaa45872f9347011d10419a067ebeb15b2ca57","user":{"login":"effigies","id":83442,"avatar_url":"https://avatars0.githubusercontent.com/u/83442?v=4","gravatar_id":"","url":"https://api.github.com/users/effigies","html_url":"https://github.com/effigies","followers_url":"https://api.github.com/users/effigies/followers","following_url":"https://api.github.com/users/effigies/following{/other_user}","gists_url":"https://api.github.com/users/effigies/gists{/gist_id}","starred_url":"https://api.github.com/users/effigies/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/effigies/subscriptions","organizations_url":"https://api.github.com/users/effigies/orgs","repos_url":"https://api.github.com/users/effigies/repos","events_url":"https://api.github.com/users/effigies/events{/privacy}","received_events_url":"https://api.github.com/users/effigies/received_events","type":"User","site_admin":false},"body":"I mean, we're already in the scheduling business, at least insofar as there's topological sorting for all other plugins, and memory-then-threads for `MultiProc`.\r\n\r\nThe interface could be dead simple:\r\n\r\n```Python\r\ndef mem_thread_scheduler(jobids, plugin):\r\n    return sorted(jobids, key=lambda item: (plugin.procs[item]._get_mem_gb(),\r\n                                            plugin.procs[item]._get_n_procs()))\r\n\r\ndef tsort(jobids, plugin):\r\n    return jobids\r\n```","created_at":"2017-09-28T18:16:02Z","updated_at":"2017-09-28T18:16:02Z","html_url":"https://github.com/nipy/nipype/pull/2200#discussion_r141696545","pull_request_url":"https://api.github.com/repos/nipy/nipype/pulls/2200","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/nipy/nipype/pulls/comments/141696545"},"html":{"href":"https://github.com/nipy/nipype/pull/2200#discussion_r141696545"},"pull_request":{"href":"https://api.github.com/repos/nipy/nipype/pulls/2200"}},"in_reply_to_id":141610373},"pull_request":{"url":"https://api.github.com/repos/nipy/nipype/pulls/2200","id":143501122,"html_url":"https://github.com/nipy/nipype/pull/2200","diff_url":"https://github.com/nipy/nipype/pull/2200.diff","patch_url":"https://github.com/nipy/nipype/pull/2200.patch","issue_url":"https://api.github.com/repos/nipy/nipype/issues/2200","number":2200,"state":"open","locked":false,"title":"[ENH] New ResourceMonitor (replaces resource profiler)","user":{"login":"oesteban","id":598470,"avatar_url":"https://avatars2.githubusercontent.com/u/598470?v=4","gravatar_id":"","url":"https://api.github.com/users/oesteban","html_url":"https://github.com/oesteban","followers_url":"https://api.github.com/users/oesteban/followers","following_url":"https://api.github.com/users/oesteban/following{/other_user}","gists_url":"https://api.github.com/users/oesteban/gists{/gist_id}","starred_url":"https://api.github.com/users/oesteban/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oesteban/subscriptions","organizations_url":"https://api.github.com/users/oesteban/orgs","repos_url":"https://api.github.com/users/oesteban/repos","events_url":"https://api.github.com/users/oesteban/events{/privacy}","received_events_url":"https://api.github.com/users/oesteban/received_events","type":"User","site_admin":false},"body":"Supersedes #2193 (I removed the specs to make code review easier)\r\n\r\nThis PR revises the resource profiler (with a new name: **resource monitor**):\r\n\r\n  - [x] Created new `nipype.utils.profiler` where all the code related to resource monitoring is gathered together. Tests are also brought into the `nipype.utils` module.\r\n  - [x] Removed monitoring responsibility from the runner into the interfaces. Consequences:\r\n    1. Resources can be monitored when running bare interfaces\r\n    2. All kinds of interfaces can be monitored (it was reduced to only `CommandLine`-based and `Function` interfaces before).\r\n    3. There was a bit of a mixture of resource-management and resource-monitoring in the node execution code. That has been cleaned up.\r\n    4. Interfaces save the traces directly to a file, so the log callback is not needed anymore (it has been left here just in case users want to generate the old gantt chart).\r\n    5. Interfaces place peak usage in their runtime object.\r\n  - [x] Previously, even though resource consumption with a certain frequency, only peak usage was finally reported in the Gantt chart. Now the traces are kept in the `proc_dict` member of the `runtime` object.\r\n  - [x] When the workflow is finished, the execution graph is post-processed and a new `runtime_monitor.json` file is generated, with all the traces and necessary information to reconstruct the performance profile with the resolution of the new `runtime_monitor_frequency` option (default: every 1s).\r\n  - [x] The resource manager of MultiProc blocked if a node was defined with `n_procs` > MultiProc's setting `n_procs` (similarly with the estimated memory). Now, either a warning or an error are raised (depending on the new plugin arg `raise_insufficient`).\r\n\r\n\r\n**Important**: this PRs removes the old `filemanip` logger and replaces it by a more generic `utils`. Documentation has been updated accordingly and Deprecation warnings are generated consequently.","created_at":"2017-09-27T21:09:25Z","updated_at":"2017-09-28T18:16:02Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8eb2f1beee5a6183004a8c8552e59f223e27ce0f","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/nipy/nipype/pulls/2200/commits","review_comments_url":"https://api.github.com/repos/nipy/nipype/pulls/2200/comments","review_comment_url":"https://api.github.com/repos/nipy/nipype/pulls/comments{/number}","comments_url":"https://api.github.com/repos/nipy/nipype/issues/2200/comments","statuses_url":"https://api.github.com/repos/nipy/nipype/statuses/983ac373d0ee64cd24f0780ee8b604cfa16b22d4","head":{"label":"oesteban:enh/ReviseResourceProfiler","ref":"enh/ReviseResourceProfiler","sha":"983ac373d0ee64cd24f0780ee8b604cfa16b22d4","user":{"login":"oesteban","id":598470,"avatar_url":"https://avatars2.githubusercontent.com/u/598470?v=4","gravatar_id":"","url":"https://api.github.com/users/oesteban","html_url":"https://github.com/oesteban","followers_url":"https://api.github.com/users/oesteban/followers","following_url":"https://api.github.com/users/oesteban/following{/other_user}","gists_url":"https://api.github.com/users/oesteban/gists{/gist_id}","starred_url":"https://api.github.com/users/oesteban/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oesteban/subscriptions","organizations_url":"https://api.github.com/users/oesteban/orgs","repos_url":"https://api.github.com/users/oesteban/repos","events_url":"https://api.github.com/users/oesteban/events{/privacy}","received_events_url":"https://api.github.com/users/oesteban/received_events","type":"User","site_admin":false},"repo":{"id":17021985,"name":"nipype","full_name":"oesteban/nipype","owner":{"login":"oesteban","id":598470,"avatar_url":"https://avatars2.githubusercontent.com/u/598470?v=4","gravatar_id":"","url":"https://api.github.com/users/oesteban","html_url":"https://github.com/oesteban","followers_url":"https://api.github.com/users/oesteban/followers","following_url":"https://api.github.com/users/oesteban/following{/other_user}","gists_url":"https://api.github.com/users/oesteban/gists{/gist_id}","starred_url":"https://api.github.com/users/oesteban/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oesteban/subscriptions","organizations_url":"https://api.github.com/users/oesteban/orgs","repos_url":"https://api.github.com/users/oesteban/repos","events_url":"https://api.github.com/users/oesteban/events{/privacy}","received_events_url":"https://api.github.com/users/oesteban/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/oesteban/nipype","description":"Workflows and interfaces for neuroimaging packages","fork":true,"url":"https://api.github.com/repos/oesteban/nipype","forks_url":"https://api.github.com/repos/oesteban/nipype/forks","keys_url":"https://api.github.com/repos/oesteban/nipype/keys{/key_id}","collaborators_url":"https://api.github.com/repos/oesteban/nipype/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/oesteban/nipype/teams","hooks_url":"https://api.github.com/repos/oesteban/nipype/hooks","issue_events_url":"https://api.github.com/repos/oesteban/nipype/issues/events{/number}","events_url":"https://api.github.com/repos/oesteban/nipype/events","assignees_url":"https://api.github.com/repos/oesteban/nipype/assignees{/user}","branches_url":"https://api.github.com/repos/oesteban/nipype/branches{/branch}","tags_url":"https://api.github.com/repos/oesteban/nipype/tags","blobs_url":"https://api.github.com/repos/oesteban/nipype/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/oesteban/nipype/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/oesteban/nipype/git/refs{/sha}","trees_url":"https://api.github.com/repos/oesteban/nipype/git/trees{/sha}","statuses_url":"https://api.github.com/repos/oesteban/nipype/statuses/{sha}","languages_url":"https://api.github.com/repos/oesteban/nipype/languages","stargazers_url":"https://api.github.com/repos/oesteban/nipype/stargazers","contributors_url":"https://api.github.com/repos/oesteban/nipype/contributors","subscribers_url":"https://api.github.com/repos/oesteban/nipype/subscribers","subscription_url":"https://api.github.com/repos/oesteban/nipype/subscription","commits_url":"https://api.github.com/repos/oesteban/nipype/commits{/sha}","git_commits_url":"https://api.github.com/repos/oesteban/nipype/git/commits{/sha}","comments_url":"https://api.github.com/repos/oesteban/nipype/comments{/number}","issue_comment_url":"https://api.github.com/repos/oesteban/nipype/issues/comments{/number}","contents_url":"https://api.github.com/repos/oesteban/nipype/contents/{+path}","compare_url":"https://api.github.com/repos/oesteban/nipype/compare/{base}...{head}","merges_url":"https://api.github.com/repos/oesteban/nipype/merges","archive_url":"https://api.github.com/repos/oesteban/nipype/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/oesteban/nipype/downloads","issues_url":"https://api.github.com/repos/oesteban/nipype/issues{/number}","pulls_url":"https://api.github.com/repos/oesteban/nipype/pulls{/number}","milestones_url":"https://api.github.com/repos/oesteban/nipype/milestones{/number}","notifications_url":"https://api.github.com/repos/oesteban/nipype/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/oesteban/nipype/labels{/name}","releases_url":"https://api.github.com/repos/oesteban/nipype/releases{/id}","deployments_url":"https://api.github.com/repos/oesteban/nipype/deployments","created_at":"2014-02-20T13:58:05Z","updated_at":"2015-04-26T18:20:51Z","pushed_at":"2017-09-28T15:38:20Z","git_url":"git://github.com/oesteban/nipype.git","ssh_url":"git@github.com:oesteban/nipype.git","clone_url":"https://github.com/oesteban/nipype.git","svn_url":"https://github.com/oesteban/nipype","homepage":"http://www.mit.edu/~satra/nipype-nightly/","size":28920,"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,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"nipy:master","ref":"master","sha":"2f422f02fbd956ba226eaaa206c7c2ae229c6828","user":{"login":"nipy","id":233707,"avatar_url":"https://avatars2.githubusercontent.com/u/233707?v=4","gravatar_id":"","url":"https://api.github.com/users/nipy","html_url":"https://github.com/nipy","followers_url":"https://api.github.com/users/nipy/followers","following_url":"https://api.github.com/users/nipy/following{/other_user}","gists_url":"https://api.github.com/users/nipy/gists{/gist_id}","starred_url":"https://api.github.com/users/nipy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nipy/subscriptions","organizations_url":"https://api.github.com/users/nipy/orgs","repos_url":"https://api.github.com/users/nipy/repos","events_url":"https://api.github.com/users/nipy/events{/privacy}","received_events_url":"https://api.github.com/users/nipy/received_events","type":"Organization","site_admin":false},"repo":{"id":791477,"name":"nipype","full_name":"nipy/nipype","owner":{"login":"nipy","id":233707,"avatar_url":"https://avatars2.githubusercontent.com/u/233707?v=4","gravatar_id":"","url":"https://api.github.com/users/nipy","html_url":"https://github.com/nipy","followers_url":"https://api.github.com/users/nipy/followers","following_url":"https://api.github.com/users/nipy/following{/other_user}","gists_url":"https://api.github.com/users/nipy/gists{/gist_id}","starred_url":"https://api.github.com/users/nipy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nipy/subscriptions","organizations_url":"https://api.github.com/users/nipy/orgs","repos_url":"https://api.github.com/users/nipy/repos","events_url":"https://api.github.com/users/nipy/events{/privacy}","received_events_url":"https://api.github.com/users/nipy/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nipy/nipype","description":"Workflows and interfaces for neuroimaging packages","fork":false,"url":"https://api.github.com/repos/nipy/nipype","forks_url":"https://api.github.com/repos/nipy/nipype/forks","keys_url":"https://api.github.com/repos/nipy/nipype/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nipy/nipype/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nipy/nipype/teams","hooks_url":"https://api.github.com/repos/nipy/nipype/hooks","issue_events_url":"https://api.github.com/repos/nipy/nipype/issues/events{/number}","events_url":"https://api.github.com/repos/nipy/nipype/events","assignees_url":"https://api.github.com/repos/nipy/nipype/assignees{/user}","branches_url":"https://api.github.com/repos/nipy/nipype/branches{/branch}","tags_url":"https://api.github.com/repos/nipy/nipype/tags","blobs_url":"https://api.github.com/repos/nipy/nipype/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nipy/nipype/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nipy/nipype/git/refs{/sha}","trees_url":"https://api.github.com/repos/nipy/nipype/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nipy/nipype/statuses/{sha}","languages_url":"https://api.github.com/repos/nipy/nipype/languages","stargazers_url":"https://api.github.com/repos/nipy/nipype/stargazers","contributors_url":"https://api.github.com/repos/nipy/nipype/contributors","subscribers_url":"https://api.github.com/repos/nipy/nipype/subscribers","subscription_url":"https://api.github.com/repos/nipy/nipype/subscription","commits_url":"https://api.github.com/repos/nipy/nipype/commits{/sha}","git_commits_url":"https://api.github.com/repos/nipy/nipype/git/commits{/sha}","comments_url":"https://api.github.com/repos/nipy/nipype/comments{/number}","issue_comment_url":"https://api.github.com/repos/nipy/nipype/issues/comments{/number}","contents_url":"https://api.github.com/repos/nipy/nipype/contents/{+path}","compare_url":"https://api.github.com/repos/nipy/nipype/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nipy/nipype/merges","archive_url":"https://api.github.com/repos/nipy/nipype/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nipy/nipype/downloads","issues_url":"https://api.github.com/repos/nipy/nipype/issues{/number}","pulls_url":"https://api.github.com/repos/nipy/nipype/pulls{/number}","milestones_url":"https://api.github.com/repos/nipy/nipype/milestones{/number}","notifications_url":"https://api.github.com/repos/nipy/nipype/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nipy/nipype/labels{/name}","releases_url":"https://api.github.com/repos/nipy/nipype/releases{/id}","deployments_url":"https://api.github.com/repos/nipy/nipype/deployments","created_at":"2010-07-22T17:06:49Z","updated_at":"2017-09-20T13:29:47Z","pushed_at":"2017-09-28T15:38:21Z","git_url":"git://github.com/nipy/nipype.git","ssh_url":"git@github.com:nipy/nipype.git","clone_url":"https://github.com/nipy/nipype.git","svn_url":"https://github.com/nipy/nipype","homepage":"http://nipype.readthedocs.org/en/latest/","size":67437,"stargazers_count":269,"watchers_count":269,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":305,"mirror_url":null,"open_issues_count":276,"forks":305,"open_issues":276,"watchers":269,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/nipy/nipype/pulls/2200"},"html":{"href":"https://github.com/nipy/nipype/pull/2200"},"issue":{"href":"https://api.github.com/repos/nipy/nipype/issues/2200"},"comments":{"href":"https://api.github.com/repos/nipy/nipype/issues/2200/comments"},"review_comments":{"href":"https://api.github.com/repos/nipy/nipype/pulls/2200/comments"},"review_comment":{"href":"https://api.github.com/repos/nipy/nipype/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/nipy/nipype/pulls/2200/commits"},"statuses":{"href":"https://api.github.com/repos/nipy/nipype/statuses/983ac373d0ee64cd24f0780ee8b604cfa16b22d4"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"effigies"}}