jupyter-duckdb 1.2.101__py3-none-any.whl → 1.2.103__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,13 @@
1
1
  from typing import Optional, List
2
2
 
3
- from . import MagicCommand
4
- from .StringWrapper import StringWrapper
3
+ from . import MagicCommand, MagicState
5
4
 
6
5
 
7
6
  class MagicCommandCallback:
8
- def __init__(self, mc: MagicCommand, silent: bool, code: StringWrapper, *args, **kwargs):
7
+ def __init__(self, mc: MagicCommand, silent: bool, state: MagicState, *args, **kwargs):
9
8
  self._mc: MagicCommand = mc
10
9
  self._silent: bool = silent
11
- self._code: StringWrapper = code
10
+ self._state: MagicState = state
12
11
  self._args = args
13
12
  self._kwargs = kwargs
14
13
 
@@ -18,14 +17,8 @@ class MagicCommandCallback:
18
17
 
19
18
  def __call__(self, columns: Optional[List[str]] = None, rows: Optional[List[List]] = None):
20
19
  if self._mc.requires_code:
21
- result = self._mc(self._silent, self._code.value, *self._args, **self._kwargs)
22
- if 'generated_code' in result:
23
- self._code.value = result['generated_code']
24
-
25
- return result
26
-
27
- if self._mc.requires_query_result:
28
- return self._mc(self._silent, columns, rows, *self._args, **self._kwargs)
29
-
20
+ self._mc(self._silent, self._state, *self._args, **self._kwargs)
21
+ elif self._mc.requires_query_result:
22
+ self._mc(self._silent, self._state, columns, rows, *self._args, **self._kwargs)
30
23
  else:
31
- return self._mc(self._silent, *self._args, **self._kwargs)
24
+ self._mc(self._silent, self._state, *self._args, **self._kwargs)
@@ -2,7 +2,8 @@ import re
2
2
  from typing import Dict, Tuple, List
3
3
 
4
4
  from . import MagicCommand, MagicCommandException, MagicCommandCallback
5
- from .StringWrapper import StringWrapper
5
+ from .MagicState import MagicState
6
+ from ..db import Connection
6
7
 
7
8
 
8
9
  class MagicCommandHandler:
@@ -18,8 +19,8 @@ class MagicCommandHandler:
18
19
  def __getitem__(self, key: str) -> MagicCommand:
19
20
  return self._magics[key.lower()]
20
21
 
21
- def __call__(self, silent: bool, code: str) -> Tuple[str, List[MagicCommandCallback], List[MagicCommandCallback]]:
22
- code_wrapper = StringWrapper()
22
+ def __call__(self, silent: bool, state: MagicState) \
23
+ -> Tuple[List[MagicCommandCallback], List[MagicCommandCallback]]:
23
24
  enabled_callbacks: List[MagicCommandCallback] = []
24
25
 
25
26
  # enable commands with default==True
@@ -27,21 +28,21 @@ class MagicCommandHandler:
27
28
  if magic.is_default:
28
29
  flags = {name: False for name, _ in magic.flags}
29
30
  optionals = {name: default for name, default, _ in magic.optionals}
30
- callback = MagicCommandCallback(magic, silent, code_wrapper, **flags, **optionals)
31
+ callback = MagicCommandCallback(magic, silent, state, **flags, **optionals)
31
32
 
32
33
  enabled_callbacks.append(callback)
33
34
 
34
35
  # search for magic commands in code
35
36
  while True:
36
37
  # ensure code starts with '%' or '%%' but not with '%%%'
37
- match = re.match(r'^%{1,2}([^% ]+?)([ \t]*$| .+?$)', code, re.MULTILINE | re.IGNORECASE)
38
+ match = re.match(r'^%{1,2}([^% ]+?)([ \t]*$| .+?$)', state.code, re.MULTILINE | re.IGNORECASE)
38
39
 
39
40
  if match is None:
40
41
  break
41
42
 
42
43
  # remove magic command from code
43
44
  start, end = match.span()
44
- code = code[:start] + code[end + 1:]
45
+ state.code = state.code[:start] + state.code[end + 1:]
45
46
 
46
47
  # extract command
47
48
  command = match.group(1).lower()
@@ -99,7 +100,7 @@ class MagicCommandHandler:
99
100
  optionals[name.lower()] = value
100
101
 
101
102
  # add to callbacks
102
- callback = MagicCommandCallback(magic, silent, code_wrapper, *args, **flags, **optionals)
103
+ callback = MagicCommandCallback(magic, silent, state, *args, **flags, **optionals)
103
104
  enabled_callbacks.append(callback)
104
105
 
105
106
  # disable overwritten callbacks
@@ -129,5 +130,4 @@ class MagicCommandHandler:
129
130
  post_query_callbacks.append(callback)
130
131
 
131
132
  # return callbacks
132
- code_wrapper.value = code
133
- return code, pre_query_callbacks, post_query_callbacks
133
+ return pre_query_callbacks, post_query_callbacks
@@ -0,0 +1,11 @@
1
+ from typing import Union, Dict, Optional
2
+
3
+ from ..db import Connection
4
+
5
+
6
+ class MagicState:
7
+ def __init__(self, db: Connection, code: str, max_rows: Optional[int]):
8
+ self.db: Connection = db
9
+ self.code: Union[str, Dict] = code
10
+ self.max_rows: Optional[int] = max_rows
11
+ self.column_name_mapping: Dict[str, str] = {}
@@ -2,3 +2,4 @@ from .MagicCommand import MagicCommand
2
2
  from .MagicCommandCallback import MagicCommandCallback
3
3
  from .MagicCommandException import MagicCommandException
4
4
  from .MagicCommandHandler import MagicCommandHandler
5
+ from .MagicState import MagicState
@@ -1,22 +1,9 @@
1
- from decimal import Decimal
2
-
3
- PLOTLY_VERSION = '3.0.1'
4
-
5
1
  import json
6
- from uuid import uuid4
2
+ from decimal import Decimal
7
3
  from typing import Dict, List, Optional
4
+ from uuid import uuid4
8
5
 
9
- __PLOTLY_INITIALIZED = False
10
-
11
-
12
- def __init() -> str:
13
- global __PLOTLY_INITIALIZED
14
-
15
- if not __PLOTLY_INITIALIZED:
16
- __PLOTLY_INITIALIZED = True
17
- return f'<script src="https://cdn.plot.ly/plotly-{PLOTLY_VERSION}.min.js"></script>'
18
- else:
19
- return ''
6
+ from .lib import init_plotly
20
7
 
21
8
 
22
9
  def __div_id() -> str:
@@ -60,7 +47,7 @@ def __fix_decimal(x: List):
60
47
 
61
48
 
62
49
  def draw_chart(title: Optional[str], traces: List[Dict] | Dict) -> str:
63
- init = __init()
50
+ init = init_plotly()
64
51
  div_id = __div_id()
65
52
  layout = __layout(title)
66
53
  config = __config()
@@ -69,7 +56,10 @@ def draw_chart(title: Optional[str], traces: List[Dict] | Dict) -> str:
69
56
  traces = json.dumps(traces)
70
57
 
71
58
  return f'''
72
- {init}
59
+ <script type="text/javascript">
60
+ {init}
61
+ </script>
62
+
73
63
  <div id="{div_id}"></div>
74
64
  <script type="text/javascript">
75
65
  Plotly.newPlot('{div_id}', {traces}, {json.dumps(layout)}, {json.dumps(config)});
@@ -1,12 +1,14 @@
1
- from typing import Dict
1
+ from typing import Dict, Optional
2
2
 
3
3
  from graphviz import Digraph
4
+ from uuid import uuid4
4
5
 
5
6
  from duckdb_kernel.db import Table
6
7
  from duckdb_kernel.parser.elements import RAElement
7
8
  from duckdb_kernel.util.formatting import row_count
8
9
  from .Drawer import Drawer
9
10
  from ..db import Connection
11
+ from .lib import *
10
12
 
11
13
 
12
14
  class RATreeDrawer(Drawer):
@@ -15,6 +17,9 @@ class RATreeDrawer(Drawer):
15
17
  self.root_node: RAElement = root_node
16
18
  self.tables: Dict[str, Table] = tables
17
19
 
20
+ self.nodes: Dict[str, RAElement] = {}
21
+ self.root_node_id: Optional[str] = None
22
+
18
23
  def to_graph(self) -> Digraph:
19
24
  # create graph
20
25
  ps = Digraph('Schema',
@@ -31,7 +36,11 @@ class RATreeDrawer(Drawer):
31
36
 
32
37
  def __add_node(self, ps: Digraph, node: RAElement) -> str:
33
38
  # use id of node object as identifier
34
- node_id = f'node_{id(node)}'
39
+ node_id = f'node_{str(uuid4()).replace("-", "_")}'
40
+
41
+ self.nodes[node_id] = node
42
+ if node == self.root_node:
43
+ self.root_node_id = node_id
35
44
 
36
45
  # generate child nodes
37
46
  child_ids = [self.__add_node(ps, child) for child in node.children]
@@ -69,3 +78,26 @@ class RATreeDrawer(Drawer):
69
78
 
70
79
  # return node identifier to generate edges
71
80
  return node_id
81
+
82
+ def to_interactive_svg(self) -> str:
83
+ div_id = f'div-{str(uuid4())}'
84
+
85
+ css = init_css()
86
+ ra = init_ra()
87
+ svg = self.to_svg(True)
88
+
89
+ return f'''
90
+ <style type="text/css">
91
+ {css}
92
+ </style>
93
+
94
+ <div id="{div_id}">
95
+ {svg}
96
+ </div>
97
+
98
+ <script type="text/javascript">
99
+ {ra}
100
+
101
+ animate_ra('{div_id}', '{self.root_node_id}')
102
+ </script>
103
+ '''
@@ -0,0 +1,53 @@
1
+ import os
2
+
3
+ __CSS_INITIALIZED = False
4
+ __RA_INITIALIZED = False
5
+ __PLOTLY_INITIALIZED = False
6
+
7
+ __location = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
8
+
9
+
10
+ def init_css() -> str:
11
+ global __CSS_INITIALIZED
12
+
13
+ if not __CSS_INITIALIZED:
14
+ with open(os.path.join(__location, 'ra.css')) as ra_file:
15
+ css = ra_file.read()
16
+ else:
17
+ css = ''
18
+
19
+ __CSS_INITIALIZED = True
20
+ return css
21
+
22
+
23
+ def init_ra() -> str:
24
+ global __RA_INITIALIZED
25
+
26
+ if not __RA_INITIALIZED:
27
+ with open(os.path.join(__location, 'ra.js')) as ra_file:
28
+ ra = ra_file.read()
29
+ else:
30
+ ra = ''
31
+
32
+ __RA_INITIALIZED = True
33
+ return ra
34
+
35
+
36
+ def init_plotly() -> str:
37
+ global __PLOTLY_INITIALIZED
38
+
39
+ if not __PLOTLY_INITIALIZED:
40
+ with open(os.path.join(__location, 'plotly-3.0.1.min.js')) as plotly_file:
41
+ plotly = plotly_file.read()
42
+ else:
43
+ plotly = ''
44
+
45
+ __PLOTLY_INITIALIZED = True
46
+ return plotly
47
+
48
+
49
+ __all__ = [
50
+ 'init_css',
51
+ 'init_ra',
52
+ 'init_plotly',
53
+ ]