### Install crosszip with pip Source: https://www.indrapatil.com/crosszip Install the crosszip package using pip. ```bash pip install crosszip ``` -------------------------------- ### Install crosszip with uv Source: https://www.indrapatil.com/crosszip Install the crosszip package using uv. ```bash uv add crosszip ``` -------------------------------- ### Basic usage of crosszip with various iterables Source: https://www.indrapatil.com/crosszip/reference/crosszip Examples demonstrating the use of crosszip with lists, tuples, sets, and generators to apply functions across combinations of inputs. ```python # Example 1: Basic usage with lists def concat(a, b, c): return f"{a}-{b}-{c}" list1 = [1, 2] list2 = ["a", "b"] list3 = [True, False] crosszip(concat, list1, list2, list3) # ['1-a-True', '1-a-False', '1-b-True', '1-b-False', '2-a-True', '2-a-False', # '2-b-True', '2-b-False'] # Example 2: Using tuples and a mathematical function def add(a, b): return a + b crosszip(add, (1, 2), (10, 20)) [11, 21, 12, 22] # Example 3: Using sets (order may vary) and a string concatenation function crosszip(concat, {1, 2}, {"x", "y"}, {"foo", "bar"}) # ['1-x-foo', '1-x-bar', '1-y-foo', '1-y-bar', '2-x-foo', '2-x-bar', # '2-y-foo', '2-y-bar'] # Example 4: Using a generator def gen(): yield 1 yield 2 crosszip(concat, gen(), ["a", "b"], ["x", "y"]) # >> ['1-a-x', '1-a-y', '1-b-x', '1-b-y', '2-a-x', '2-a-y', '2-b-x', '2-b-y'] ``` -------------------------------- ### Example usage of crosszip_parametrize marker Source: https://www.indrapatil.com/crosszip/reference/plugin Example showing how to use the crosszip_parametrize marker to parametrize a test with the Cartesian product of parameter values. The test_power_function test is parametrized with base values [2, 10] and exponent values [-1, 0, 1]. Also shows an empty marker usage with test_example. ```python import math import crosszip import pytest @pytest.mark.crosszip_parametrize( "base", [2, 10], "exponent", [-1, 0, 1], ) def test_power_function(base, exponent): result = math.pow(base, exponent) assert result == base**exponent @pytest.mark.crosszip_parametrize() def test_example(): pass ``` -------------------------------- ### Use pytest marker crosszip_parametrize Source: https://www.indrapatil.com/crosszip Example of using the pytest marker crosszip_parametrize to run a test with all combinations of base and exponent values. The output confirms successful execution. ```python # @pyodide # Testing Power Function import math import crosszip import pytest @pytest.mark.crosszip_parametrize( "base", [2, 10], "exponent", [-1, 0, 1], ) def test_power_function(base, exponent): result = math.pow(base, exponent) assert result == base**exponent print("Tests executed successfully.") ``` ```python Tests executed successfully. ``` -------------------------------- ### Use crosszip to generate labels Source: https://www.indrapatil.com/crosszip Example of using crosszip to apply a label generation function to all combinations of categories, subcategories, and versions. The output is a list of generated labels. ```python # @pyodide # Label Generation for Machine Learning from crosszip import crosszip def create_label(category, subcategory, version): return f"{category}_{subcategory}_v{version}" categories = ["cat", "dog"] subcategories = ["small", "large"] versions = ["1.0", "2.0"] labels = crosszip(create_label, categories, subcategories, versions) print(labels) ``` ```python ['cat_small_v1.0', 'cat_small_v2.0', 'cat_large_v1.0', 'cat_large_v2.0', 'dog_small_v1.0', 'dog_small_v2.0', 'dog_large_v1.0', 'dog_large_v2.0'] ``` -------------------------------- ### pytest_generate_tests hook for crosszip_parametrize marker Source: https://www.indrapatil.com/crosszip/reference/plugin This pytest hook is called for each test function and checks for the 'crosszip_parametrize' marker. It extracts parameter names and values from alternating marker arguments, validates them, computes the Cartesian product, and calls metafunc.parametrize with the combined names and combinations. The docstring includes usage examples and error cases. ```python def pytest_generate_tests(metafunc: pytest.Metafunc) -> None: """Generate parametrized tests using the cross-product of parameter values. This pytest hook parametrizes tests based on the `crosszip_parametrize` marker. It extracts parameter names and their corresponding lists of values, computes their Cartesian product, and parametrizes the test function accordingly. Args: metafunc (pytest.Metafunc): The test function's metadata provided by pytest. Example: ```python import math import crosszip import pytest @pytest.mark.crosszip_parametrize( "base", [2, 10], "exponent", [-1, 0, 1], ) def test_power_function(base, exponent): result = math.pow(base, exponent) assert result == base**exponent @pytest.mark.crosszip_parametrize() def test_example(): pass # Error: Parameter names and values must be provided. @pytest.mark.crosszip_parametrize( "x", 1, "y", [3, 4], ) def test_example(x, y): pass # Error: All parameter values must be non-empty sequences. ``` """ marker = metafunc.definition.get_closest_marker("crosszip_parametrize") if marker: args: tuple[Any, ...] = marker.args param_names: tuple[Any, ...] = args[::2] param_values: tuple[Any, ...] = args[1::2] validate_parameters(param_names, param_values) combinations: list[tuple[Any, ...]] = list(product(*param_values)) # Validation proves every name in this immutable tuple is a string. validated_names = cast("tuple[str, ...]", param_names) param_names_str = ",".join(validated_names) metafunc.parametrize(param_names_str, combinations) ``` -------------------------------- ### Generate combinatorial test cases with crosszip_parametrize Source: https://www.indrapatil.com/crosszip/advanced Demonstrates the basic usage of crosszip_parametrize to generate a Cartesian product of parameters, resulting in 64 test cases. ```python import pytest @pytest.mark.crosszip_parametrize( "protocol", ["http", "https", "ftp", "ssh"], "method", ["GET", "POST", "PUT", "DELETE"], "auth_type", ["none", "basic", "token", "oauth"], ) def test_api_client(protocol, method, auth_type): ... # 4 × 4 × 4 = 64 test cases ``` -------------------------------- ### Apply function to combinations with crosszip Source: https://www.indrapatil.com/crosszip/llms-full.txt Demonstrates using crosszip to apply a function to all combinations of provided iterables. ```python # @pyodide # Label Generation for Machine Learning from crosszip import crosszip def create_label(category, subcategory, version): return f"{category}_{subcategory}_v{version}" categories = ["cat", "dog"] subcategories = ["small", "large"] versions = ["1.0", "2.0"] labels = crosszip(create_label, categories, subcategories, versions) print(labels) ``` -------------------------------- ### Implementation of crosszip Source: https://www.indrapatil.com/crosszip/reference/crosszip The source code implementation of the crosszip function using itertools.product and itertools.starmap. ```python def crosszip(func: Callable[..., T], *iterables: Iterable[Any]) -> list[T]: """Apply a given function to all combinations of elements from multiple iterables. This function computes the Cartesian product of the input iterables (i.e., all possible combinations of their elements) and applies the provided function to each combination. Args: func (Callable[..., T]): A function that accepts as many arguments as there are iterables. *iterables (Iterable[T]): Two or more iterables to generate combinations from. Each iterable should contain elements that are valid inputs for the function `func`. Returns: list[T]: A list of results from applying the function to each combination of elements. Example: ```python # Example 1: Basic usage with lists def concat(a, b, c): return f"{a}-{b}-{c}" list1 = [1, 2] list2 = ["a", "b"] list3 = [True, False] crosszip(concat, list1, list2, list3) # ['1-a-True', '1-a-False', '1-b-True', '1-b-False', '2-a-True', '2-a-False', # '2-b-True', '2-b-False'] # Example 2: Using tuples and a mathematical function def add(a, b): return a + b crosszip(add, (1, 2), (10, 20)) [11, 21, 12, 22] # Example 3: Using sets (order may vary) and a string concatenation function crosszip(concat, {1, 2}, {"x", "y"}, {"foo", "bar"}) # ['1-x-foo', '1-x-bar', '1-y-foo', '1-y-bar', '2-x-foo', '2-x-bar', # '2-y-foo', '2-y-bar'] # Example 4: Using a generator def gen(): yield 1 yield 2 crosszip(concat, gen(), ["a", "b"], ["x", "y"]) # >> ['1-a-x', '1-a-y', '1-b-x', '1-b-y', '2-a-x', '2-a-y', '2-b-x', '2-b-y'] ``` Notes: - The function assumes that each iterable contains values compatible with the function `func`. - For large input iterables, the number of combinations grows exponentially, so use with care when working with large datasets. """ combinations = itertools.product(*iterables) return list(itertools.starmap(func, combinations)) ``` -------------------------------- ### Run focused tests with pytest -k Source: https://www.indrapatil.com/crosszip/advanced Uses the -k flag to execute a subset of generated tests by matching substrings in test IDs. ```bash # Run only the https combinations pytest -k "https" # Run only POST combinations pytest -k "POST" # Narrow further with boolean operators pytest -k "https and POST" ``` -------------------------------- ### Lazy processing with itertools.product Source: https://www.indrapatil.com/crosszip/advanced A generator-based approach to process combinations one at a time, avoiding full list materialization. ```python import itertools def process_lazily(func, *iterables): """Generator version of crosszip — yields one result at a time.""" for combo in itertools.product(*iterables): yield func(*combo) # Consume without materializing the full result list large_a = range(1_000) large_b = range(1_000) for result in process_lazily(lambda a, b: a + b, large_a, large_b): # Each result is produced and can be discarded before the next is computed. pass ``` -------------------------------- ### Register custom marks in pyproject.toml Source: https://www.indrapatil.com/crosszip/advanced Configures the slow mark in the project configuration to avoid warnings. ```toml [tool.pytest.ini_options] markers = [ "slow: marks tests as slow (deselect with '-m \"not slow\"')", ] ``` -------------------------------- ### Perform random sampling with a fixed seed Source: https://www.indrapatil.com/crosszip/advanced Selects a random subset of combinations for testing, using a fixed seed to ensure reproducibility in CI environments. ```python import itertools import random import pytest protocols = ["http", "https", "ftp", "ssh"] methods = ["GET", "POST", "PUT", "DELETE"] all_combos = list(itertools.product(protocols, methods)) SEED = 42 # fix the seed so CI runs are reproducible sampled = random.Random(SEED).sample(all_combos, k=min(5, len(all_combos))) @pytest.mark.parametrize("protocol,method", sampled) def test_api_sample(protocol, method): ... ``` -------------------------------- ### Calculate total combinations Source: https://www.indrapatil.com/crosszip/advanced Formula and Python code to estimate the total number of combinations before executing crosszip. ```python total_combinations = N₁ × N₂ × … × Nₖ ``` ```python import math sizes = [100, 50, 20, 10] total = math.prod(sizes) print(f"Total combinations: {total:,}") # 1,000,000 ``` -------------------------------- ### Organize tests into focused classes Source: https://www.indrapatil.com/crosszip/advanced Splits a large parameter space into smaller, purpose-scoped test classes to manage complexity. ```python import pytest class TestCoreProtocols: @pytest.mark.crosszip_parametrize( "method", ["GET", "POST"], "auth", ["none", "basic"], ) def test_http_methods(self, method, auth): ... # 2 × 2 = 4 tests class TestSecureProtocols: @pytest.mark.crosszip_parametrize( "method", ["GET", "POST", "PUT", "DELETE"], "token", ["valid", "expired"], ) def test_https_methods(self, method, token): ... # 4 × 2 = 8 tests ``` -------------------------------- ### Pre-filter combinations with itertools.product Source: https://www.indrapatil.com/crosszip/advanced Reduces the test matrix by filtering combinations before passing them to pytest.mark.parametrize. ```python import itertools import pytest protocols = ["http", "https", "ftp", "ssh"] methods = ["GET", "POST", "PUT", "DELETE"] # Only test secure protocols with write methods meaningful_combos = [ (proto, method) for proto, method in itertools.product(protocols, methods) if proto == "https" or method == "GET" ] # Reduces 4 × 4 = 16 → 7 combinations @pytest.mark.parametrize("protocol,method", meaningful_combos) def test_secure_api(protocol, method): ... ``` -------------------------------- ### Execute tests selectively by mark Source: https://www.indrapatil.com/crosszip/advanced Runs tests based on their assigned marks to control execution time. ```bash # Fast CI run — skip the full matrix pytest -m "not slow" # Nightly run — include everything pytest -m "slow" ``` -------------------------------- ### Register crosszip_parametrize marker with pytest_configure Source: https://www.indrapatil.com/crosszip/reference/plugin Pytest hook implementation that registers the crosszip_parametrize marker. Uses trylast=True to ensure it runs after other plugins. The marker is defined as 'crosszip_parametrize(*args): mark test to be cross-parametrized'. ```python @pytest.hookimpl(trylast=True) def pytest_configure(config: pytest.Config) -> None: """Register the `crosszip_parametrize` marker with pytest. This pytest hook registers the `crosszip_parametrize` marker with pytest. The marker is used to parametrize tests with the Cartesian product of parameter values. """ config.addinivalue_line( "markers", "crosszip_parametrize(*args): mark test to be cross-parametrized", ) ``` -------------------------------- ### validate_parameters(param_names, param_values) Source: https://www.indrapatil.com/crosszip/reference/plugin Validates the parameter names and values extracted from the crosszip_parametrize marker. Ensures that names and values are provided, have matching counts, names are strings, and value sequences are non-empty. Raises appropriate errors when validation fails. ```APIDOC ## validate_parameters(param_names, param_values) ### Description Validates marker parameter names and their corresponding value sequences. Ensures that both names and values are supplied, have equal lengths, names are strings, and value sequences are non-empty. Raises CrosszipValueError or CrosszipTypeError on invalid input. ### Method Function call ### Endpoint N/A - This is a helper function, not an HTTP endpoint. ### Parameters #### Parameter - **param_names** (Sequence[Any]) - Required - Names parsed from the marker's alternating arguments. - **param_values** (Sequence[Any]) - Required - Value collections paired with the parameter names. ### Request Example Not applicable; this is a function call. ### Response No return value. ### Response Example Not applicable. ### Error Handling - **CrosszipValueError** - Raised if names or values are missing or their counts differ. - **CrosszipTypeError** - Raised if names are not strings or a value collection is empty. ``` -------------------------------- ### Happy-path combinations test Source: https://www.indrapatil.com/crosszip/advanced Generates 9 test cases by creating a Cartesian product of input types and valid values. ```python import pytest @pytest.mark.crosszip_parametrize( "input_type", [int, str, float], "valid_value", [1, "hello", 3.14], ) def test_validate_input_happy_path(input_type, valid_value): result = validate_input(input_type(valid_value)) assert result is True ``` -------------------------------- ### crosszip(func, *iterables) Source: https://www.indrapatil.com/crosszip/reference/crosszip Applies a given function to all combinations of elements from multiple iterables. Computes the Cartesian product of the input iterables and applies the provided function to each combination. ```APIDOC ## crosszip(func, *iterables) ### Description Applies a given function to all combinations of elements from multiple iterables. This function computes the Cartesian product of the input iterables (i.e., all possible combinations of their elements) and applies the provided function to each combination. ### Parameters - **func** (Callable[..., T]) - Required - A function that accepts as many arguments as there are iterables. - **\*iterables** (Iterable[T]) - Optional (default: ()) - Two or more iterables to generate combinations from. Each iterable should contain elements that are valid inputs for the function `func`. ### Returns - **list[T]** - A list of results from applying the function to each combination of elements. ### Example ```python # Example 1: Basic usage with lists def concat(a, b, c): return f"{a}-{b}-{c}" list1 = [1, 2] list2 = ["a", "b"] list3 = [True, False] crosszip(concat, list1, list2, list3) # ['1-a-True', '1-a-False', '1-b-True', '1-b-False', '2-a-True', '2-a-False', # '2-b-True', '2-b-False'] # Example 2: Using tuples and a mathematical function def add(a, b): return a + b crosszip(add, (1, 2), (10, 20)) [11, 21, 12, 22] # Example 3: Using sets (order may vary) and a string concatenation function crosszip(concat, {1, 2}, {"x", "y"}, {"foo", "bar"}) # ['1-x-foo', '1-x-bar', '1-y-foo', '1-y-bar', '2-x-foo', '2-x-bar', # '2-y-foo', '2-y-bar'] # Example 4: Using a generator def gen(): yield 1 yield 2 crosszip(concat, gen(), ["a", "b"], ["x", "y"]) # >> ['1-a-x', '1-a-y', '1-b-x', '1-b-y', '2-a-x', '2-a-y', '2-b-x', '2-b-y'] ``` ### Notes - The function assumes that each iterable contains values compatible with the function `func`. - For large input iterables, the number of combinations grows exponentially, so use with care when working with large datasets. ``` -------------------------------- ### Per-combination assertions with pytest.raises Source: https://www.indrapatil.com/crosszip/advanced Asserts specific exception types per combination using pytest.raises. ```python import pytest @pytest.mark.crosszip_parametrize( "bad_value", [None, "", 0, -1], "expected_exc", [TypeError, ValueError], ) def test_validate_input_error_types(bad_value, expected_exc): with pytest.raises((TypeError, ValueError)): validate_input(bad_value) ``` -------------------------------- ### Chunked crosszip processing Source: https://www.indrapatil.com/crosszip/advanced Process combinations in fixed-size batches to manage memory when writing to disk or network. ```python import itertools def chunked_crosszip(func, chunk_size, *iterables): """Process combinations in fixed-size chunks.""" combo_iter = itertools.product(*iterables) while True: chunk = list(itertools.islice(combo_iter, chunk_size)) if not chunk: break yield [func(*combo) for combo in chunk] # Process 1 000 combinations at a time for batch in chunked_crosszip(str, 1_000, range(500), range(500)): # Flush batch to disk before fetching the next one pass ``` -------------------------------- ### Edge-case combinations with xfail Source: https://www.indrapatil.com/crosszip/llms-full.txt Marks all generated test cases as expected failures using @pytest.mark.xfail. ```python import pytest @pytest.mark.xfail(raises=(TypeError, ValueError), strict=True) @pytest.mark.crosszip_parametrize( "input_type", [int, str, float], "edge_case", [None, "", 0], ) def test_validate_input_edge_cases(input_type, edge_case): validate_input(edge_case) ``` -------------------------------- ### Implement tiered testing with custom marks Source: https://www.indrapatil.com/crosszip/advanced Separates fast smoke tests from full combinatorial tests using custom pytest marks. ```python import pytest # Always runs — representative single combination def test_api_smoke(): ... # Skipped in fast mode, run on schedule @pytest.mark.slow @pytest.mark.crosszip_parametrize( "protocol", ["http", "https", "ftp", "ssh"], "method", ["GET", "POST", "PUT", "DELETE"], ) def test_api_full_matrix( protocol, method ): ... # 4 × 4 = 16 tests, guarded by the slow mark ``` -------------------------------- ### pytest_generate_tests(metafunc: pytest.Metafunc) -> None Source: https://www.indrapatil.com/crosszip/reference/plugin This pytest hook automatically parametrizes tests marked with crosszip_parametrize. It extracts parameter names and their value sequences, computes the Cartesian product, and invokes metafunc.parametrize to generate test cases. Note: This hook is part of the pytest plugin and is called internally by pytest, not by user code directly. ```APIDOC ## pytest_generate_tests(metafunc: pytest.Metafunc) -> None ### Description This pytest hook is automatically invoked by pytest to parametrize tests that use the crosszip_parametrize marker. It extracts the alternating parameter names and value sequences from the marker, validates them, computes the Cartesian product of the value sequences, and calls metafunc.parametrize to generate the final test cases. ### Method Hook function (called by pytest internally) ### Endpoint N/A - This is a pytest plugin hook, not an HTTP endpoint. ### Parameters #### Parameter - **metafunc** (pytest.Metafunc) - Required - The test function's metadata provided by pytest. ### Request Example No request body; this hook is invoked by pytest during test collection. ### Response No return value; the hook modifies test collection via metafunc.parametrize. ### Response Example No response body. ``` -------------------------------- ### Edge-case combinations with xfail Source: https://www.indrapatil.com/crosszip/advanced Uses @pytest.mark.xfail to mark all generated test cases as expected failures, with strict=True to catch unexpected passes. ```python import pytest @pytest.mark.xfail(raises=(TypeError, ValueError), strict=True) @pytest.mark.crosszip_parametrize( "input_type", [int, str, float], "edge_case", [None, "", 0], ) def test_validate_input_edge_cases(input_type, edge_case): validate_input(edge_case) ``` -------------------------------- ### Safe crosszip guard pattern Source: https://www.indrapatil.com/crosszip/advanced A wrapper function that validates the total combination count against a limit before execution to prevent memory overflow. ```python import math from crosszip import crosszip def safe_crosszip(func, *iterables, limit: int = 10_000): """Call crosszip only if combination count is within the limit.""" # Convert to lists so we can measure length without exhausting generators lists = [list(it) for it in iterables] total = math.prod(len(lst) for lst in lists) if total > limit: raise ValueError( f"Combination count {total:,} exceeds limit {limit:,}. " "Reduce input sizes or use a lazy approach." ) return crosszip(func, *lists) ``` -------------------------------- ### Validation function under test Source: https://www.indrapatil.com/crosszip/advanced The target function validate_input that accepts only non-empty strings and positive numbers. ```python def validate_input(value): """Accept only non-empty strings and positive numbers.""" if not isinstance(value, (int, float, str)): raise TypeError(f"Unsupported type: {type(value).__name__}") if isinstance(value, str) and len(value) == 0: raise ValueError("String must not be empty") if isinstance(value, (int, float)) and value <= 0: raise ValueError("Number must be positive") return True ``` -------------------------------- ### validate_parameters function for crosszip marker validation Source: https://www.indrapatil.com/crosszip/reference/plugin Validates the parameter names and values extracted from the crosszip_parametrize marker. Raises CrosszipValueError if names or values are missing or counts differ, and CrosszipTypeError if names are not strings or any value collection is empty. ```python def validate_parameters( param_names: Sequence[Any], param_values: Sequence[Any], ) -> None: """Validate marker parameter names and their corresponding values. Args: param_names: Names parsed from alternating marker arguments. param_values: Value collections paired with the parameter names. Raises: CrosszipValueError: If names or values are missing or their counts differ. CrosszipTypeError: If names are not strings or a value collection is empty. """ if not param_names or not param_values: raise CrosszipValueError(PARAMS_REQUIRED_ERROR) if len(param_names) != len(param_values): raise CrosszipValueError(PARAMS_COUNT_MISMATCH_ERROR) if not all(isinstance(name, str) for name in param_names): raise CrosszipTypeError(PARAMS_NAME_TYPE_ERROR) if any(not values for values in param_values): raise CrosszipTypeError(PARAMS_VALUES_TYPE_ERROR) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.