11from functools import wraps
2- from typing import Any , Callable , Dict , List , Literal , Optional , cast
2+ from typing import Any , Callable , Dict , List , Optional , cast
33
4- from dataframe_expectations .core .types import DataFrameLike
4+ from dataframe_expectations .core .types import DataFrameLike , TagMatchMode
55from dataframe_expectations .core .tagging import TagSet
66from dataframe_expectations .registry import (
77 DataFrameExpectationRegistry ,
@@ -62,35 +62,32 @@ class DataFrameExpectationsSuiteRunner:
6262 def _matches_tag_filter (
6363 expectation : Any ,
6464 filter_tag_set : TagSet ,
65- tag_match_mode : Literal [ "any" , "all" ] ,
65+ tag_match_mode : TagMatchMode ,
6666 ) -> bool :
6767 """
6868 Check if an expectation matches the tag filter criteria.
6969
7070 :param expectation: Expectation instance to check.
7171 :param filter_tag_set: Tag filter to match against.
72- :param tag_match_mode: Match mode - "any" (OR) or "all" (AND).
72+ :param tag_match_mode: Match mode - TagMatchMode.ANY (OR) or TagMatchMode.ALL (AND).
7373 :return: True if expectation matches filter, False otherwise.
74- :raises ValueError: If tag_match_mode is invalid.
7574 """
7675 exp_tag_set = expectation .get_tags ()
7776
7877 # Check if expectation matches filter
7978 match tag_match_mode :
80- case "any" :
79+ case TagMatchMode . ANY :
8180 return exp_tag_set .has_any_tag_from (filter_tag_set )
82- case "all" :
81+ case TagMatchMode . ALL :
8382 return exp_tag_set .has_all_tags_from (filter_tag_set )
84- case _:
85- raise ValueError (f"Invalid tag_match_mode: { tag_match_mode } " )
8683
8784 def __init__ (
8885 self ,
8986 expectations : List [Any ],
9087 suite_name : Optional [str ] = None ,
9188 violation_sample_limit : int = 5 ,
9289 tags : Optional [List [str ]] = None ,
93- tag_match_mode : Optional [Literal [ "any" , "all" ] ] = None ,
90+ tag_match_mode : Optional [TagMatchMode ] = None ,
9491 ):
9592 """
9693 Initialize the runner with a list of expectations and metadata.
@@ -101,10 +98,10 @@ def __init__(
10198 :param tags: Optional tag filters as list of strings in "key:value" format.
10299 Example: ["priority:high", "priority:medium"]
103100 If None or empty, all expectations will run.
104- :param tag_match_mode: How to match tags - "any" (OR logic) or "all" (AND logic).
101+ :param tag_match_mode: How to match tags - TagMatchMode.ANY (OR logic) or TagMatchMode.ALL (AND logic).
105102 Required if tags are provided, must be None if tags are not provided.
106- - "any" : Expectation matches if it has ANY of the filter tags
107- - "all" : Expectation matches if it has ALL of the filter tags
103+ - TagMatchMode.ANY : Expectation matches if it has ANY of the filter tags
104+ - TagMatchMode.ALL : Expectation matches if it has ALL of the filter tags
108105 :raises ValueError: If tag_match_mode is provided without tags, or if tags are provided without tag_match_mode,
109106 or if tag filters result in zero expectations to run.
110107 """
@@ -122,15 +119,21 @@ def __init__(
122119
123120 if not self .__filter_tag_set .is_empty () and tag_match_mode is None :
124121 raise ValueError (
125- "tag_match_mode must be specified ('any' or 'all' ) when tags are provided."
122+ "tag_match_mode must be specified (TagMatchMode.ANY or TagMatchMode.ALL ) when tags are provided."
126123 )
127124
128125 self .__tag_match_mode = tag_match_mode
129126
130127 # Filter expectations based on tags and track skipped ones
131128 if not self .__filter_tag_set .is_empty ():
132129 # At this point, validation ensures tag_match_mode is not None
133- assert tag_match_mode is not None
130+ # This check is for type narrowing (mypy/pyright)
131+ if tag_match_mode is None :
132+ # This should never happen due to validation above, but satisfies type checker
133+ raise ValueError (
134+ "tag_match_mode must be specified (TagMatchMode.ANY or TagMatchMode.ALL) when tags are provided."
135+ )
136+
134137 filtered = []
135138 skipped = []
136139 for exp in self .__all_expectations :
@@ -201,7 +204,7 @@ def run(
201204 data_frame : DataFrameLike ,
202205 raise_on_failure : bool = True ,
203206 context : Optional [Dict [str , Any ]] = None ,
204- ) -> Optional [ SuiteExecutionResult ] :
207+ ) -> SuiteExecutionResult :
205208 """
206209 Run all expectations on the provided DataFrame with PySpark caching optimization.
207210
@@ -458,11 +461,11 @@ class DataFrameExpectationsSuite:
458461 runner_all.run(df) # Runs all 3 expectations
459462
460463 # Build runner for high OR medium priority expectations (OR logic)
461- runner_any = suite.build(tags=["priority:high", "priority:medium"], tag_match_mode="any" )
464+ runner_any = suite.build(tags=["priority:high", "priority:medium"], tag_match_mode=TagMatchMode.ANY )
462465 runner_any.run(df) # Runs 2 expectations (age and salary checks)
463466
464467 # Build runner for expectations with both high priority AND compliance category (AND logic)
465- runner_and = suite.build(tags=["priority:high", "category:compliance"], tag_match_mode="all" )
468+ runner_and = suite.build(tags=["priority:high", "category:compliance"], tag_match_mode=TagMatchMode.ALL )
466469 runner_and.run(df) # Runs 1 expectation (age check - has both tags)
467470 """
468471
@@ -530,7 +533,7 @@ def dynamic_method(tags: Optional[List[str]] = None, **kwargs):
530533 def build (
531534 self ,
532535 tags : Optional [List [str ]] = None ,
533- tag_match_mode : Optional [Literal [ "any" , "all" ] ] = None ,
536+ tag_match_mode : Optional [TagMatchMode ] = None ,
534537 ) -> DataFrameExpectationsSuiteRunner :
535538 """
536539 Build an immutable runner from the current expectations.
@@ -542,10 +545,10 @@ def build(
542545 :param tags: Optional tag filters as list of strings in "key:value" format.
543546 Example: ["priority:high", "priority:medium"]
544547 If None or empty, all expectations will be included.
545- :param tag_match_mode: How to match tags - "any" (OR logic) or "all" (AND logic).
548+ :param tag_match_mode: How to match tags - TagMatchMode.ANY (OR logic) or TagMatchMode.ALL (AND logic).
546549 Required if tags are provided, must be None if tags are not provided.
547- - "any" : Include expectations with ANY of the filter tags
548- - "all" : Include expectations with ALL of the filter tags
550+ - TagMatchMode.ANY : Include expectations with ANY of the filter tags
551+ - TagMatchMode.ALL : Include expectations with ALL of the filter tags
549552 :return: An immutable DataFrameExpectationsSuiteRunner instance.
550553 :raises ValueError: If no expectations have been added, if tag_match_mode validation fails,
551554 or if no expectations match the tag filters.
0 commit comments