def key_periods(ciphertext, max_key_period):
    """Rank all key periods for ``ciphertext`` up to and including ``max_key_period``

    Example:
        >>> key_periods(ciphertext, 30)
        [2, 4, 8, 3, ...]

    Args:
        ciphertext (str): The text to analyze
        max_key_period (int): The maximum period the key could be

    Returns:
        Sorted list of keys

    Raises:
        ValueError: If max_key_period is less than or equal to 0
    """
    if max_key_period <= 0:
        raise ValueError("max_key_period must be a positive integer")

    key_scores = []
    for period in range(1, min(max_key_period, len(ciphertext)) + 1):
        score = abs(ENGLISH_IC - index_of_coincidence(*split_columns(ciphertext, period)))
        key_scores.append((period, score))

    return [p[0] for p in sorted(key_scores, key=lambda x: x[1])]
def key_periods ( ciphertext , max_key_period ) : if max_key_period <= 0 : raise ValueError ( "max_key_period must be a positive integer" ) key_scores = [ ] for period in range ( 1 , min ( max_key_period , len ( ciphertext ) ) + 1 ) : score = abs ( ENGLISH_IC - index_of_coincidence ( * split_columns ( ciphertext , period ) ) ) key_scores . append ( ( period , score ) ) return [ p [ 0 ] for p in sorted ( key_scores , key = lambda x : x [ 1 ] ) ]
Rank all key periods for ``ciphertext`` up to and including ``max_key_period``

    Example:
        >>> key_periods(ciphertext, 30)
        [2, 4, 8, 3, ...]

    Args:
        ciphertext (str): The text to analyze
        max_key_period (int): The maximum period the key could be

    Returns:
        Sorted list of keys

    Raises:
        ValueError: If max_key_period is less than or equal to 0