kernel.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. """
  2. jupyter-mysql-kernel
  3. author:rabin
  4. """
  5. from ipykernel.kernelbase import Kernel
  6. from pexpect import replwrap, EOF
  7. import pexpect
  8. from subprocess import check_output
  9. import os.path
  10. import re
  11. import signal
  12. __version__ = '0.0.1'
  13. version_pat = re.compile(r'version (\d+(\.\d+)+)')
  14. class MysqlWrapper(replwrap.REPLWrapper):
  15. def __init__(self, cmd_or_spawn, orig_prompt, prompt_change,
  16. extra_init_cmd=None, line_output_callback=None):
  17. self.line_output_callback = line_output_callback
  18. replwrap.REPLWrapper.__init__(self, cmd_or_spawn, orig_prompt,
  19. prompt_change, extra_init_cmd=extra_init_cmd)
  20. def _expect_prompt(self, timeout=-1):
  21. if timeout == None:
  22. while True:
  23. pos = self.child.expect_exact([self.prompt, self.continuation_prompt, u'\r\n'],
  24. timeout=None)
  25. if pos == 2:
  26. self.line_output_callback(self.child.before + '\n')
  27. else:
  28. if len(self.child.before) != 0:
  29. self.line_output_callback(self.child.before)
  30. break
  31. else:
  32. pos = replwrap.REPLWrapper._expect_prompt(self, timeout=timeout)
  33. return pos
  34. class MysqlKernel(Kernel):
  35. implementation = 'jupyter-mysql-kernel'
  36. implementation_version = __version__
  37. @property
  38. def language_version(self):
  39. m = version_pat.search(self.banner)
  40. return m.group(1)
  41. _banner = None
  42. @property
  43. def banner(self):
  44. if self._banner is None:
  45. self._banner = check_output(['mysql', '--version']).decode('utf-8')
  46. return self._banner
  47. language_info = {'name': 'mysql',
  48. 'mimetype': 'text/x-sh',
  49. 'file_extension': '.sql'}
  50. mysql_setting_file = os.path.join(os.path.expanduser('~'), '.local/config/mysql_config.json')
  51. mysql_config = {
  52. 'prompt' : u'>'
  53. ,'user' : 'root'
  54. ,'host' : '192.168.15.10'
  55. ,'port' : '3309'
  56. ,'charset' : 'utf8'
  57. ,'password' : '123456'
  58. }
  59. def __init__(self, **kwargs):
  60. Kernel.__init__(self, **kwargs)
  61. if os.path.exists(self.mysql_setting_file):
  62. with open(self.mysql_setting_file,"r") as f:
  63. self.mysql_config.update(json.load(f))
  64. self.prompt = self.mysql_config['prompt']
  65. self.start_mysql()
  66. def start_mysql(self):
  67. sig = signal.signal(signal.SIGINT, signal.SIG_DFL)
  68. try:
  69. if 'password' in self.mysql_config:
  70. 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')
  71. else:
  72. child = pexpect.spawn('mysql -A -h {host} -P {port} -u {user}'.format(**self.mysql_config))
  73. prompt_change = None
  74. init_cmd = None
  75. self.wrapper = MysqlWrapper(child, u'>', prompt_change=prompt_change, extra_init_cmd=init_cmd, line_output_callback=self.process_output)
  76. finally:
  77. signal.signal(signal.SIGINT, sig)
  78. def process_output(self, output):
  79. if not self.silent:
  80. #output = output.decode(self.mysql_config['charset'])
  81. stream_content = {'name': 'stdout', 'text': output}
  82. self.send_response(self.iopub_socket, 'stream', stream_content)
  83. def do_execute(self, code, silent, store_history=True,
  84. user_expressions=None, allow_stdin=False):
  85. self.silent = silent
  86. if not code.strip():
  87. return {'status': 'ok', 'execution_count': self.execution_count,
  88. 'payload': [], 'user_expressions': {}}
  89. interrupted = False
  90. try:
  91. self.wrapper.run_command(code.rstrip(), timeout=None)
  92. except KeyboardInterrupt:
  93. self.wrapper.child.sendintr()
  94. interrupted = True
  95. self.wrapper._expect_prompt()
  96. output = self.wrapper.child.before
  97. self.process_output(output)
  98. except EOF:
  99. output = self.wrapper.child.before + 'Restarting Mysql'
  100. self.start_mysql()
  101. self.process_output(output)
  102. if interrupted:
  103. return {'status': 'abort', 'execution_count': self.execution_count}
  104. return {'status': 'ok', 'execution_count': self.execution_count,
  105. 'payload': [], 'user_expressions': {}}