sier2 0.17__py3-none-any.whl → 0.22__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 +46 -19
- {sier2-0.17.dist-info → sier2-0.22.dist-info}/METADATA +4 -3
- {sier2-0.17.dist-info → sier2-0.22.dist-info}/RECORD +8 -8
- {sier2-0.17.dist-info → sier2-0.22.dist-info}/LICENSE +0 -0
- {sier2-0.17.dist-info → sier2-0.22.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
|
|
|
@@ -122,7 +131,9 @@ def _show_dag(dag: Dag):
|
|
|
122
131
|
align='center'
|
|
123
132
|
)
|
|
124
133
|
|
|
125
|
-
|
|
134
|
+
# A place to stash the info FloatPanel.
|
|
135
|
+
#
|
|
136
|
+
info_fp_holder = pn.Column(visible=False)
|
|
126
137
|
|
|
127
138
|
sidebar_title = pn.Row(info_button, '## Blocks')
|
|
128
139
|
template = pn.template.BootstrapTemplate(
|
|
@@ -143,7 +154,8 @@ def _show_dag(dag: Dag):
|
|
|
143
154
|
'contentOverflow': 'scroll'
|
|
144
155
|
}
|
|
145
156
|
fp = pn.layout.FloatPanel(text, name=dag.title, width=550, height=450, contained=False, position='center', theme='dark filleddark', config=config)
|
|
146
|
-
|
|
157
|
+
info_fp_holder[:] = [fp]
|
|
158
|
+
|
|
147
159
|
info_button.on_click(display_info)
|
|
148
160
|
|
|
149
161
|
switch = pn.widgets.Switch(name='Stop')
|
|
@@ -204,7 +216,7 @@ def _show_dag(dag: Dag):
|
|
|
204
216
|
switch,
|
|
205
217
|
pn.panel(dag.hv_graph().opts(invert_yaxis=True, xaxis=None, yaxis=None)),
|
|
206
218
|
log_feed,
|
|
207
|
-
|
|
219
|
+
info_fp_holder
|
|
208
220
|
)
|
|
209
221
|
)
|
|
210
222
|
|
|
@@ -260,8 +272,8 @@ class BlockCard(pn.Card):
|
|
|
260
272
|
value=-1
|
|
261
273
|
)
|
|
262
274
|
|
|
263
|
-
if w
|
|
264
|
-
# This is
|
|
275
|
+
if isinstance(w, InputBlock):
|
|
276
|
+
# This is an input block, so add a 'Continue' button.
|
|
265
277
|
#
|
|
266
278
|
def on_continue(_event):
|
|
267
279
|
# The user may not have changed anything from the default values,
|
|
@@ -276,12 +288,27 @@ class BlockCard(pn.Card):
|
|
|
276
288
|
if dag_logger:
|
|
277
289
|
dag_logger.info('', block_name=None, block_state=None)
|
|
278
290
|
dag_logger.info('Execute dag', block_name='', block_state=BlockState.DAG)
|
|
279
|
-
|
|
291
|
+
|
|
292
|
+
# We want this block's execute() method to run first
|
|
293
|
+
# after the user clicks the "Continue" button.
|
|
294
|
+
# We make this happen by pushing this block on the head
|
|
295
|
+
# of the queue, but without any values - we don't want
|
|
296
|
+
# to trigger any param changes.
|
|
297
|
+
#
|
|
298
|
+
try:
|
|
299
|
+
dag.execute_after_input(w, dag_logger=dag_logger)
|
|
300
|
+
except BlockValidateError as e:
|
|
301
|
+
# Display the error as a notification.
|
|
302
|
+
#
|
|
303
|
+
block_name = html.escape(e.block_name)
|
|
304
|
+
error = html.escape(str(e))
|
|
305
|
+
notif = f'<b>{block_name}</b>:<br>{error}'
|
|
306
|
+
pn.state.notifications.error(notif, duration=0)
|
|
280
307
|
finally:
|
|
281
308
|
parent_template.main[0].loading = False
|
|
282
309
|
|
|
283
|
-
c_button = pn.widgets.Button(name=
|
|
284
|
-
|
|
310
|
+
c_button = pn.widgets.Button(name=w.continue_label, button_type='primary')
|
|
311
|
+
c_button.on_click(on_continue)
|
|
285
312
|
|
|
286
313
|
w_ = pn.Column(
|
|
287
314
|
w,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: sier2
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.22
|
|
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=XdkpUlXd2dkVhZrJiIBlDRbCvoabZkmuK3sHd8w4F4M,12118
|
|
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.22.dist-info/LICENSE,sha256=2AKq0yxLLDdGsj6xQuNjDPG5d2IbFWFGiB_cnCBtMp4,1064
|
|
14
|
+
sier2-0.22.dist-info/METADATA,sha256=-qzCWs4dbWiT2haxDg2V9H0h0340IbpYsx2Y_dUd2P8,2492
|
|
15
|
+
sier2-0.22.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
16
|
+
sier2-0.22.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|