1+ import asyncio
12import functools
23from collections .abc import Awaitable , Iterable
34from datetime import datetime , timedelta
@@ -162,10 +163,7 @@ def get_inner_queryer_for_back_compat(self) -> "CachingInstanceQueryer":
162163 return self ._queryer
163164
164165 def _get_partitions_def (self , key : T_EntityKey ) -> Optional ["PartitionsDefinition" ]:
165- if isinstance (key , AssetKey ):
166- return self .asset_graph .get (key ).partitions_def
167- else :
168- return None
166+ return self .asset_graph .get (key ).partitions_def
169167
170168 @cached_method
171169 @use_partition_loading_context
@@ -374,6 +372,16 @@ def get_asset_subset_from_asset_partitions(
374372 )
375373 return EntitySubset (self , key = key , value = _ValidatedEntitySubsetValue (value ))
376374
375+ @use_partition_loading_context
376+ def get_subset_from_partition_keys (
377+ self ,
378+ key : T_EntityKey ,
379+ partitions_def : "PartitionsDefinition" ,
380+ partition_keys : AbstractSet [str ],
381+ ) -> EntitySubset [T_EntityKey ]:
382+ value = partitions_def .subset_with_partition_keys (partition_keys )
383+ return EntitySubset (self , key = key , value = _ValidatedEntitySubsetValue (value ))
384+
377385 @use_partition_loading_context
378386 def compute_parent_subset_and_required_but_nonexistent_subset (
379387 self , parent_key , subset : EntitySubset [T_EntityKey ]
@@ -548,11 +556,19 @@ def compute_latest_time_window_subset(
548556 check .failed (f"Unsupported partitions_def: { partitions_def } " )
549557
550558 async def compute_subset_with_status (
551- self , key : AssetCheckKey , status : Optional ["AssetCheckExecutionResolvedStatus" ]
552- ):
559+ self ,
560+ key : AssetCheckKey ,
561+ status : Optional ["AssetCheckExecutionResolvedStatus" ],
562+ from_subset : EntitySubset ,
563+ ) -> EntitySubset [AssetCheckKey ]:
564+ """Returns the subset of an asset check that matches a given status."""
553565 from dagster ._core .storage .event_log .base import AssetCheckSummaryRecord
554566
555- """Returns the subset of an asset check that matches a given status."""
567+ # Handle partitioned asset checks with partition-level granularity
568+ if self ._get_partitions_def (key ):
569+ return await self ._get_partitioned_check_subset_with_status (key , status , from_subset )
570+
571+ # Handle non-partitioned asset checks with existing logic
556572 summary = await AssetCheckSummaryRecord .gen (self , key )
557573 latest_record = summary .last_check_execution_record if summary else None
558574 resolved_status = (
@@ -586,31 +602,61 @@ async def compute_subset_with_freshness_state(
586602 return self .get_empty_subset (key = key )
587603
588604 async def _compute_run_in_progress_check_subset (
589- self , key : AssetCheckKey
605+ self , key : AssetCheckKey , from_subset : EntitySubset
590606 ) -> EntitySubset [AssetCheckKey ]:
591607 from dagster ._core .storage .asset_check_execution_record import (
592608 AssetCheckExecutionResolvedStatus ,
593609 )
594610
595611 return await self .compute_subset_with_status (
596- key , AssetCheckExecutionResolvedStatus .IN_PROGRESS
612+ key , AssetCheckExecutionResolvedStatus .IN_PROGRESS , from_subset
597613 )
598614
599615 async def _compute_execution_failed_check_subset (
600- self , key : AssetCheckKey
616+ self , key : AssetCheckKey , from_subset : EntitySubset
601617 ) -> EntitySubset [AssetCheckKey ]:
602618 from dagster ._core .storage .asset_check_execution_record import (
603619 AssetCheckExecutionResolvedStatus ,
604620 )
605621
606622 return await self .compute_subset_with_status (
607- key , AssetCheckExecutionResolvedStatus .EXECUTION_FAILED
623+ key , AssetCheckExecutionResolvedStatus .EXECUTION_FAILED , from_subset
608624 )
609625
610626 async def _compute_missing_check_subset (
611- self , key : AssetCheckKey
627+ self , key : AssetCheckKey , from_subset : EntitySubset
628+ ) -> EntitySubset [AssetCheckKey ]:
629+ return await self .compute_subset_with_status (key , None , from_subset )
630+
631+ async def _get_asset_check_partition_status (
632+ self , key : AssetCheckKey , partition : str
633+ ) -> Optional ["AssetCheckExecutionResolvedStatus" ]:
634+ # NOTE: we should add a LoadingContext-native version of this
635+ record = self .instance .event_log_storage .get_latest_asset_check_execution_by_key (
636+ [key ], partition
637+ ).get (key )
638+ if record :
639+ targets_latest = await record .targets_latest_materialization (self )
640+ return await record .resolve_status (self ) if targets_latest else None
641+ else :
642+ return None
643+
644+ async def _get_partitioned_check_subset_with_status (
645+ self ,
646+ key : AssetCheckKey ,
647+ status : Optional ["AssetCheckExecutionResolvedStatus" ],
648+ from_subset : EntitySubset ,
612649 ) -> EntitySubset [AssetCheckKey ]:
613- return await self .compute_subset_with_status (key , None )
650+ check_node = self .asset_graph .get (key )
651+ if not check_node or not check_node .partitions_def :
652+ check .failed (f"Asset check { key } not found or not partitioned." )
653+
654+ partitions = list (from_subset .expensively_compute_partition_keys ())
655+ statuses = await asyncio .gather (
656+ * (self ._get_asset_check_partition_status (key , p ) for p in partitions )
657+ )
658+ matching_partitions = {p for p , s in zip (partitions , statuses ) if s == status }
659+ return from_subset .compute_intersection_with_partition_keys (matching_partitions )
614660
615661 async def _compute_run_in_progress_asset_subset (self , key : AssetKey ) -> EntitySubset [AssetKey ]:
616662 from dagster ._core .storage .partition_status_cache import AssetStatusCacheValue
@@ -735,15 +781,21 @@ async def _compute_missing_asset_subset(
735781 )
736782
737783 @cached_method
738- async def compute_run_in_progress_subset (self , * , key : EntityKey ) -> EntitySubset :
784+ async def compute_run_in_progress_subset (
785+ self , * , key : EntityKey , from_subset : EntitySubset
786+ ) -> EntitySubset :
739787 return await _dispatch (
740788 key = key ,
741- check_method = self ._compute_run_in_progress_check_subset ,
789+ check_method = functools .partial (
790+ self ._compute_run_in_progress_check_subset , from_subset = from_subset
791+ ),
742792 asset_method = self ._compute_run_in_progress_asset_subset ,
743793 )
744794
745795 @cached_method
746- async def compute_backfill_in_progress_subset (self , * , key : EntityKey ) -> EntitySubset :
796+ async def compute_backfill_in_progress_subset (
797+ self , * , key : EntityKey , from_subset : EntitySubset
798+ ) -> EntitySubset :
747799 async def get_empty_subset (key : EntityKey ) -> EntitySubset :
748800 return self .get_empty_subset (key = key )
749801
@@ -755,10 +807,14 @@ async def get_empty_subset(key: EntityKey) -> EntitySubset:
755807 )
756808
757809 @cached_method
758- async def compute_execution_failed_subset (self , * , key : EntityKey ) -> EntitySubset :
810+ async def compute_execution_failed_subset (
811+ self , * , key : EntityKey , from_subset : EntitySubset
812+ ) -> EntitySubset :
759813 return await _dispatch (
760814 key = key ,
761- check_method = self ._compute_execution_failed_check_subset ,
815+ check_method = functools .partial (
816+ self ._compute_execution_failed_check_subset , from_subset = from_subset
817+ ),
762818 asset_method = self ._compute_execution_failed_asset_subset ,
763819 )
764820
@@ -768,7 +824,9 @@ async def compute_missing_subset(
768824 ) -> EntitySubset :
769825 return await _dispatch (
770826 key = key ,
771- check_method = self ._compute_missing_check_subset ,
827+ check_method = functools .partial (
828+ self ._compute_missing_check_subset , from_subset = from_subset
829+ ),
772830 asset_method = functools .partial (
773831 self ._compute_missing_asset_subset , from_subset = from_subset
774832 ),
0 commit comments