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.
- metaxy/__init__.py +61 -0
- metaxy/_testing.py +542 -0
- metaxy/_utils.py +16 -0
- metaxy/_version.py +1 -0
- metaxy/cli/app.py +76 -0
- metaxy/cli/context.py +71 -0
- metaxy/cli/graph.py +576 -0
- metaxy/cli/graph_diff.py +290 -0
- metaxy/cli/list.py +42 -0
- metaxy/cli/metadata.py +271 -0
- metaxy/cli/migrations.py +862 -0
- metaxy/cli/push.py +55 -0
- metaxy/config.py +450 -0
- metaxy/data_versioning/__init__.py +24 -0
- metaxy/data_versioning/calculators/__init__.py +13 -0
- metaxy/data_versioning/calculators/base.py +97 -0
- metaxy/data_versioning/calculators/duckdb.py +186 -0
- metaxy/data_versioning/calculators/ibis.py +225 -0
- metaxy/data_versioning/calculators/polars.py +135 -0
- metaxy/data_versioning/diff/__init__.py +15 -0
- metaxy/data_versioning/diff/base.py +150 -0
- metaxy/data_versioning/diff/narwhals.py +108 -0
- metaxy/data_versioning/hash_algorithms.py +19 -0
- metaxy/data_versioning/joiners/__init__.py +9 -0
- metaxy/data_versioning/joiners/base.py +70 -0
- metaxy/data_versioning/joiners/narwhals.py +235 -0
- metaxy/entrypoints.py +309 -0
- metaxy/ext/__init__.py +1 -0
- metaxy/ext/alembic.py +326 -0
- metaxy/ext/sqlmodel.py +172 -0
- metaxy/ext/sqlmodel_system_tables.py +139 -0
- metaxy/graph/__init__.py +21 -0
- metaxy/graph/diff/__init__.py +21 -0
- metaxy/graph/diff/diff_models.py +399 -0
- metaxy/graph/diff/differ.py +740 -0
- metaxy/graph/diff/models.py +418 -0
- metaxy/graph/diff/rendering/__init__.py +18 -0
- metaxy/graph/diff/rendering/base.py +274 -0
- metaxy/graph/diff/rendering/cards.py +188 -0
- metaxy/graph/diff/rendering/formatter.py +805 -0
- metaxy/graph/diff/rendering/graphviz.py +246 -0
- metaxy/graph/diff/rendering/mermaid.py +320 -0
- metaxy/graph/diff/rendering/rich.py +165 -0
- metaxy/graph/diff/rendering/theme.py +48 -0
- metaxy/graph/diff/traversal.py +247 -0
- metaxy/graph/utils.py +58 -0
- metaxy/metadata_store/__init__.py +31 -0
- metaxy/metadata_store/_protocols.py +38 -0
- metaxy/metadata_store/base.py +1676 -0
- metaxy/metadata_store/clickhouse.py +161 -0
- metaxy/metadata_store/duckdb.py +167 -0
- metaxy/metadata_store/exceptions.py +43 -0
- metaxy/metadata_store/ibis.py +451 -0
- metaxy/metadata_store/memory.py +228 -0
- metaxy/metadata_store/sqlite.py +187 -0
- metaxy/metadata_store/system_tables.py +257 -0
- metaxy/migrations/__init__.py +34 -0
- metaxy/migrations/detector.py +153 -0
- metaxy/migrations/executor.py +208 -0
- metaxy/migrations/loader.py +260 -0
- metaxy/migrations/models.py +718 -0
- metaxy/migrations/ops.py +390 -0
- metaxy/models/__init__.py +0 -0
- metaxy/models/bases.py +6 -0
- metaxy/models/constants.py +24 -0
- metaxy/models/feature.py +665 -0
- metaxy/models/feature_spec.py +105 -0
- metaxy/models/field.py +25 -0
- metaxy/models/plan.py +155 -0
- metaxy/models/types.py +157 -0
- metaxy/py.typed +0 -0
- metaxy-0.0.0.dist-info/METADATA +247 -0
- metaxy-0.0.0.dist-info/RECORD +75 -0
- metaxy-0.0.0.dist-info/WHEEL +4 -0
- 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
|
metaxy/graph/__init__.py
ADDED
|
@@ -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
|
+
]
|