1
1
#
2
2
# Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
3
3
#
4
-
5
4
""" This module provides various ways to make a Deephaven table. """
6
-
5
+ from functools import wraps
7
6
from typing import Callable , List , Dict , Any , Union , Sequence , Tuple , Mapping , Optional
8
7
9
8
import jpy
32
31
_JRingTableTools = jpy .get_type ("io.deephaven.engine.table.impl.sources.ring.RingTableTools" )
33
32
_JSupplier = jpy .get_type ('java.util.function.Supplier' )
34
33
_JFunctionGeneratedTableFactory = jpy .get_type ("io.deephaven.engine.table.impl.util.FunctionGeneratedTableFactory" )
34
+ _JPythonInputTableStatusListenerAdapter = jpy .get_type (
35
+ "io.deephaven.integrations.python.PythonInputTableStatusListenerAdapter" )
36
+
37
+ _DEFAULT_INPUT_TABLE_ON_ERROR_CALLBACK = lambda e : print (f"An error occurred during InputTable async operation: { e } " )
38
+
39
+
40
+ def _error_callback_wrapper (callback : Callable [[Exception ], None ]):
41
+ @wraps (callback )
42
+ def wrapper (e ):
43
+ callback (RuntimeError (e ))
44
+
45
+ return wrapper
35
46
36
47
37
48
def empty_table (size : int ) -> Table :
@@ -243,8 +254,8 @@ def __init__(self, j_table: jpy.JType):
243
254
raise DHError ("the provided table's InputTable attribute type is not of InputTableUpdater type." )
244
255
245
256
def add (self , table : Table ) -> None :
246
- """Synchronously writes rows from the provided table to this input table. If this is a keyed input table, added rows with keys
247
- that match existing rows will replace those rows.
257
+ """Synchronously writes rows from the provided table to this input table. If this is a keyed input table,
258
+ added rows with keys that match existing rows will replace those rows.
248
259
249
260
Args:
250
261
table (Table): the table that provides the rows to write
@@ -258,8 +269,8 @@ def add(self, table: Table) -> None:
258
269
raise DHError (e , "add to InputTable failed." ) from e
259
270
260
271
def delete (self , table : Table ) -> None :
261
- """Synchronously deletes the keys contained in the provided table from this keyed input table. If this method is called on an
262
- append-only input table, an error will be raised.
272
+ """Synchronously deletes the keys contained in the provided table from this keyed input table. If this
273
+ method is called on an append-only input table, an error will be raised.
263
274
264
275
Args:
265
276
table (Table): the table with the keys to delete
@@ -272,6 +283,76 @@ def delete(self, table: Table) -> None:
272
283
except Exception as e :
273
284
raise DHError (e , "delete data in the InputTable failed." ) from e
274
285
286
+ def add_async (self , table : Table , on_success : Callable [[], None ] = None ,
287
+ on_error : Callable [[Exception ], None ] = None ) -> None :
288
+ """Asynchronously writes rows from the provided table to this input table. If this is a keyed input table,
289
+ added rows with keys that match existing rows will replace those rows. This method returns immediately without
290
+ waiting for the operation to complete. If the operation succeeds, the optional on_success callback if provided
291
+ will be called. If the operation fails, the optional on_error callback if provided will be called. If on_error
292
+ is not provided, a default callback function will be called that simply prints out the received exception.
293
+
294
+ Note, multiple calls to this method on the same thread will be queued and processed in order. However, ordering
295
+ is not guaranteed across threads.
296
+
297
+ Args:
298
+ table (Table): the table that provides the rows to write
299
+ on_success (Callable[[], None]): the success callback function, default is None
300
+ on_error (Callable[[Exception], None]): the error callback function, default is None. When None, a default
301
+ callback function will be provided that simply prints out the received exception. If the callback
302
+ function itself raises an exception, the new exception will be logged in the Deephaven server log and
303
+ will not be further processed by the server.
304
+
305
+ Raises:
306
+ DHError
307
+ """
308
+ try :
309
+ if on_error :
310
+ on_error_callback = _error_callback_wrapper (on_error )
311
+ else :
312
+ on_error_callback = _error_callback_wrapper (_DEFAULT_INPUT_TABLE_ON_ERROR_CALLBACK )
313
+
314
+ j_input_table_status_listener = _JPythonInputTableStatusListenerAdapter .create (on_success ,
315
+ on_error_callback )
316
+ self .j_input_table .addAsync (table .j_table , j_input_table_status_listener )
317
+ except Exception as e :
318
+ raise DHError (e , "async add to InputTable failed." ) from e
319
+
320
+ def delete_async (self , table : Table , on_success : Callable [[], None ] = None ,
321
+ on_error : Callable [[Exception ], None ] = None ) -> None :
322
+ """Asynchronously deletes the keys contained in the provided table from this keyed input table. If this
323
+ method is
324
+ called on an append-only input table, an error will be raised. This method returns immediately without
325
+ waiting for
326
+ the operation to complete. If the operation succeeds, the optional on_success callback if provided
327
+ will be called. If the operation fails, the optional on_error callback if provided will be called. If on_error
328
+ is not provided, a default callback function will be called that simply prints out the received exception.
329
+
330
+ Note, multiple calls to this method on the same thread will be queued and processed in order. However, ordering
331
+ is not guaranteed across threads.
332
+
333
+ Args:
334
+ table (Table): the table with the keys to delete
335
+ on_success (Callable[[], None]): the success callback function, default is None
336
+ on_error (Callable[[Exception], None]): the error callback function, default is None. When None, a default
337
+ callback function will be provided that simply prints out the received exception. If the callback
338
+ function itself raises an exception, the new exception will be logged in the Deephaven server log and
339
+ will not be further processed by the server.
340
+
341
+ Raises:
342
+ DHError
343
+ """
344
+ try :
345
+ if on_error :
346
+ on_error_callback = _error_callback_wrapper (on_error )
347
+ else :
348
+ on_error_callback = _error_callback_wrapper (_DEFAULT_INPUT_TABLE_ON_ERROR_CALLBACK )
349
+
350
+ j_input_table_status_listener = _JPythonInputTableStatusListenerAdapter .create (on_success ,
351
+ on_error_callback )
352
+ self .j_input_table .deleteAsync (table .j_table , j_input_table_status_listener )
353
+ except Exception as e :
354
+ raise DHError (e , "async delete data in the InputTable failed." ) from e
355
+
275
356
@property
276
357
def key_names (self ) -> List [str ]:
277
358
"""The names of the key columns of the InputTable."""
@@ -354,11 +435,11 @@ def ring_table(parent: Table, capacity: int, initialize: bool = True) -> Table:
354
435
355
436
356
437
def function_generated_table (table_generator : Callable [..., Table ],
357
- source_tables : Union [Table , List [Table ]] = None ,
358
- refresh_interval_ms : int = None ,
359
- exec_ctx : ExecutionContext = None ,
360
- args : Tuple = (),
361
- kwargs : Dict = {}) -> Table :
438
+ source_tables : Union [Table , List [Table ]] = None ,
439
+ refresh_interval_ms : int = None ,
440
+ exec_ctx : ExecutionContext = None ,
441
+ args : Tuple = (),
442
+ kwargs : Dict = {}) -> Table :
362
443
"""Creates an abstract table that is generated by running the table_generator() function. The function will first be
363
444
run to generate the table when this method is called, then subsequently either (a) whenever one of the
364
445
'source_tables' ticks or (b) after refresh_interval_ms have elapsed. Either 'refresh_interval_ms' or
@@ -368,13 +449,15 @@ def function_generated_table(table_generator: Callable[..., Table],
368
449
function-generated tables can create tables that are produced by arbitrary Python logic (including using Pandas or
369
450
numpy). They can also be used to retrieve data from external sources (such as files or websites).
370
451
371
- The table definition must not change between invocations of the 'table_generator' function, or an exception will be raised.
452
+ The table definition must not change between invocations of the 'table_generator' function, or an exception will
453
+ be raised.
372
454
373
455
Note that the 'table_generator' may access data in the sourceTables but should not perform further table operations
374
456
on them without careful handling. Table operations may be memoized, and it is possible that a table operation will
375
457
return a table created by a previous invocation of the same operation. Since that result will not have been included
376
458
in the 'source_table', it's not automatically treated as a dependency for purposes of determining when it's safe to
377
- invoke 'table_generator', allowing races to exist between accessing the operation result and that result's own update
459
+ invoke 'table_generator', allowing races to exist between accessing the operation result and that result's own
460
+ update
378
461
processing. It's best to include all dependencies directly in 'source_table', or only compute on-demand inputs under
379
462
a LivenessScope.
380
463
@@ -441,6 +524,6 @@ def table_generator_function():
441
524
j_function_generated_table = _JFunctionGeneratedTableFactory .create (
442
525
table_generator_j_function ,
443
526
source_j_tables
444
- )
527
+ )
445
528
446
529
return Table (j_function_generated_table )
0 commit comments