dagster 1.12.11__py3-none-any.whl → 1.12.13__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.
- dagster/_cli/asset.py +15 -4
- dagster/_cli/job.py +8 -3
- dagster/_core/asset_graph_view/asset_graph_view.py +83 -19
- dagster/_core/asset_graph_view/entity_subset.py +14 -9
- dagster/_core/asset_graph_view/serializable_entity_subset.py +15 -0
- dagster/_core/code_pointer.py +8 -1
- dagster/_core/definitions/asset_checks/asset_check_evaluation.py +41 -68
- dagster/_core/definitions/asset_checks/asset_check_result.py +10 -0
- dagster/_core/definitions/asset_checks/asset_check_spec.py +11 -0
- dagster/_core/definitions/assets/graph/asset_graph.py +1 -0
- dagster/_core/definitions/assets/graph/base_asset_graph.py +29 -2
- dagster/_core/definitions/assets/graph/remote_asset_graph.py +9 -5
- dagster/_core/definitions/declarative_automation/legacy/valid_asset_subset.py +4 -4
- dagster/_core/definitions/declarative_automation/operands/operands.py +10 -4
- dagster/_core/definitions/declarative_automation/serialized_objects.py +36 -0
- dagster/_core/definitions/decorators/asset_check_decorator.py +6 -0
- dagster/_core/definitions/decorators/asset_decorator.py +13 -13
- dagster/_core/event_api.py +10 -0
- dagster/_core/execution/context/asset_check_execution_context.py +39 -0
- dagster/_core/execution/plan/execute_step.py +4 -3
- dagster/_core/execution/run_cancellation_thread.py +1 -0
- dagster/_core/instance/runs/run_domain.py +73 -90
- dagster/_core/remote_representation/external_data.py +6 -0
- dagster/_core/storage/asset_check_execution_record.py +49 -5
- dagster/_core/storage/asset_check_state.py +263 -0
- dagster/_core/storage/dagster_run.py +77 -0
- dagster/_core/storage/event_log/base.py +59 -1
- dagster/_core/storage/event_log/sql_event_log.py +174 -7
- dagster/_core/storage/event_log/sqlite/sqlite_event_log.py +6 -1
- dagster/_core/storage/legacy_storage.py +26 -5
- dagster/_core/telemetry.py +3 -0
- dagster/_core/workspace/load_target.py +1 -1
- dagster/_daemon/monitoring/run_monitoring.py +5 -1
- dagster/_generate/download.py +1 -0
- dagster/_utils/__init__.py +11 -0
- dagster/components/list/list.py +4 -1
- dagster/version.py +1 -1
- {dagster-1.12.11.dist-info → dagster-1.12.13.dist-info}/METADATA +4 -4
- {dagster-1.12.11.dist-info → dagster-1.12.13.dist-info}/RECORD +43 -42
- {dagster-1.12.11.dist-info → dagster-1.12.13.dist-info}/WHEEL +1 -1
- {dagster-1.12.11.dist-info → dagster-1.12.13.dist-info}/entry_points.txt +0 -0
- {dagster-1.12.11.dist-info → dagster-1.12.13.dist-info}/licenses/LICENSE +0 -0
- {dagster-1.12.11.dist-info → dagster-1.12.13.dist-info}/top_level.txt +0 -0
|
@@ -38,6 +38,7 @@ from dagster._core.errors import (
|
|
|
38
38
|
)
|
|
39
39
|
from dagster._core.event_api import (
|
|
40
40
|
EventRecordsResult,
|
|
41
|
+
PartitionKeyFilter,
|
|
41
42
|
RunShardedEventsCursor,
|
|
42
43
|
RunStatusChangeRecordsFilter,
|
|
43
44
|
)
|
|
@@ -58,6 +59,7 @@ from dagster._core.storage.asset_check_execution_record import (
|
|
|
58
59
|
COMPLETED_ASSET_CHECK_EXECUTION_RECORD_STATUSES,
|
|
59
60
|
AssetCheckExecutionRecord,
|
|
60
61
|
AssetCheckExecutionRecordStatus,
|
|
62
|
+
AssetCheckPartitionInfo,
|
|
61
63
|
)
|
|
62
64
|
from dagster._core.storage.dagster_run import DagsterRunStatsSnapshot
|
|
63
65
|
from dagster._core.storage.event_log.base import (
|
|
@@ -2992,15 +2994,25 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
2992
2994
|
planned = cast(
|
|
2993
2995
|
"AssetCheckEvaluationPlanned", check.not_none(event.dagster_event).event_specific_data
|
|
2994
2996
|
)
|
|
2997
|
+
partition_keys = (
|
|
2998
|
+
planned.partitions_subset.get_partition_keys() if planned.partitions_subset else [None]
|
|
2999
|
+
)
|
|
2995
3000
|
with self.index_connection() as conn:
|
|
2996
3001
|
conn.execute(
|
|
2997
3002
|
AssetCheckExecutionsTable.insert().values(
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3003
|
+
[
|
|
3004
|
+
dict(
|
|
3005
|
+
asset_key=planned.asset_key.to_string(),
|
|
3006
|
+
check_name=planned.check_name,
|
|
3007
|
+
partition=partition_key,
|
|
3008
|
+
run_id=event.run_id,
|
|
3009
|
+
execution_status=AssetCheckExecutionRecordStatus.PLANNED.value,
|
|
3010
|
+
evaluation_event=serialize_value(event),
|
|
3011
|
+
evaluation_event_timestamp=self._event_insert_timestamp(event),
|
|
3012
|
+
evaluation_event_storage_id=event_id,
|
|
3013
|
+
)
|
|
3014
|
+
for partition_key in partition_keys
|
|
3015
|
+
]
|
|
3004
3016
|
)
|
|
3005
3017
|
)
|
|
3006
3018
|
|
|
@@ -3033,6 +3045,7 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3033
3045
|
if evaluation.target_materialization_data
|
|
3034
3046
|
else None
|
|
3035
3047
|
),
|
|
3048
|
+
partition=evaluation.partition,
|
|
3036
3049
|
)
|
|
3037
3050
|
)
|
|
3038
3051
|
|
|
@@ -3049,6 +3062,9 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3049
3062
|
AssetCheckExecutionsTable.c.asset_key == evaluation.asset_key.to_string(),
|
|
3050
3063
|
AssetCheckExecutionsTable.c.check_name == evaluation.check_name,
|
|
3051
3064
|
AssetCheckExecutionsTable.c.run_id == event.run_id,
|
|
3065
|
+
self._get_asset_check_partition_filter_clause(
|
|
3066
|
+
PartitionKeyFilter(key=evaluation.partition)
|
|
3067
|
+
),
|
|
3052
3068
|
)
|
|
3053
3069
|
)
|
|
3054
3070
|
.values(
|
|
@@ -3065,6 +3081,7 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3065
3081
|
if evaluation.target_materialization_data
|
|
3066
3082
|
else None
|
|
3067
3083
|
),
|
|
3084
|
+
partition=evaluation.partition,
|
|
3068
3085
|
)
|
|
3069
3086
|
).rowcount
|
|
3070
3087
|
|
|
@@ -3089,6 +3106,7 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3089
3106
|
if evaluation.target_materialization_data
|
|
3090
3107
|
else None
|
|
3091
3108
|
),
|
|
3109
|
+
partition=evaluation.partition,
|
|
3092
3110
|
)
|
|
3093
3111
|
).rowcount
|
|
3094
3112
|
|
|
@@ -3100,12 +3118,23 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3100
3118
|
"as a result of duplicate AssetCheckPlanned events."
|
|
3101
3119
|
)
|
|
3102
3120
|
|
|
3121
|
+
def _get_asset_check_partition_filter_clause(
|
|
3122
|
+
self, partition_filter: Optional[PartitionKeyFilter]
|
|
3123
|
+
):
|
|
3124
|
+
if partition_filter is None:
|
|
3125
|
+
return True
|
|
3126
|
+
elif partition_filter.key is None:
|
|
3127
|
+
return AssetCheckExecutionsTable.c.partition.is_(None)
|
|
3128
|
+
else:
|
|
3129
|
+
return AssetCheckExecutionsTable.c.partition == partition_filter.key
|
|
3130
|
+
|
|
3103
3131
|
def get_asset_check_execution_history(
|
|
3104
3132
|
self,
|
|
3105
3133
|
check_key: AssetCheckKey,
|
|
3106
3134
|
limit: int,
|
|
3107
3135
|
cursor: Optional[int] = None,
|
|
3108
3136
|
status: Optional[AbstractSet[AssetCheckExecutionRecordStatus]] = None,
|
|
3137
|
+
partition_filter: Optional[PartitionKeyFilter] = None,
|
|
3109
3138
|
) -> Sequence[AssetCheckExecutionRecord]:
|
|
3110
3139
|
check.inst_param(check_key, "key", AssetCheckKey)
|
|
3111
3140
|
check.int_param(limit, "limit")
|
|
@@ -3119,12 +3148,14 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3119
3148
|
AssetCheckExecutionsTable.c.execution_status,
|
|
3120
3149
|
AssetCheckExecutionsTable.c.evaluation_event,
|
|
3121
3150
|
AssetCheckExecutionsTable.c.create_timestamp,
|
|
3151
|
+
AssetCheckExecutionsTable.c.partition,
|
|
3122
3152
|
]
|
|
3123
3153
|
)
|
|
3124
3154
|
.where(
|
|
3125
3155
|
db.and_(
|
|
3126
3156
|
AssetCheckExecutionsTable.c.asset_key == check_key.asset_key.to_string(),
|
|
3127
3157
|
AssetCheckExecutionsTable.c.check_name == check_key.name,
|
|
3158
|
+
self._get_asset_check_partition_filter_clause(partition_filter),
|
|
3128
3159
|
)
|
|
3129
3160
|
)
|
|
3130
3161
|
.order_by(AssetCheckExecutionsTable.c.id.desc())
|
|
@@ -3144,8 +3175,13 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3144
3175
|
return [AssetCheckExecutionRecord.from_db_row(row, key=check_key) for row in rows]
|
|
3145
3176
|
|
|
3146
3177
|
def get_latest_asset_check_execution_by_key(
|
|
3147
|
-
self,
|
|
3178
|
+
self,
|
|
3179
|
+
check_keys: Sequence[AssetCheckKey],
|
|
3180
|
+
partition_filter: Optional[PartitionKeyFilter] = None,
|
|
3148
3181
|
) -> Mapping[AssetCheckKey, AssetCheckExecutionRecord]:
|
|
3182
|
+
"""Returns the latest AssetCheckExecutionRecord for each check key. By default, returns the latest
|
|
3183
|
+
record regardless of partitioning.
|
|
3184
|
+
"""
|
|
3149
3185
|
if not check_keys:
|
|
3150
3186
|
return {}
|
|
3151
3187
|
|
|
@@ -3161,6 +3197,7 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3161
3197
|
[key.asset_key.to_string() for key in check_keys]
|
|
3162
3198
|
),
|
|
3163
3199
|
AssetCheckExecutionsTable.c.check_name.in_([key.name for key in check_keys]),
|
|
3200
|
+
self._get_asset_check_partition_filter_clause(partition_filter),
|
|
3164
3201
|
)
|
|
3165
3202
|
)
|
|
3166
3203
|
.group_by(
|
|
@@ -3178,6 +3215,7 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3178
3215
|
AssetCheckExecutionsTable.c.execution_status,
|
|
3179
3216
|
AssetCheckExecutionsTable.c.evaluation_event,
|
|
3180
3217
|
AssetCheckExecutionsTable.c.create_timestamp,
|
|
3218
|
+
AssetCheckExecutionsTable.c.partition,
|
|
3181
3219
|
]
|
|
3182
3220
|
).select_from(
|
|
3183
3221
|
AssetCheckExecutionsTable.join(
|
|
@@ -3200,6 +3238,135 @@ class SqlEventLogStorage(EventLogStorage):
|
|
|
3200
3238
|
results[check_key] = AssetCheckExecutionRecord.from_db_row(row, key=check_key)
|
|
3201
3239
|
return results
|
|
3202
3240
|
|
|
3241
|
+
def _get_asset_check_partition_info_for_key(
|
|
3242
|
+
self,
|
|
3243
|
+
check_key: AssetCheckKey,
|
|
3244
|
+
after_storage_id: Optional[int],
|
|
3245
|
+
partition_keys: Optional[Sequence[str]],
|
|
3246
|
+
latest_unpartitioned_materialization_storage_ids: Mapping[AssetKey, int],
|
|
3247
|
+
) -> Sequence[AssetCheckPartitionInfo]:
|
|
3248
|
+
# Build the base filter conditions
|
|
3249
|
+
filter_conditions = [
|
|
3250
|
+
AssetCheckExecutionsTable.c.asset_key == check_key.asset_key.to_string(),
|
|
3251
|
+
AssetCheckExecutionsTable.c.check_name == check_key.name,
|
|
3252
|
+
# Historical records may have NULL in the evaluation_event_storage_id column for
|
|
3253
|
+
# PLANNED events
|
|
3254
|
+
AssetCheckExecutionsTable.c.evaluation_event_storage_id.isnot(None),
|
|
3255
|
+
]
|
|
3256
|
+
if partition_keys is not None:
|
|
3257
|
+
filter_conditions.append(AssetCheckExecutionsTable.c.partition.in_(partition_keys))
|
|
3258
|
+
|
|
3259
|
+
# Subquery to find the max id for each partition
|
|
3260
|
+
latest_check_ids_subquery = db_subquery(
|
|
3261
|
+
db_select(
|
|
3262
|
+
[
|
|
3263
|
+
db.func.max(AssetCheckExecutionsTable.c.id).label("id"),
|
|
3264
|
+
AssetCheckExecutionsTable.c.partition.label("partition"),
|
|
3265
|
+
]
|
|
3266
|
+
)
|
|
3267
|
+
.where(db.and_(*filter_conditions))
|
|
3268
|
+
.group_by(AssetCheckExecutionsTable.c.partition),
|
|
3269
|
+
"latest_check_ids_subquery",
|
|
3270
|
+
)
|
|
3271
|
+
|
|
3272
|
+
# Subquery to find the latest materialization storage id for each partition of the
|
|
3273
|
+
# target asset. Note: we don't filter by after_storage_id here because we always want
|
|
3274
|
+
# to return the latest materialization storage id, even if it's older than after_storage_id.
|
|
3275
|
+
latest_materialization_ids_subquery = self._latest_event_ids_by_partition_subquery(
|
|
3276
|
+
check_key.asset_key,
|
|
3277
|
+
[DagsterEventType.ASSET_MATERIALIZATION],
|
|
3278
|
+
asset_partitions=partition_keys,
|
|
3279
|
+
)
|
|
3280
|
+
|
|
3281
|
+
# Main query to get all columns for the latest records, joined with latest
|
|
3282
|
+
# materialization storage ids
|
|
3283
|
+
query = db_select(
|
|
3284
|
+
[
|
|
3285
|
+
AssetCheckExecutionsTable.c.id,
|
|
3286
|
+
AssetCheckExecutionsTable.c.partition,
|
|
3287
|
+
AssetCheckExecutionsTable.c.execution_status,
|
|
3288
|
+
AssetCheckExecutionsTable.c.evaluation_event_storage_id,
|
|
3289
|
+
AssetCheckExecutionsTable.c.materialization_event_storage_id,
|
|
3290
|
+
AssetCheckExecutionsTable.c.run_id,
|
|
3291
|
+
latest_materialization_ids_subquery.c.id.label("latest_materialization_storage_id"),
|
|
3292
|
+
]
|
|
3293
|
+
).select_from(
|
|
3294
|
+
AssetCheckExecutionsTable.join(
|
|
3295
|
+
latest_check_ids_subquery,
|
|
3296
|
+
AssetCheckExecutionsTable.c.id == latest_check_ids_subquery.c.id,
|
|
3297
|
+
).join(
|
|
3298
|
+
latest_materialization_ids_subquery,
|
|
3299
|
+
AssetCheckExecutionsTable.c.partition
|
|
3300
|
+
== latest_materialization_ids_subquery.c.partition,
|
|
3301
|
+
isouter=True,
|
|
3302
|
+
)
|
|
3303
|
+
)
|
|
3304
|
+
|
|
3305
|
+
# these filters are applied to the main query rather than the individual subqueries to ensure
|
|
3306
|
+
# we don't miss records that only have a new materialization or a new check execution but not both
|
|
3307
|
+
if after_storage_id is not None:
|
|
3308
|
+
query = query.where(
|
|
3309
|
+
db.or_(
|
|
3310
|
+
AssetCheckExecutionsTable.c.evaluation_event_storage_id > after_storage_id,
|
|
3311
|
+
latest_materialization_ids_subquery.c.id > after_storage_id,
|
|
3312
|
+
)
|
|
3313
|
+
)
|
|
3314
|
+
|
|
3315
|
+
with self.index_connection() as conn:
|
|
3316
|
+
rows = db_fetch_mappings(conn, query)
|
|
3317
|
+
|
|
3318
|
+
return [
|
|
3319
|
+
AssetCheckPartitionInfo(
|
|
3320
|
+
check_key=check_key,
|
|
3321
|
+
partition_key=row["partition"],
|
|
3322
|
+
latest_execution_status=AssetCheckExecutionRecordStatus(row["execution_status"]),
|
|
3323
|
+
latest_target_materialization_storage_id=row["materialization_event_storage_id"],
|
|
3324
|
+
latest_planned_run_id=row["run_id"],
|
|
3325
|
+
latest_check_event_storage_id=row["evaluation_event_storage_id"],
|
|
3326
|
+
latest_materialization_storage_id=max(
|
|
3327
|
+
filter(
|
|
3328
|
+
None,
|
|
3329
|
+
[
|
|
3330
|
+
row["latest_materialization_storage_id"],
|
|
3331
|
+
latest_unpartitioned_materialization_storage_ids.get(
|
|
3332
|
+
check_key.asset_key
|
|
3333
|
+
),
|
|
3334
|
+
],
|
|
3335
|
+
),
|
|
3336
|
+
default=None,
|
|
3337
|
+
),
|
|
3338
|
+
)
|
|
3339
|
+
for row in rows
|
|
3340
|
+
]
|
|
3341
|
+
|
|
3342
|
+
def get_asset_check_partition_info(
|
|
3343
|
+
self,
|
|
3344
|
+
keys: Sequence[AssetCheckKey],
|
|
3345
|
+
after_storage_id: Optional[int] = None,
|
|
3346
|
+
partition_keys: Optional[Sequence[str]] = None,
|
|
3347
|
+
) -> Sequence[AssetCheckPartitionInfo]:
|
|
3348
|
+
check.list_param(keys, "keys", of_type=AssetCheckKey)
|
|
3349
|
+
check.opt_int_param(after_storage_id, "after_storage_id")
|
|
3350
|
+
|
|
3351
|
+
infos = []
|
|
3352
|
+
latest_unpartitioned_materialization_storage_ids = (
|
|
3353
|
+
self._get_latest_unpartitioned_materialization_storage_ids(
|
|
3354
|
+
list(set(key.asset_key for key in keys))
|
|
3355
|
+
)
|
|
3356
|
+
)
|
|
3357
|
+
# the inner query is not feasible to join in a single query because the latest materialization ids subquery,
|
|
3358
|
+
# so for now we fetch the info for each key separately
|
|
3359
|
+
for key in keys:
|
|
3360
|
+
infos.extend(
|
|
3361
|
+
self._get_asset_check_partition_info_for_key(
|
|
3362
|
+
key,
|
|
3363
|
+
after_storage_id,
|
|
3364
|
+
partition_keys,
|
|
3365
|
+
latest_unpartitioned_materialization_storage_ids,
|
|
3366
|
+
)
|
|
3367
|
+
)
|
|
3368
|
+
return infos
|
|
3369
|
+
|
|
3203
3370
|
@property
|
|
3204
3371
|
def supports_asset_checks(self): # pyright: ignore[reportIncompatibleMethodOverride]
|
|
3205
3372
|
return self.has_table(AssetCheckExecutionsTable.name)
|
|
@@ -276,7 +276,12 @@ class SqliteEventLogStorage(SqlEventLogStorage, ConfigurableClass):
|
|
|
276
276
|
self.store_asset_event_tags([event], [event_id])
|
|
277
277
|
|
|
278
278
|
if event.is_dagster_event and event.dagster_event_type in ASSET_CHECK_EVENTS:
|
|
279
|
-
|
|
279
|
+
# mirror the event in the cross-run index database
|
|
280
|
+
with self.index_connection() as conn:
|
|
281
|
+
result = conn.execute(insert_event_statement)
|
|
282
|
+
event_id = result.inserted_primary_key[0]
|
|
283
|
+
|
|
284
|
+
self.store_asset_check_event(event, event_id)
|
|
280
285
|
|
|
281
286
|
if event.is_dagster_event and event.dagster_event_type in EVENT_TYPE_TO_PIPELINE_RUN_STATUS:
|
|
282
287
|
# should mirror run status change events in the index shard
|
|
@@ -4,17 +4,17 @@ from typing import TYPE_CHECKING, AbstractSet, Optional, Union # noqa: UP035
|
|
|
4
4
|
|
|
5
5
|
from dagster import _check as check
|
|
6
6
|
from dagster._config.config_schema import UserConfigSchema
|
|
7
|
-
from dagster._core.definitions.asset_checks.asset_check_spec import AssetCheckKey
|
|
8
7
|
from dagster._core.definitions.asset_key import EntityKey
|
|
9
8
|
from dagster._core.definitions.declarative_automation.serialized_objects import (
|
|
10
9
|
AutomationConditionEvaluationWithRunIds,
|
|
11
10
|
)
|
|
12
11
|
from dagster._core.definitions.events import AssetKey
|
|
13
12
|
from dagster._core.definitions.freshness import FreshnessStateRecord
|
|
14
|
-
from dagster._core.event_api import EventHandlerFn
|
|
13
|
+
from dagster._core.event_api import EventHandlerFn, PartitionKeyFilter
|
|
15
14
|
from dagster._core.storage.asset_check_execution_record import (
|
|
16
15
|
AssetCheckExecutionRecord,
|
|
17
16
|
AssetCheckExecutionRecordStatus,
|
|
17
|
+
AssetCheckPartitionInfo,
|
|
18
18
|
)
|
|
19
19
|
from dagster._core.storage.base_storage import DagsterStorage
|
|
20
20
|
from dagster._core.storage.event_log.base import (
|
|
@@ -60,6 +60,7 @@ if TYPE_CHECKING:
|
|
|
60
60
|
)
|
|
61
61
|
from dagster._core.snap.execution_plan_snapshot import ExecutionPlanSnapshot
|
|
62
62
|
from dagster._core.snap.job_snapshot import JobSnap
|
|
63
|
+
from dagster._core.storage.asset_check_state import AssetCheckState
|
|
63
64
|
from dagster._core.storage.dagster_run import (
|
|
64
65
|
DagsterRun,
|
|
65
66
|
DagsterRunStatsSnapshot,
|
|
@@ -745,19 +746,39 @@ class LegacyEventLogStorage(EventLogStorage, ConfigurableClass):
|
|
|
745
746
|
limit: int,
|
|
746
747
|
cursor: Optional[int] = None,
|
|
747
748
|
status: Optional[AbstractSet[AssetCheckExecutionRecordStatus]] = None,
|
|
749
|
+
partition_filter: Optional[PartitionKeyFilter] = None,
|
|
748
750
|
) -> Sequence[AssetCheckExecutionRecord]:
|
|
749
751
|
return self._storage.event_log_storage.get_asset_check_execution_history(
|
|
750
752
|
check_key=check_key,
|
|
751
753
|
limit=limit,
|
|
752
754
|
cursor=cursor,
|
|
753
755
|
status=status,
|
|
756
|
+
partition_filter=partition_filter,
|
|
754
757
|
)
|
|
755
758
|
|
|
756
|
-
def get_latest_asset_check_execution_by_key(
|
|
759
|
+
def get_latest_asset_check_execution_by_key(
|
|
757
760
|
self,
|
|
758
761
|
check_keys: Sequence["AssetCheckKey"],
|
|
759
|
-
|
|
760
|
-
|
|
762
|
+
partition_filter: Optional[PartitionKeyFilter] = None,
|
|
763
|
+
) -> Mapping["AssetCheckKey", AssetCheckExecutionRecord]:
|
|
764
|
+
return self._storage.event_log_storage.get_latest_asset_check_execution_by_key(
|
|
765
|
+
check_keys, partition_filter=partition_filter
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
def get_asset_check_partition_info(
|
|
769
|
+
self,
|
|
770
|
+
keys: Sequence["AssetCheckKey"],
|
|
771
|
+
after_storage_id: Optional[int] = None,
|
|
772
|
+
partition_keys: Optional[Sequence[str]] = None,
|
|
773
|
+
) -> Sequence[AssetCheckPartitionInfo]:
|
|
774
|
+
return self._storage.event_log_storage.get_asset_check_partition_info(
|
|
775
|
+
keys=keys, after_storage_id=after_storage_id, partition_keys=partition_keys
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
def get_checkpointed_asset_check_state(
|
|
779
|
+
self, keys: Sequence["AssetCheckKey"]
|
|
780
|
+
) -> Mapping["AssetCheckKey", "AssetCheckState"]:
|
|
781
|
+
return self._storage.event_log_storage.get_checkpointed_asset_check_state(keys)
|
|
761
782
|
|
|
762
783
|
|
|
763
784
|
class LegacyScheduleStorage(ScheduleStorage, ConfigurableClass):
|
dagster/_core/telemetry.py
CHANGED
|
@@ -25,6 +25,7 @@ from dagster_shared.telemetry import (
|
|
|
25
25
|
TelemetrySettings,
|
|
26
26
|
dagster_home_if_set,
|
|
27
27
|
get_or_set_instance_id,
|
|
28
|
+
get_or_set_user_id,
|
|
28
29
|
log_telemetry_action,
|
|
29
30
|
write_telemetry_log_line,
|
|
30
31
|
)
|
|
@@ -379,6 +380,7 @@ def log_remote_repo_stats(
|
|
|
379
380
|
client_time=str(datetime.datetime.now()),
|
|
380
381
|
event_id=str(uuid.uuid4()),
|
|
381
382
|
instance_id=instance_id,
|
|
383
|
+
user_id=get_or_set_user_id(),
|
|
382
384
|
metadata={
|
|
383
385
|
**get_stats_from_remote_repo(remote_repo),
|
|
384
386
|
"source": source,
|
|
@@ -450,6 +452,7 @@ def log_repo_stats(
|
|
|
450
452
|
client_time=str(datetime.datetime.now()),
|
|
451
453
|
event_id=str(uuid.uuid4()),
|
|
452
454
|
instance_id=instance_id,
|
|
455
|
+
user_id=get_or_set_user_id(),
|
|
453
456
|
metadata={
|
|
454
457
|
"source": source,
|
|
455
458
|
"pipeline_name_hash": job_name_hash,
|
|
@@ -67,7 +67,7 @@ def validate_dagster_block_for_module_name_or_modules(dagster_block):
|
|
|
67
67
|
modules_present = "modules" in dagster_block and isinstance(dagster_block.get("modules"), list)
|
|
68
68
|
|
|
69
69
|
if module_name_present and modules_present:
|
|
70
|
-
# Here we have the check only for list; to be a bit more forgiving in comparison to 'is_valid_modules_list' in case it's an empty list next to 'module_name'
|
|
70
|
+
# Here we have the check only for list; to be a bit more forgiving in comparison to 'is_valid_modules_list' in case it's an empty list next to 'module_name' existence
|
|
71
71
|
if len(dagster_block["modules"]) > 0:
|
|
72
72
|
raise ValueError(
|
|
73
73
|
"Only one of 'module_name' or 'modules' should be specified, not both."
|
|
@@ -235,7 +235,11 @@ def check_run_timeout(
|
|
|
235
235
|
MAX_RUNTIME_SECONDS_TAG, run_record.dagster_run.tags.get("dagster/max_runtime_seconds")
|
|
236
236
|
)
|
|
237
237
|
if max_time_str:
|
|
238
|
-
|
|
238
|
+
try:
|
|
239
|
+
max_time = float(max_time_str)
|
|
240
|
+
except ValueError:
|
|
241
|
+
logger.warning(f"Invalid max runtime value: {max_time_str}")
|
|
242
|
+
max_time = None
|
|
239
243
|
else:
|
|
240
244
|
max_time = default_timeout_seconds
|
|
241
245
|
|
dagster/_generate/download.py
CHANGED
dagster/_utils/__init__.py
CHANGED
|
@@ -465,6 +465,17 @@ def git_repository_root() -> str:
|
|
|
465
465
|
return subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode("utf-8").strip()
|
|
466
466
|
|
|
467
467
|
|
|
468
|
+
_DAGSTER_OSS_SUBDIRECTORY = "dagster-oss"
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def discover_oss_root(path: Path) -> Path:
|
|
472
|
+
while path != path.parent:
|
|
473
|
+
if (path / ".git").exists() or path.name == _DAGSTER_OSS_SUBDIRECTORY:
|
|
474
|
+
return path
|
|
475
|
+
path = path.parent
|
|
476
|
+
raise ValueError("Could not find OSS root")
|
|
477
|
+
|
|
478
|
+
|
|
468
479
|
def segfault() -> None:
|
|
469
480
|
"""Reliable cross-Python version segfault.
|
|
470
481
|
|
dagster/components/list/list.py
CHANGED
|
@@ -28,6 +28,7 @@ from dagster._cli.workspace.cli_target import get_repository_python_origin_from_
|
|
|
28
28
|
from dagster._config.pythonic_config.resource import get_resource_type_name
|
|
29
29
|
from dagster._core.definitions.asset_selection import AssetSelection
|
|
30
30
|
from dagster._core.definitions.assets.job.asset_job import is_reserved_asset_job_name
|
|
31
|
+
from dagster._core.definitions.declarative_automation.serialized_objects import get_expanded_label
|
|
31
32
|
from dagster._core.definitions.definitions_load_context import (
|
|
32
33
|
DefinitionsLoadContext,
|
|
33
34
|
DefinitionsLoadType,
|
|
@@ -177,7 +178,9 @@ def list_definitions(
|
|
|
177
178
|
group=node.group_name,
|
|
178
179
|
kinds=sorted(list(node.kinds)),
|
|
179
180
|
description=node.description,
|
|
180
|
-
automation_condition=
|
|
181
|
+
automation_condition=" ".join(
|
|
182
|
+
get_expanded_label(node.automation_condition.get_snapshot())
|
|
183
|
+
)
|
|
181
184
|
if node.automation_condition
|
|
182
185
|
else None,
|
|
183
186
|
tags=sorted(f'"{k}"="{v}"' for k, v in node.tags.items() if _tag_filter(k)),
|
dagster/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.12.
|
|
1
|
+
__version__ = "1.12.13"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dagster
|
|
3
|
-
Version: 1.12.
|
|
3
|
+
Version: 1.12.13
|
|
4
4
|
Summary: Dagster is an orchestration platform for the development, production, and observation of data assets.
|
|
5
5
|
Author: Dagster Labs
|
|
6
6
|
Author-email: hello@dagsterlabs.com
|
|
@@ -60,8 +60,8 @@ Requires-Dist: universal_pathlib; python_version < "3.12"
|
|
|
60
60
|
Requires-Dist: universal_pathlib>=0.2.0; python_version >= "3.12"
|
|
61
61
|
Requires-Dist: rich
|
|
62
62
|
Requires-Dist: filelock
|
|
63
|
-
Requires-Dist: dagster-pipes==1.12.
|
|
64
|
-
Requires-Dist: dagster-shared==1.12.
|
|
63
|
+
Requires-Dist: dagster-pipes==1.12.13
|
|
64
|
+
Requires-Dist: dagster-shared==1.12.13
|
|
65
65
|
Requires-Dist: antlr4-python3-runtime
|
|
66
66
|
Provides-Extra: docker
|
|
67
67
|
Requires-Dist: docker; extra == "docker"
|
|
@@ -88,7 +88,7 @@ Requires-Dist: ruff==0.11.5; extra == "test"
|
|
|
88
88
|
Provides-Extra: test-components
|
|
89
89
|
Requires-Dist: tomlkit; extra == "test-components"
|
|
90
90
|
Requires-Dist: jsonschema; extra == "test-components"
|
|
91
|
-
Requires-Dist: pandas; extra == "test-components"
|
|
91
|
+
Requires-Dist: pandas<3.0.0; extra == "test-components"
|
|
92
92
|
Requires-Dist: duckdb; extra == "test-components"
|
|
93
93
|
Provides-Extra: mypy
|
|
94
94
|
Requires-Dist: mypy==1.8.0; extra == "mypy"
|