metaxy 0.0.0__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 metaxy might be problematic. Click here for more details.

Files changed (75) hide show
  1. metaxy/__init__.py +61 -0
  2. metaxy/_testing.py +542 -0
  3. metaxy/_utils.py +16 -0
  4. metaxy/_version.py +1 -0
  5. metaxy/cli/app.py +76 -0
  6. metaxy/cli/context.py +71 -0
  7. metaxy/cli/graph.py +576 -0
  8. metaxy/cli/graph_diff.py +290 -0
  9. metaxy/cli/list.py +42 -0
  10. metaxy/cli/metadata.py +271 -0
  11. metaxy/cli/migrations.py +862 -0
  12. metaxy/cli/push.py +55 -0
  13. metaxy/config.py +450 -0
  14. metaxy/data_versioning/__init__.py +24 -0
  15. metaxy/data_versioning/calculators/__init__.py +13 -0
  16. metaxy/data_versioning/calculators/base.py +97 -0
  17. metaxy/data_versioning/calculators/duckdb.py +186 -0
  18. metaxy/data_versioning/calculators/ibis.py +225 -0
  19. metaxy/data_versioning/calculators/polars.py +135 -0
  20. metaxy/data_versioning/diff/__init__.py +15 -0
  21. metaxy/data_versioning/diff/base.py +150 -0
  22. metaxy/data_versioning/diff/narwhals.py +108 -0
  23. metaxy/data_versioning/hash_algorithms.py +19 -0
  24. metaxy/data_versioning/joiners/__init__.py +9 -0
  25. metaxy/data_versioning/joiners/base.py +70 -0
  26. metaxy/data_versioning/joiners/narwhals.py +235 -0
  27. metaxy/entrypoints.py +309 -0
  28. metaxy/ext/__init__.py +1 -0
  29. metaxy/ext/alembic.py +326 -0
  30. metaxy/ext/sqlmodel.py +172 -0
  31. metaxy/ext/sqlmodel_system_tables.py +139 -0
  32. metaxy/graph/__init__.py +21 -0
  33. metaxy/graph/diff/__init__.py +21 -0
  34. metaxy/graph/diff/diff_models.py +399 -0
  35. metaxy/graph/diff/differ.py +740 -0
  36. metaxy/graph/diff/models.py +418 -0
  37. metaxy/graph/diff/rendering/__init__.py +18 -0
  38. metaxy/graph/diff/rendering/base.py +274 -0
  39. metaxy/graph/diff/rendering/cards.py +188 -0
  40. metaxy/graph/diff/rendering/formatter.py +805 -0
  41. metaxy/graph/diff/rendering/graphviz.py +246 -0
  42. metaxy/graph/diff/rendering/mermaid.py +320 -0
  43. metaxy/graph/diff/rendering/rich.py +165 -0
  44. metaxy/graph/diff/rendering/theme.py +48 -0
  45. metaxy/graph/diff/traversal.py +247 -0
  46. metaxy/graph/utils.py +58 -0
  47. metaxy/metadata_store/__init__.py +31 -0
  48. metaxy/metadata_store/_protocols.py +38 -0
  49. metaxy/metadata_store/base.py +1676 -0
  50. metaxy/metadata_store/clickhouse.py +161 -0
  51. metaxy/metadata_store/duckdb.py +167 -0
  52. metaxy/metadata_store/exceptions.py +43 -0
  53. metaxy/metadata_store/ibis.py +451 -0
  54. metaxy/metadata_store/memory.py +228 -0
  55. metaxy/metadata_store/sqlite.py +187 -0
  56. metaxy/metadata_store/system_tables.py +257 -0
  57. metaxy/migrations/__init__.py +34 -0
  58. metaxy/migrations/detector.py +153 -0
  59. metaxy/migrations/executor.py +208 -0
  60. metaxy/migrations/loader.py +260 -0
  61. metaxy/migrations/models.py +718 -0
  62. metaxy/migrations/ops.py +390 -0
  63. metaxy/models/__init__.py +0 -0
  64. metaxy/models/bases.py +6 -0
  65. metaxy/models/constants.py +24 -0
  66. metaxy/models/feature.py +665 -0
  67. metaxy/models/feature_spec.py +105 -0
  68. metaxy/models/field.py +25 -0
  69. metaxy/models/plan.py +155 -0
  70. metaxy/models/types.py +157 -0
  71. metaxy/py.typed +0 -0
  72. metaxy-0.0.0.dist-info/METADATA +247 -0
  73. metaxy-0.0.0.dist-info/RECORD +75 -0
  74. metaxy-0.0.0.dist-info/WHEEL +4 -0
  75. metaxy-0.0.0.dist-info/entry_points.txt +3 -0
metaxy/ext/sqlmodel.py ADDED
@@ -0,0 +1,172 @@
1
+ """SQLModel integration for Metaxy.
2
+
3
+ This module provides a combined metaclass that allows Metaxy Feature classes
4
+ to also be SQLModel table classes, enabling seamless integration with SQLAlchemy/SQLModel ORMs.
5
+ """
6
+
7
+ from typing import Any
8
+
9
+ from sqlalchemy.types import JSON
10
+ from sqlmodel import Field, SQLModel
11
+ from sqlmodel.main import SQLModelMetaclass
12
+
13
+ from metaxy.config import MetaxyConfig
14
+ from metaxy.models.feature import Feature, MetaxyMeta
15
+ from metaxy.models.feature_spec import FeatureSpec
16
+
17
+
18
+ class SQLModelFeatureMeta(MetaxyMeta, SQLModelMetaclass): # pyright: ignore[reportUnsafeMultipleInheritance]
19
+ """Combined metaclass for SQLModel + Metaxy Feature.
20
+
21
+ This metaclass inherits from both MetaxyMeta and SQLModelMetaclass,
22
+ allowing classes to be both SQLModel tables and Metaxy features.
23
+
24
+ The MRO (Method Resolution Order) ensures that:
25
+ 1. MetaxyMeta handles Metaxy feature registration
26
+ 2. SQLModelMetaclass handles SQLAlchemy table creation
27
+
28
+ Note: MetaxyMeta comes first in the inheritance to ensure spec parameter is handled.
29
+
30
+ Automatic table naming:
31
+ __tablename__ is automatically generated from the feature key if not explicitly provided.
32
+ This ensures consistency with Metaxy's metadata store table naming conventions.
33
+
34
+ Example:
35
+ >>> from metaxy.integrations.sqlmodel import SQLModelFeature
36
+ >>> from metaxy import FeatureSpec, FeatureKey, FieldSpec, FieldKey
37
+ >>> from sqlmodel import Field
38
+ >>>
39
+ >>> class MyFeature(
40
+ ... SQLModelFeature,
41
+ ... table=True,
42
+ ... spec=FeatureSpec(
43
+ ... key=FeatureKey(["my", "feature"]),
44
+ ... deps=None,
45
+ ... fields=[
46
+ ... FieldSpec(
47
+ ... key=FieldKey(["data"]),
48
+ ... code_version=1,
49
+ ... ),
50
+ ... ],
51
+ ... ),
52
+ ... ):
53
+ ... __tablename__ = "my_feature"
54
+ ...
55
+ ... uid: str = Field(primary_key=True)
56
+ ... data: str
57
+ """
58
+
59
+ def __new__(
60
+ cls,
61
+ cls_name: str,
62
+ bases: tuple[type[Any], ...],
63
+ namespace: dict[str, Any],
64
+ *,
65
+ spec: FeatureSpec | None = None,
66
+ **kwargs: Any,
67
+ ) -> type[Any]:
68
+ """Create a new SQLModel + Feature class.
69
+
70
+ Args:
71
+ cls_name: Name of the class being created
72
+ bases: Base classes
73
+ namespace: Class namespace (attributes and methods)
74
+ spec: Metaxy FeatureSpec (required for concrete features)
75
+ **kwargs: Additional keyword arguments (e.g., table=True for SQLModel)
76
+
77
+ Returns:
78
+ New class that is both a SQLModel table and a Metaxy feature
79
+ """
80
+ # If this is a concrete table (table=True) with a spec
81
+ if kwargs.get("table") and spec is not None:
82
+ # Automatically set __tablename__ from the feature key if not provided
83
+ if (
84
+ "__tablename__" not in namespace
85
+ and MetaxyConfig.get().ext.sqlmodel.infer_db_table_names
86
+ ):
87
+ namespace["__tablename__"] = spec.key.table_name
88
+
89
+ # Call super().__new__ which follows MRO: MetaxyMeta -> SQLModelMetaclass -> ...
90
+ # MetaxyMeta will consume the spec parameter and pass remaining kwargs to SQLModelMetaclass
91
+ return super().__new__(cls, cls_name, bases, namespace, spec=spec, **kwargs)
92
+
93
+
94
+ # pyright: reportIncompatibleMethodOverride=false, reportIncompatibleVariableOverride=false
95
+ class SQLModelFeature(SQLModel, Feature, metaclass=SQLModelFeatureMeta, spec=None): # type: ignore[misc]
96
+ """Base class for features that are also SQLModel tables.
97
+
98
+ Use this as a base class when you want to create Metaxy features
99
+ that are also SQLAlchemy/SQLModel ORM models.
100
+
101
+ This class combines:
102
+ - Metaxy's Feature functionality (versioning, dependency tracking)
103
+ - SQLModel's ORM functionality (database mapping, queries)
104
+
105
+ Note: Unlike regular Feature classes, SQLModelFeature instances are mutable
106
+ to support SQLModel ORM operations. Only the spec and graph class attributes
107
+ are used from Feature, not the instance behavior.
108
+
109
+ System-managed fields are defined as optional here and will be populated
110
+ by the metadata store when reading/writing data.
111
+
112
+ Example:
113
+ >>> from metaxy.integrations.sqlmodel import SQLModelFeature
114
+ >>> from metaxy import FeatureSpec, FeatureKey, FieldSpec, FieldKey
115
+ >>> from sqlmodel import Field
116
+ >>>
117
+ >>> class VideoFeature(
118
+ ... SQLModelFeature,
119
+ ... table=True,
120
+ ... spec=FeatureSpec(
121
+ ... key=FeatureKey(["video"]),
122
+ ... deps=None, # Root feature
123
+ ... fields=[
124
+ ... FieldSpec(
125
+ ... key=FieldKey(["video_file"]),
126
+ ... code_version=1,
127
+ ... ),
128
+ ... ],
129
+ ... ),
130
+ ... ):
131
+ ... __tablename__ = "video"
132
+ ...
133
+ ... uid: str = Field(primary_key=True)
134
+ ... path: str
135
+ ... duration: float
136
+ ...
137
+ ... # Now you can use both Metaxy and SQLModel features:
138
+ ... # - VideoFeature.feature_version() -> Metaxy versioning
139
+ ... # - session.exec(select(VideoFeature)) -> SQLModel queries
140
+ """
141
+
142
+ # Override the frozen config from Feature's FrozenBaseModel
143
+ # SQLModel instances need to be mutable for ORM operations
144
+ model_config = {"frozen": False} # pyright: ignore[reportAssignmentType]
145
+
146
+ # System-managed metadata fields - these are optional and populated by Metaxy
147
+ # The metadata store will populate these when reading/writing data
148
+ # Users can override these definitions in subclasses if they need different constraints
149
+ sample_uid: str | None = Field(default=None, nullable=True)
150
+
151
+ # Using sa_column_kwargs to map to the actual column names used by Metaxy
152
+ metaxy_data_version: str | None = Field(
153
+ default=None,
154
+ sa_type=JSON,
155
+ sa_column_kwargs={"name": "data_version", "nullable": True},
156
+ )
157
+
158
+ metaxy_feature_version: str | None = Field(
159
+ default=None, sa_column_kwargs={"name": "feature_version", "nullable": True}
160
+ )
161
+
162
+ metaxy_snapshot_version: str | None = Field(
163
+ default=None, sa_column_kwargs={"name": "snapshot_version", "nullable": True}
164
+ )
165
+
166
+ # All Feature class methods and attributes are inherited from Feature base class:
167
+ # - spec: ClassVar[FeatureSpec]
168
+ # - graph: ClassVar[FeatureGraph]
169
+ # - feature_version() -> str
170
+ # - data_version() -> dict[str, str]
171
+ # - load_input(...)
172
+ # - resolve_data_version_diff(...)
@@ -0,0 +1,139 @@
1
+ """SQLModel definitions for metaxy system tables.
2
+
3
+ This module provides SQLModel table classes that mirror the Polars schemas
4
+ from system_tables.py. These are used primarily for Alembic migrations
5
+ when the SQLModel integration is enabled.
6
+
7
+ The actual data flow remains unchanged (using Polars DataFrames).
8
+ These models are only for schema definition and migrations.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from datetime import datetime
14
+ from typing import Any
15
+
16
+ from sqlalchemy import JSON, Index
17
+ from sqlmodel import Field, SQLModel
18
+
19
+ # Import the namespace constant from the core module
20
+ from metaxy.metadata_store.system_tables import SYSTEM_NAMESPACE
21
+
22
+ # System tables that metaxy uses internally
23
+ SYSTEM_TABLES: list[str] = [
24
+ f"{SYSTEM_NAMESPACE}__feature_versions",
25
+ f"{SYSTEM_NAMESPACE}__migration_events",
26
+ ]
27
+
28
+
29
+ class FeatureVersionsTable(SQLModel, table=True):
30
+ """SQLModel definition for the feature_versions system table.
31
+
32
+ This table records when feature specifications are pushed to production,
33
+ tracking the evolution of feature definitions over time.
34
+ """
35
+
36
+ __tablename__: str = f"{SYSTEM_NAMESPACE}__feature_versions" # pyright: ignore[reportIncompatibleVariableOverride]
37
+
38
+ # Composite primary key: feature_key + snapshot_version
39
+ feature_key: str = Field(primary_key=True)
40
+ snapshot_version: str = Field(primary_key=True)
41
+
42
+ # Version and timestamp
43
+ feature_version: str = Field(index=True)
44
+ recorded_at: datetime = Field(index=True)
45
+
46
+ # Serialized feature specification and class path
47
+ feature_spec: str # JSON string
48
+ feature_class_path: str
49
+
50
+ # Additional indexes for common queries
51
+ __table_args__ = (
52
+ Index("idx_feature_versions_lookup", "feature_key", "feature_version"),
53
+ )
54
+
55
+
56
+ class MigrationEventsTable(SQLModel, table=True):
57
+ """SQLModel definition for the migration_events system table.
58
+
59
+ This table stores append-only events tracking migration execution,
60
+ enabling recovery from partial failures and progress monitoring.
61
+ """
62
+
63
+ __tablename__: str = f"{SYSTEM_NAMESPACE}__migration_events" # pyright: ignore[reportIncompatibleVariableOverride]
64
+
65
+ # Auto-incrementing ID for append-only events
66
+ id: int | None = Field(default=None, primary_key=True)
67
+
68
+ # Event fields
69
+ migration_id: str = Field(index=True)
70
+ event_type: str = (
71
+ Field()
72
+ ) # "started", "feature_started", "feature_completed", "completed", "failed"
73
+ timestamp: datetime = Field(index=True)
74
+ feature_key: str = Field(default="") # Empty for migration-level events
75
+ rows_affected: int = Field(default=0)
76
+ error_message: str = Field(default="") # Empty if no error
77
+
78
+ # Additional indexes for common queries
79
+ __table_args__ = (
80
+ Index("idx_migration_events_lookup", "migration_id", "event_type"),
81
+ )
82
+
83
+
84
+ class MetaxyFeatureMetadataTemplate(SQLModel):
85
+ """Template showing standard metaxy columns for feature tables.
86
+
87
+ This class demonstrates the standard columns that metaxy adds to
88
+ feature tables when using SQLModel integration.
89
+
90
+ Users should NOT inherit from this class directly, but can use it
91
+ as a reference for the required columns.
92
+ """
93
+
94
+ # Standard metaxy columns
95
+ sample_uid: str = Field(primary_key=True)
96
+ data_version: dict[str, Any] | None = Field(
97
+ default=None, sa_type=JSON
98
+ ) # Struct column as JSON
99
+ feature_version: str | None = Field(default=None, index=True)
100
+ snapshot_version: str | None = Field(default=None, index=True)
101
+
102
+ # This is just a template, not meant to be instantiated
103
+ model_config = {"arbitrary_types_allowed": True} # pyright: ignore[reportAssignmentType]
104
+
105
+
106
+ # Registry of all system tables
107
+ SYSTEM_TABLE_MODELS = {
108
+ "feature_versions": FeatureVersionsTable,
109
+ "migration_events": MigrationEventsTable,
110
+ }
111
+
112
+
113
+ def get_system_tables() -> list[type[SQLModel]]:
114
+ """Get all system table SQLModel classes.
115
+
116
+ Returns:
117
+ List of SQLModel table classes
118
+ """
119
+ return [FeatureVersionsTable, MigrationEventsTable]
120
+
121
+
122
+ def get_system_metadata():
123
+ """Get SQLAlchemy metadata containing all system tables.
124
+
125
+ This function returns the metadata object that contains all
126
+ system table definitions, which can be used with Alembic
127
+ for migration generation.
128
+
129
+ Returns:
130
+ SQLModel.metadata containing all system table definitions
131
+
132
+ Example:
133
+ >>> from metaxy.ext.sqlmodel_system_tables import get_system_metadata
134
+ >>> metadata = get_system_metadata()
135
+ >>> # Use with Alembic target_metadata
136
+ """
137
+ # All tables are automatically registered in SQLModel.metadata
138
+ # when their classes are defined with table=True
139
+ return SQLModel.metadata
@@ -0,0 +1,21 @@
1
+ """Graph visualization and rendering utilities."""
2
+
3
+ from metaxy.graph.diff import GraphData
4
+ from metaxy.graph.diff.rendering import (
5
+ BaseRenderer,
6
+ CardsRenderer,
7
+ GraphvizRenderer,
8
+ MermaidRenderer,
9
+ RenderConfig,
10
+ TerminalRenderer,
11
+ )
12
+
13
+ __all__ = [
14
+ "BaseRenderer",
15
+ "RenderConfig",
16
+ "GraphData",
17
+ "TerminalRenderer",
18
+ "CardsRenderer",
19
+ "MermaidRenderer",
20
+ "GraphvizRenderer",
21
+ ]
@@ -0,0 +1,21 @@
1
+ """Graph diff infrastructure - models and traversal for graph comparison."""
2
+
3
+ from metaxy.graph.diff.models import (
4
+ EdgeData,
5
+ FieldNode,
6
+ GraphData,
7
+ GraphNode,
8
+ NodeStatus,
9
+ )
10
+ from metaxy.graph.diff.traversal import GraphWalker
11
+
12
+ __all__ = [
13
+ # Core models
14
+ "EdgeData",
15
+ "FieldNode",
16
+ "GraphData",
17
+ "GraphNode",
18
+ "NodeStatus",
19
+ # Traversal
20
+ "GraphWalker",
21
+ ]