From 024f1c64eed9b5c55daf5b8b082f3f55aec46981 Mon Sep 17 00:00:00 2001 From: Owen Kephart Date: Thu, 10 Oct 2024 17:26:36 -0700 Subject: [PATCH] Propagate automation condition information through the UI for user code conditions --- .../dagster-ui/packages/ui-core/client.json | 14 +- .../ui-core/src/assets/AssetGroupRoot.tsx | 4 +- .../ui-core/src/assets/AssetNodeOverview.tsx | 2 +- .../ui-core/src/assets/AssetTableFragment.tsx | 4 + .../packages/ui-core/src/assets/AssetTabs.tsx | 4 +- .../assets/__tests__/useAssetTabs.test.tsx | 4 +- .../src/assets/types/AssetGroupRoot.types.ts | 4 +- .../assets/types/AssetTableFragment.types.ts | 10 + .../assets/types/AssetsCatalogTable.types.ts | 19 +- .../AutomationAssetSelectionFragment.tsx | 2 +- .../src/automation/AutomationTargetList.tsx | 4 +- .../AutomationAssetSelectionFragment.types.ts | 4 +- .../packages/ui-core/src/nav/JobMetadata.tsx | 4 +- .../src/nav/types/JobMetadata.types.ts | 6 +- .../ScheduleAssetSelectionsQuery.types.ts | 4 +- .../src/sensors/types/SensorRoot.types.ts | 4 +- .../types/WorkspaceAssetsQuery.types.ts | 12 +- .../schema/asset_condition_evaluations.py | 11 +- .../dagster_graphql/schema/asset_graph.py | 16 +- .../schema/automation_condition.py | 10 +- .../__snapshots__/test_all_snapshot_ids.ambr | 198 +++++++++++------- .../graphql/__snapshots__/test_assets.ambr | 13 ++ .../graphql/__snapshots__/test_solids.ambr | 16 ++ .../dagster_graphql_tests/graphql/repo.py | 13 ++ .../graphql/test_assets.py | 10 + .../remote_representation/external_data.py | 38 +++- .../definitions/custom_condition.py | 26 +++ .../daemon_tests/test_e2e.py | 26 +++ 28 files changed, 356 insertions(+), 126 deletions(-) create mode 100644 python_modules/dagster/dagster_tests/definitions_tests/declarative_automation_tests/daemon_tests/definitions/custom_condition.py diff --git a/js_modules/dagster-ui/packages/ui-core/client.json b/js_modules/dagster-ui/packages/ui-core/client.json index 83df9014fb8bf..d1f06583616bc 100644 --- a/js_modules/dagster-ui/packages/ui-core/client.json +++ b/js_modules/dagster-ui/packages/ui-core/client.json @@ -9,13 +9,13 @@ "AssetGraphQuery": "26030b5c565bdc4d84b54b2c9a7e8172562cf7434912511768bde20875d47b44", "AssetForNavigationQuery": "eb695ab88044ddd7068ea0dc1e2482eaba1fcb11b83de11050ff52f55e83ed3d", "AssetDefinitionCollisionQuery": "84027ea05480797a69eb150ce07ac7dfd40d6007a8107f90a6c558cf3a2662f5", - "AssetGroupMetadataQuery": "260d747ab8d454c1fe55a5a5fa6e11a548a301ea44740566c0c43756cca363eb", + "AssetGroupMetadataQuery": "649fd8034ea453acebec574365ec19b678930cdbc976f5da2addfe40f985886f", "AssetMaterializationUpstreamQuery": "754bab88738acc8d310c71f577ac3cf06dc57950bb1f98a18844e6e00bae756d", "AssetPartitionDetailQuery": "a4ac5bb0f9ddbeda637f54b1d0937386f0e86e3ef17e7d59e51d4d9f9bf9aff6", "AssetPartitionStaleQuery": "4215f4014e9d7592142e1775c4b07377703e913389396f9ca14dc6bb779ce764", "AssetViewDefinitionQuery": "74d10d49cfe5620c16ce66d285b26c4020c758003076c17255a0451ebdc757ce", - "AssetCatalogTableQuery": "3b43af2e45ec4be8c630c66fb4b4d774fc877ff69a717132128db8fc15b7c17c", - "AssetCatalogGroupTableQuery": "b96b5c3d49db723bd17b5ac54567a5ff646bc907a6774233b2538072d7c75b81", + "AssetCatalogTableQuery": "34085ac8df88f975f14f998aaccebb770f7744772b64666cfc6a5bdf50171723", + "AssetCatalogGroupTableQuery": "d2eb0f7a5af67bbce8f20add4c6b98db97e79d7e139bfc7ee36f04337409614d", "AssetsOverviewRootQuery": "77ab0417c979b92c9ec01cd76a0f49b59f5b8ce7af775cab7e9b3e57b7871f7d", "FullPartitionsQuery": "bfe939600c7396798b3c92b0e8335e639c9d76479c1cecaabc309a83c8f7ca4d", "RunStatusAndPartitionKey": "4642abda7da52fb70cc0a47c19cd5bf2fd8b854bb104b6a73eb8545fcd0146b2", @@ -85,7 +85,7 @@ "PipelineExecutionConfigSchemaQuery": "a6fabdacce7f63c8ecbac472835a022f11de013a5625a8db9155832262035d08", "ConfigForRunQuery": "3c4bb0f771599d50a7e4c05b683f8f7b4b3f0ab844b85501bb85527707a4982a", "OpSelectorQuery": "f1b601d74e6ffb2854418109f56c90bc7feb37cbabd9a4b60dd7075aa45fcadf", - "JobMetadataQuery": "e44915164a1174b291978e4bee269eb293e3953dc6d5fa5831a731b2533e1bf5", + "JobMetadataQuery": "489183f897f5a30e8c9883a6b96fcaa6141734c79613e5979baa3e5a15050efd", "LatestRunTagQuery": "6b18755e69bb01ee63d4ef02333c219a8c935b087e938b5da89ca99b95824e60", "InstigationStatesQuery": "98c41676dfb3c489e46455a3c2716e375050c9bed2d73e74c765453f2c63d0da", "LocationStateChangeSubscription": "d6cb6b73be1c484a2f592e60be15fb89b344e385f703ce2c92516e2779df8217", @@ -141,7 +141,7 @@ "OngoingRunTimelineQuery": "055420e85ba799b294bab52c01d3f4a4470580606a40483031c35777d88d527f", "CompletedRunTimelineQuery": "a551b5ebeb919ea7ea4ca74385d3711d6a7e4f0e4042c04ab43bf9b939f4975c", "FutureTicksQuery": "9b947053273ecaa20ef19df02f0aa8e6f33b8a1628175987670e3c73a350e640", - "ScheduleAssetSelectionQuery": "ff337e4645f6881b8240ef02dc13ef8dcdee46de71badedd37eb811bab741b87", + "ScheduleAssetSelectionQuery": "6942bd68a512ac71d6449844dbc07fcfd18226ab14b46e844f432f73a81eeccf", "StartThisSchedule": "85ef7cd6041adc25adff7ea24b2434e2a6dfae5700b3a8d5683ba069d81890a7", "StopSchedule": "d2d45e914fce611fa1adfffd488af554e29d4ee87220636fb841c668e4b83832", "ResetSchedule": "4de0dab719e737defe9787ab0b0bcef44f5384c92b2dd1c0bc0942643681b09b", @@ -159,7 +159,7 @@ "ResetSensor": "fba64da1f1979a7c53b618ba02c58cb72bd20c06220eeeef0318b15b502e3783", "PreviousRunsForSensorQuery": "11280246962f31faf7d5e8a479dd3e97bdfe074bb64a56a76ff436eda018d5b6", "SensorRootQuery": "fd32c8557a75c273133137c289091357635f3be0af17b9a57b052087f8e9d023", - "SensorAssetSelectionQuery": "a3410d20906553473a54e9045ecb19e92d08defefc17c2d9f1802338147ed470", + "SensorAssetSelectionQuery": "188cd7bab57cb2a04cf4941133f43327d91cf9edef01018d3635cacf6e36582d", "SensorStateQuery": "867ed8f85db89c801fcd6f099356971c9c8a64ce52e6c61e6b73dc18680439aa", "SnapshotQuery": "6ada4abd4592a558d98b2557ec511e87c9420bab5cbc155ec8473c55bd820a7a", "getSchedule": "cac3a9203bf5f9e0c4bbec02c590ffb225b4a140133203b030e719ae1fa37820", @@ -174,7 +174,7 @@ "SingleJobQuery": "5ff8f070e59507f5369f1a19abb9a72cfa12439ab04a08dc340866885f6e4702", "SingleScheduleQuery": "508a47e32ce04ba5be52c66cd592b74147bf98ec85b9f5d0e4db45172bd9a897", "SingleSensorQuery": "dbda5ba47d4ba10f8c527c9a7cd45fba0811276441a17a8ac6f173ed588f025b", - "WorkspaceAssetsQuery": "e8592b84ffb6dafd46473b7be4784371a51f4e4f546399e5cc197b1b823ac4c3", + "WorkspaceAssetsQuery": "66cc791cdcc9c02c4f6d959b631c1905e306cfa5aead1bb9d03814ab323b0183", "LocationWorkspaceQuery": "611c0706fbdde2c2159648e1a0d70a2ab23f79b7ef4e8bfc9a3ee4e50ff6dad2", "CodeLocationStatusQuery": "f92885e073b8b4b9bd588bf248df7b06025e2a1f6e74c082233ac7863f5eef8e", "WorkspaceGraphsQuery": "ccbef870f327b56beb0d781a476c8afbbc22ff2621181c8576861daaf7667ecf", diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetGroupRoot.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetGroupRoot.tsx index f8954701a5b2c..96ba4c125ab2d 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetGroupRoot.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetGroupRoot.tsx @@ -143,7 +143,7 @@ export const ASSET_GROUP_METADATA_QUERY = gql` query AssetGroupMetadataQuery($selector: AssetGroupSelector!) { assetNodes(group: $selector) { id - autoMaterializePolicy { + automationCondition { __typename } } @@ -172,7 +172,7 @@ export const AssetGroupTags = ({ if ( automaterializeSensorsFlagState === 'has-global-amp' && - assetNodes.some((a) => !!a.autoMaterializePolicy) + assetNodes.some((a) => !!a.automationCondition) ) { return ; } diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetNodeOverview.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetNodeOverview.tsx index afbffc3380d38..11e4aa61c3b6c 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/AssetNodeOverview.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/AssetNodeOverview.tsx @@ -481,7 +481,7 @@ export const AssetNodeOverview = ({ if ( attributes.every((props) => isEmptyChildren(props.children)) && - !cachedOrLiveAssetNode.autoMaterializePolicy + !cachedOrLiveAssetNode.automationCondition ) { return ( { title: 'Automation', to: buildAssetViewParams({...params, view: 'automation'}), disabled: !definition, - hidden: !definition?.autoMaterializePolicy, + hidden: !definition?.automationCondition, } as AssetTabConfig, }; }; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/useAssetTabs.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/useAssetTabs.test.tsx index 86c2fb9a47bdc..cc71810388a3b 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/useAssetTabs.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/useAssetTabs.test.tsx @@ -250,7 +250,7 @@ describe('buildAssetTabs', () => { it('hides auto-materialize tab if no auto-materialize policy', () => { const hookResult = renderHook(() => useAssetTabs({ - definition: {...definitionWithPartition, autoMaterializePolicy: null}, + definition: {...definitionWithPartition, automationCondition: null}, params, }), ); @@ -272,7 +272,7 @@ describe('buildAssetTabs', () => { it('hides partitions and auto-materialize tabs if no partitions or auto-materializing', () => { const hookResult = renderHook(() => useAssetTabs({ - definition: {...definitionWithoutPartition, autoMaterializePolicy: null}, + definition: {...definitionWithoutPartition, automationCondition: null}, params, }), ); diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetGroupRoot.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetGroupRoot.types.ts index bd3c3e40c98e5..534f3e91b2178 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetGroupRoot.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetGroupRoot.types.ts @@ -11,8 +11,8 @@ export type AssetGroupMetadataQuery = { assetNodes: Array<{ __typename: 'AssetNode'; id: string; - autoMaterializePolicy: {__typename: 'AutoMaterializePolicy'} | null; + automationCondition: {__typename: 'AutomationCondition'} | null; }>; }; -export const AssetGroupMetadataQueryVersion = '260d747ab8d454c1fe55a5a5fa6e11a548a301ea44740566c0c43756cca363eb'; +export const AssetGroupMetadataQueryVersion = '649fd8034ea453acebec574365ec19b678930cdbc976f5da2addfe40f985886f'; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetTableFragment.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetTableFragment.types.ts index 6a7258719eb7f..a24b6e27081bf 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetTableFragment.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetTableFragment.types.ts @@ -32,6 +32,11 @@ export type AssetTableDefinitionFragment = { __typename: 'AutoMaterializePolicy'; policyType: Types.AutoMaterializePolicyType; } | null; + automationCondition: { + __typename: 'AutomationCondition'; + label: string | null; + expandedLabel: Array; + } | null; owners: Array< {__typename: 'TeamAssetOwner'; team: string} | {__typename: 'UserAssetOwner'; email: string} >; @@ -78,6 +83,11 @@ export type AssetTableFragment = { __typename: 'AutoMaterializePolicy'; policyType: Types.AutoMaterializePolicyType; } | null; + automationCondition: { + __typename: 'AutomationCondition'; + label: string | null; + expandedLabel: Array; + } | null; owners: Array< {__typename: 'TeamAssetOwner'; team: string} | {__typename: 'UserAssetOwner'; email: string} >; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetsCatalogTable.types.ts b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetsCatalogTable.types.ts index c236fedb08b93..b10edbcf936a6 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetsCatalogTable.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/types/AssetsCatalogTable.types.ts @@ -47,6 +47,11 @@ export type AssetCatalogTableQuery = { __typename: 'AutoMaterializePolicy'; policyType: Types.AutoMaterializePolicyType; } | null; + automationCondition: { + __typename: 'AutomationCondition'; + label: string | null; + expandedLabel: Array; + } | null; owners: Array< | {__typename: 'TeamAssetOwner'; team: string} | {__typename: 'UserAssetOwner'; email: string} @@ -109,6 +114,11 @@ export type AssetCatalogGroupTableQuery = { __typename: 'AutoMaterializePolicy'; policyType: Types.AutoMaterializePolicyType; } | null; + automationCondition: { + __typename: 'AutomationCondition'; + label: string | null; + expandedLabel: Array; + } | null; owners: Array< {__typename: 'TeamAssetOwner'; team: string} | {__typename: 'UserAssetOwner'; email: string} >; @@ -152,6 +162,11 @@ export type AssetCatalogGroupTableNodeFragment = { __typename: 'AutoMaterializePolicy'; policyType: Types.AutoMaterializePolicyType; } | null; + automationCondition: { + __typename: 'AutomationCondition'; + label: string | null; + expandedLabel: Array; + } | null; owners: Array< {__typename: 'TeamAssetOwner'; team: string} | {__typename: 'UserAssetOwner'; email: string} >; @@ -164,6 +179,6 @@ export type AssetCatalogGroupTableNodeFragment = { }; }; -export const AssetCatalogTableQueryVersion = '3b43af2e45ec4be8c630c66fb4b4d774fc877ff69a717132128db8fc15b7c17c'; +export const AssetCatalogTableQueryVersion = '34085ac8df88f975f14f998aaccebb770f7744772b64666cfc6a5bdf50171723'; -export const AssetCatalogGroupTableQueryVersion = 'b96b5c3d49db723bd17b5ac54567a5ff646bc907a6774233b2538072d7c75b81'; +export const AssetCatalogGroupTableQueryVersion = 'd2eb0f7a5af67bbce8f20add4c6b98db97e79d7e139bfc7ee36f04337409614d'; diff --git a/js_modules/dagster-ui/packages/ui-core/src/automation/AutomationAssetSelectionFragment.tsx b/js_modules/dagster-ui/packages/ui-core/src/automation/AutomationAssetSelectionFragment.tsx index 04cb71ef64348..f5641f02fff6a 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/automation/AutomationAssetSelectionFragment.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/automation/AutomationAssetSelectionFragment.tsx @@ -24,7 +24,7 @@ export const AUTOMATION_ASSET_SELECTION_FRAGMENT = gql` } definition { id - autoMaterializePolicy { + automationCondition { __typename } } diff --git a/js_modules/dagster-ui/packages/ui-core/src/automation/AutomationTargetList.tsx b/js_modules/dagster-ui/packages/ui-core/src/automation/AutomationTargetList.tsx index 38f2fdc1b9467..9c3b5c8c2e96d 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/automation/AutomationTargetList.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/automation/AutomationTargetList.tsx @@ -106,11 +106,11 @@ const AssetSelectionTag = ({ }, [assetSelection.assetsOrError]); const assetsWithAMP = useMemo( - () => sortedAssets.filter((asset) => !!asset.definition?.autoMaterializePolicy), + () => sortedAssets.filter((asset) => !!asset.definition?.automationCondition), [sortedAssets], ); const assetsWithoutAMP = useMemo( - () => sortedAssets.filter((asset) => !asset.definition?.autoMaterializePolicy), + () => sortedAssets.filter((asset) => !asset.definition?.automationCondition), [sortedAssets], ); diff --git a/js_modules/dagster-ui/packages/ui-core/src/automation/types/AutomationAssetSelectionFragment.types.ts b/js_modules/dagster-ui/packages/ui-core/src/automation/types/AutomationAssetSelectionFragment.types.ts index 328ea61d89501..8195307a90ca9 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/automation/types/AutomationAssetSelectionFragment.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/automation/types/AutomationAssetSelectionFragment.types.ts @@ -15,7 +15,7 @@ export type AutomationAssetSelectionFragment = { definition: { __typename: 'AssetNode'; id: string; - autoMaterializePolicy: {__typename: 'AutoMaterializePolicy'} | null; + automationCondition: {__typename: 'AutomationCondition'} | null; } | null; }>; } @@ -38,6 +38,6 @@ export type AssetSelectionNodeFragment = { definition: { __typename: 'AssetNode'; id: string; - autoMaterializePolicy: {__typename: 'AutoMaterializePolicy'} | null; + automationCondition: {__typename: 'AutomationCondition'} | null; } | null; }; diff --git a/js_modules/dagster-ui/packages/ui-core/src/nav/JobMetadata.tsx b/js_modules/dagster-ui/packages/ui-core/src/nav/JobMetadata.tsx index 941e935608c2c..5fcecd4caf150 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/nav/JobMetadata.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/nav/JobMetadata.tsx @@ -87,7 +87,7 @@ export const JobMetadata = (props: Props) => { ) : null} - {metadata.assetNodes && metadata.assetNodes.some((a) => !!a.autoMaterializePolicy) && ( + {metadata.assetNodes && metadata.assetNodes.some((a) => !!a.automationCondition) && ( )} {metadata.runsForAssetScan ? ( @@ -214,7 +214,7 @@ export const JOB_METADATA_QUERY = gql` fragment JobMetadataAssetNode on AssetNode { id - autoMaterializePolicy { + automationCondition { __typename } assetKey { diff --git a/js_modules/dagster-ui/packages/ui-core/src/nav/types/JobMetadata.types.ts b/js_modules/dagster-ui/packages/ui-core/src/nav/types/JobMetadata.types.ts index 4bababce2687a..d328c2f2085e1 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/nav/types/JobMetadata.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/nav/types/JobMetadata.types.ts @@ -53,7 +53,7 @@ export type JobMetadataQuery = { assetNodes: Array<{ __typename: 'AssetNode'; id: string; - autoMaterializePolicy: {__typename: 'AutoMaterializePolicy'} | null; + automationCondition: {__typename: 'AutomationCondition'} | null; assetKey: {__typename: 'AssetKey'; path: Array}; }>; pipelineRunsOrError: @@ -81,7 +81,7 @@ export type JobMetadataQuery = { export type JobMetadataAssetNodeFragment = { __typename: 'AssetNode'; id: string; - autoMaterializePolicy: {__typename: 'AutoMaterializePolicy'} | null; + automationCondition: {__typename: 'AutomationCondition'} | null; assetKey: {__typename: 'AssetKey'; path: Array}; }; @@ -138,4 +138,4 @@ export type RunMetadataFragment = { }>; }; -export const JobMetadataQueryVersion = 'e44915164a1174b291978e4bee269eb293e3953dc6d5fa5831a731b2533e1bf5'; +export const JobMetadataQueryVersion = '489183f897f5a30e8c9883a6b96fcaa6141734c79613e5979baa3e5a15050efd'; diff --git a/js_modules/dagster-ui/packages/ui-core/src/schedules/types/ScheduleAssetSelectionsQuery.types.ts b/js_modules/dagster-ui/packages/ui-core/src/schedules/types/ScheduleAssetSelectionsQuery.types.ts index 5c0ce0a6801fe..67ec28e394e8b 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/schedules/types/ScheduleAssetSelectionsQuery.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/schedules/types/ScheduleAssetSelectionsQuery.types.ts @@ -35,7 +35,7 @@ export type ScheduleAssetSelectionQuery = { definition: { __typename: 'AssetNode'; id: string; - autoMaterializePolicy: {__typename: 'AutoMaterializePolicy'} | null; + automationCondition: {__typename: 'AutomationCondition'} | null; } | null; }>; } @@ -54,4 +54,4 @@ export type ScheduleAssetSelectionQuery = { | {__typename: 'ScheduleNotFoundError'}; }; -export const ScheduleAssetSelectionQueryVersion = 'ff337e4645f6881b8240ef02dc13ef8dcdee46de71badedd37eb811bab741b87'; +export const ScheduleAssetSelectionQueryVersion = '6942bd68a512ac71d6449844dbc07fcfd18226ab14b46e844f432f73a81eeccf'; diff --git a/js_modules/dagster-ui/packages/ui-core/src/sensors/types/SensorRoot.types.ts b/js_modules/dagster-ui/packages/ui-core/src/sensors/types/SensorRoot.types.ts index 0ce67b221be2d..e6f956cf2ab57 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/sensors/types/SensorRoot.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/sensors/types/SensorRoot.types.ts @@ -162,7 +162,7 @@ export type SensorAssetSelectionQuery = { definition: { __typename: 'AssetNode'; id: string; - autoMaterializePolicy: {__typename: 'AutoMaterializePolicy'} | null; + automationCondition: {__typename: 'AutomationCondition'} | null; } | null; }>; } @@ -184,4 +184,4 @@ export type SensorAssetSelectionQuery = { export const SensorRootQueryVersion = 'fd32c8557a75c273133137c289091357635f3be0af17b9a57b052087f8e9d023'; -export const SensorAssetSelectionQueryVersion = 'a3410d20906553473a54e9045ecb19e92d08defefc17c2d9f1802338147ed470'; +export const SensorAssetSelectionQueryVersion = '188cd7bab57cb2a04cf4941133f43327d91cf9edef01018d3635cacf6e36582d'; diff --git a/js_modules/dagster-ui/packages/ui-core/src/workspace/types/WorkspaceAssetsQuery.types.ts b/js_modules/dagster-ui/packages/ui-core/src/workspace/types/WorkspaceAssetsQuery.types.ts index 559445ae65a5c..8d03cc13cc312 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/workspace/types/WorkspaceAssetsQuery.types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/workspace/types/WorkspaceAssetsQuery.types.ts @@ -32,6 +32,11 @@ export type RepoAssetTableFragment = { __typename: 'AutoMaterializePolicy'; policyType: Types.AutoMaterializePolicyType; } | null; + automationCondition: { + __typename: 'AutomationCondition'; + label: string | null; + expandedLabel: Array; + } | null; owners: Array< {__typename: 'TeamAssetOwner'; team: string} | {__typename: 'UserAssetOwner'; email: string} >; @@ -95,6 +100,11 @@ export type WorkspaceAssetsQuery = { __typename: 'AutoMaterializePolicy'; policyType: Types.AutoMaterializePolicyType; } | null; + automationCondition: { + __typename: 'AutomationCondition'; + label: string | null; + expandedLabel: Array; + } | null; owners: Array< | {__typename: 'TeamAssetOwner'; team: string} | {__typename: 'UserAssetOwner'; email: string} @@ -111,4 +121,4 @@ export type WorkspaceAssetsQuery = { | {__typename: 'RepositoryNotFoundError'}; }; -export const WorkspaceAssetsQueryVersion = 'e8592b84ffb6dafd46473b7be4784371a51f4e4f546399e5cc197b1b823ac4c3'; +export const WorkspaceAssetsQueryVersion = '66cc791cdcc9c02c4f6d959b631c1905e306cfa5aead1bb9d03814ab323b0183'; diff --git a/python_modules/dagster-graphql/dagster_graphql/schema/asset_condition_evaluations.py b/python_modules/dagster-graphql/dagster_graphql/schema/asset_condition_evaluations.py index abbd6e0ef7da9..a47b3a549d8b5 100644 --- a/python_modules/dagster-graphql/dagster_graphql/schema/asset_condition_evaluations.py +++ b/python_modules/dagster-graphql/dagster_graphql/schema/asset_condition_evaluations.py @@ -9,6 +9,7 @@ ) from dagster._core.definitions.declarative_automation.serialized_objects import ( AutomationConditionEvaluation, + AutomationConditionSnapshot, ) from dagster._core.definitions.partition import PartitionsDefinition from dagster._core.scheduler.instigation import AutoMaterializeAssetEvaluationRecord @@ -329,7 +330,8 @@ def _flatten_evaluation( def get_expanded_label( - item: Union[AutomationConditionEvaluation, AutomationCondition], use_label=False + item: Union[AutomationConditionEvaluation, AutomationCondition, AutomationConditionSnapshot], + use_label=False, ) -> Sequence[str]: if isinstance(item, AutomationCondition): label, name, description, children = ( @@ -338,6 +340,13 @@ def get_expanded_label( item.description, item.children, ) + elif isinstance(item, AutomationConditionSnapshot): + label, name, description, children = ( + item.node_snapshot.label, + item.node_snapshot.name, + item.node_snapshot.description, + item.children, + ) else: snapshot = item.condition_snapshot label, name, description, children = ( diff --git a/python_modules/dagster-graphql/dagster_graphql/schema/asset_graph.py b/python_modules/dagster-graphql/dagster_graphql/schema/asset_graph.py index 62b7aab391a21..90308cbe01765 100644 --- a/python_modules/dagster-graphql/dagster_graphql/schema/asset_graph.py +++ b/python_modules/dagster-graphql/dagster_graphql/schema/asset_graph.py @@ -14,6 +14,9 @@ StaleCauseCategory, StaleStatus, ) +from dagster._core.definitions.declarative_automation.serialized_objects import ( + AutomationConditionSnapshot, +) from dagster._core.definitions.partition import CachingDynamicPartitionsLoader, PartitionsDefinition from dagster._core.definitions.partition_mapping import PartitionMapping from dagster._core.definitions.remote_asset_graph import RemoteAssetGraph, RemoteAssetNode @@ -842,8 +845,17 @@ def resolve_autoMaterializePolicy( def resolve_automationCondition( self, _graphene_info: ResolveInfo ) -> Optional[GrapheneAutoMaterializePolicy]: - if self._asset_node_snap.automation_condition: - return GrapheneAutomationCondition(self._asset_node_snap.automation_condition) + automation_condition = ( + self._asset_node_snap.automation_condition_snapshot + or self._asset_node_snap.automation_condition + ) + if automation_condition: + return GrapheneAutomationCondition( + # we only store one of automation_condition or automation_condition_snapshot + automation_condition + if isinstance(automation_condition, AutomationConditionSnapshot) + else automation_condition.get_snapshot() + ) return None def _sensor_targets_asset( diff --git a/python_modules/dagster-graphql/dagster_graphql/schema/automation_condition.py b/python_modules/dagster-graphql/dagster_graphql/schema/automation_condition.py index 4c4108a9fa9ae..630b55790f4bc 100644 --- a/python_modules/dagster-graphql/dagster_graphql/schema/automation_condition.py +++ b/python_modules/dagster-graphql/dagster_graphql/schema/automation_condition.py @@ -1,6 +1,6 @@ import graphene -from dagster._core.definitions.declarative_automation.automation_condition import ( - AutomationCondition, +from dagster._core.definitions.declarative_automation.serialized_objects import ( + AutomationConditionSnapshot, ) from dagster_graphql.schema.asset_condition_evaluations import get_expanded_label @@ -14,8 +14,8 @@ class GrapheneAutomationCondition(graphene.ObjectType): class Meta: name = "AutomationCondition" - def __init__(self, automation_condition: AutomationCondition): + def __init__(self, snapshot: AutomationConditionSnapshot): super().__init__( - label=automation_condition.get_label(), - expandedLabel=get_expanded_label(automation_condition), + label=snapshot.node_snapshot.label, + expandedLabel=get_expanded_label(snapshot), ) diff --git a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_all_snapshot_ids.ambr b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_all_snapshot_ids.ambr index da047dd9dfe76..931398a75aafc 100644 --- a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_all_snapshot_ids.ambr +++ b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_all_snapshot_ids.ambr @@ -489,6 +489,56 @@ "scalar_kind": null, "type_param_keys": null }, + "Shape.2b5e6e2b190fb25e32288ec068c8ff7fb8db3014": { + "__class__": "ConfigTypeSnap", + "description": null, + "enum_values": null, + "fields": [ + { + "__class__": "ConfigFieldSnap", + "default_provided": true, + "default_value_as_json_str": "{\"config\": {\"retries\": {\"enabled\": {}}}}", + "description": "Configure how steps are executed within a run.", + "is_required": false, + "name": "execution", + "type_key": "Shape.09d73f0755bf4752d3f121837669c8660dcf451e" + }, + { + "__class__": "ConfigFieldSnap", + "default_provided": true, + "default_value_as_json_str": "{}", + "description": "Configure how loggers emit messages within a run.", + "is_required": false, + "name": "loggers", + "type_key": "Shape.e895d95ee6d0eff1b884c76f44a2ab7089f0c49b" + }, + { + "__class__": "ConfigFieldSnap", + "default_provided": true, + "default_value_as_json_str": "{\"asset_1\": {}, \"asset_1_my_check\": {}, \"asset_2\": {}, \"asset_3\": {}, \"asset_one\": {}, \"asset_two\": {}, \"asset_with_automation_condition\": {}, \"asset_with_compute_storage_kinds\": {\"config\": {}}, \"asset_with_custom_automation_condition\": {}, \"asset_yields_observation\": {}, \"bar\": {}, \"baz\": {}, \"check_in_op_asset\": {}, \"downstream_asset\": {}, \"downstream_dynamic_partitioned_asset\": {}, \"downstream_static_partitioned_asset\": {}, \"downstream_time_partitioned_asset\": {}, \"downstream_weekly_partitioned_asset\": {}, \"dynamic_in_multipartitions_fail\": {}, \"dynamic_in_multipartitions_success\": {}, \"executable_asset\": {}, \"fail_partition_materialization\": {}, \"first_asset\": {}, \"foo\": {}, \"foo_bar\": {}, \"fresh_diamond_bottom\": {}, \"fresh_diamond_left\": {}, \"fresh_diamond_right\": {}, \"fresh_diamond_top\": {}, \"grouped_asset_1\": {}, \"grouped_asset_2\": {}, \"grouped_asset_4\": {}, \"hanging_asset\": {}, \"hanging_graph\": {\"ops\": {\"hanging_op\": {}, \"my_op\": {}, \"never_runs_op\": {}}}, \"hanging_partition_asset\": {}, \"integers_asset\": {}, \"middle_static_partitioned_asset_1\": {}, \"middle_static_partitioned_asset_2\": {}, \"multi_asset_with_kinds\": {\"config\": {}}, \"multi_run_backfill_policy_asset\": {}, \"multipartitions_1\": {}, \"multipartitions_2\": {}, \"multipartitions_fail\": {}, \"never_runs_asset\": {}, \"no_multipartitions_1\": {}, \"output_then_hang_asset\": {}, \"single_run_backfill_policy_asset\": {}, \"subsettable_checked_multi_asset\": {\"config\": {}}, \"typed_asset\": {}, \"typed_multi_asset\": {\"config\": {}}, \"unconnected\": {}, \"ungrouped_asset_3\": {}, \"ungrouped_asset_5\": {}, \"unpartitioned_upstream_of_partitioned\": {}, \"untyped_asset\": {}, \"upstream_daily_partitioned_asset\": {}, \"upstream_dynamic_partitioned_asset\": {}, \"upstream_static_partitioned_asset\": {}, \"upstream_time_partitioned_asset\": {}, \"yield_partition_materialization\": {}}", + "description": "Configure runtime parameters for ops or assets.", + "is_required": false, + "name": "ops", + "type_key": "Shape.a5a176434a175a95d1824c99b433d2da5d2d1fcf" + }, + { + "__class__": "ConfigFieldSnap", + "default_provided": false, + "default_value_as_json_str": null, + "description": "Configure how shared resources are implemented within a run.", + "is_required": true, + "name": "resources", + "type_key": "Shape.7493b137e48f8d4b013bce61e92617ff1bc51f7f" + } + ], + "given_name": null, + "key": "Shape.2b5e6e2b190fb25e32288ec068c8ff7fb8db3014", + "kind": { + "__enum__": "ConfigTypeKind.STRICT_SHAPE" + }, + "scalar_kind": null, + "type_param_keys": null + }, "Shape.35d3e42b53e66506c5867f04644849cd03763bc6": { "__class__": "ConfigTypeSnap", "description": null, @@ -567,56 +617,6 @@ "scalar_kind": null, "type_param_keys": null }, - "Shape.4966d8cb5c8020bf08c9267b9784db8f336f3245": { - "__class__": "ConfigTypeSnap", - "description": null, - "enum_values": null, - "fields": [ - { - "__class__": "ConfigFieldSnap", - "default_provided": true, - "default_value_as_json_str": "{\"config\": {\"retries\": {\"enabled\": {}}}}", - "description": "Configure how steps are executed within a run.", - "is_required": false, - "name": "execution", - "type_key": "Shape.09d73f0755bf4752d3f121837669c8660dcf451e" - }, - { - "__class__": "ConfigFieldSnap", - "default_provided": true, - "default_value_as_json_str": "{}", - "description": "Configure how loggers emit messages within a run.", - "is_required": false, - "name": "loggers", - "type_key": "Shape.e895d95ee6d0eff1b884c76f44a2ab7089f0c49b" - }, - { - "__class__": "ConfigFieldSnap", - "default_provided": true, - "default_value_as_json_str": "{\"asset_1\": {}, \"asset_1_my_check\": {}, \"asset_2\": {}, \"asset_3\": {}, \"asset_one\": {}, \"asset_two\": {}, \"asset_with_automation_condition\": {}, \"asset_with_compute_storage_kinds\": {\"config\": {}}, \"asset_yields_observation\": {}, \"bar\": {}, \"baz\": {}, \"check_in_op_asset\": {}, \"downstream_asset\": {}, \"downstream_dynamic_partitioned_asset\": {}, \"downstream_static_partitioned_asset\": {}, \"downstream_time_partitioned_asset\": {}, \"downstream_weekly_partitioned_asset\": {}, \"dynamic_in_multipartitions_fail\": {}, \"dynamic_in_multipartitions_success\": {}, \"executable_asset\": {}, \"fail_partition_materialization\": {}, \"first_asset\": {}, \"foo\": {}, \"foo_bar\": {}, \"fresh_diamond_bottom\": {}, \"fresh_diamond_left\": {}, \"fresh_diamond_right\": {}, \"fresh_diamond_top\": {}, \"grouped_asset_1\": {}, \"grouped_asset_2\": {}, \"grouped_asset_4\": {}, \"hanging_asset\": {}, \"hanging_graph\": {\"ops\": {\"hanging_op\": {}, \"my_op\": {}, \"never_runs_op\": {}}}, \"hanging_partition_asset\": {}, \"integers_asset\": {}, \"middle_static_partitioned_asset_1\": {}, \"middle_static_partitioned_asset_2\": {}, \"multi_asset_with_kinds\": {\"config\": {}}, \"multi_run_backfill_policy_asset\": {}, \"multipartitions_1\": {}, \"multipartitions_2\": {}, \"multipartitions_fail\": {}, \"never_runs_asset\": {}, \"no_multipartitions_1\": {}, \"output_then_hang_asset\": {}, \"single_run_backfill_policy_asset\": {}, \"subsettable_checked_multi_asset\": {\"config\": {}}, \"typed_asset\": {}, \"typed_multi_asset\": {\"config\": {}}, \"unconnected\": {}, \"ungrouped_asset_3\": {}, \"ungrouped_asset_5\": {}, \"unpartitioned_upstream_of_partitioned\": {}, \"untyped_asset\": {}, \"upstream_daily_partitioned_asset\": {}, \"upstream_dynamic_partitioned_asset\": {}, \"upstream_static_partitioned_asset\": {}, \"upstream_time_partitioned_asset\": {}, \"yield_partition_materialization\": {}}", - "description": "Configure runtime parameters for ops or assets.", - "is_required": false, - "name": "ops", - "type_key": "Shape.c6d0be00ce427a42f60d371338f7d9b650c5f7ce" - }, - { - "__class__": "ConfigFieldSnap", - "default_provided": false, - "default_value_as_json_str": null, - "description": "Configure how shared resources are implemented within a run.", - "is_required": true, - "name": "resources", - "type_key": "Shape.7493b137e48f8d4b013bce61e92617ff1bc51f7f" - } - ], - "given_name": null, - "key": "Shape.4966d8cb5c8020bf08c9267b9784db8f336f3245", - "kind": { - "__enum__": "ConfigTypeKind.STRICT_SHAPE" - }, - "scalar_kind": null, - "type_param_keys": null - }, "Shape.4b53b73df342381d0d05c5f36183dc99cb9676e2": { "__class__": "ConfigTypeSnap", "description": null, @@ -791,30 +791,7 @@ "scalar_kind": null, "type_param_keys": null }, - "Shape.b13a6c5637084590cc1538f9522324bfeb4b46b3": { - "__class__": "ConfigTypeSnap", - "description": null, - "enum_values": null, - "fields": [ - { - "__class__": "ConfigFieldSnap", - "default_provided": false, - "default_value_as_json_str": null, - "description": null, - "is_required": true, - "name": "config", - "type_key": "Shape.9a3a315bff2146cca750edbec49c6b4b4d0ce58e" - } - ], - "given_name": null, - "key": "Shape.b13a6c5637084590cc1538f9522324bfeb4b46b3", - "kind": { - "__enum__": "ConfigTypeKind.STRICT_SHAPE" - }, - "scalar_kind": null, - "type_param_keys": null - }, - "Shape.c6d0be00ce427a42f60d371338f7d9b650c5f7ce": { + "Shape.a5a176434a175a95d1824c99b433d2da5d2d1fcf": { "__class__": "ConfigTypeSnap", "description": null, "enum_values": null, @@ -891,6 +868,15 @@ "name": "asset_with_compute_storage_kinds", "type_key": "Shape.62edccaf30696e25335ae92685bdc41e204e30e6" }, + { + "__class__": "ConfigFieldSnap", + "default_provided": true, + "default_value_as_json_str": "{}", + "description": null, + "is_required": false, + "name": "asset_with_custom_automation_condition", + "type_key": "Shape.743e47901855cb245064dd633e217bfcb49a11a7" + }, { "__class__": "ConfigFieldSnap", "default_provided": true, @@ -1352,7 +1338,30 @@ } ], "given_name": null, - "key": "Shape.c6d0be00ce427a42f60d371338f7d9b650c5f7ce", + "key": "Shape.a5a176434a175a95d1824c99b433d2da5d2d1fcf", + "kind": { + "__enum__": "ConfigTypeKind.STRICT_SHAPE" + }, + "scalar_kind": null, + "type_param_keys": null + }, + "Shape.b13a6c5637084590cc1538f9522324bfeb4b46b3": { + "__class__": "ConfigTypeSnap", + "description": null, + "enum_values": null, + "fields": [ + { + "__class__": "ConfigFieldSnap", + "default_provided": false, + "default_value_as_json_str": null, + "description": null, + "is_required": true, + "name": "config", + "type_key": "Shape.9a3a315bff2146cca750edbec49c6b4b4d0ce58e" + } + ], + "given_name": null, + "key": "Shape.b13a6c5637084590cc1538f9522324bfeb4b46b3", "kind": { "__enum__": "ConfigTypeKind.STRICT_SHAPE" }, @@ -1655,6 +1664,14 @@ "dagster/compute_kind": "python" } }, + { + "__class__": "SolidInvocationSnap", + "input_dep_snaps": [], + "is_dynamic_mapped": false, + "solid_def_name": "asset_with_custom_automation_condition", + "solid_name": "asset_with_custom_automation_condition", + "tags": {} + }, { "__class__": "SolidInvocationSnap", "input_dep_snaps": [], @@ -2437,7 +2454,7 @@ "name": "io_manager" } ], - "root_config_key": "Shape.4966d8cb5c8020bf08c9267b9784db8f336f3245" + "root_config_key": "Shape.2b5e6e2b190fb25e32288ec068c8ff7fb8db3014" } ], "name": "__ASSET_JOB", @@ -2788,6 +2805,33 @@ "dagster/compute_kind": "python" } }, + { + "__class__": "SolidDefSnap", + "config_field_snap": { + "__class__": "ConfigFieldSnap", + "default_provided": false, + "default_value_as_json_str": null, + "description": null, + "is_required": false, + "name": "config", + "type_key": "Any" + }, + "description": null, + "input_def_snaps": [], + "name": "asset_with_custom_automation_condition", + "output_def_snaps": [ + { + "__class__": "OutputDefSnap", + "dagster_type_key": "Nothing", + "description": null, + "is_dynamic": false, + "is_required": true, + "name": "result" + } + ], + "required_resource_keys": [], + "tags": {} + }, { "__class__": "SolidDefSnap", "config_field_snap": { @@ -34009,7 +34053,7 @@ 'd9f6d85793df3d9df94d4aedb21bb659c1202bda' # --- # name: test_all_snapshot_ids[1] - '0310355b0e75065dcff5d60c86667dce4b61d922' + '6a10762c0be27c5d99bc14d1e1964cc7b60351df' # --- # name: test_all_snapshot_ids[20] ''' diff --git a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_assets.ambr b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_assets.ambr index 4cb99b5d5e766..e5105cbd84425 100644 --- a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_assets.ambr +++ b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_assets.ambr @@ -61,6 +61,14 @@ ]), }), }), + dict({ + 'id': 'test.test_repo.["asset_with_custom_automation_condition"]', + 'key': dict({ + 'path': list([ + 'asset_with_custom_automation_condition', + ]), + }), + }), dict({ 'id': 'test.test_repo.["asset_yields_observation"]', 'key': dict({ @@ -608,6 +616,11 @@ 'freshnessPolicy': None, 'id': 'test.test_repo.["asset_with_automation_condition"]', }), + dict({ + 'freshnessInfo': None, + 'freshnessPolicy': None, + 'id': 'test.test_repo.["asset_with_custom_automation_condition"]', + }), dict({ 'freshnessInfo': None, 'freshnessPolicy': None, diff --git a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_solids.ambr b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_solids.ambr index b07ab3bc9a511..7df38bd9f1bd0 100644 --- a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_solids.ambr +++ b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/__snapshots__/test_solids.ambr @@ -339,6 +339,22 @@ }), ]), }), + dict({ + '__typename': 'UsedSolid', + 'definition': dict({ + 'name': 'asset_with_custom_automation_condition', + }), + 'invocations': list([ + dict({ + 'pipeline': dict({ + 'name': '__ASSET_JOB', + }), + 'solidHandle': dict({ + 'handleID': 'asset_with_custom_automation_condition', + }), + }), + ]), + }), dict({ '__typename': 'UsedSolid', 'definition': dict({ diff --git a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/repo.py b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/repo.py index 931d35cfe2efc..a9d14f79dfe14 100644 --- a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/repo.py +++ b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/repo.py @@ -1801,6 +1801,18 @@ def asset_with_compute_storage_kinds(): def asset_with_automation_condition() -> None: ... +class MyAutomationCondition(AutomationCondition): + @property + def name(self) -> str: + return "some_custom_name" + + def evaluate(self): ... + + +@asset(automation_condition=MyAutomationCondition().since_last_handled()) +def asset_with_custom_automation_condition() -> None: ... + + fresh_diamond_assets_job = define_asset_job( "fresh_diamond_assets_job", AssetSelection.assets(fresh_diamond_bottom).upstream() ) @@ -2117,6 +2129,7 @@ def define_assets(): multi_asset_with_kinds, asset_with_compute_storage_kinds, asset_with_automation_condition, + asset_with_custom_automation_condition, ] diff --git a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_assets.py b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_assets.py index 727446fae35ee..7d03e37723ae5 100644 --- a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_assets.py +++ b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_assets.py @@ -2626,6 +2626,16 @@ def test_automation_condition(self, graphql_context: WorkspaceRequestContext): assert condition["label"] == "eager" assert "(in_latest_time_window)" in condition["expandedLabel"] + custom_automation_condition_asset = [ + a + for a in result.data["assetNodes"] + if a["id"] == 'test.test_repo.["asset_with_custom_automation_condition"]' + ] + assert len(custom_automation_condition_asset) == 1 + condition = custom_automation_condition_asset[0]["automationCondition"] + assert condition["label"] is None + assert condition["expandedLabel"] == ["(some_custom_name)", "SINCE", "(handled)"] + def test_tags(self, graphql_context: WorkspaceRequestContext): result = execute_dagster_graphql( graphql_context, diff --git a/python_modules/dagster/dagster/_core/remote_representation/external_data.py b/python_modules/dagster/dagster/_core/remote_representation/external_data.py index 0e99ca2e5cc9b..c83ef2d2cb22f 100644 --- a/python_modules/dagster/dagster/_core/remote_representation/external_data.py +++ b/python_modules/dagster/dagster/_core/remote_representation/external_data.py @@ -1286,6 +1286,7 @@ class AssetCheckNodeSnap(IHaveNew): blocking: bool additional_asset_keys: Sequence[AssetKey] automation_condition: Optional[AutomationCondition] + automation_condition_snapshot: Optional[AutomationConditionSnapshot] def __new__( cls, @@ -1297,6 +1298,7 @@ def __new__( blocking: bool = False, additional_asset_keys: Optional[Sequence[AssetKey]] = None, automation_condition: Optional[AutomationCondition] = None, + automation_condition_snapshot: Optional[AutomationConditionSnapshot] = None, ): return super().__new__( cls, @@ -1308,6 +1310,7 @@ def __new__( blocking=blocking, additional_asset_keys=additional_asset_keys or [], automation_condition=automation_condition, + automation_condition_snapshot=automation_condition_snapshot, ) @property @@ -1463,11 +1466,6 @@ def __new__( # job, and no source assets could be part of any job is_source = len(job_names or []) == 0 - if auto_materialize_policy and auto_materialize_policy.asset_condition: - # do not include automation conditions containing user-defined info on the ExternalAssetNode - if not auto_materialize_policy.asset_condition.is_serializable: - auto_materialize_policy = None - return super().__new__( cls, asset_key=asset_key, @@ -1494,7 +1492,7 @@ def __new__( execution_set_identifier=execution_set_identifier, required_top_level_resources=required_top_level_resources or [], auto_materialize_policy=auto_materialize_policy, - automation_condition_snapshot=None, + automation_condition_snapshot=automation_condition_snapshot, backfill_policy=backfill_policy, auto_observe_interval_minutes=auto_observe_interval_minutes, owners=owners or [], @@ -1579,6 +1577,9 @@ def asset_check_node_snaps_from_repo(repo: RepositoryDefinition) -> Sequence[Ass asset_check_node_snaps: List[AssetCheckNodeSnap] = [] for check_key, job_names in job_names_by_check_key.items(): spec = repo.asset_graph.get_check_spec(check_key) + automation_condition, automation_condition_snapshot = resolve_automation_condition_args( + spec.automation_condition + ) asset_check_node_snaps.append( AssetCheckNodeSnap( name=check_key.name, @@ -1588,7 +1589,8 @@ def asset_check_node_snaps_from_repo(repo: RepositoryDefinition) -> Sequence[Ass job_names=job_names, blocking=spec.blocking, additional_asset_keys=[dep.asset_key for dep in spec.additional_deps], - automation_condition=spec.automation_condition, + automation_condition=automation_condition, + automation_condition_snapshot=automation_condition_snapshot, ) ) @@ -1668,6 +1670,9 @@ def asset_node_snaps_from_repo(repo: RepositoryDefinition) -> Sequence[AssetNode ) and isinstance(partition_mapping, builtin_partition_mapping_types): partition_mappings[pk] = partition_mapping + automation_condition, automation_condition_snapshot = resolve_automation_condition_args( + asset_node.automation_condition + ) asset_node_snaps.append( AssetNodeSnap( asset_key=key, @@ -1703,7 +1708,10 @@ def asset_node_snaps_from_repo(repo: RepositoryDefinition) -> Sequence[AssetNode is_observable=asset_node.is_observable, execution_set_identifier=repo.asset_graph.get_execution_set_identifier(key), required_top_level_resources=required_top_level_resources, - auto_materialize_policy=asset_node.auto_materialize_policy, + auto_materialize_policy=automation_condition.as_auto_materialize_policy() + if automation_condition + else None, + automation_condition_snapshot=automation_condition_snapshot, backfill_policy=asset_node.backfill_policy, auto_observe_interval_minutes=asset_node.auto_observe_interval_minutes, owners=asset_node.owners, @@ -1826,3 +1834,17 @@ def active_presets_from_job_def(job_def: JobDefinition) -> Sequence[PresetSnap]: tags={}, ) ] + + +def resolve_automation_condition_args( + automation_condition: Optional[AutomationCondition], +) -> Tuple[Optional[AutomationCondition], Optional[AutomationConditionSnapshot]]: + if automation_condition is None: + return None, None + elif automation_condition.is_serializable: + # to avoid serializing too much data, only store the full condition if + # it is available + return automation_condition, None + else: + # for non-serializable conditions, only include the snapshot + return None, automation_condition.get_snapshot() diff --git a/python_modules/dagster/dagster_tests/definitions_tests/declarative_automation_tests/daemon_tests/definitions/custom_condition.py b/python_modules/dagster/dagster_tests/definitions_tests/declarative_automation_tests/daemon_tests/definitions/custom_condition.py new file mode 100644 index 0000000000000..9b6b6af5a686c --- /dev/null +++ b/python_modules/dagster/dagster_tests/definitions_tests/declarative_automation_tests/daemon_tests/definitions/custom_condition.py @@ -0,0 +1,26 @@ +import dagster as dg + + +class MyCondition(dg.AutomationCondition): + def evaluate(self, context: dg.AutomationContext) -> dg.AutomationResult: + # kick off on the 5th evaluation + if len(context.cursor or "") == 4: + true_subset = context.candidate_subset + else: + true_subset = context.get_empty_subset() + + return dg.AutomationResult( + context, true_subset=true_subset, cursor=(context.cursor or "") + "." + ) + + +@dg.asset(automation_condition=MyCondition().since_last_handled()) +def foo() -> None: ... + + +defs = dg.Definitions( + assets=[foo], + sensors=[ + dg.AutomationConditionSensorDefinition("the_sensor", asset_selection="*", user_code=True) + ], +) diff --git a/python_modules/dagster/dagster_tests/definitions_tests/declarative_automation_tests/daemon_tests/test_e2e.py b/python_modules/dagster/dagster_tests/definitions_tests/declarative_automation_tests/daemon_tests/test_e2e.py index 3afd061be02e5..daeae8f397247 100644 --- a/python_modules/dagster/dagster_tests/definitions_tests/declarative_automation_tests/daemon_tests/test_e2e.py +++ b/python_modules/dagster/dagster_tests/definitions_tests/declarative_automation_tests/daemon_tests/test_e2e.py @@ -521,3 +521,29 @@ def test_backfill_with_runs_and_checks() -> None: assert len(backfills) == 0 runs = _get_runs_for_latest_ticks(context) assert len(runs) == 0 + + +def test_custom_condition() -> None: + with get_workspace_request_context( + ["custom_condition"] + ) as context, get_threadpool_executor() as executor: + time = datetime.datetime(2024, 8, 16, 1, 35) + + # custom condition only materializes on the 5th tick + for _ in range(4): + with freeze_time(time): + _execute_ticks(context, executor) + runs = _get_runs_for_latest_ticks(context) + assert len(runs) == 0 + time += datetime.timedelta(minutes=1) + + with freeze_time(time): + _execute_ticks(context, executor) + runs = _get_runs_for_latest_ticks(context) + assert len(runs) == 1 + + time += datetime.timedelta(minutes=1) + with freeze_time(time): + _execute_ticks(context, executor) + runs = _get_runs_for_latest_ticks(context) + assert len(runs) == 0