| 3407 | class StringPrefixTest(unittest.TestCase): |
| 3408 | @staticmethod |
| 3409 | def determine_valid_prefixes(): |
| 3410 | # Try all lengths until we find a length that has zero valid |
| 3411 | # prefixes. This will miss the case where for example there |
| 3412 | # are no valid 3 character prefixes, but there are valid 4 |
| 3413 | # character prefixes. That seems unlikely. |
| 3414 | |
| 3415 | single_char_valid_prefixes = set() |
| 3416 | |
| 3417 | # Find all of the single character string prefixes. Just get |
| 3418 | # the lowercase version, we'll deal with combinations of upper |
| 3419 | # and lower case later. I'm using this logic just in case |
| 3420 | # some uppercase-only prefix is added. |
| 3421 | for letter in itertools.chain(string.ascii_lowercase, string.ascii_uppercase): |
| 3422 | try: |
| 3423 | eval(f'{letter}""') |
| 3424 | single_char_valid_prefixes.add(letter.lower()) |
| 3425 | except SyntaxError: |
| 3426 | pass |
| 3427 | |
| 3428 | # This logic assumes that all combinations of valid prefixes only use |
| 3429 | # the characters that are valid single character prefixes. That seems |
| 3430 | # like a valid assumption, but if it ever changes this will need |
| 3431 | # adjusting. |
| 3432 | valid_prefixes = set() |
| 3433 | for length in itertools.count(): |
| 3434 | num_at_this_length = 0 |
| 3435 | for prefix in ( |
| 3436 | "".join(l) |
| 3437 | for l in itertools.combinations(single_char_valid_prefixes, length) |
| 3438 | ): |
| 3439 | for t in itertools.permutations(prefix): |
| 3440 | for u in itertools.product(*[(c, c.upper()) for c in t]): |
| 3441 | p = "".join(u) |
| 3442 | if p == "not": |
| 3443 | # 'not' can never be a string prefix, |
| 3444 | # because it's a valid expression: not "" |
| 3445 | continue |
| 3446 | try: |
| 3447 | eval(f'{p}""') |
| 3448 | |
| 3449 | # No syntax error, so p is a valid string |
| 3450 | # prefix. |
| 3451 | |
| 3452 | valid_prefixes.add(p) |
| 3453 | num_at_this_length += 1 |
| 3454 | except SyntaxError: |
| 3455 | pass |
| 3456 | if num_at_this_length == 0: |
| 3457 | return valid_prefixes |
| 3458 | |
| 3459 | |
| 3460 | def test_prefixes(self): |