rabin 7 years ago
parent
commit
aaa8cb948a

+ 4 - 5
jupyter-mysql-kernel/__init__.py

@@ -1,7 +1,6 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
 """
-    jupyter-mysql-kernel
-    author:rabin
+	jupyter-mysql-kernel
+	author:rabin
 """
-__version__ = 1.0
+
+from .kernel import __version__

+ 3 - 5
jupyter-mysql-kernel/__main__.py

@@ -1,9 +1,7 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
 """
-    jupyter-mysql-kernel
-    author:rabin
+	jupyter-mysql-kernel
+	author:rabin
 """
 from ipykernel.kernelapp import IPKernelApp
 from .kernel import MysqlKernel
-IPKernelApp.launch_instance(kernel_class=MysqlKernel)
+IPKernelApp.launch_instance(kernel_class=MysqlKernel)

+ 70 - 0
jupyter-mysql-kernel/install.py

@@ -0,0 +1,70 @@
+"""
+    jupyter-mysql-kernel
+    author:rabin
+"""
+import json
+import os
+import sys
+import argparse
+
+from jupyter_client.kernelspec import KernelSpecManager
+from IPython.utils.tempdir import TemporaryDirectory
+
+kernel_json = {"argv":[sys.executable,"-m","jupyter-mysql-kernel", "-f", "{connection_file}"],
+ "display_name":"Mysql",
+ "language":"mysql"
+}
+
+def install_my_kernel_spec(user=True, prefix=None):
+    with TemporaryDirectory() as td:
+        os.chmod(td, 0o755)
+        with open(os.path.join(td, 'kernel.json'), 'w') as f:
+            json.dump(kernel_json, f, sort_keys=True)
+
+        print('Installing IPython kernel spec')
+        KernelSpecManager().install_kernel_spec(td, 'mysql', user=user, replace=True, prefix=prefix)
+
+def _is_root():
+    try:
+        return os.geteuid() == 0
+    except AttributeError:
+        return False
+
+def main(argv=None):
+    parser = argparse.ArgumentParser(
+        description='Install KernelSpec for Mysql Kernel'
+    )
+    prefix_locations = parser.add_mutually_exclusive_group()
+
+    prefix_locations.add_argument(
+        '--user',
+        help='Install KernelSpec in user homedirectory',
+        action='store_true'
+    )
+    prefix_locations.add_argument(
+        '--sys-prefix',
+        help='Install KernelSpec in sys.prefix. Useful in conda / virtualenv',
+        action='store_true',
+        dest='sys_prefix'
+    )
+    prefix_locations.add_argument(
+        '--prefix',
+        help='Install KernelSpec in this prefix',
+        default=None
+    )
+
+    args = parser.parse_args(argv)
+
+    user = False
+    prefix = None
+    if args.sys_prefix:
+        prefix = sys.prefix
+    elif args.prefix:
+        prefix = args.prefix
+    elif args.user or not _is_root():
+        user = True
+
+    install_my_kernel_spec(user=user, prefix=prefix)
+
+if __name__ == '__main__':
+    main()

+ 107 - 78
jupyter-mysql-kernel/kernel.py

@@ -1,97 +1,126 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
 """
 	jupyter-mysql-kernel
 	author:rabin
 """
-import json
-import os
+from ipykernel.kernelbase import Kernel
+from pexpect import replwrap, EOF
+import pexpect
+
+from subprocess import check_output
+import os.path
+
 import re
 import signal
 
-from ipykernel.kernelbase import Kernel
-import pexpect
+__version__ = '0.0.1'
+
+version_pat = re.compile(r'version (\d+(\.\d+)+)')
+
+
+class MysqlWrapper(replwrap.REPLWrapper):
+	def __init__(self, cmd_or_spawn, orig_prompt, prompt_change,
+				 extra_init_cmd=None, line_output_callback=None):
+		self.line_output_callback = line_output_callback
+		replwrap.REPLWrapper.__init__(self, cmd_or_spawn, orig_prompt,
+									  prompt_change, extra_init_cmd=extra_init_cmd)
+
+	def _expect_prompt(self, timeout=-1):
+		if timeout == None:
+			while True:
+				pos = self.child.expect_exact([self.prompt, self.continuation_prompt, u'\r\n'],
+											  timeout=None)
+				if pos == 2:
+					self.line_output_callback(self.child.before + '\n')
+				else:
+					if len(self.child.before) != 0:
+						self.line_output_callback(self.child.before)
+					break
+		else:
+			pos = replwrap.REPLWrapper._expect_prompt(self, timeout=timeout)
+
+		return pos
 
 class MysqlKernel(Kernel):
-	implementation = 'Mysql'
-	implementation_version = '1.0'
-	language = 'mysql'
-	language_version = 'm1.0'
-	language_info = {
-		'name': 'mysql'
-		,'mimetype': 'text/plain'
-		,'file_extension': '.sql'
-	}
-	banner = 'Mysql kernel'
+	implementation = 'jupyter-mysql-kernel'
+	implementation_version = __version__
+
+	@property
+	def language_version(self):
+		m = version_pat.search(self.banner)
+		return m.group(1)
+
+	_banner = None
+
+	@property
+	def banner(self):
+		if self._banner is None:
+			self._banner = check_output(['mysql', '--version']).decode('utf-8')
+		return self._banner
+
+	language_info = {'name': 'mysql',
+					 'mimetype': 'text/x-sh',
+					 'file_extension': '.sql'}
 
 	mysql_setting_file = os.path.join(os.path.expanduser('~'), '.local/config/mysql_config.json')
 	mysql_config = {
-	   'prompt'		: '>'
-	   ,'user'		: 'root'
-	   ,'host'		: '192.168.15.10'
-	   ,'port'		: '3309'
-	   ,'charset'	: 'utf8'
-	   ,'password'	: '123456'
+	   'prompt'	 : u'>'
+	   ,'user'	  : 'root'
+	   ,'host'	  : '192.168.15.10'
+	   ,'port'	  : '3309'
+	   ,'charset'   : 'utf8'
+	   ,'password'  : '123456'
 	}
 
-	def __init__(self, *args, **kwargs):
-		super(MysqlKernel, self).__init__(*args, **kwargs)
+	def __init__(self, **kwargs):
+		Kernel.__init__(self, **kwargs)
 		if os.path.exists(self.mysql_setting_file):
 			with open(self.mysql_setting_file,"r") as f:
 				self.mysql_config.update(json.load(f))
-		self.prompt = self.mysql_config["prompt"]
-		self.start()
-
-	def start(self):
-		if 'password' in self.mysql_config:
-			self.process = pexpect.spawn('mysql -A -h {host} -P {port} -u {user} -p'.format(**self.mysql_config))
-			self.process.expect(':')
-			self.process.sendline(self.mysql_config['password'])
-		else:
-			self.process = pexpect.spawn('mysql -A -h {host} -P {port} -u {user}'.format(**self.mysql_config))
-		if self.process:
-			self.process.expect(self.prompt)
-			#self.process.interact()
+		self.prompt = self.mysql_config['prompt']
+		self.start_mysql()
 
-	def do_execute(self, code, silent, store_history=True, user_expressions=None, allow_stdin=False):
+	def start_mysql(self):
+		sig = signal.signal(signal.SIGINT, signal.SIG_DFL)
+		try:
+			if 'password' in self.mysql_config:
+				child = pexpect.spawn('mysql -A -h {host} -P {port} -u {user} -p{password}'.format(**self.mysql_config), echo=False, encoding='utf-8', codec_errors='replace')
+			else:
+				child = pexpect.spawn('mysql -A -h {host} -P {port} -u {user}'.format(**self.mysql_config))
+			prompt_change = None
+			init_cmd = None
+			self.wrapper = MysqlWrapper(child, u'>', prompt_change=prompt_change, extra_init_cmd=init_cmd, line_output_callback=self.process_output)
+		finally:
+			signal.signal(signal.SIGINT, sig)
+
+	def process_output(self, output):
+		if not self.silent:
+			#output = output.decode(self.mysql_config['charset'])
+			stream_content = {'name': 'stdout', 'text': output}
+			self.send_response(self.iopub_socket, 'stream', stream_content)
+
+	def do_execute(self, code, silent, store_history=True,
+				   user_expressions=None, allow_stdin=False):
+		self.silent = silent
 		if not code.strip():
-			return
-			{
-				'status': 'ok',
-				'execution_count': self.execution_count,
-				'payload': [],
-				'user_expressions': {}
-			}
-
-		msg = ''
-		for c in code.split("\n"):
-			c = c.strip()
-			if len(c) > 0:
-				if c[0] == '#':
-					continue
-				msg += c + ';'
-		msg = msg.strip()
-
-		self.process.sendline(msg)
-		self.process.expect(self.prompt)
-		output = self.process.before
-		result = output.decode(self.mysql_config['charset'])
-		self.out(result)
-		return
-		{
-			'status': 'ok',
-			'execution_count': self.execution_count,
-			'payload': [],
-			'user_expressions': {}
-		}
-
-	def out(self, content):
-		stream_content = {'name': 'stdout', 'text': result}
-		self.send_response(self.iopub_socket, 'stream', stream_content)
-	def err(self, content):
-		stream_content = {'name': 'stderr', 'text': result}
-		self.send_response(self.iopub_socket, 'stream', stream_content)
-
-if __name__ == '__main__':
-    from ipykernel.kernelapp import IPKernelApp                                                      
-    IPKernelApp.launch_instance(kernel_class=MysqlKernel)
+			return {'status': 'ok', 'execution_count': self.execution_count,
+					'payload': [], 'user_expressions': {}}
+
+		interrupted = False
+		try:
+			self.wrapper.run_command(code.rstrip(), timeout=None)
+		except KeyboardInterrupt:
+			self.wrapper.child.sendintr()
+			interrupted = True
+			self.wrapper._expect_prompt()
+			output = self.wrapper.child.before
+			self.process_output(output)
+		except EOF:
+			output = self.wrapper.child.before + 'Restarting Mysql'
+			self.start_mysql()
+			self.process_output(output)
+
+		if interrupted:
+			return {'status': 'abort', 'execution_count': self.execution_count}
+
+		return {'status': 'ok', 'execution_count': self.execution_count,
+					'payload': [], 'user_expressions': {}}

+ 36 - 6
test.py

@@ -7,19 +7,49 @@
 """
 
 import pexpect
-print 22
+from pexpect import replwrap, EOF
+
+class MysqlWrapper(replwrap.REPLWrapper):
+    def __init__(self, cmd_or_spawn, orig_prompt, prompt_change,
+                 extra_init_cmd=None, line_output_callback=None):
+        self.line_output_callback = line_output_callback
+        replwrap.REPLWrapper.__init__(self, cmd_or_spawn, orig_prompt,
+                                      prompt_change, extra_init_cmd=extra_init_cmd)
+
+    def _expect_prompt(self, timeout=-1):
+        if timeout == None:
+            while True:
+                pos = self.child.expect_exact([self.prompt, self.continuation_prompt, u'\r\n'],
+                                              timeout=None)
+                if pos == 2:
+                    self.line_output_callback(self.child.before + '\n')
+                else:
+                    if len(self.child.before) != 0:
+                        self.line_output_callback(self.child.before)
+                    break
+        else:
+            pos = replwrap.REPLWrapper._expect_prompt(self, timeout=timeout)
+        return pos
+
+def output(content):
+    print content
 if __name__ == '__main__':
     user = 'root'
     ip = '192.168.15.10'
     port = '3309'
     password = '123456'
-
+    child = pexpect.spawn('mysql -u%s -h%s -P%s -p%s' % (user, ip, port,password))
+    py = MysqlWrapper(child, u"mysql>", None,extra_init_cmd=None,line_output_callback=output)
+    py.run_command("show databases;", timeout=None)
+    """
     child = pexpect.spawn('mysql -u%s -h%s -P%s -p' % (user, ip, port))
     child.expect ('password:')
     child.sendline (password)
  
-    child.expect('>')
+    child.expect('mysql>')
     child.sendline('show databases;')
-    #print child.before   # Print the result of the ls command.
-    child.sendline('exit')
-    child.interact()     # Give control of the child to the user.
+    child.expect('mysql>')
+    child.sendline('use dever;')
+    print child.after   # Print the result of the ls command.
+    #child.interact()     # Give control of the child to the user.
+    """