kosh 3.4__tar.gz → 3.5__tar.gz

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.
Files changed (136) hide show
  1. {kosh-3.4/kosh.egg-info → kosh-3.5}/PKG-INFO +1 -1
  2. kosh-3.5/kosh/current_version.py +1 -0
  3. {kosh-3.4 → kosh-3.5}/kosh/dataset.py +44 -1
  4. {kosh-3.4 → kosh-3.5}/kosh/ensemble.py +44 -1
  5. {kosh-3.4 → kosh-3.5}/kosh/store.py +44 -1
  6. {kosh-3.4 → kosh-3.5/kosh.egg-info}/PKG-INFO +1 -1
  7. {kosh-3.4 → kosh-3.5}/kosh.egg-info/SOURCES.txt +12 -0
  8. {kosh-3.4 → kosh-3.5}/kosh.egg-info/top_level.txt +1 -4
  9. kosh-3.5/kosh_aml_files/dead/cassandra/__init__.py +1 -0
  10. kosh-3.5/kosh_aml_files/dead/cassandra/core.py +329 -0
  11. kosh-3.5/kosh_aml_files/dead/cassandra/init_casandra.py +70 -0
  12. kosh-3.5/kosh_aml_files/dead/cassandra/models.py +32 -0
  13. kosh-3.5/kosh_aml_files/dead/tests/cassandra/test_kosh_00.py +2 -0
  14. kosh-3.5/kosh_aml_files/dead/tests/cassandra/test_kosh_01.py +26 -0
  15. kosh-3.5/kosh_aml_files/dead/tests/cassandra/test_kosh_02.py +23 -0
  16. kosh-3.5/kosh_aml_files/dead/tests/cassandra/test_kosh_03.py +8 -0
  17. kosh-3.5/kosh_aml_files/dead/tests/sina/test_kosh_00.py +5 -0
  18. kosh-3.5/kosh_aml_files/dead/tests/sina/test_kosh_01.py +22 -0
  19. kosh-3.5/kosh_aml_files/dead/tests/sina/test_kosh_02.py +27 -0
  20. kosh-3.5/kosh_aml_files/dead/tests/sina/test_kosh_03.py +15 -0
  21. kosh-3.4/kosh/current_version.py +0 -1
  22. {kosh-3.4 → kosh-3.5}/LICENSE +0 -0
  23. {kosh-3.4 → kosh-3.5}/NOTICE +0 -0
  24. {kosh-3.4 → kosh-3.5}/README.md +0 -0
  25. {kosh-3.4 → kosh-3.5}/docs/gen_api_docs.py +0 -0
  26. {kosh-3.4 → kosh-3.5}/docs/source/conf.py +0 -0
  27. {kosh-3.4 → kosh-3.5}/examples/cluster.py +0 -0
  28. {kosh-3.4 → kosh-3.5}/examples/some_user_io_functions.py +0 -0
  29. {kosh-3.4 → kosh-3.5}/kosh/__init__.py +0 -0
  30. {kosh-3.4 → kosh-3.5}/kosh/_version.py +0 -0
  31. {kosh-3.4 → kosh-3.5}/kosh/cli.py +0 -0
  32. {kosh-3.4 → kosh-3.5}/kosh/core_sina.py +0 -0
  33. {kosh-3.4 → kosh-3.5}/kosh/exec_graphs/__init__.py +0 -0
  34. {kosh-3.4 → kosh-3.5}/kosh/exec_graphs/core.py +0 -0
  35. {kosh-3.4 → kosh-3.5}/kosh/kosh_command.py +0 -0
  36. {kosh-3.4 → kosh-3.5}/kosh/loaders/UltraLoader.py +0 -0
  37. {kosh-3.4 → kosh-3.5}/kosh/loaders/__init__.py +0 -0
  38. {kosh-3.4 → kosh-3.5}/kosh/loaders/core.py +0 -0
  39. {kosh-3.4 → kosh-3.5}/kosh/loaders/hdf5.py +0 -0
  40. {kosh-3.4 → kosh-3.5}/kosh/loaders/jsons.py +0 -0
  41. {kosh-3.4 → kosh-3.5}/kosh/loaders/npy.py +0 -0
  42. {kosh-3.4 → kosh-3.5}/kosh/loaders/pandas_loader.py +0 -0
  43. {kosh-3.4 → kosh-3.5}/kosh/loaders/pgm.py +0 -0
  44. {kosh-3.4 → kosh-3.5}/kosh/loaders/pil.py +0 -0
  45. {kosh-3.4 → kosh-3.5}/kosh/loaders/sidre.py +0 -0
  46. {kosh-3.4 → kosh-3.5}/kosh/lock_strategies.py +0 -0
  47. {kosh-3.4 → kosh-3.5}/kosh/operators/__init__.py +0 -0
  48. {kosh-3.4 → kosh-3.5}/kosh/operators/core.py +0 -0
  49. {kosh-3.4 → kosh-3.5}/kosh/operators/koshClustering.py +0 -0
  50. {kosh-3.4 → kosh-3.5}/kosh/operators/koshMaths.py +0 -0
  51. {kosh-3.4 → kosh-3.5}/kosh/parameter_store.py +0 -0
  52. {kosh-3.4 → kosh-3.5}/kosh/sampling_methods/__init__.py +0 -0
  53. {kosh-3.4 → kosh-3.5}/kosh/sampling_methods/cluster_sampling/Clustering.py +0 -0
  54. {kosh-3.4 → kosh-3.5}/kosh/sampling_methods/cluster_sampling/__init__.py +0 -0
  55. {kosh-3.4 → kosh-3.5}/kosh/schema.py +0 -0
  56. {kosh-3.4 → kosh-3.5}/kosh/skills/kosh/SKILL.md +0 -0
  57. {kosh-3.4 → kosh-3.5}/kosh/skills/kosh/agents/openai.yaml +0 -0
  58. {kosh-3.4 → kosh-3.5}/kosh/threadsafe.py +0 -0
  59. {kosh-3.4 → kosh-3.5}/kosh/threadsafe_decorators.py +0 -0
  60. {kosh-3.4 → kosh-3.5}/kosh/transformers/__init__.py +0 -0
  61. {kosh-3.4 → kosh-3.5}/kosh/transformers/core.py +0 -0
  62. {kosh-3.4 → kosh-3.5}/kosh/transformers/npy.py +0 -0
  63. {kosh-3.4 → kosh-3.5}/kosh/transformers/sidre.py +0 -0
  64. {kosh-3.4 → kosh-3.5}/kosh/transformers/skl.py +0 -0
  65. {kosh-3.4 → kosh-3.5}/kosh/transformers/utils.py +0 -0
  66. {kosh-3.4 → kosh-3.5}/kosh/utils.py +0 -0
  67. {kosh-3.4 → kosh-3.5}/kosh/workflow.py +0 -0
  68. {kosh-3.4 → kosh-3.5}/kosh/wrapper.py +0 -0
  69. {kosh-3.4 → kosh-3.5}/kosh.egg-info/dependency_links.txt +0 -0
  70. {kosh-3.4 → kosh-3.5}/kosh.egg-info/entry_points.txt +0 -0
  71. {kosh-3.4 → kosh-3.5}/kosh.egg-info/requires.txt +0 -0
  72. {kosh-3.4 → kosh-3.5}/pyproject.toml +0 -0
  73. {kosh-3.4 → kosh-3.5}/scripts/render_logos.py +0 -0
  74. {kosh-3.4 → kosh-3.5}/scripts/sbang +0 -0
  75. {kosh-3.4 → kosh-3.5}/setup.cfg +0 -0
  76. {kosh-3.4 → kosh-3.5}/setup.py +0 -0
  77. {kosh-3.4 → kosh-3.5}/tests/baselines/npy/gen.py +0 -0
  78. {kosh-3.4 → kosh-3.5}/tests/baselines/scripts/dummy.py +0 -0
  79. {kosh-3.4 → kosh-3.5}/tests/conftest.py +0 -0
  80. {kosh-3.4 → kosh-3.5}/tests/kosh_scaling.py +0 -0
  81. {kosh-3.4 → kosh-3.5}/tests/koshbase.py +0 -0
  82. {kosh-3.4 → kosh-3.5}/tests/non_parallel/test_kosh_cp.py +0 -0
  83. {kosh-3.4 → kosh-3.5}/tests/parallel/kosh_scaling.py +0 -0
  84. {kosh-3.4 → kosh-3.5}/tests/parallel/kosh_scaling_pgen.py +0 -0
  85. {kosh-3.4 → kosh-3.5}/tests/parallel/test_kosh_clustering.py +0 -0
  86. {kosh-3.4 → kosh-3.5}/tests/parallel/test_kosh_clustering_raw.py +0 -0
  87. {kosh-3.4 → kosh-3.5}/tests/parallel/test_kosh_mariadb_mpi.py +0 -0
  88. {kosh-3.4 → kosh-3.5}/tests/parallel/test_kosh_scaling_parallel.py +0 -0
  89. {kosh-3.4 → kosh-3.5}/tests/test_kosh_aliases.py +0 -0
  90. {kosh-3.4 → kosh-3.5}/tests/test_kosh_broken_loader.py +0 -0
  91. {kosh-3.4 → kosh-3.5}/tests/test_kosh_command_line.py +0 -0
  92. {kosh-3.4 → kosh-3.5}/tests/test_kosh_context_manager.py +0 -0
  93. {kosh-3.4 → kosh-3.5}/tests/test_kosh_curves.py +0 -0
  94. {kosh-3.4 → kosh-3.5}/tests/test_kosh_datasets.py +0 -0
  95. {kosh-3.4 → kosh-3.5}/tests/test_kosh_describe_feature.py +0 -0
  96. {kosh-3.4 → kosh-3.5}/tests/test_kosh_ensembles.py +0 -0
  97. {kosh-3.4 → kosh-3.5}/tests/test_kosh_ensembles_cp.py +0 -0
  98. {kosh-3.4 → kosh-3.5}/tests/test_kosh_fast_load.py +0 -0
  99. {kosh-3.4 → kosh-3.5}/tests/test_kosh_fix_fastsha.py +0 -0
  100. {kosh-3.4 → kosh-3.5}/tests/test_kosh_flake8.py +0 -0
  101. {kosh-3.4 → kosh-3.5}/tests/test_kosh_getitem_back_propagate.py +0 -0
  102. {kosh-3.4 → kosh-3.5}/tests/test_kosh_import_export_datasets.py +0 -0
  103. {kosh-3.4 → kosh-3.5}/tests/test_kosh_list_features.py +0 -0
  104. {kosh-3.4 → kosh-3.5}/tests/test_kosh_load_sina.py +0 -0
  105. {kosh-3.4 → kosh-3.5}/tests/test_kosh_loaders.py +0 -0
  106. {kosh-3.4 → kosh-3.5}/tests/test_kosh_loaders_multiple_features_name.py +0 -0
  107. {kosh-3.4 → kosh-3.5}/tests/test_kosh_lot_big_curves.py +0 -0
  108. {kosh-3.4 → kosh-3.5}/tests/test_kosh_mv.py +0 -0
  109. {kosh-3.4 → kosh-3.5}/tests/test_kosh_operators.py +0 -0
  110. {kosh-3.4 → kosh-3.5}/tests/test_kosh_operators_chain_preprocess.py +0 -0
  111. {kosh-3.4 → kosh-3.5}/tests/test_kosh_operators_decorators.py +0 -0
  112. {kosh-3.4 → kosh-3.5}/tests/test_kosh_parameter_store.py +0 -0
  113. {kosh-3.4 → kosh-3.5}/tests/test_kosh_protected_attributes.py +0 -0
  114. {kosh-3.4 → kosh-3.5}/tests/test_kosh_reassociate.py +0 -0
  115. {kosh-3.4 → kosh-3.5}/tests/test_kosh_rm.py +0 -0
  116. {kosh-3.4 → kosh-3.5}/tests/test_kosh_scaling.py +0 -0
  117. {kosh-3.4 → kosh-3.5}/tests/test_kosh_schema.py +0 -0
  118. {kosh-3.4 → kosh-3.5}/tests/test_kosh_script_wrapper.py +0 -0
  119. {kosh-3.4 → kosh-3.5}/tests/test_kosh_search.py +0 -0
  120. {kosh-3.4 → kosh-3.5}/tests/test_kosh_search_speed.py +0 -0
  121. {kosh-3.4 → kosh-3.5}/tests/test_kosh_sina_curves_as_associated.py +0 -0
  122. {kosh-3.4 → kosh-3.5}/tests/test_kosh_sina_files_section_as_associated.py +0 -0
  123. {kosh-3.4 → kosh-3.5}/tests/test_kosh_sina_section_for_kosh.py +0 -0
  124. {kosh-3.4 → kosh-3.5}/tests/test_kosh_skill.py +0 -0
  125. {kosh-3.4 → kosh-3.5}/tests/test_kosh_skill_codex_smoke.py +0 -0
  126. {kosh-3.4 → kosh-3.5}/tests/test_kosh_special_sina_types.py +0 -0
  127. {kosh-3.4 → kosh-3.5}/tests/test_kosh_store.py +0 -0
  128. {kosh-3.4 → kosh-3.5}/tests/test_kosh_store_custom_loaders.py +0 -0
  129. {kosh-3.4 → kosh-3.5}/tests/test_kosh_store_mv_cp_tar.py +0 -0
  130. {kosh-3.4 → kosh-3.5}/tests/test_kosh_sync.py +0 -0
  131. {kosh-3.4 → kosh-3.5}/tests/test_kosh_transformers.py +0 -0
  132. {kosh-3.4 → kosh-3.5}/tests/test_kosh_transformers_decorators.py +0 -0
  133. {kosh-3.4 → kosh-3.5}/tests/test_kosh_transformers_parent.py +0 -0
  134. {kosh-3.4 → kosh-3.5}/tests/test_kosh_users_and_groups.py +0 -0
  135. {kosh-3.4 → kosh-3.5}/tests/test_kosh_verbose_list_features.py +0 -0
  136. {kosh-3.4 → kosh-3.5}/tests/test_kosh_workflow_cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kosh
3
- Version: 3.4
3
+ Version: 3.5
4
4
  Summary: Manages Data Store with External Bulk Data
5
5
  Author: Charles Doutriaux, Renee Olson
6
6
  License: MIT
@@ -0,0 +1 @@
1
+ current_version = "3.5"
@@ -1463,7 +1463,7 @@ class KoshDataset(KoshSinaObject):
1463
1463
  return attributes
1464
1464
 
1465
1465
  @lock_strategies.lock_method
1466
- def to_dataframe(self, data_columns=[], *atts, **keys):
1466
+ def to_dataframe(self, data_columns=[], typed_columns=None, *atts, **keys):
1467
1467
  """Return the find object as a Pandas DataFrame.
1468
1468
 
1469
1469
  Pass in the same arguments and keyword arguments as the find method.
@@ -1482,6 +1482,39 @@ class KoshDataset(KoshSinaObject):
1482
1482
  :param data_columns: Columns to extract. By default this will include ['id', 'mime_type', 'uri', 'associated'].
1483
1483
  If nothing is passed, will return all data.
1484
1484
  :type data_columns: Union(str, list), optional
1485
+ :param typed_columns: Dictionary of column types and replacement values.
1486
+ If omitted, MySQL defaults are returned.
1487
+
1488
+ Supported types:
1489
+ [
1490
+ "Int8", "Int16", "Int32", "Int64",
1491
+ "UInt8", "UInt16", "UInt32", "UInt64",
1492
+ "float16", "float32", "float64",
1493
+ "Float32", "Float64",
1494
+ "bool", "boolean", "string", "object",
1495
+ "category", "datetime64[ns]", "timedelta64[ns]",
1496
+ ]
1497
+
1498
+ Example:
1499
+ {
1500
+ "my_int": {
1501
+ "type": "Int64",
1502
+ "replace": {None: 42},
1503
+ },
1504
+ "my_float": {
1505
+ "type": "float64",
1506
+ "replace": {None: np.nan, 999: -1},
1507
+ },
1508
+ "my_boolean": {
1509
+ "type": "boolean",
1510
+ "replace": {None: False},
1511
+ },
1512
+ "my_string": {
1513
+ "type": "string",
1514
+ "replace": {"This is empty": "Nothing Here"},
1515
+ },
1516
+ }
1517
+ :type typed_columns: dict, optional
1485
1518
  :return: Pandas DataFrame
1486
1519
  :rtype: Pandas DataFrame
1487
1520
  """
@@ -1522,4 +1555,14 @@ class KoshDataset(KoshSinaObject):
1522
1555
  attr_dict[column][i] = source['data'].get(column, {}).get('value', pd.NA)
1523
1556
 
1524
1557
  df = pd.DataFrame(attr_dict)
1558
+
1559
+ if isinstance(typed_columns, dict):
1560
+ for key, config in typed_columns.items():
1561
+ series = df[key]
1562
+
1563
+ if "replace" in config:
1564
+ series = series.replace(config["replace"]).infer_objects(copy=False)
1565
+
1566
+ df[key] = series.astype(config["type"])
1567
+
1525
1568
  return df
@@ -337,7 +337,7 @@ These datasets will inherit attributes and associated sources from the ensemble.
337
337
 
338
338
  @lock_strategies.lock_method
339
339
  def to_dataframe(self, data_columns=[], include_ensemble_attributes=True, include_ensemble_tags=True,
340
- *atts, **keys):
340
+ typed_columns=None, *atts, **keys):
341
341
  """Return the find_datasets object as a Pandas DataFrame.
342
342
 
343
343
  Pass in the same arguments and keyword arguments as the find method.
@@ -362,6 +362,39 @@ These datasets will inherit attributes and associated sources from the ensemble.
362
362
  :type include_ensemble_attributes: bool, optional
363
363
  :param include_ensemble_tags: Include ensemble tags in DataFrame.
364
364
  :type include_ensemble_tags: bool, optional
365
+ :param typed_columns: Dictionary of column types and replacement values.
366
+ If omitted, MySQL defaults are returned.
367
+
368
+ Supported types:
369
+ [
370
+ "Int8", "Int16", "Int32", "Int64",
371
+ "UInt8", "UInt16", "UInt32", "UInt64",
372
+ "float16", "float32", "float64",
373
+ "Float32", "Float64",
374
+ "bool", "boolean", "string", "object",
375
+ "category", "datetime64[ns]", "timedelta64[ns]",
376
+ ]
377
+
378
+ Example:
379
+ {
380
+ "my_int": {
381
+ "type": "Int64",
382
+ "replace": {None: 42},
383
+ },
384
+ "my_float": {
385
+ "type": "float64",
386
+ "replace": {None: np.nan, 999: -1},
387
+ },
388
+ "my_boolean": {
389
+ "type": "boolean",
390
+ "replace": {None: False},
391
+ },
392
+ "my_string": {
393
+ "type": "string",
394
+ "replace": {"This is empty": "Nothing Here"},
395
+ },
396
+ }
397
+ :type typed_columns: dict, optional
365
398
  :return: Pandas DataFrame
366
399
  :rtype: Pandas DataFrame
367
400
  """
@@ -425,4 +458,14 @@ These datasets will inherit attributes and associated sources from the ensemble.
425
458
  attr_dict[f"{self.id}_ENSEMBLE_ATTRIBUTE_{key}"] = [val] * total_datasets
426
459
 
427
460
  df = pd.DataFrame(attr_dict)
461
+
462
+ if isinstance(typed_columns, dict):
463
+ for key, config in typed_columns.items():
464
+ series = df[key]
465
+
466
+ if "replace" in config:
467
+ series = series.replace(config["replace"]).infer_objects(copy=False)
468
+
469
+ df[key] = series.astype(config["type"])
470
+
428
471
  return df
@@ -2307,7 +2307,7 @@ class KoshStore(object):
2307
2307
  KoshCmd._tar(self, tar_type, store_args=cmmd, opts=opts)
2308
2308
 
2309
2309
  @lock_strategies.lock_method
2310
- def to_dataframe(self, data_columns=[], *atts, **keys):
2310
+ def to_dataframe(self, data_columns=[], typed_columns=None, *atts, **keys):
2311
2311
  """Return the find object as a Pandas DataFrame.
2312
2312
 
2313
2313
  Pass in the same arguments and keyword arguments as the find method.
@@ -2328,6 +2328,39 @@ class KoshStore(object):
2328
2328
  'creation_date', 'last_modified_date'].
2329
2329
  If nothing is passed, will return all data.
2330
2330
  :type data_columns: Union(str, list), optional
2331
+ :param typed_columns: Dictionary of column types and replacement values.
2332
+ If omitted, MySQL defaults are returned.
2333
+
2334
+ Supported types:
2335
+ [
2336
+ "Int8", "Int16", "Int32", "Int64",
2337
+ "UInt8", "UInt16", "UInt32", "UInt64",
2338
+ "float16", "float32", "float64",
2339
+ "Float32", "Float64",
2340
+ "bool", "boolean", "string", "object",
2341
+ "category", "datetime64[ns]", "timedelta64[ns]",
2342
+ ]
2343
+
2344
+ Example:
2345
+ {
2346
+ "my_int": {
2347
+ "type": "Int64",
2348
+ "replace": {None: 42},
2349
+ },
2350
+ "my_float": {
2351
+ "type": "float64",
2352
+ "replace": {None: np.nan, 999: -1},
2353
+ },
2354
+ "my_boolean": {
2355
+ "type": "boolean",
2356
+ "replace": {None: False},
2357
+ },
2358
+ "my_string": {
2359
+ "type": "string",
2360
+ "replace": {"This is empty": "Nothing Here"},
2361
+ },
2362
+ }
2363
+ :type typed_columns: dict, optional
2331
2364
  :return: Pandas DataFrame
2332
2365
  :rtype: Pandas DataFrame
2333
2366
  """
@@ -2365,4 +2398,14 @@ class KoshStore(object):
2365
2398
  attr_dict[column][i] = dataset['data'].get(column, {}).get('value', pd.NA)
2366
2399
 
2367
2400
  df = pd.DataFrame(attr_dict)
2401
+
2402
+ if isinstance(typed_columns, dict):
2403
+ for key, config in typed_columns.items():
2404
+ series = df[key]
2405
+
2406
+ if "replace" in config:
2407
+ series = series.replace(config["replace"]).infer_objects(copy=False)
2408
+
2409
+ df[key] = series.astype(config["type"])
2410
+
2368
2411
  return df
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kosh
3
- Version: 3.4
3
+ Version: 3.5
4
4
  Summary: Manages Data Store with External Bulk Data
5
5
  Author: Charles Doutriaux, Renee Olson
6
6
  License: MIT
@@ -57,6 +57,18 @@ kosh/transformers/npy.py
57
57
  kosh/transformers/sidre.py
58
58
  kosh/transformers/skl.py
59
59
  kosh/transformers/utils.py
60
+ kosh_aml_files/dead/cassandra/__init__.py
61
+ kosh_aml_files/dead/cassandra/core.py
62
+ kosh_aml_files/dead/cassandra/init_casandra.py
63
+ kosh_aml_files/dead/cassandra/models.py
64
+ kosh_aml_files/dead/tests/cassandra/test_kosh_00.py
65
+ kosh_aml_files/dead/tests/cassandra/test_kosh_01.py
66
+ kosh_aml_files/dead/tests/cassandra/test_kosh_02.py
67
+ kosh_aml_files/dead/tests/cassandra/test_kosh_03.py
68
+ kosh_aml_files/dead/tests/sina/test_kosh_00.py
69
+ kosh_aml_files/dead/tests/sina/test_kosh_01.py
70
+ kosh_aml_files/dead/tests/sina/test_kosh_02.py
71
+ kosh_aml_files/dead/tests/sina/test_kosh_03.py
60
72
  scripts/render_logos.py
61
73
  scripts/sbang
62
74
  tests/conftest.py
@@ -1,11 +1,8 @@
1
- 21742
2
- 23834
3
- 33823
4
- 43672
5
1
  dist
6
2
  docs
7
3
  examples
8
4
  kosh
5
+ kosh_aml_files
9
6
  recipe
10
7
  scripts
11
8
  share
@@ -0,0 +1 @@
1
+ from .core import KoshStoreCassandra, KoshArrayCassandra, KoshConnect
@@ -0,0 +1,329 @@
1
+ # Cassandra implementation
2
+ from kosh.core import KoshStoreClass, KoshDataset, KoshArray
3
+ import cassandra
4
+ from cassandra.cluster import Cluster, Session
5
+ from cassandra.auth import PlainTextAuthProvider
6
+ from cassandra.cqlengine.models import Model
7
+ from cassandra.cqlengine import connection, columns
8
+ from cassandra.cqlengine.management import sync_table
9
+ from cassandra.util import uuid_from_time
10
+ from cassandra.query import BatchStatement, ConsistencyLevel
11
+ from .models import DataSetModel, UsersModel, MetadataModel, types_mapping
12
+ from collections import OrderedDict
13
+ import warnings
14
+ import time
15
+ import uuid
16
+ import numpy
17
+
18
+
19
+ types = {"dataset": 0, "array": 1, "image": 2}
20
+
21
+
22
+ class KoshCassandraObject(object):
23
+ def __init__(self, Id, koshType, protected=[]):
24
+ self.__dict__["__protected__"] = [
25
+ "__id__", "__type__", "__protected__"] + protected
26
+ self.__dict__["__id__"] = Id
27
+ self.__dict__["__type__"] = koshType
28
+
29
+ def __setattr__(self, name, value):
30
+ if name in self.__protected__:
31
+ self.__dict__[name] = value
32
+ return
33
+ exists = MetadataModel.objects(
34
+ id=self.__id__, id_type=self.__type__, name=name)
35
+ if exists.count() != 0:
36
+ # we need to drop it first, replacing
37
+ for e in exists:
38
+ e.delete()
39
+ MetadataModel.create(
40
+ id=self.__id__, id_type=self.__type__, name=name, value=repr(value))
41
+
42
+ def __getattr__(self, name):
43
+ if name in self.__dict__["__protected__"]:
44
+ return self.__dict__.get(name)
45
+ if name == "__attributes__":
46
+ return self.__getattributes__()
47
+
48
+ exists = MetadataModel.objects(
49
+ id=self.__id__, id_type=self.__type__, name=name)
50
+ if exists.count() == 0:
51
+ raise RuntimeError(
52
+ "Object {} does not have {} attribute".format(self.__id__, name))
53
+ return eval(exists[0].value)
54
+
55
+ def __delattr__(self, name):
56
+ if name in self.__protected__:
57
+ return
58
+ exists = MetadataModel.objects(
59
+ id=self.__id__, id_type=self.__type__, name=name)
60
+ if exists.count() == 0:
61
+ raise RuntimeError(
62
+ "Object {} does not have {} attribute".format(self.__id__, name))
63
+ exists[0].delete()
64
+
65
+ def listattributes(self):
66
+ exists = MetadataModel.objects(id=self.__id__, id_type=self.__type__)
67
+ attributes = []
68
+ for e in exists:
69
+ attributes.append(e.name)
70
+ return attributes
71
+
72
+ def __getattributes__(self):
73
+ exists = MetadataModel.objects(id=self.__id__, id_type=self.__type__)
74
+ attributes = {}
75
+ for e in exists:
76
+ attributes[e.name] = eval(e.value)
77
+ return attributes
78
+
79
+
80
+ class KoshConnect(object):
81
+ def __init__(self, username, token, keyspace=None, cluster=[
82
+ "sonar8", ], auth_provider=None, cassandraRoot="kosh"):
83
+ # This allows me to have test tables, etc...
84
+ self.__cassandraRoot__ = cassandraRoot
85
+ print("Connecting")
86
+ self.connect(username, token, keyspace, cluster, auth_provider)
87
+
88
+ def connect(self, username, token, keyspace=None,
89
+ cluster_names=["sonar8", ], auth_provider=None):
90
+ """ Connect to a cassandra database """
91
+ from cassandra.cluster import Cluster, Session
92
+ if auth_provider is None:
93
+ print("CREATING AUTH", username, token)
94
+ from cassandra.auth import PlainTextAuthProvider
95
+ auth_provider = PlainTextAuthProvider(
96
+ username=username, password=token)
97
+
98
+ if not isinstance(cluster_names, list):
99
+ cluster_names = [cluster_names, ]
100
+ # print("CLUSTER TO:", cluster_names)
101
+ cluster = Cluster(cluster_names, auth_provider=auth_provider)
102
+ if keyspace is None:
103
+ keyspace = username + "_k"
104
+ # print("KSPACE:", keyspace)
105
+ self.__session__ = cluster.connect(keyspace)
106
+ # print("CONNECTED TO:", self.__session__, auth_provider.username, auth_provider.password)
107
+ self.__username__ = username
108
+ connection.setup(cluster_names, default_keyspace=keyspace,
109
+ auth_provider=auth_provider)
110
+ for obj in [DataSetModel, UsersModel, MetadataModel]:
111
+ obj.__keyspace__ = self.__session__.keyspace
112
+ obj.__table_name__ = "{}_{}".format(
113
+ self.__cassandraRoot__, obj.__table_suffix__)
114
+ sync_table(obj)
115
+ self.__user_id__ = UsersModel.objects(name=self.__username__)[0].id
116
+ # self.prepared = {}
117
+ # self.prepared["datasetids"] = self.session.prepare("SELECT id from {}_datasets".format(self.cassandraRoot))
118
+ # self.prepared["metadata"] = self.session.prepare("SELECT * from {}_metadata where id=? and id_type=?".format(self.cassandraRoot))
119
+
120
+ def __del__(self):
121
+ # when destroying let's shutdown Cassandra cluster
122
+ # print("Shutting down Cassandra Cluster")
123
+ self.__session__.cluster.shutdown()
124
+ del(self.__session__)
125
+
126
+
127
+ class KoshArrayCassandra(KoshConnect, KoshCassandraObject, KoshArray):
128
+ def __init__(self, Id, dimensions, username, token, keyspace=None, cluster=[
129
+ "sonar8", ], auth_provider=None, cassandraRoot="kosh"):
130
+ """ Create a Casandra-based array, needs a connection to a cassandra database for metadata
131
+
132
+ Id: can be set to None to indicate new/inexisting array, otherwise point to array to read/extend
133
+ dimensions: ignored if array already exists, otherwise dictionary with dimension names as keys and metadata as dictinoary value
134
+ """
135
+ if Id is None: # New array?
136
+ Id = uuid.uuid1().hex
137
+
138
+ KoshCassandraObject.__init__(self, Id, types["array"], protected=[
139
+ "__name__", "__creator__", "__type__", "__dims__",
140
+ "__session__", "__username__", "__cassandraRoot__",
141
+ "__table_id__", "__user_id__",
142
+ "__readers__", "__exporters__"])
143
+
144
+ KoshConnect.__init__(
145
+ self,
146
+ username,
147
+ token,
148
+ keyspace,
149
+ cluster,
150
+ auth_provider,
151
+ cassandraRoot)
152
+
153
+ self.__type__ = types["array"]
154
+ # Ok now create associted table, based on dimensions
155
+ self.__table_id__ = "{}_array_{}".format(self.__cassandraRoot__, Id)
156
+
157
+ dims = []
158
+ primary = []
159
+ if isinstance(dimensions, (list, tuple)):
160
+ tmp = OrderedDict()
161
+ for d in dimensions:
162
+ tmp[d] = {}
163
+ dimensions = tmp
164
+ if not isinstance(dimensions, OrderedDict):
165
+ raise RuntimeError("'dimensions' must be list or ordered dict")
166
+ self.__dims__ = dimensions
167
+ for dim in dimensions:
168
+ dim_dict = dimensions[dim]
169
+ dim_type = dim_dict.get("type", "float")
170
+ if dim_dict.get("primary", False):
171
+ primary.append(dim)
172
+ dims += [dim + " " + dim_type]
173
+ if primary == []:
174
+ primary = dimensions.keys()
175
+ tables = self.__session__.cluster.metadata.keyspaces[self.__session__.keyspace].tables
176
+ dims.append("value float")
177
+ if not self.__table_id__ in tables:
178
+ self.__session__.execute("create table {}({}, primary key({}))".format(
179
+ self.__table_id__, ",".join(dims), ",".join(primary)))
180
+ # self.__ArrayModel__ = ArrayModel
181
+
182
+ def load_from_numpy(self, data, offsets=None):
183
+ dims = list(self.__dims__.keys()) + ["value", ]
184
+ print("DIMS:", dims)
185
+ vals = ["?", ] * len(dims)
186
+ ps = self.__session__.prepare(
187
+ "INSERT INTO {} ( {} ) VALUES ( {} )".format(
188
+ self.__table_id__, ",".join(dims), ",".join(vals)))
189
+ # Ok did user send us dimensions values?
190
+ for i, d in enumerate(self.__dims__):
191
+ if self.__dims__[d].get("values", None) is None:
192
+ self.__dims__[d]["values"] = list(range(data.shape[i]))
193
+
194
+ batch = BatchStatement(consistency_level=ConsistencyLevel.QUORUM)
195
+ for i in range(data.size):
196
+ values = list(numpy.unravel_index(i, data.shape))
197
+ values += [float(data.flat[i]), ]
198
+ if data.size < 65535:
199
+ batch.add(ps, values)
200
+ else:
201
+ self.__session__.execute_async(ps, values)
202
+ if data.size < 65535:
203
+ self.__session__.execute_async(batch)
204
+
205
+ def __getitem__(self, *args):
206
+ args = args[0]
207
+ dims = list(self.__dims__.keys())
208
+ values = []
209
+ for i in range(len(args)):
210
+ a = self.__dims__[dims[i]]["values"][args[i]]
211
+ vals = ", ".join([str(_) for _ in a])
212
+ cmd = dims[i] + " IN ( {} )".format(vals)
213
+ values.append(cmd)
214
+ stmnt = "SELECT value FROM " + self.__table_id__ + \
215
+ " WHERE " + " AND ".join(values) + ";"
216
+ return self.__session__.execute(stmnt)
217
+
218
+ def __str__(self):
219
+ st = ""
220
+ st += "KOSH Array\n"
221
+ st += "\tid: {}\n".format(self.__id__)
222
+ st += "\tdimensions:{}\n".format(self.__dims__)
223
+ atts = self.__attributes__
224
+ if len(atts) > 0:
225
+ st += "\n--- Attributes ---\n"
226
+ for a in atts:
227
+ st += "\t{}: {}\n".format(a, atts[a])
228
+ st += "DONE!"
229
+ return st
230
+
231
+
232
+ class KoshDatasetCassandra(KoshDataset, KoshCassandraObject):
233
+ def __init__(self, Id):
234
+ KoshCassandraObject.__init__(self, Id, types["dataset"], protected=[
235
+ "__name__", "__creator__"])
236
+ ds = DataSetModel.objects(id=Id)[0] # unique by design
237
+ self.__creator__ = ds.creator
238
+ self.__name__ = ds.name
239
+
240
+ def __str__(self):
241
+ st = ""
242
+ st += "KOSH DATASET\n"
243
+ st += "\tid: {}\n".format(self.__id__)
244
+ st += "\tname:{}\n".format(self.__name__)
245
+ st += "\tcreator: {}\n".format(self.__creator__)
246
+ atts = self.__attributes__
247
+ if len(atts) > 0:
248
+ st += "\n--- Attributes ---\n"
249
+ for a in atts:
250
+ st += "\t{}: {}\n".format(a, atts[a])
251
+ return st
252
+
253
+
254
+ class KoshStoreCassandra(KoshConnect, KoshStoreClass):
255
+ def __name_value_search(self, name, value):
256
+ if isinstance(value, str):
257
+ value = "''{}''".format(value)
258
+ values = "(name, id_type, value) = ('{}', {}, '{}' )".format(
259
+ name, types["dataset"], value)
260
+ stmnt = "select id from {}_metadata where {} allow filtering".format(
261
+ self.__cassandraRoot__, values)
262
+ print("STE:", stmnt)
263
+ rows = self.__session__.execute(stmnt)
264
+ return rows
265
+
266
+ def search(self, *atts, **keys):
267
+ """ Search cassandra for datasets matching some metadata
268
+ arguments are the metadata name we are looking for e.g search("attr1", "attr2")
269
+ you can further restrict by specifying exact value for a metadata via key=value
270
+ """
271
+ no_values = "name in ({}) and id_type={}".format(
272
+ ",".join(["'{}'".format(a) for a in atts]), types["dataset"])
273
+
274
+ if len(atts) == 0 and len(keys) == 0:
275
+ raise RuntimeError("You need to pass some search")
276
+
277
+ rows = self.__session__.execute(
278
+ "select id from {}_metadata where {} allow filtering".format(
279
+ self.__cassandraRoot__, no_values))
280
+ ids = set()
281
+ for row in rows:
282
+ ids.add(row.id)
283
+ # Need to "escape quotes"
284
+ for k in keys:
285
+ value = keys[k]
286
+ if not isinstance(value, (list, tuple)):
287
+ value = [value, ]
288
+ rows = []
289
+ for val in value:
290
+ rows += self.__name_value_search(k, val)
291
+ limited = set()
292
+ for row in rows:
293
+ if row.id in ids:
294
+ limited.add(row.id)
295
+ for an_id in list(ids):
296
+ if not an_id in limited:
297
+ ids.remove(an_id)
298
+
299
+ # Return the datasets
300
+ ds = []
301
+ for ds_id in ids:
302
+ ds.append(self.open(ds_id))
303
+ return ds
304
+
305
+ def open(self, id):
306
+ """Returns a dataset from Cassandra, based on its id"""
307
+ return KoshDatasetCassandra(id)
308
+
309
+ def create(self, name=None, id=None, metadata={}):
310
+ """create a new (possibly named) dataset"""
311
+ # existingDatasets = self.session.execute_async(self.prepared["datasetids"])
312
+ if id is None:
313
+ if name is None:
314
+ name = "Unnamed Dataset"
315
+ ds = DataSetModel.create(
316
+ id=uuid_from_time(
317
+ time.time()),
318
+ name=name,
319
+ creator=self.__user_id__)
320
+ else:
321
+ ds = DataSetModel.objects(id=id)
322
+ if ds.count() == 0:
323
+ ds = DataSetModel.create(
324
+ id=id, name=name, creator=self.__user_id__)
325
+ else:
326
+ raise RuntimeError(
327
+ "Dataset Id {}, already exists, cannot create duplicate dataset".format(id))
328
+ ds = KoshDatasetCassandra(str(ds.id))
329
+ return ds
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env python
2
+
3
+ import argparse
4
+ from cassandra.cluster import Cluster, Session
5
+ from cassandra.auth import PlainTextAuthProvider
6
+ import os
7
+
8
+ parser = argparse.ArgumentParser()
9
+ parser.add_argument("--user", default="cdoutrix", help="username to connect to cassandra")
10
+ parser.add_argument("--token", default=None, help="token to log, will try to read from ${HOME}/.cassandra/cqlshrc")
11
+ parser.add_argument("--keyspace", default=None, help="keyspace, will try to read from ${HOME}/.cassandra/cqlshrc")
12
+ parser.add_argument("--cluster", default="sonar8", help="Cluster")
13
+ parser.add_argument("--tables_root", default="kosh", help="root for tables names")
14
+ args = parser.parse_args()
15
+
16
+ token = args.token
17
+ keyspace = args.keyspace
18
+ with open(os.path.expanduser("~/.cassandra/cqlshrc")) as f:
19
+ lines = f.readlines()
20
+ if token is None:
21
+ token = lines[2].split("=", 0)[-1].strip()
22
+ if keyspace is None:
23
+ keyspace = lines[3].split("=")[1].strip()
24
+ auth_provider = PlainTextAuthProvider(username=args.user, password=token)
25
+ cluster = Cluster(args.cluster.split(),auth_provider=auth_provider, protocol_version=2)
26
+ session = cluster.connect(keyspace)
27
+
28
+ drop_commands = """
29
+ drop table {root}_metadata
30
+ drop table {root}_datasets
31
+ drop table {root}_permissions
32
+ drop table {root}_users
33
+ drop table {root}_targets
34
+ """.format(root=args.tables_root)
35
+
36
+ create_commands = """
37
+ create table {root}_metadata (id timeuuid , id_type int , name text, value text, primary key ((id), name, id_type, value))
38
+ create index on {root}_metadata (name)
39
+ create index on {root}_metadata (value)
40
+ create index on {root}_metadata (id_type)
41
+ create table {root}_datasets (id timeuuid, creator int, name text, primary key (id, creator))
42
+ create table {root}_users(id int, name text, primary key (name, id))
43
+ create table {root}_permissions(user_id int, resource_id text, resource_type int, permission int, primary key (user_id, resource_id, resource_type))
44
+ create table {root}_targets(id timeuuid primary key, source_type int, source_parameters map<text, text>, target_url text)
45
+ insert into {root}_users (id, name) values (0, '{user}')
46
+ """.format(root=args.tables_root, user=args.user)
47
+ for command in drop_commands.split("\n"):
48
+ if len(command)>0:
49
+ print("Executing:", command)
50
+ try:
51
+ session.execute(command)
52
+ except Exception:
53
+ pass
54
+
55
+ # Now drop array tables
56
+ tables = list(cluster.metadata.keyspaces[keyspace].tables.keys())
57
+ for table in tables:
58
+ if table.startswith("{}_array".format(args.tables_root)):
59
+ try:
60
+ session.execute("drop table {}".format(table))
61
+ except Exception as err:
62
+ print("EEROR: ", err)
63
+ pass
64
+
65
+ # Create tables
66
+ for command in create_commands.split("\n"):
67
+ if len(command)>0:
68
+ print("Executing:", command)
69
+ session.execute(command)
70
+
@@ -0,0 +1,32 @@
1
+ from cassandra.cqlengine.models import Model
2
+ from cassandra.cqlengine import columns
3
+ import time
4
+
5
+ types_mapping = {
6
+ "int": columns.Integer,
7
+ "text": columns.Text,
8
+ "uuid": columns.TimeUUID,
9
+ "float": columns.Float,
10
+ }
11
+
12
+
13
+ class DataSetModel(Model):
14
+ __table_suffix__ = "datasets"
15
+ id = columns.TimeUUID(primary_key=True)
16
+ creator = columns.Integer(required=True, primary_key=True)
17
+ name = columns.Text()
18
+
19
+
20
+ class UsersModel(Model):
21
+ __table_suffix__ = "users"
22
+ name = columns.Text(primary_key=True, required=True)
23
+ id = columns.Integer(primary_key=True)
24
+
25
+
26
+ class MetadataModel(Model):
27
+ __table_suffix__ = "metadata"
28
+ id = columns.TimeUUID(primary_key=True)
29
+
30
+ name = columns.Text(primary_key=True, required=True)
31
+ id_type = columns.Integer(primary_key=True)
32
+ value = columns.Text(primary_key=True)