Skip to content

Commit 1d28985

Browse files
committed
update
1 parent 4a05300 commit 1d28985

File tree

4 files changed

+124
-71
lines changed

4 files changed

+124
-71
lines changed

.github/workflows/python-package.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name: Python package
55

66
on:
77
push:
8-
branches: [master,dev]
8+
branches: [master, dev]
99
pull_request:
1010
branches: [master]
1111

@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515
strategy:
1616
matrix:
17-
python-version: [3.6, 3.7, 3.8, 3.9]
17+
python-version: [3.8, 3.9]
1818

1919
steps:
2020
- uses: actions/checkout@v2
@@ -32,3 +32,6 @@ jobs:
3232
- name: Lint with pep8
3333
run: |
3434
pycodestyle --max-line-length=140 --ignore=E501 --first --statistics postgresql_kernel
35+
- name: Static check with mypy
36+
run: |
37+
mypy --ignore-missing-imports --show-column-numbers --follow-imports=silent --check-untyped-defs --disallow-untyped-defs --no-implicit-optional --warn-unused-ignores --scripts-are-modules postgresql_kernel

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 0.0.1
2+
3+
1. 增加类型注释
4+
2. 更新依赖项,将psycopg2改为psycopg2-binary
5+
3. 不再支持python3.7及以下版本
6+
17
# 0.0.0
28

3-
项目创建,原样复刻了[postgres_kernel](https://github.com/bgschiller/postgres_kernel)的功能
9+
项目创建,原样复刻了[postgres_kernel](https://github.com/bgschiller/postgres_kernel)的功.

postgresql_kernel/kernel.py

Lines changed: 105 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
from pydoc import Helper
23
import re
34
import sys
45
import json
@@ -14,16 +15,46 @@
1415
import psycopg2
1516
from psycopg2 import Error, OperationalError
1617
from psycopg2.extensions import (
17-
QueryCanceledError, POLL_OK, POLL_READ, POLL_WRITE, STATUS_BEGIN,
18+
QueryCanceledError, POLL_OK, POLL_READ, POLL_WRITE, STATUS_BEGIN, Union
1819
)
19-
20+
from typing import Any, List, Optional, TypedDict, Iterable, Sequence, Mapping, Union, Tuple
2021
from . import __version__
2122

23+
KernelDictType = TypedDict(
24+
'KernelDictType',
25+
{
26+
"argv": List[str],
27+
"display_name": str,
28+
"mimetype": str,
29+
"language": str,
30+
"name": str
31+
},
32+
total=False)
33+
34+
HelpLinkDictType = TypedDict(
35+
'HelpLinkDictType',
36+
{
37+
"text": str,
38+
"url": str
39+
},
40+
total=False)
41+
42+
LanguageInfoDictType = TypedDict(
43+
'LanguageInfoDictType',
44+
{
45+
'mimetype': str,
46+
'name': str,
47+
'file_extension': str,
48+
'version': str,
49+
'help_links': List[HelpLinkDictType]
50+
},
51+
total=False)
52+
2253
version_pat = re.compile(r'^PostgreSQL (\d+(\.\d+)+)')
2354
CONN_STRING_COMMENT = re.compile(r'--\s*connection:\s*(.*)\s*$')
2455
AUTOCOMMIT_SWITCH_COMMENT = re.compile(r'--\s*autocommit:\s*(\w+)\s*$')
2556

26-
HELP_LINKS = [
57+
HELP_LINKS: List[HelpLinkDictType] = [
2758
{
2859
'text': "PostgreSQL",
2960
'url': "http://www.postgres.cn/docs/12/index.html",
@@ -32,15 +63,12 @@
3263
'text': "SQL",
3364
'url': "https://blog.hszofficial.site/TutorialForSQL/#/",
3465
},
35-
# {
36-
# 'text': "PostgreSQL Kernel",
37-
# 'url': "https://github.com/Calysto/octave_kernel",
38-
# },
66+
3967

4068
] + MetaKernel.help_links
4169

4270

43-
def get_kernel_json():
71+
def get_kernel_json() -> KernelDictType:
4472
"""Get the kernel json for the kernel."""
4573
here = Path(__file__)
4674
default_json_file = here.parent.joinpath('kernel.json')
@@ -51,11 +79,11 @@ def get_kernel_json():
5179
return data
5280

5381

54-
def wait_select_inter(conn):
55-
"""等待连接建立
82+
def wait_select_inter(conn: psycopg2.connection) -> None:
83+
"""等待连接建立.
5684
5785
Args:
58-
conn (psycopg2.Connection): pg的连接
86+
conn (psycopg2.connection): pg的连接
5987
6088
Raises:
6189
conn.OperationalError: 连接报错
@@ -83,7 +111,7 @@ class MissingConnection(Exception):
83111

84112

85113
class RowsDisplay:
86-
def __init__(self, header, rows):
114+
def __init__(self, header: Union[str, Mapping[str, str], Sequence[str]], rows: Union[Mapping[str, Iterable], Iterable[Iterable]]) -> None:
87115
self.header = header
88116
self.rows = rows
89117

@@ -98,44 +126,53 @@ def _repr_latex_(self) -> str:
98126

99127

100128
class PostgreSQLKernel(MetaKernel):
101-
app_name = 'postgresql_kernel'
102-
implementation = 'PostgreSQL Kernel'
103-
implementation_version = __version__,
104-
language = 'sql'
105-
help_links = HELP_LINKS
106-
kernel_json = Dict(get_kernel_json()).tag(config=True)
107-
_language_version = None
108-
_banner = None
129+
130+
app_name: str = 'postgresql_kernel'
131+
implementation: str = 'PostgreSQL Kernel'
132+
implementation_version: str = __version__
133+
language: str = 'sql'
134+
help_links: List[HelpLinkDictType] = HELP_LINKS
135+
kernel_json: Dict = Dict(get_kernel_json()).tag(config=True)
136+
_language_version: Optional[str] = None
137+
_banner: Optional[str] = None
138+
139+
_conn_string: str
140+
_autocommit: bool
141+
_conn: Optional[psycopg2.connection]
109142

110143
@property
111-
def language_version(self):
144+
def language_version(self) -> str:
112145
if self._language_version:
113146
return self._language_version
114-
115-
m = version_pat.search(self.banner)
116-
if m:
117-
self._language_version = m.group(1)
118-
return self._language_version
147+
if self.banner:
148+
m = version_pat.search(self.banner)
149+
if m:
150+
self._language_version = m.group(1)
151+
return self._language_version
152+
else:
153+
return "unknown"
119154
else:
120155
return "unknown"
121156

122157
@property
123-
def banner(self):
158+
def banner(self) -> Optional[str]:
124159
if self._banner is None:
125160
if self._conn is None:
126161
return 'not yet connected to a database'
127-
self._banner = self.fetchone('SELECT VERSION();')[0]
162+
res = self.fetchone('SELECT VERSION();')
163+
if res and len(res) >= 1:
164+
self._banner = res[0]
128165
return self._banner
129166

130167
@property
131-
def language_info(self):
168+
def language_info(self) -> LanguageInfoDictType:
132169
return {'mimetype': 'text/x-sql',
133170
'name': 'sql',
134171
'file_extension': '.sql',
135172
'version': self.language_version,
136173
'help_links': HELP_LINKS}
137174

138-
def __init__(self, *args, **kwargs):
175+
def __init__(self, *args: Any, **kwargs: Any):
139176
super(PostgreSQLKernel, self).__init__(*args, **kwargs)
140177
psycopg2.extensions.set_wait_callback(wait_select_inter)
141178
self._conn_string = os.getenv('DATABASE_URL', '')
@@ -144,7 +181,7 @@ def __init__(self, *args, **kwargs):
144181
if self._conn_string:
145182
self._start_connection()
146183

147-
def _start_connection(self):
184+
def _start_connection(self) -> None:
148185
"""与pg建立连接."""
149186
self.log.info('starting connection')
150187
try:
@@ -156,23 +193,25 @@ def _start_connection(self):
156193
self.send_response(self.iopub_socket, 'stream',
157194
{'name': 'stderr', 'text': message})
158195

159-
def fetchone(self, query):
196+
def fetchone(self, query: str) -> Optional[Sequence[Union[str, bytes, int, float]]]:
160197
"""拉取一行数据
161198
162199
Args:
163200
query (str): 请求的sql语句
164201
165202
Returns:
166-
[type]: [description]
203+
Optional[Sequence[Union[str, bytes, int, float]]]: 获取的结果
167204
"""
168-
self.log.info(f'fetching one from: \n{query}')
169-
with self._conn.cursor() as c:
170-
c.execute(query)
171-
one = c.fetchone()
172-
self.log.info(one)
173-
return one
174-
175-
def fetchall(self, query):
205+
if self._conn:
206+
self.log.info(f'fetching one from: \n{query}')
207+
with self._conn.cursor() as c:
208+
c.execute(query)
209+
one = c.fetchone()
210+
self.log.info(one)
211+
return one
212+
return None
213+
214+
def fetchall(self, query: str) -> Tuple[Optional[List[str]], Optional[List[Sequence[Union[str, bytes, int, float]]]]]:
176215
"""拉取多行数据.
177216
178217
Args:
@@ -181,21 +220,24 @@ def fetchall(self, query):
181220
Returns:
182221
[type]: [description]
183222
"""
184-
self.log.info(f'fetching all from: \n{query}')
185-
with self._conn.cursor() as c:
186-
c.execute(query)
187-
desc = c.description
188-
if desc:
189-
keys = [col[0] for col in desc]
190-
return keys, c.fetchall()
191-
return None, None
192-
193-
def change_connection(self, conn_string):
223+
if not self._conn:
224+
raise Exception("need to connect to pg first")
225+
else:
226+
self.log.info(f'fetching all from: \n{query}')
227+
with self._conn.cursor() as c:
228+
c.execute(query)
229+
desc = c.description
230+
if desc:
231+
keys = [col[0] for col in desc]
232+
return keys, c.fetchall()
233+
return None, None
234+
235+
def change_connection(self, conn_string: str) -> None:
194236
"""更换连接的库."""
195237
self._conn_string = conn_string
196238
self._start_connection()
197239

198-
def switch_autocommit(self, switch_to):
240+
def switch_autocommit(self, switch_to: bool) -> bool:
199241
"""切换是否要自动提交."""
200242
self._autocommit = switch_to
201243
committed = False
@@ -208,7 +250,7 @@ def switch_autocommit(self, switch_to):
208250
self._start_connection()
209251
return committed
210252

211-
def change_autocommit_mode(self, switch):
253+
def change_autocommit_mode(self, switch: str) -> None:
212254
"""根据输入的字符串切换是否要自动提交.
213255
214256
如果输入的字符串的全小写是true或者false则按指定的值设置,否则抛出错误.
@@ -223,7 +265,7 @@ def change_autocommit_mode(self, switch):
223265
)
224266

225267
switch_bool = (parsed_switch == 'true')
226-
committed = self.switch_autocommit(switch_bool) | ''
268+
committed = "True" if self.switch_autocommit(switch_bool) else ''
227269
message = f'committed current transaction & {committed} switched autocommit mode to {self._autocommit}'
228270

229271
self.send_response(
@@ -233,7 +275,7 @@ def change_autocommit_mode(self, switch):
233275
}
234276
)
235277

236-
def get_kernel_help_on(self, info, level=1, none_on_fail=False):
278+
def get_kernel_help_on(self, info: Mapping[str, str], level: int = 1, none_on_fail: bool = False) -> Optional[str]:
237279
self.log.warning("get kernel help")
238280
code = info['code'].strip()
239281
if not code or len(code.split()) > 1:
@@ -244,7 +286,7 @@ def get_kernel_help_on(self, info, level=1, none_on_fail=False):
244286
shell_magic = self.line_magics['shell']
245287
return shell_magic.get_help_on(info, 1)
246288

247-
def do_execute_meta(self, code):
289+
def do_execute_meta(self, code: str) -> ExceptionWrapper:
248290
"""
249291
Execute meta code in the kernel. This uses the execute infrastructure
250292
but allows JavaScript to talk directly to the kernel bypassing normal
@@ -261,11 +303,11 @@ def do_execute_meta(self, code):
261303
tb = traceback.format_exception(exc_type, exc_value, exc_traceback)
262304
return ExceptionWrapper(ename=str(type(e)), evalue=str(e), traceback=tb)
263305

264-
def do_execute_direct(self, code, silent=False):
306+
def do_execute_direct(self, code: str, silent: bool = False) -> Optional[Union[RowsDisplay, ExceptionWrapper]]:
265307
if code.strip().lower() in ['quit', 'quit()', 'exit', 'exit()']:
266308
self.do_shutdown(True)
267309
self.payload = [{"source": "ask_exit"}]
268-
return
310+
return None
269311
try:
270312
connection_string = CONN_STRING_COMMENT.findall(code)
271313
autocommit_switch = AUTOCOMMIT_SWITCH_COMMENT.findall(code)
@@ -276,7 +318,7 @@ def do_execute_direct(self, code, silent=False):
276318

277319
code = AUTOCOMMIT_SWITCH_COMMENT.sub('', CONN_STRING_COMMENT.sub('', code))
278320
if not code.strip():
279-
return
321+
return None
280322
if self._conn is None:
281323
raise MissingConnection(f'''\
282324
Error: Unable to connect to a database at "{self._conn_string}".
@@ -289,8 +331,7 @@ def do_execute_direct(self, code, silent=False):
289331
self._conn.rollback()
290332
raise qce
291333
except Error as e:
292-
self.send_response(self.iopub_socket, 'stream',
293-
{'name': 'stderr', 'text': str(e)})
334+
self.send_response(self.iopub_socket, 'stream', {'name': 'stderr', 'text': str(e)})
294335
self._conn.rollback()
295336
raise e
296337
else:
@@ -308,9 +349,10 @@ def do_execute_direct(self, code, silent=False):
308349
'text': str(notice)
309350
})
310351
self._conn.notices = []
311-
if header is not None and len(rows) > 0:
352+
if header is not None and rows and len(rows) > 0:
312353
return RowsDisplay(header, rows)
313-
354+
else:
355+
return None
314356
except Exception as e:
315357
exc_type, exc_value, exc_traceback = sys.exc_info()
316358
tb = traceback.format_exception(exc_type, exc_value, exc_traceback)

0 commit comments

Comments
 (0)