From f80d93bb994ab0e3514ac303d410bffc5b706a96 2014-05-07 05:39:44
From: MinRK <benjaminrk@gmail.com>
Date: 2014-05-07 05:39:44
Subject: [PATCH] support password in input_request

---

diff --git a/IPython/html/static/notebook/js/outputarea.js b/IPython/html/static/notebook/js/outputarea.js
index 497141d..1459ea4 100644
--- a/IPython/html/static/notebook/js/outputarea.js
+++ b/IPython/html/static/notebook/js/outputarea.js
@@ -748,6 +748,8 @@ var IPython = (function (IPython) {
         // disable any other raw_inputs, if they are left around
         $("div.output_subarea.raw_input_container").remove();
         
+        var input_type = content.password ? 'password' : 'text';
+        
         area.append(
             $("<div/>")
             .addClass("box-flex1 output_subarea raw_input_container")
@@ -759,7 +761,7 @@ var IPython = (function (IPython) {
             .append(
                 $("<input/>")
                 .addClass("raw_input")
-                .attr('type', 'text')
+                .attr('type', input_type)
                 .attr("size", 47)
                 .keydown(function (event, ui) {
                     // make sure we submit on enter,
@@ -788,10 +790,15 @@ var IPython = (function (IPython) {
         var theprompt = container.find("span.raw_input_prompt");
         var theinput = container.find("input.raw_input");
         var value = theinput.val();
+        var echo  = value;
+        // don't echo if it's a password
+        if (theinput.attr('type') == 'password') {
+            echo = '········';
+        }
         var content = {
             output_type : 'stream',
             name : 'stdout',
-            text : theprompt.text() + value + '\n'
+            text : theprompt.text() + echo + '\n'
         }
         // remove form container
         container.parent().remove();
diff --git a/IPython/kernel/zmq/ipkernel.py b/IPython/kernel/zmq/ipkernel.py
index b46239e..42686c5 100755
--- a/IPython/kernel/zmq/ipkernel.py
+++ b/IPython/kernel/zmq/ipkernel.py
@@ -6,6 +6,7 @@
 
 from __future__ import print_function
 
+import getpass
 import sys
 import time
 import traceback
@@ -333,7 +334,42 @@ class Kernel(Configurable):
                           parent=parent,
                           ident=self._topic('status'),
                           )
+    
+    def _forward_raw_input(self, ident, parent, allow_stdin):
+        """Replace raw_input. Note that is not sufficient to replace
+        raw_input in the user namespace.
+        """
+        
+        if allow_stdin:
+            raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
+            input = lambda prompt='': eval(raw_input(prompt))
+            _getpass = lambda prompt='', stream=None: self._raw_input(
+                prompt, ident, parent, password=True
+            )
+        else:
+            _getpass = raw_input = input = lambda prompt='' : self._no_raw_input()
+            
+
+        if py3compat.PY3:
+            self._sys_raw_input = builtin_mod.input
+            builtin_mod.input = raw_input
+        else:
+            self._sys_raw_input = builtin_mod.raw_input
+            self._sys_eval_input = builtin_mod.input
+            builtin_mod.raw_input = raw_input
+            builtin_mod.input = input
+        self._save_getpass = getpass.getpass
+        getpass.getpass = _getpass
+
+    def _restore_raw_input(self):
+        # Restore raw_input
+        if py3compat.PY3:
+            builtin_mod.input = self._sys_raw_input
+        else:
+            builtin_mod.raw_input = self._sys_raw_input
+            builtin_mod.input = self._sys_eval_input
         
+        getpass.getpass = self._save_getpass
 
     def execute_request(self, stream, ident, parent):
         """handle an execute_request"""
@@ -354,22 +390,7 @@ class Kernel(Configurable):
 
         shell = self.shell # we'll need this a lot here
 
-        # Replace raw_input. Note that is not sufficient to replace
-        # raw_input in the user namespace.
-        if content.get('allow_stdin', False):
-            raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
-            input = lambda prompt='': eval(raw_input(prompt))
-        else:
-            raw_input = input = lambda prompt='' : self._no_raw_input()
-
-        if py3compat.PY3:
-            self._sys_raw_input = builtin_mod.input
-            builtin_mod.input = raw_input
-        else:
-            self._sys_raw_input = builtin_mod.raw_input
-            self._sys_eval_input = builtin_mod.input
-            builtin_mod.raw_input = raw_input
-            builtin_mod.input = input
+        self._forward_raw_input(ident, parent, content.get('allow_stdin', False))
 
         # Set the parent message of the display hook and out streams.
         shell.set_parent(parent)
@@ -398,12 +419,7 @@ class Kernel(Configurable):
         else:
             status = u'ok'
         finally:
-            # Restore raw_input.
-             if py3compat.PY3:
-                 builtin_mod.input = self._sys_raw_input
-             else:
-                 builtin_mod.raw_input = self._sys_raw_input
-                 builtin_mod.input = self._sys_eval_input
+            self._restore_raw_input()
 
         reply_content[u'status'] = status
 
@@ -727,8 +743,8 @@ class Kernel(Configurable):
         stdin."""
         raise StdinNotImplementedError("raw_input was called, but this "
                                        "frontend does not support stdin.") 
-        
-    def _raw_input(self, prompt, ident, parent):
+    
+    def _raw_input(self, prompt, ident, parent, password=False):
         # Flush output before making the request.
         sys.stderr.flush()
         sys.stdout.flush()
@@ -743,7 +759,7 @@ class Kernel(Configurable):
                     raise
         
         # Send the input request.
-        content = json_clean(dict(prompt=prompt))
+        content = json_clean(dict(prompt=prompt, password=password))
         self.session.send(self.stdin_socket, u'input_request', content, parent,
                           ident=ident)