sier2 0.17__py3-none-any.whl → 0.23__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.
Potentially problematic release.
This version of sier2 might be problematic. Click here for more details.
- sier2/__init__.py +1 -1
- sier2/_block.py +53 -7
- sier2/_dag.py +91 -29
- sier2/panel/_panel.py +67 -23
- {sier2-0.17.dist-info → sier2-0.23.dist-info}/METADATA +4 -3
- {sier2-0.17.dist-info → sier2-0.23.dist-info}/RECORD +8 -8
- {sier2-0.17.dist-info → sier2-0.23.dist-info}/LICENSE +0 -0
- {sier2-0.17.dist-info → sier2-0.23.dist-info}/WHEEL +0 -0
sier2/__init__.py
CHANGED
sier2/_block.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
from enum import StrEnum
|
|
2
2
|
import inspect
|
|
3
3
|
import param
|
|
4
|
-
from typing import Any
|
|
5
|
-
from collections import defaultdict
|
|
4
|
+
from typing import Any
|
|
6
5
|
|
|
7
6
|
from . import _logger
|
|
8
7
|
|
|
9
8
|
class BlockError(Exception):
|
|
10
|
-
"""Raised if a Block configuration is invalid.
|
|
9
|
+
"""Raised if a Block configuration is invalid.
|
|
10
|
+
|
|
11
|
+
If this exception is raised, the executing dag sets its stop
|
|
12
|
+
flag (which must be manually reset), and displays a stacktrace.
|
|
13
|
+
"""
|
|
11
14
|
|
|
12
15
|
pass
|
|
13
16
|
|
|
@@ -50,14 +53,14 @@ class Block(param.Parameterized):
|
|
|
50
53
|
|
|
51
54
|
SIER2_KEY = '_sier2__key'
|
|
52
55
|
|
|
53
|
-
def __init__(self, *args,
|
|
56
|
+
def __init__(self, *args, continue_label='Continue', **kwargs):
|
|
54
57
|
super().__init__(*args, **kwargs)
|
|
55
58
|
|
|
56
59
|
if not self.__doc__:
|
|
57
60
|
raise BlockError(f'Class {self.__class__} must have a docstring')
|
|
58
61
|
|
|
59
|
-
self.
|
|
60
|
-
self._block_state = BlockState.
|
|
62
|
+
self.continue_label = continue_label
|
|
63
|
+
# self._block_state = BlockState.READY
|
|
61
64
|
self.logger = _logger.get_logger(self.name)
|
|
62
65
|
|
|
63
66
|
# Maintain a map of "block+output parameter being watched" -> "input parameter".
|
|
@@ -66,7 +69,7 @@ class Block(param.Parameterized):
|
|
|
66
69
|
self._block_name_map: dict[tuple[str, str], str] = {}
|
|
67
70
|
|
|
68
71
|
# Record this block's output parameters.
|
|
69
|
-
# If this is
|
|
72
|
+
# If this is an input block, we need to trigger
|
|
70
73
|
# the output values before executing the next block,
|
|
71
74
|
# in case the user didn't change anything.
|
|
72
75
|
#
|
|
@@ -146,3 +149,46 @@ class Block(param.Parameterized):
|
|
|
146
149
|
result = {name: getattr(self, name) for name in out_names}
|
|
147
150
|
|
|
148
151
|
return result
|
|
152
|
+
|
|
153
|
+
class InputBlock(Block):
|
|
154
|
+
"""A ``Block`` that accepts user input.
|
|
155
|
+
|
|
156
|
+
An ``InputBlock`` executes in two steps().
|
|
157
|
+
|
|
158
|
+
When the block is executed by a dag, the dag first sets the input
|
|
159
|
+
params, then calls ``prepare()``. Execution of the dag then stops.
|
|
160
|
+
|
|
161
|
+
The dag is then restarted using ``dag.execute_after_input(input_block)``.
|
|
162
|
+
(An input block must be specified because it is not required that the
|
|
163
|
+
same input block be used immediately.) This causes the block's
|
|
164
|
+
``execute()`` method to be called without resetting the input params.
|
|
165
|
+
|
|
166
|
+
Dag execution then continues as normal.
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
def __init__(self, *args, continue_label='Continue', **kwargs):
|
|
170
|
+
super().__init__(*args, continue_label=continue_label, **kwargs)
|
|
171
|
+
self._block_state = BlockState.INPUT
|
|
172
|
+
|
|
173
|
+
def prepare(self):
|
|
174
|
+
"""Called by a dag before calling ``execute()```.
|
|
175
|
+
|
|
176
|
+
This gives the block author an opportunity to validate the
|
|
177
|
+
input params and set up a user inteface.
|
|
178
|
+
|
|
179
|
+
After the dag restarts on this block, ``execute()`` will be called.
|
|
180
|
+
"""
|
|
181
|
+
|
|
182
|
+
pass
|
|
183
|
+
|
|
184
|
+
class BlockValidateError(BlockError):
|
|
185
|
+
"""Raised if ``InputBlock.prepare()`` or ``Block.execute()`` determines that input data is invalid.
|
|
186
|
+
|
|
187
|
+
If this exception is raised, it will be caught by the executing dag.
|
|
188
|
+
The dag will not set its stop flag, no stacktrace will be displayed,
|
|
189
|
+
and the error message will be displayed.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
def __init__(self, block_name: str, error: str):
|
|
193
|
+
super().__init__(error)
|
|
194
|
+
self.block_name = block_name
|
sier2/_dag.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from ._block import Block, BlockError, BlockState
|
|
1
|
+
from ._block import Block, InputBlock, BlockError, BlockValidateError, BlockState
|
|
2
2
|
from dataclasses import dataclass, field #, KW_ONLY, field
|
|
3
3
|
from collections import defaultdict, deque
|
|
4
4
|
import holoviews as hv
|
|
@@ -28,7 +28,8 @@ class _InputValues:
|
|
|
28
28
|
"""Record a param value change.
|
|
29
29
|
|
|
30
30
|
When a block updates an output param, the update is queued until
|
|
31
|
-
the block finishes executing.
|
|
31
|
+
the block finishes executing. Instances of this class are
|
|
32
|
+
what is queued.
|
|
32
33
|
"""
|
|
33
34
|
|
|
34
35
|
# The block to be updated.
|
|
@@ -36,6 +37,9 @@ class _InputValues:
|
|
|
36
37
|
dst: Block
|
|
37
38
|
|
|
38
39
|
# The values to be set before the block executes.
|
|
40
|
+
# For a normal block, values will be non-empty when execute() is called.
|
|
41
|
+
# For an input block, if values is non-empty, prepare()
|
|
42
|
+
# will be called, else execute() will be called
|
|
39
43
|
#
|
|
40
44
|
values: dict[str, Any] = field(default_factory=dict)
|
|
41
45
|
|
|
@@ -63,21 +67,35 @@ class _BlockContext:
|
|
|
63
67
|
|
|
64
68
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
65
69
|
if exc_type is None:
|
|
66
|
-
self.block._block_state = BlockState.WAITING if self.block
|
|
67
|
-
elif
|
|
70
|
+
self.block._block_state = BlockState.WAITING if isinstance(self.block, InputBlock) else BlockState.SUCCESSFUL
|
|
71
|
+
elif exc_type is KeyboardInterrupt:
|
|
68
72
|
self.block_state._block_state = BlockState.INTERRUPTED
|
|
69
73
|
self.dag._stopper.event.set()
|
|
70
74
|
print(f'KEYBOARD INTERRUPT IN BLOCK {self.name}')
|
|
71
75
|
else:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
state = BlockState.ERROR
|
|
77
|
+
self.block._block_state = state
|
|
78
|
+
if exc_type is not BlockValidateError:
|
|
79
|
+
# Validation errors don't set the stopper;
|
|
80
|
+
# they just stop execution.
|
|
81
|
+
#
|
|
82
|
+
if self.dag_logger:
|
|
83
|
+
self.dag_logger.exception(
|
|
84
|
+
block_name=self.block.name,
|
|
85
|
+
block_state=state
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# msg = f'While in {self.block.name}.execute(): {exc_val}'
|
|
89
|
+
# LOGGER.exception(msg)
|
|
90
|
+
self.dag._stopper.event.set()
|
|
91
|
+
|
|
92
|
+
if not issubclass(exc_type, BlockError):
|
|
93
|
+
# Convert non-BlockErrors in the block to a BlockError.
|
|
94
|
+
#
|
|
95
|
+
raise BlockError(f'Block {self.block.name}: {str(exc_val)}') from exc_val
|
|
96
|
+
|
|
97
|
+
# Don't suppress the original exception.
|
|
98
|
+
#
|
|
81
99
|
return False
|
|
82
100
|
|
|
83
101
|
class _Stopper:
|
|
@@ -213,21 +231,52 @@ class Dag:
|
|
|
213
231
|
item.values[inp] = new
|
|
214
232
|
self._block_queue.append(item)
|
|
215
233
|
|
|
234
|
+
def execute_after_input(self, block: InputBlock, *, dag_logger=None):
|
|
235
|
+
"""Execute the dag after running ``prepare()`` in an input block.
|
|
236
|
+
|
|
237
|
+
After prepare() executes, and the user has possibly
|
|
238
|
+
provided input, the dag must continue with execute() in the
|
|
239
|
+
same block.
|
|
240
|
+
|
|
241
|
+
This method will prime the block queue with the specified block's
|
|
242
|
+
output, and call execute().
|
|
243
|
+
|
|
244
|
+
Parameters
|
|
245
|
+
----------
|
|
246
|
+
block: InputBlock
|
|
247
|
+
The block to restart the dag at.
|
|
248
|
+
dag_logger:
|
|
249
|
+
A logger adapter that will accept log messages.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
if not isinstance(block, InputBlock):
|
|
253
|
+
raise BlockError(f'A dag can only restart an InputBlock, not {block.name}')
|
|
254
|
+
|
|
255
|
+
# Prime the block queue, using an empty input param values dict
|
|
256
|
+
# to indicate that this is a restart, and Block.execute()
|
|
257
|
+
# must be called.
|
|
258
|
+
#
|
|
259
|
+
self._block_queue.appendleft(_InputValues(block, {}))
|
|
260
|
+
self.execute(dag_logger=dag_logger)
|
|
261
|
+
|
|
216
262
|
def execute(self, *, dag_logger=None):
|
|
217
263
|
"""Execute the dag.
|
|
218
264
|
|
|
219
|
-
The dag is executed by iterating through the block
|
|
265
|
+
The dag is executed by iterating through the block event queue
|
|
220
266
|
and popping events from the head of the queue. For each event,
|
|
221
267
|
update the destination block's input parameters and call
|
|
222
268
|
that block's execute() method.
|
|
223
269
|
|
|
224
|
-
If the current destination block
|
|
225
|
-
the loop will
|
|
226
|
-
|
|
270
|
+
If the current destination block is an ``InputBlock``,
|
|
271
|
+
the loop will call ``block.prepare()` instead of ``block.execute()``,
|
|
272
|
+
then stop. The dag can then be restarted with
|
|
273
|
+
``dag.execute_after_input()``.
|
|
227
274
|
|
|
228
|
-
To start
|
|
229
|
-
|
|
230
|
-
output param before the dag's execute() is called.
|
|
275
|
+
To start the dag, there must be something in the event queue -
|
|
276
|
+
the dag must be "primed". A block must have updated at least one
|
|
277
|
+
output param before the dag's execute() is called. Calling
|
|
278
|
+
``dag.execute()`` will then execute the dag starting with
|
|
279
|
+
the blocks connected to the first block.
|
|
231
280
|
"""
|
|
232
281
|
|
|
233
282
|
if not self._block_queue:
|
|
@@ -252,15 +301,32 @@ class Dag:
|
|
|
252
301
|
self._stopper.event.set()
|
|
253
302
|
raise BlockError(msg) from e
|
|
254
303
|
|
|
304
|
+
# Execute the block.
|
|
305
|
+
# Don't execute input blocks when we get to them,
|
|
306
|
+
# unless this is after the user has selected the "Continue"
|
|
307
|
+
# button.
|
|
308
|
+
#
|
|
309
|
+
is_input_block = isinstance(item.dst, InputBlock)
|
|
255
310
|
if can_execute:
|
|
256
311
|
with self._block_context(block=item.dst, dag=self, dag_logger=dag_logger) as g:
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
312
|
+
# If this is an input block, and there are input
|
|
313
|
+
# values, call prepare() if it exists.
|
|
314
|
+
#
|
|
315
|
+
if is_input_block and item.values:
|
|
316
|
+
g.prepare()
|
|
317
|
+
else:
|
|
318
|
+
g.execute()
|
|
319
|
+
|
|
320
|
+
if is_input_block and item.values:
|
|
260
321
|
# If the current destination block requires user input,
|
|
261
|
-
#
|
|
322
|
+
# stop executing the dag immediately, because we don't
|
|
323
|
+
# want to be setting the input params of further blocks
|
|
324
|
+
# and causing them to do things.
|
|
262
325
|
#
|
|
263
|
-
|
|
326
|
+
# This possibly leaves items on the queue, which will be
|
|
327
|
+
# executed on the next call to execute().
|
|
328
|
+
#
|
|
329
|
+
break
|
|
264
330
|
|
|
265
331
|
def disconnect(self, g: Block) -> None:
|
|
266
332
|
"""Disconnect block g from other blocks.
|
|
@@ -373,10 +439,6 @@ class Dag:
|
|
|
373
439
|
if hasattr(g, var):
|
|
374
440
|
args[var] = getattr(g, var)
|
|
375
441
|
|
|
376
|
-
# TODO is there a better way of checking for user_input?
|
|
377
|
-
if hasattr(g, 'user_input'):
|
|
378
|
-
args['user_input'] = getattr(g, 'user_input')
|
|
379
|
-
|
|
380
442
|
block = {
|
|
381
443
|
'block': g.block_key(),
|
|
382
444
|
'instance': i,
|
sier2/panel/_panel.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import ctypes
|
|
2
2
|
from datetime import datetime
|
|
3
|
+
import html
|
|
3
4
|
import panel as pn
|
|
4
5
|
import sys
|
|
5
6
|
import threading
|
|
6
7
|
|
|
7
|
-
from sier2 import Block, BlockState, Dag, BlockError
|
|
8
|
+
from sier2 import Block, InputBlock, BlockValidateError, BlockState, Dag, BlockError
|
|
9
|
+
from .._dag import _InputValues
|
|
8
10
|
from ._feedlogger import getDagPanelLogger, getBlockPanelLogger
|
|
9
11
|
from ._panel_util import _get_state_color, dag_doc
|
|
10
12
|
|
|
@@ -20,7 +22,7 @@ INFO_SVG = '''<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" vie
|
|
|
20
22
|
</svg>
|
|
21
23
|
'''
|
|
22
24
|
|
|
23
|
-
pn.extension('floatpanel', inline=True, nthreads=NTHREADS, loading_spinner='bar')
|
|
25
|
+
pn.extension('floatpanel', inline=True, nthreads=NTHREADS, loading_spinner='bar', notifications=True)
|
|
24
26
|
|
|
25
27
|
def _hms(sec):
|
|
26
28
|
h, sec = divmod(int(sec), 3600)
|
|
@@ -64,7 +66,7 @@ class _PanelContext:
|
|
|
64
66
|
self.block._progress.active = False
|
|
65
67
|
|
|
66
68
|
if exc_type is None:
|
|
67
|
-
state = BlockState.WAITING if self.block
|
|
69
|
+
state = BlockState.WAITING if isinstance(self.block, InputBlock) else BlockState.SUCCESSFUL
|
|
68
70
|
self.block._block_state = state
|
|
69
71
|
if self.dag_logger:
|
|
70
72
|
self.dag_logger.info(f'after {_hms(delta)}', block_name=self.block.name, block_state=state.value)
|
|
@@ -77,14 +79,21 @@ class _PanelContext:
|
|
|
77
79
|
else:
|
|
78
80
|
state = BlockState.ERROR
|
|
79
81
|
self.block._block_state = state
|
|
80
|
-
if
|
|
81
|
-
self.dag_logger
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
if exc_type is not BlockValidateError:
|
|
83
|
+
if self.dag_logger:
|
|
84
|
+
self.dag_logger.exception(
|
|
85
|
+
f'after {_hms(delta)}',
|
|
86
|
+
block_name=self.block.name,
|
|
87
|
+
block_state=state
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# msg = f'While in {self.block.name}.execute(): {exc_val}'
|
|
91
|
+
self.dag._stopper.event.set()
|
|
92
|
+
|
|
93
|
+
if not issubclass(exc_type, BlockError):
|
|
94
|
+
# Convert the error in the block to a BlockError.
|
|
95
|
+
#
|
|
96
|
+
raise BlockError(f'Block {self.block.name}: {str(exc_val)}') from exc_val
|
|
88
97
|
|
|
89
98
|
return False
|
|
90
99
|
|
|
@@ -107,10 +116,8 @@ def interrupt_thread(tid, exctype):
|
|
|
107
116
|
#
|
|
108
117
|
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_ulong(tid), None)
|
|
109
118
|
raise SystemError('PyThreadState_SetAsyncExc failed')
|
|
110
|
-
|
|
111
|
-
def
|
|
112
|
-
"""Display the dag in a panel template."""
|
|
113
|
-
|
|
119
|
+
|
|
120
|
+
def _prepare_to_show(dag: Dag):
|
|
114
121
|
# Replace the default text-based context with the panel-based context.
|
|
115
122
|
#
|
|
116
123
|
dag._block_context = _PanelContext
|
|
@@ -122,7 +129,9 @@ def _show_dag(dag: Dag):
|
|
|
122
129
|
align='center'
|
|
123
130
|
)
|
|
124
131
|
|
|
125
|
-
|
|
132
|
+
# A place to stash the info FloatPanel.
|
|
133
|
+
#
|
|
134
|
+
info_fp_holder = pn.Column(visible=False)
|
|
126
135
|
|
|
127
136
|
sidebar_title = pn.Row(info_button, '## Blocks')
|
|
128
137
|
template = pn.template.BootstrapTemplate(
|
|
@@ -143,7 +152,8 @@ def _show_dag(dag: Dag):
|
|
|
143
152
|
'contentOverflow': 'scroll'
|
|
144
153
|
}
|
|
145
154
|
fp = pn.layout.FloatPanel(text, name=dag.title, width=550, height=450, contained=False, position='center', theme='dark filleddark', config=config)
|
|
146
|
-
|
|
155
|
+
info_fp_holder[:] = [fp]
|
|
156
|
+
|
|
147
157
|
info_button.on_click(display_info)
|
|
148
158
|
|
|
149
159
|
switch = pn.widgets.Switch(name='Stop')
|
|
@@ -204,14 +214,30 @@ def _show_dag(dag: Dag):
|
|
|
204
214
|
switch,
|
|
205
215
|
pn.panel(dag.hv_graph().opts(invert_yaxis=True, xaxis=None, yaxis=None)),
|
|
206
216
|
log_feed,
|
|
207
|
-
|
|
217
|
+
info_fp_holder
|
|
208
218
|
)
|
|
209
219
|
)
|
|
210
220
|
|
|
221
|
+
return template
|
|
222
|
+
|
|
223
|
+
def _show_dag(dag: Dag):
|
|
224
|
+
"""Display the dag in a panel template."""
|
|
225
|
+
|
|
226
|
+
template = _prepare_to_show(dag)
|
|
227
|
+
|
|
211
228
|
pn.state.on_session_destroyed(_quit)
|
|
212
229
|
|
|
213
230
|
template.show(threaded=False)
|
|
214
231
|
|
|
232
|
+
def _serveable_dag(dag: Dag):
|
|
233
|
+
"""Serve the dag in a panel template."""
|
|
234
|
+
|
|
235
|
+
template = _prepare_to_show(dag)
|
|
236
|
+
|
|
237
|
+
pn.state.on_session_destroyed(_quit)
|
|
238
|
+
|
|
239
|
+
template.servable()
|
|
240
|
+
|
|
215
241
|
class BlockCard(pn.Card):
|
|
216
242
|
"""A custom card to wrap around a block.
|
|
217
243
|
|
|
@@ -260,8 +286,8 @@ class BlockCard(pn.Card):
|
|
|
260
286
|
value=-1
|
|
261
287
|
)
|
|
262
288
|
|
|
263
|
-
if w
|
|
264
|
-
# This is
|
|
289
|
+
if isinstance(w, InputBlock):
|
|
290
|
+
# This is an input block, so add a 'Continue' button.
|
|
265
291
|
#
|
|
266
292
|
def on_continue(_event):
|
|
267
293
|
# The user may not have changed anything from the default values,
|
|
@@ -276,12 +302,27 @@ class BlockCard(pn.Card):
|
|
|
276
302
|
if dag_logger:
|
|
277
303
|
dag_logger.info('', block_name=None, block_state=None)
|
|
278
304
|
dag_logger.info('Execute dag', block_name='', block_state=BlockState.DAG)
|
|
279
|
-
|
|
305
|
+
|
|
306
|
+
# We want this block's execute() method to run first
|
|
307
|
+
# after the user clicks the "Continue" button.
|
|
308
|
+
# We make this happen by pushing this block on the head
|
|
309
|
+
# of the queue, but without any values - we don't want
|
|
310
|
+
# to trigger any param changes.
|
|
311
|
+
#
|
|
312
|
+
try:
|
|
313
|
+
dag.execute_after_input(w, dag_logger=dag_logger)
|
|
314
|
+
except BlockValidateError as e:
|
|
315
|
+
# Display the error as a notification.
|
|
316
|
+
#
|
|
317
|
+
block_name = html.escape(e.block_name)
|
|
318
|
+
error = html.escape(str(e))
|
|
319
|
+
notif = f'<b>{block_name}</b>:<br>{error}'
|
|
320
|
+
pn.state.notifications.error(notif, duration=0)
|
|
280
321
|
finally:
|
|
281
322
|
parent_template.main[0].loading = False
|
|
282
323
|
|
|
283
|
-
c_button = pn.widgets.Button(name=
|
|
284
|
-
|
|
324
|
+
c_button = pn.widgets.Button(name=w.continue_label, button_type='primary')
|
|
325
|
+
c_button.on_click(on_continue)
|
|
285
326
|
|
|
286
327
|
w_ = pn.Column(
|
|
287
328
|
w,
|
|
@@ -318,3 +359,6 @@ class PanelDag(Dag):
|
|
|
318
359
|
|
|
319
360
|
def show(self):
|
|
320
361
|
_show_dag(self)
|
|
362
|
+
|
|
363
|
+
def servable(self):
|
|
364
|
+
_serveable_dag(self)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sier2
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.23
|
|
4
|
+
Summary: Blocks of code that are executed in dags
|
|
5
5
|
Author: algol60
|
|
6
6
|
Author-email: algol60@users.noreply.github.com
|
|
7
7
|
Requires-Python: >=3.11,<4.0
|
|
8
8
|
Classifier: Intended Audience :: Developers
|
|
9
9
|
Classifier: Intended Audience :: Science/Research
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
11
|
Classifier: Operating System :: OS Independent
|
|
11
12
|
Classifier: Programming Language :: Python :: 3
|
|
12
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -14,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
16
|
Classifier: Topic :: Scientific/Engineering
|
|
16
17
|
Classifier: Topic :: Software Development :: Libraries
|
|
17
|
-
Requires-Dist: holoviews (>=1.
|
|
18
|
+
Requires-Dist: holoviews (>=1.19.0)
|
|
18
19
|
Requires-Dist: panel (>=1.4.4)
|
|
19
20
|
Requires-Dist: param (>=2.1.0)
|
|
20
21
|
Description-Content-Type: text/x-rst
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
sier2/__init__.py,sha256=
|
|
1
|
+
sier2/__init__.py,sha256=t1dLAlWzyhcRxkH-lcmN4NmPFs1Z57iQ93HBO8Fcpmo,186
|
|
2
2
|
sier2/__main__.py,sha256=HZfzJLaD2_JOyKFkFYTD2vs-UARxNMjP4D7ZdJg405A,3140
|
|
3
|
-
sier2/_block.py,sha256=
|
|
4
|
-
sier2/_dag.py,sha256=
|
|
3
|
+
sier2/_block.py,sha256=wEXIk5UtV7utYSUNzQuXshgkKg6dVb7SGm4E6tfoTmM,6590
|
|
4
|
+
sier2/_dag.py,sha256=KlLvGImFZoJfzgjRHJ7l-mpkUtPUdiyFgAbdz8WJF-Y,21278
|
|
5
5
|
sier2/_library.py,sha256=aG1f6xHE2qtzvlFCgIp0cMXd6OKlkW_OvbQQb-b2l_8,7536
|
|
6
6
|
sier2/_logger.py,sha256=lwRmYjXMkP7TyURo5gvOf266vwGDFkLGau-EXpo5eEw,2379
|
|
7
7
|
sier2/_util.py,sha256=NmXI7QMSdkoSMe6EYJ-q8zI9iGJeMUto3g4314UVoM8,1932
|
|
8
8
|
sier2/_version.py,sha256=K5EdVMOTOHqhr-mIMjXhh84WHTSES2K-MJ_b--KryBM,71
|
|
9
9
|
sier2/panel/__init__.py,sha256=wDEf_v859flQX4udAVYZW1m79sfB1NIrI3pyNIpNiEM,29
|
|
10
10
|
sier2/panel/_feedlogger.py,sha256=tsrA8R2FZUecVY2egifVu2qosRfjccgvGRE0lLZSXZY,5270
|
|
11
|
-
sier2/panel/_panel.py,sha256=
|
|
11
|
+
sier2/panel/_panel.py,sha256=Q3a5Y1TTkhKzU5n0ZpmKH5MkSDOJAlidVz2Sq3F_cvc,12451
|
|
12
12
|
sier2/panel/_panel_util.py,sha256=omcLO0OIHhH00l9YXv09Qv8lnaY6VKsQ1F0qbsrs3vk,2450
|
|
13
|
-
sier2-0.
|
|
14
|
-
sier2-0.
|
|
15
|
-
sier2-0.
|
|
16
|
-
sier2-0.
|
|
13
|
+
sier2-0.23.dist-info/LICENSE,sha256=2AKq0yxLLDdGsj6xQuNjDPG5d2IbFWFGiB_cnCBtMp4,1064
|
|
14
|
+
sier2-0.23.dist-info/METADATA,sha256=ak30FoB2FhtDAuby3K97gbjc7NZkUgNXOPwCAlzYGNI,2492
|
|
15
|
+
sier2-0.23.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
16
|
+
sier2-0.23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|