kernel.py 4.0 KB

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