supertable 2.0.4__tar.gz → 2.0.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 (168) hide show
  1. {supertable-2.0.4/supertable.egg-info → supertable-2.0.5}/PKG-INFO +1 -1
  2. {supertable-2.0.4 → supertable-2.0.5}/pyproject.toml +1 -1
  3. {supertable-2.0.4 → supertable-2.0.5}/setup.py +1 -1
  4. {supertable-2.0.4 → supertable-2.0.5}/supertable/__init__.py +1 -1
  5. {supertable-2.0.4 → supertable-2.0.5}/supertable/redis_infra.py +24 -7
  6. supertable-2.0.5/supertable/redis_keys.py +404 -0
  7. {supertable-2.0.4 → supertable-2.0.5}/supertable/super_table.py +12 -0
  8. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_redis_key_prefix.py +79 -7
  9. {supertable-2.0.4 → supertable-2.0.5/supertable.egg-info}/PKG-INFO +1 -1
  10. {supertable-2.0.4 → supertable-2.0.5}/supertable.egg-info/SOURCES.txt +0 -1
  11. supertable-2.0.4/supertable/redis_keys.py +0 -286
  12. supertable-2.0.4/supertable/service_registry.py +0 -253
  13. {supertable-2.0.4 → supertable-2.0.5}/LICENSE +0 -0
  14. {supertable-2.0.4 → supertable-2.0.5}/README.md +0 -0
  15. {supertable-2.0.4 → supertable-2.0.5}/requirements.txt +0 -0
  16. {supertable-2.0.4 → supertable-2.0.5}/setup.cfg +0 -0
  17. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/__init__.py +0 -0
  18. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/admin.py +0 -0
  19. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/chain.py +0 -0
  20. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/consumers.py +0 -0
  21. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/crypto.py +0 -0
  22. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/events.py +0 -0
  23. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/export.py +0 -0
  24. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/logger.py +0 -0
  25. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/middleware.py +0 -0
  26. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/reader.py +0 -0
  27. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/retention.py +0 -0
  28. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/tests/__init__.py +0 -0
  29. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/tests/test_chain.py +0 -0
  30. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/tests/test_crypto.py +0 -0
  31. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/tests/test_emit.py +0 -0
  32. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/tests/test_events.py +0 -0
  33. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/tests/test_retention.py +0 -0
  34. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/writer_parquet.py +0 -0
  35. {supertable-2.0.4 → supertable-2.0.5}/supertable/audit/writer_redis.py +0 -0
  36. {supertable-2.0.4 → supertable-2.0.5}/supertable/config/__init__.py +0 -0
  37. {supertable-2.0.4 → supertable-2.0.5}/supertable/config/defaults.py +0 -0
  38. {supertable-2.0.4 → supertable-2.0.5}/supertable/config/homedir.py +0 -0
  39. {supertable-2.0.4 → supertable-2.0.5}/supertable/config/settings.py +0 -0
  40. {supertable-2.0.4 → supertable-2.0.5}/supertable/config/tests/__init__.py +0 -0
  41. {supertable-2.0.4 → supertable-2.0.5}/supertable/config/tests/test_defaults.py +0 -0
  42. {supertable-2.0.4 → supertable-2.0.5}/supertable/config/tests/test_homedir.py +0 -0
  43. {supertable-2.0.4 → supertable-2.0.5}/supertable/config/tests/test_settings.py +0 -0
  44. {supertable-2.0.4 → supertable-2.0.5}/supertable/data_classes.py +0 -0
  45. {supertable-2.0.4 → supertable-2.0.5}/supertable/data_reader.py +0 -0
  46. {supertable-2.0.4 → supertable-2.0.5}/supertable/data_writer.py +0 -0
  47. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/__init__.py +0 -0
  48. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/__init__.py +0 -0
  49. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/__main__.py +0 -0
  50. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/check_filter_builder.py +0 -0
  51. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/controller.py +0 -0
  52. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/data_writer_helpers.py +0 -0
  53. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/defaults.py +0 -0
  54. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/dummy_data.py +0 -0
  55. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/read_parquet_header.py +0 -0
  56. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s01_01_01_create_super_table.py +0 -0
  57. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s01_01_02_enable_mirroring_formats.py +0 -0
  58. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s01_02_create_roles.py +0 -0
  59. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s01_03_create_users.py +0 -0
  60. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s02_01_write_dummy_data.py +0 -0
  61. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s02_02_write_single_data.py +0 -0
  62. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s02_03_01_write_staging.py +0 -0
  63. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s02_03_02_create_pipe.py +0 -0
  64. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s02_04_01_write_monitoring_simple.py +0 -0
  65. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s02_04_02_write_monitoring_parallel.py +0 -0
  66. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s02_05_write_tombstone.py +0 -0
  67. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_01_read_data_error.py +0 -0
  68. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_02_01_read_super_data_ok.py +0 -0
  69. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_02_02_read_table_data_ok.py +0 -0
  70. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_03_read_meta.py +0 -0
  71. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_04_read_staging.py +0 -0
  72. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_06_01_read_roles.py +0 -0
  73. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_06_02_read_user.py +0 -0
  74. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_07_01_estimate_read.py +0 -0
  75. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_07_02_estimate_files.py +0 -0
  76. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s03_08_read_snapshot_history.py +0 -0
  77. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s04_01_03_delete_pipe.py +0 -0
  78. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s05_01_delete_table.py +0 -0
  79. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/quickstart/s05_02_delete_super_table.py +0 -0
  80. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/webshop/__init__.py +0 -0
  81. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/webshop/core.py +0 -0
  82. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/webshop/defaults.py +0 -0
  83. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/webshop/generate.py +0 -0
  84. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/webshop/load.py +0 -0
  85. {supertable-2.0.4 → supertable-2.0.5}/supertable/demo/webshop/topup.py +0 -0
  86. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/__init__.py +0 -0
  87. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/data_estimator.py +0 -0
  88. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/duckdb_lite.py +0 -0
  89. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/duckdb_pro.py +0 -0
  90. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/engine_common.py +0 -0
  91. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/engine_enum.py +0 -0
  92. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/executor.py +0 -0
  93. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/plan_stats.py +0 -0
  94. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/spark_thrift.py +0 -0
  95. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/tests/__init__.py +0 -0
  96. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/tests/conftest.py +0 -0
  97. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/tests/test_dedup_read.py +0 -0
  98. {supertable-2.0.4 → supertable-2.0.5}/supertable/engine/tests/test_engine.py +0 -0
  99. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/__init__.py +0 -0
  100. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/benchmarks/__init__.py +0 -0
  101. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/benchmarks/benchmark_locking.py +0 -0
  102. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/benchmarks/measure_lock_speed.py +0 -0
  103. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/benchmarks/measure_lock_time.py +0 -0
  104. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/file_lock.py +0 -0
  105. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/redis_lock.py +0 -0
  106. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/tests/__init__.py +0 -0
  107. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/tests/test_file_lock.py +0 -0
  108. {supertable-2.0.4 → supertable-2.0.5}/supertable/locking/tests/test_redis_lock.py +0 -0
  109. {supertable-2.0.4 → supertable-2.0.5}/supertable/logging.py +0 -0
  110. {supertable-2.0.4 → supertable-2.0.5}/supertable/meta_reader.py +0 -0
  111. {supertable-2.0.4 → supertable-2.0.5}/supertable/mirroring/__init__.py +0 -0
  112. {supertable-2.0.4 → supertable-2.0.5}/supertable/mirroring/mirror_delta.py +0 -0
  113. {supertable-2.0.4 → supertable-2.0.5}/supertable/mirroring/mirror_formats.py +0 -0
  114. {supertable-2.0.4 → supertable-2.0.5}/supertable/mirroring/mirror_iceberg.py +0 -0
  115. {supertable-2.0.4 → supertable-2.0.5}/supertable/mirroring/mirror_parquet.py +0 -0
  116. {supertable-2.0.4 → supertable-2.0.5}/supertable/monitoring_writer.py +0 -0
  117. {supertable-2.0.4 → supertable-2.0.5}/supertable/plan_extender.py +0 -0
  118. {supertable-2.0.4 → supertable-2.0.5}/supertable/processing.py +0 -0
  119. {supertable-2.0.4 → supertable-2.0.5}/supertable/query_plan_manager.py +0 -0
  120. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/__init__.py +0 -0
  121. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/access_control.py +0 -0
  122. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/filter_builder.py +0 -0
  123. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/permissions.py +0 -0
  124. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/role_manager.py +0 -0
  125. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/row_column_security.py +0 -0
  126. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/tests/test_filter_builder.py +0 -0
  127. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/tests/test_rbac.py +0 -0
  128. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/tests/test_rbac_per_table.py +0 -0
  129. {supertable-2.0.4 → supertable-2.0.5}/supertable/rbac/user_manager.py +0 -0
  130. {supertable-2.0.4 → supertable-2.0.5}/supertable/redis_catalog.py +0 -0
  131. {supertable-2.0.4 → supertable-2.0.5}/supertable/redis_connector.py +0 -0
  132. {supertable-2.0.4 → supertable-2.0.5}/supertable/simple_table.py +0 -0
  133. {supertable-2.0.4 → supertable-2.0.5}/supertable/staging_area.py +0 -0
  134. {supertable-2.0.4 → supertable-2.0.5}/supertable/storage/__init__.py +0 -0
  135. {supertable-2.0.4 → supertable-2.0.5}/supertable/storage/azure_storage.py +0 -0
  136. {supertable-2.0.4 → supertable-2.0.5}/supertable/storage/gcp_storage.py +0 -0
  137. {supertable-2.0.4 → supertable-2.0.5}/supertable/storage/local_storage.py +0 -0
  138. {supertable-2.0.4 → supertable-2.0.5}/supertable/storage/minio_storage.py +0 -0
  139. {supertable-2.0.4 → supertable-2.0.5}/supertable/storage/s3_storage.py +0 -0
  140. {supertable-2.0.4 → supertable-2.0.5}/supertable/storage/storage_factory.py +0 -0
  141. {supertable-2.0.4 → supertable-2.0.5}/supertable/storage/storage_interface.py +0 -0
  142. {supertable-2.0.4 → supertable-2.0.5}/supertable/storage/tests/test_storage.py +0 -0
  143. {supertable-2.0.4 → supertable-2.0.5}/supertable/super_pipe.py +0 -0
  144. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/__init__.py +0 -0
  145. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_align_to_schema_fix.py +0 -0
  146. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_data_reader.py +0 -0
  147. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_data_writer.py +0 -0
  148. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_data_writer_comprehensive.py +0 -0
  149. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_data_writer_tombstones.py +0 -0
  150. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_dedup_on_read_write.py +0 -0
  151. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_meta_reader.py +0 -0
  152. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_newer_than.py +0 -0
  153. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_process_delete_only.py +0 -0
  154. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_processing.py +0 -0
  155. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_query_sql.py +0 -0
  156. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_simple_table.py +0 -0
  157. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_small_file_compaction.py +0 -0
  158. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_super_table.py +0 -0
  159. {supertable-2.0.4 → supertable-2.0.5}/supertable/tests/test_supertable_all.py +0 -0
  160. {supertable-2.0.4 → supertable-2.0.5}/supertable/utils/__init__.py +0 -0
  161. {supertable-2.0.4 → supertable-2.0.5}/supertable/utils/helper.py +0 -0
  162. {supertable-2.0.4 → supertable-2.0.5}/supertable/utils/sql_parser.py +0 -0
  163. {supertable-2.0.4 → supertable-2.0.5}/supertable/utils/tests/test_sql_parser_columns.py +0 -0
  164. {supertable-2.0.4 → supertable-2.0.5}/supertable/utils/timer.py +0 -0
  165. {supertable-2.0.4 → supertable-2.0.5}/supertable.egg-info/dependency_links.txt +0 -0
  166. {supertable-2.0.4 → supertable-2.0.5}/supertable.egg-info/entry_points.txt +0 -0
  167. {supertable-2.0.4 → supertable-2.0.5}/supertable.egg-info/requires.txt +0 -0
  168. {supertable-2.0.4 → supertable-2.0.5}/supertable.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: supertable
3
- Version: 2.0.4
3
+ Version: 2.0.5
4
4
  Summary: SuperTable — versioned data lake library for SQL analytics on Parquet + Redis.
5
5
  Author: Levente Kupas
6
6
  Author-email: Levente Kupas <lkupas@kladnasoft.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "supertable"
7
- version = "2.0.4"
7
+ version = "2.0.5"
8
8
  description = "SuperTable — versioned data lake library for SQL analytics on Parquet + Redis."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -19,7 +19,7 @@ long_description = readme.read_text(encoding="utf-8") if readme.exists() else ""
19
19
 
20
20
  setup(
21
21
  name="supertable",
22
- version="2.0.4",
22
+ version="2.0.5",
23
23
  description="SuperTable — versioned data lake library for SQL analytics on Parquet + Redis.",
24
24
  long_description=long_description,
25
25
  long_description_content_type="text/markdown",
@@ -25,7 +25,7 @@ See the ``supertable.demo`` package for runnable end-to-end demos and the
25
25
  project documentation for the full API surface.
26
26
  """
27
27
 
28
- __version__ = "2.0.4"
28
+ __version__ = "2.0.5"
29
29
 
30
30
  # Re-export the core public surface so users can do ``from supertable import …``
31
31
  # instead of remembering submodule paths.
@@ -64,13 +64,25 @@ if settings.SUPERTABLE_LOGIN_MASK not in (1, 2, 3):
64
64
  f"Invalid SUPERTABLE_LOGIN_MASK (must be 1, 2, or 3): {settings.SUPERTABLE_LOGIN_MASK}"
65
65
  )
66
66
 
67
- _missing_envs: List[str] = []
68
- if not settings.SUPERTABLE_ORGANIZATION:
69
- _missing_envs.append("SUPERTABLE_ORGANIZATION")
70
- if not (settings.SUPERTABLE_SUPERUSER_TOKEN or "").strip():
71
- _missing_envs.append("SUPERTABLE_SUPERUSER_TOKEN")
72
- if _missing_envs:
73
- raise RuntimeError("Missing required environment variables: " + ", ".join(_missing_envs))
67
+ def _require_runtime_env() -> None:
68
+ """Validate the env vars needed to actually talk to Redis.
69
+
70
+ Called lazily by code paths that open a real Redis connection or
71
+ otherwise need the deployment's organization / superuser token.
72
+ Importing the SDK no longer fails when these are unset — only
73
+ running against Redis does. This keeps the module importable in
74
+ test, build, and inspection contexts where the runtime
75
+ credentials aren't (and shouldn't be) present.
76
+ """
77
+ missing: List[str] = []
78
+ if not settings.SUPERTABLE_ORGANIZATION:
79
+ missing.append("SUPERTABLE_ORGANIZATION")
80
+ if not (settings.SUPERTABLE_SUPERUSER_TOKEN or "").strip():
81
+ missing.append("SUPERTABLE_SUPERUSER_TOKEN")
82
+ if missing:
83
+ raise RuntimeError(
84
+ "Missing required environment variables: " + ", ".join(missing)
85
+ )
74
86
 
75
87
 
76
88
  def _now_ms() -> int:
@@ -297,6 +309,11 @@ def _build_redis_client() -> redis.Redis:
297
309
  If SUPERTABLE_REDIS_SENTINEL is enabled and SUPERTABLE_REDIS_SENTINELS is set,
298
310
  use the same Sentinel connection behavior as RedisCatalog (ping-probe + optional fallback).
299
311
  """
312
+ # Gate runtime-credential validation here so that simply importing the
313
+ # module (e.g. to inspect ``redis_keys`` helpers or run unit tests
314
+ # against the public API) does not require an organization + token to
315
+ # be set. Anything that actually opens a connection still fails fast.
316
+ _require_runtime_env()
300
317
  settings = Settings()
301
318
  url = (settings.SUPERTABLE_REDIS_URL or "").strip() or None
302
319
 
@@ -0,0 +1,404 @@
1
+ # route: supertable.redis_keys
2
+ """
3
+ Single source of truth for every Redis key used by SuperTable + the
4
+ platform layer (dataisland-core).
5
+
6
+ Rule (enforced by tests/test_redis_key_prefix.py):
7
+ Every key constructed here MUST start with one of the two recognised
8
+ top-level prefixes:
9
+ * ``supertable:`` — SuperTable SDK state (catalog, RBAC, locks,
10
+ audit, share federation, table meta, …).
11
+ * ``dataisland:`` — platform / dataisland-core state that is not
12
+ SuperTable's concern (service registry, app
13
+ bootstrap config, etc.).
14
+ Per-app config keys (lighthouse, gatekeeper, studio, …) live under
15
+ their own app-name prefix and are written via the MCP server's
16
+ ``store_app_config`` tool — they do **not** go through this module.
17
+
18
+ Hierarchy
19
+ ---------
20
+
21
+ dataisland:
22
+ apps:{app_name}:master_mcp ← per-app bootstrap (one global key)
23
+ {org}:
24
+ registry:{service_type}:{host}:{pid} ← service-instance heartbeats (TTL)
25
+
26
+ supertable:
27
+ {org}: ← organization / company scope
28
+ _system_: ← reserved system scope (supertable-side)
29
+ auth:tokens ← organization login tokens
30
+ shares:doc:{share_id}
31
+ shares:index
32
+ audit:stream
33
+ audit:chain_head:{instance_id}
34
+ audit:config ← runtime toggle (per org)
35
+ spark:thrifts
36
+ spark:plugs
37
+ {sup}: ← supertable scope
38
+ meta:root
39
+ meta:leaf:{simple}
40
+ meta:mirrors
41
+ meta:table_config:{simple}
42
+ meta:staging:{staging_name}
43
+ meta:staging:meta
44
+ meta:staging:{staging_name}:pipe:{pipe_name}
45
+ meta:staging:{staging_name}:pipe:meta
46
+ config:engine
47
+ lock:leaf:{simple}
48
+ lock:stage:{stage_name}
49
+ rbac:users:meta
50
+ rbac:users:index
51
+ rbac:users:doc:{user_id}
52
+ rbac:users:name_to_id
53
+ rbac:roles:meta
54
+ rbac:roles:index
55
+ rbac:roles:doc:{role_id}
56
+ rbac:roles:type:{role_type}
57
+ rbac:roles:name_to_id
58
+ schema:{simple}
59
+ table_names
60
+ linked_shares:doc:{link_id}
61
+ linked_shares:index
62
+ monitor:{monitor_type}
63
+
64
+ Reserved supertable names
65
+ -------------------------
66
+
67
+ ``_system_`` is reserved. It MUST NOT be used as a supertable name and
68
+ ``SuperTable(..., super_name="_system_")`` raises ``ValueError``. The
69
+ name is reserved because we keep everything system-related — service
70
+ registry heartbeats, organization-level auth tokens, future
71
+ system-only scopes — under that prefix to avoid collisions with
72
+ user-created supertables.
73
+ """
74
+ from __future__ import annotations
75
+
76
+ from typing import FrozenSet
77
+
78
+ # The canonical SuperTable SDK prefix. Everything the SDK itself writes
79
+ # lives under this.
80
+ SUPERTABLE_PREFIX: str = "supertable"
81
+
82
+ # The platform-layer prefix. dataisland-core writes its own
83
+ # infrastructure (service-registry heartbeats, app-bootstrap configs)
84
+ # here. Per-app config keys (lighthouse:*, gatekeeper:*, …) live in
85
+ # yet another set of namespaces and are not built through this module.
86
+ DATAISLAND_PREFIX: str = "dataisland"
87
+
88
+ # Recognised top-level prefixes for assert_prefixed(). Adding a new
89
+ # layer to the platform → extend this set.
90
+ _RECOGNISED_PREFIXES: FrozenSet[str] = frozenset({SUPERTABLE_PREFIX, DATAISLAND_PREFIX})
91
+
92
+ # The org-level system scope. Reserved as a supertable name (see
93
+ # ``is_reserved_super_name`` below). Everything system-related under an
94
+ # organization lives here so user-supplied supertable names can never
95
+ # collide with infrastructure keys.
96
+ SYSTEM_SCOPE: str = "_system_"
97
+
98
+ # All names that may NOT be used for user-created supertables.
99
+ RESERVED_SUPER_NAMES: FrozenSet[str] = frozenset({SYSTEM_SCOPE})
100
+
101
+
102
+ # --------------------------------------------------------------------------- #
103
+ # Guards
104
+ # --------------------------------------------------------------------------- #
105
+
106
+ def assert_prefixed(key: str) -> str:
107
+ """Raise ValueError if *key* does not start with a recognised prefix.
108
+
109
+ Recognised prefixes: ``supertable:`` (SDK state) and
110
+ ``dataisland:`` (platform state). Returns the key unchanged so
111
+ callers can write::
112
+
113
+ self.r.set(assert_prefixed(some_key), value)
114
+ """
115
+ if not isinstance(key, str):
116
+ raise ValueError(
117
+ f"Redis key violates namespace policy (must be a str): {key!r}"
118
+ )
119
+ if not any(key.startswith(p + ":") for p in _RECOGNISED_PREFIXES):
120
+ raise ValueError(
121
+ f"Redis key violates namespace policy (must start with one "
122
+ f"of {sorted(_RECOGNISED_PREFIXES)}): {key!r}"
123
+ )
124
+ return key
125
+
126
+
127
+ def is_reserved_super_name(name: str) -> bool:
128
+ """Return True when *name* is reserved (cannot be a supertable name)."""
129
+ if not isinstance(name, str):
130
+ return False
131
+ return name.strip() in RESERVED_SUPER_NAMES
132
+
133
+
134
+ # --------------------------------------------------------------------------- #
135
+ # Per-organization system scope (registry, auth tokens, future system keys)
136
+ # --------------------------------------------------------------------------- #
137
+
138
+ def system_scope(org: str) -> str:
139
+ """Return the system-scope prefix for one organization."""
140
+ return f"{SUPERTABLE_PREFIX}:{org}:{SYSTEM_SCOPE}"
141
+
142
+
143
+ def system_scope_pattern(org: str) -> str:
144
+ """SCAN pattern for everything under one org's system scope."""
145
+ return f"{SUPERTABLE_PREFIX}:{org}:{SYSTEM_SCOPE}:*"
146
+
147
+
148
+ # --------------------------------------------------------------------------- #
149
+ # Service registry (per organization) — under the dataisland: prefix
150
+ # --------------------------------------------------------------------------- #
151
+ #
152
+ # Service-instance heartbeats are a *platform* concern, not a SuperTable
153
+ # concern. They live at:
154
+ #
155
+ # dataisland:{org}:registry:{service_type}:{host}:{pid}
156
+ #
157
+ # (No ``_system_`` segment — that segment exists only inside
158
+ # ``supertable:{org}:`` to avoid colliding with user-created supertable
159
+ # names. Under ``dataisland:`` there are no user supertables, so the
160
+ # extra segment is dropped.)
161
+
162
+ def registry(org: str, service_type: str, host: str, pid: int) -> str:
163
+ """Per-organization service registry entry.
164
+
165
+ Example::
166
+
167
+ dataisland:kladna-soft:registry:api:host1:1234
168
+ """
169
+ return f"{DATAISLAND_PREFIX}:{org}:registry:{service_type}:{host}:{pid}"
170
+
171
+
172
+ def registry_pattern_for_org(org: str) -> str:
173
+ """SCAN pattern for all service-registry entries in one organization."""
174
+ return f"{DATAISLAND_PREFIX}:{org}:registry:*"
175
+
176
+
177
+ def registry_pattern() -> str:
178
+ """SCAN pattern for service-registry entries across every organization.
179
+
180
+ Matches ``dataisland:*:registry:*`` — the cross-org pattern that
181
+ scanners use when no org is supplied (e.g. fleet-wide monitoring).
182
+ """
183
+ return f"{DATAISLAND_PREFIX}:*:registry:*"
184
+
185
+
186
+ # --------------------------------------------------------------------------- #
187
+ # App bootstrap (per application — Lighthouse, Gatekeeper, Studio, …)
188
+ # --------------------------------------------------------------------------- #
189
+ #
190
+ # The very first thing an app reads on boot is its master-MCP config.
191
+ # That happens before any org context exists, so the key sits at a
192
+ # single global location keyed only by app_name:
193
+ #
194
+ # dataisland:apps:{app_name}:master_mcp
195
+ #
196
+ # Written via the platform REST API (``POST /api/v1/apps/{app}/master-mcp``,
197
+ # admin-only) and read on every app boot.
198
+
199
+ def app_master_mcp(app_name: str) -> str:
200
+ """The platform-side key holding an app's master-MCP coordinates."""
201
+ return f"{DATAISLAND_PREFIX}:apps:{app_name}:master_mcp"
202
+
203
+
204
+ # --------------------------------------------------------------------------- #
205
+ # Organization auth (login tokens) — also under _system_ for the same reason:
206
+ # "auth" must not collide with a possible user-created supertable called "auth".
207
+ # --------------------------------------------------------------------------- #
208
+
209
+ def auth_tokens(org: str) -> str:
210
+ return f"{SUPERTABLE_PREFIX}:{org}:{SYSTEM_SCOPE}:auth:tokens"
211
+
212
+
213
+ # --------------------------------------------------------------------------- #
214
+ # Organization scope (non-system)
215
+ # --------------------------------------------------------------------------- #
216
+
217
+ def share_doc(org: str, share_id: str) -> str:
218
+ return f"{SUPERTABLE_PREFIX}:{org}:shares:doc:{share_id}"
219
+
220
+
221
+ def share_index(org: str) -> str:
222
+ return f"{SUPERTABLE_PREFIX}:{org}:shares:index"
223
+
224
+
225
+ def audit_stream(org: str) -> str:
226
+ return f"{SUPERTABLE_PREFIX}:{org}:audit:stream"
227
+
228
+
229
+ def audit_chain_head(org: str, instance_id: str) -> str:
230
+ return f"{SUPERTABLE_PREFIX}:{org}:audit:chain_head:{instance_id}"
231
+
232
+
233
+ def audit_config(org: str) -> str:
234
+ """Per-organization runtime audit configuration (enable toggle, sub-flags)."""
235
+ return f"{SUPERTABLE_PREFIX}:{org}:audit:config"
236
+
237
+
238
+ def spark_thrifts(org: str) -> str:
239
+ return f"{SUPERTABLE_PREFIX}:{org}:spark:thrifts"
240
+
241
+
242
+ def spark_plugs(org: str) -> str:
243
+ return f"{SUPERTABLE_PREFIX}:{org}:spark:plugs"
244
+
245
+
246
+ # --------------------------------------------------------------------------- #
247
+ # SuperTable scope — meta
248
+ # --------------------------------------------------------------------------- #
249
+
250
+ def meta_root(org: str, sup: str) -> str:
251
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:root"
252
+
253
+
254
+ def meta_leaf(org: str, sup: str, simple: str) -> str:
255
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:leaf:{simple}"
256
+
257
+
258
+ def meta_leaf_pattern(org: str, sup: str) -> str:
259
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:leaf:*"
260
+
261
+
262
+ def meta_root_pattern_for_org(org: str) -> str:
263
+ return f"{SUPERTABLE_PREFIX}:{org}:*:meta:root"
264
+
265
+
266
+ def meta_mirrors(org: str, sup: str) -> str:
267
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:mirrors"
268
+
269
+
270
+ def meta_table_config(org: str, sup: str, simple: str) -> str:
271
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:table_config:{simple}"
272
+
273
+
274
+ # --------------------------------------------------------------------------- #
275
+ # SuperTable scope — engine config
276
+ # --------------------------------------------------------------------------- #
277
+
278
+ def config_engine(org: str, sup: str) -> str:
279
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:config:engine"
280
+
281
+
282
+ # --------------------------------------------------------------------------- #
283
+ # SuperTable scope — locks
284
+ # --------------------------------------------------------------------------- #
285
+
286
+ def lock_leaf(org: str, sup: str, simple: str) -> str:
287
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:lock:leaf:{simple}"
288
+
289
+
290
+ def lock_stage(org: str, sup: str, stage_name: str) -> str:
291
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:lock:stage:{stage_name}"
292
+
293
+
294
+ # --------------------------------------------------------------------------- #
295
+ # SuperTable scope — RBAC users
296
+ # --------------------------------------------------------------------------- #
297
+
298
+ def rbac_user_meta(org: str, sup: str) -> str:
299
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:rbac:users:meta"
300
+
301
+
302
+ def rbac_user_index(org: str, sup: str) -> str:
303
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:rbac:users:index"
304
+
305
+
306
+ def rbac_user_doc(org: str, sup: str, user_id: str) -> str:
307
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:rbac:users:doc:{user_id}"
308
+
309
+
310
+ def rbac_username_to_id(org: str, sup: str) -> str:
311
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:rbac:users:name_to_id"
312
+
313
+
314
+ # --------------------------------------------------------------------------- #
315
+ # SuperTable scope — RBAC roles
316
+ # --------------------------------------------------------------------------- #
317
+
318
+ def rbac_role_meta(org: str, sup: str) -> str:
319
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:rbac:roles:meta"
320
+
321
+
322
+ def rbac_role_index(org: str, sup: str) -> str:
323
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:rbac:roles:index"
324
+
325
+
326
+ def rbac_role_doc(org: str, sup: str, role_id: str) -> str:
327
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:rbac:roles:doc:{role_id}"
328
+
329
+
330
+ def rbac_role_type_index(org: str, sup: str, role_type: str) -> str:
331
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:rbac:roles:type:{role_type}"
332
+
333
+
334
+ def rbac_rolename_to_id(org: str, sup: str) -> str:
335
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:rbac:roles:name_to_id"
336
+
337
+
338
+ # --------------------------------------------------------------------------- #
339
+ # SuperTable scope — staging / pipes
340
+ # --------------------------------------------------------------------------- #
341
+
342
+ def staging(org: str, sup: str, staging_name: str) -> str:
343
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:staging:{staging_name}"
344
+
345
+
346
+ def staging_index(org: str, sup: str) -> str:
347
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:staging:meta"
348
+
349
+
350
+ def staging_pattern(org: str, sup: str) -> str:
351
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:staging:*"
352
+
353
+
354
+ def staging_subkey_pattern(org: str, sup: str, staging_name: str) -> str:
355
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:staging:{staging_name}:*"
356
+
357
+
358
+ def pipe(org: str, sup: str, staging_name: str, pipe_name: str) -> str:
359
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:staging:{staging_name}:pipe:{pipe_name}"
360
+
361
+
362
+ def pipe_index(org: str, sup: str, staging_name: str) -> str:
363
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:staging:{staging_name}:pipe:meta"
364
+
365
+
366
+ def pipe_pattern(org: str, sup: str, staging_name: str) -> str:
367
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:meta:staging:{staging_name}:pipe:*"
368
+
369
+
370
+ # --------------------------------------------------------------------------- #
371
+ # SuperTable scope — schema / table_names / linked shares
372
+ # --------------------------------------------------------------------------- #
373
+
374
+ def schema(org: str, sup: str, simple: str) -> str:
375
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:schema:{simple}"
376
+
377
+
378
+ def table_names(org: str, sup: str) -> str:
379
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:table_names"
380
+
381
+
382
+ def linked_share_doc(org: str, sup: str, link_id: str) -> str:
383
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:linked_shares:doc:{link_id}"
384
+
385
+
386
+ def linked_share_index(org: str, sup: str) -> str:
387
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:linked_shares:index"
388
+
389
+
390
+ # --------------------------------------------------------------------------- #
391
+ # SuperTable scope — monitoring
392
+ # --------------------------------------------------------------------------- #
393
+
394
+ def monitor(org: str, sup: str, monitor_type: str) -> str:
395
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:monitor:{monitor_type}"
396
+
397
+
398
+ # --------------------------------------------------------------------------- #
399
+ # Wildcard / SCAN helpers used by deletes
400
+ # --------------------------------------------------------------------------- #
401
+
402
+ def super_table_pattern(org: str, sup: str) -> str:
403
+ """Matches every key for one supertable (used by delete_super_table)."""
404
+ return f"{SUPERTABLE_PREFIX}:{org}:{sup}:*"
@@ -13,6 +13,7 @@ from supertable.rbac.user_manager import UserManager
13
13
  from supertable.storage.storage_factory import get_storage
14
14
  from supertable.storage.storage_interface import StorageInterface
15
15
  from supertable.redis_catalog import RedisCatalog
16
+ from supertable.redis_keys import is_reserved_super_name, RESERVED_SUPER_NAMES
16
17
 
17
18
 
18
19
  class SuperTable:
@@ -21,9 +22,20 @@ class SuperTable:
21
22
  - Ensures storage backend is available
22
23
  - Ensures Redis meta:root exists (no file-based meta)
23
24
  - Exposes helper to read heavy simple-table snapshots from MinIO/local via StorageInterface
25
+
26
+ Reserved supertable names (e.g. ``_system_``) are rejected up-front
27
+ so they can never collide with the org-level system scope where the
28
+ service registry, organization auth tokens, and other system-only
29
+ state live.
24
30
  """
25
31
 
26
32
  def __init__(self, super_name: str, organization: str):
33
+ if is_reserved_super_name(super_name):
34
+ raise ValueError(
35
+ f"SuperTable name {super_name!r} is reserved and cannot be created. "
36
+ f"Reserved names: {sorted(RESERVED_SUPER_NAMES)}"
37
+ )
38
+
27
39
  self.identity = "super"
28
40
  self.super_name = super_name
29
41
  self.organization = organization
@@ -38,8 +38,12 @@ PIPE = "pipe1"
38
38
  def _all_helpers() -> list[tuple[str, str]]:
39
39
  """Return (helper_name, sample_key) pairs for every key formatter."""
40
40
  return [
41
- ("registry", RK.registry("api", "host", 1234)),
41
+ ("system_scope", RK.system_scope(ORG)),
42
+ ("system_scope_pattern", RK.system_scope_pattern(ORG)),
43
+ ("registry", RK.registry(ORG, "api", "host", 1234)),
44
+ ("registry_pattern_for_org", RK.registry_pattern_for_org(ORG)),
42
45
  ("registry_pattern", RK.registry_pattern()),
46
+ ("app_master_mcp", RK.app_master_mcp("lighthouse")),
43
47
  ("auth_tokens", RK.auth_tokens(ORG)),
44
48
  ("share_doc", RK.share_doc(ORG, "share_1")),
45
49
  ("share_index", RK.share_index(ORG)),
@@ -83,24 +87,92 @@ def _all_helpers() -> list[tuple[str, str]]:
83
87
 
84
88
 
85
89
  @pytest.mark.parametrize("name,key", _all_helpers())
86
- def test_helpers_emit_supertable_prefix(name, key):
90
+ def test_helpers_emit_recognised_prefix(name, key):
91
+ """Every constructor must emit a key under a recognised top-level prefix.
92
+
93
+ Recognised: ``supertable:`` (SDK state) or ``dataisland:`` (platform
94
+ state — service registry + app bootstrap). Per-app prefixes
95
+ (``lighthouse:``, ``gatekeeper:``, …) are not built through this
96
+ module — they go via the MCP ``store_app_config`` tool.
97
+ """
87
98
  assert isinstance(key, str), f"{name} returned non-str: {key!r}"
88
- assert key.startswith("supertable:"), (
99
+ assert (
100
+ key.startswith("supertable:") or key.startswith("dataisland:")
101
+ ), (
89
102
  f"{name} returned {key!r} which violates the namespace policy "
90
- f"(must start with 'supertable:')"
103
+ f"(must start with 'supertable:' or 'dataisland:')"
91
104
  )
92
105
 
93
106
 
94
- def test_assert_prefixed_accepts_valid_key():
107
+ def test_assert_prefixed_accepts_supertable_key():
95
108
  assert RK.assert_prefixed("supertable:org:foo") == "supertable:org:foo"
96
109
 
97
110
 
111
+ def test_assert_prefixed_accepts_dataisland_key():
112
+ assert RK.assert_prefixed("dataisland:org:foo") == "dataisland:org:foo"
113
+
114
+
98
115
  def test_assert_prefixed_rejects_bare_root_keys():
99
- for bad in ("monitor:org:sup:plans", "spark:org:thrifts", "registry:api"):
116
+ for bad in ("monitor:org:sup:plans", "spark:org:thrifts", "registry:api",
117
+ "lighthouse:acme:config"): # per-app prefixes not built here
100
118
  with pytest.raises(ValueError):
101
119
  RK.assert_prefixed(bad)
102
120
 
103
121
 
122
+ # ---------------------------------------------------------------------------
123
+ # 1b. Layout invariants
124
+ # ---------------------------------------------------------------------------
125
+
126
+ def test_registry_key_lives_under_dataisland_prefix():
127
+ """Service-registry keys belong to the platform layer, not SuperTable."""
128
+ key = RK.registry(ORG, "api", "host1", 1234)
129
+ assert key == f"dataisland:{ORG}:registry:api:host1:1234"
130
+
131
+
132
+ def test_app_master_mcp_lives_under_dataisland_prefix():
133
+ """Bootstrap key for an app's master MCP — global, not org-scoped."""
134
+ key = RK.app_master_mcp("lighthouse")
135
+ assert key == "dataisland:apps:lighthouse:master_mcp"
136
+
137
+
138
+ def test_auth_tokens_still_lives_under_system_scope():
139
+ """Org auth tokens stay under supertable:{org}:_system_:auth:tokens
140
+ (managed by the SuperTable SDK's RBAC / auth subsystem)."""
141
+ key = RK.auth_tokens(ORG)
142
+ assert key == f"supertable:{ORG}:_system_:auth:tokens"
143
+
144
+
145
+ def test_registry_pattern_targets_all_orgs():
146
+ """The cross-org SCAN pattern reaches every org's registry."""
147
+ assert RK.registry_pattern() == "dataisland:*:registry:*"
148
+
149
+
150
+ def test_registry_pattern_for_org_is_scoped():
151
+ assert RK.registry_pattern_for_org(ORG) == f"dataisland:{ORG}:registry:*"
152
+
153
+
154
+ # ---------------------------------------------------------------------------
155
+ # 1c. Reserved supertable names
156
+ # ---------------------------------------------------------------------------
157
+
158
+ def test_system_scope_name_is_reserved():
159
+ assert RK.is_reserved_super_name("_system_") is True
160
+ assert "_system_" in RK.RESERVED_SUPER_NAMES
161
+
162
+
163
+ def test_arbitrary_supertable_name_is_not_reserved():
164
+ for name in ("orders", "customers", "_system", "system_", "auth"):
165
+ assert RK.is_reserved_super_name(name) is False
166
+
167
+
168
+ def test_super_table_refuses_reserved_name(monkeypatch):
169
+ """``SuperTable(super_name='_system_')`` must raise before touching Redis."""
170
+ # Import lazily so the regression also covers fresh imports.
171
+ from supertable.super_table import SuperTable
172
+ with pytest.raises(ValueError, match="reserved"):
173
+ SuperTable(super_name="_system_", organization=ORG)
174
+
175
+
104
176
  # ---------------------------------------------------------------------------
105
177
  # 2. No raw f-string keys outside redis_keys.py / Lua / docs
106
178
  # ---------------------------------------------------------------------------
@@ -109,7 +181,7 @@ def test_assert_prefixed_rejects_bare_root_keys():
109
181
  # redis_keys.py. Note the search is restricted to source files in the
110
182
  # library itself.
111
183
  _FORBIDDEN_PATTERNS = re.compile(
112
- r"""f["'](?:supertable|monitor|spark|registry|audit):"""
184
+ r"""f["'](?:supertable|dataisland|monitor|spark|registry|audit):"""
113
185
  )
114
186
 
115
187
  # Files / paths that are intentionally exempt from the scan:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: supertable
3
- Version: 2.0.4
3
+ Version: 2.0.5
4
4
  Summary: SuperTable — versioned data lake library for SQL analytics on Parquet + Redis.
5
5
  Author: Levente Kupas
6
6
  Author-email: Levente Kupas <lkupas@kladnasoft.com>
@@ -17,7 +17,6 @@ supertable/redis_catalog.py
17
17
  supertable/redis_connector.py
18
18
  supertable/redis_infra.py
19
19
  supertable/redis_keys.py
20
- supertable/service_registry.py
21
20
  supertable/simple_table.py
22
21
  supertable/staging_area.py
23
22
  supertable/super_pipe.py