Marco Ricci commited on 2025-02-14 15:45:36
Zeige 4 geänderte Dateien mit 311 Einfügungen und 87 Löschungen.
This allows the version output to only calculate the status information relevant to this subcommand. As a consequence, the tests now are subcommand-specific, and much less amenable to deduplication/parametrization.
... | ... |
@@ -952,7 +952,7 @@ def validate_length( |
952 | 952 |
return int_value |
953 | 953 |
|
954 | 954 |
|
955 |
-def version_option_callback( |
|
955 |
+def common_version_output( |
|
956 | 956 |
ctx: click.Context, |
957 | 957 |
param: click.Parameter, |
958 | 958 |
value: bool, # noqa: FBT001 |
... | ... |
@@ -960,32 +960,6 @@ def version_option_callback( |
960 | 960 |
del param |
961 | 961 |
if value and not ctx.resilient_parsing: |
962 | 962 |
major_dependencies: list[str] = [] |
963 |
- derivation_schemes = {'vault': True} |
|
964 |
- foreign_configuration_formats = { |
|
965 |
- 'vault storeroom': False, |
|
966 |
- 'vault v0.2': False, |
|
967 |
- 'vault v0.3': False, |
|
968 |
- } |
|
969 |
- known_extras = { |
|
970 |
- 'export': False, |
|
971 |
- } |
|
972 |
- try: |
|
973 |
- from derivepassphrase.exporter import storeroom, vault_native # noqa: I001,PLC0415 |
|
974 |
- |
|
975 |
- foreign_configuration_formats[ |
|
976 |
- 'vault storeroom' |
|
977 |
- ] = not storeroom.STUBBED |
|
978 |
- foreign_configuration_formats[ |
|
979 |
- 'vault v0.2' |
|
980 |
- ] = not vault_native.STUBBED |
|
981 |
- foreign_configuration_formats[ |
|
982 |
- 'vault v0.3' |
|
983 |
- ] = not vault_native.STUBBED |
|
984 |
- known_extras['export'] = ( |
|
985 |
- not storeroom.STUBBED and not vault_native.STUBBED |
|
986 |
- ) |
|
987 |
- except ModuleNotFoundError: # pragma: no cover |
|
988 |
- pass |
|
989 | 963 |
try: |
990 | 964 |
cryptography_version = importlib.metadata.version('cryptography') |
991 | 965 |
except ModuleNotFoundError: |
... | ... |
@@ -1011,24 +985,14 @@ def version_option_callback( |
1011 | 985 |
), |
1012 | 986 |
color=ctx.color, |
1013 | 987 |
) |
1014 |
- click.echo() |
|
1015 |
- version_info_types = { |
|
1016 |
- _msg.Label.SUPPORTED_DERIVATION_SCHEMES: [ |
|
1017 |
- k for k, v in derivation_schemes.items() if v |
|
1018 |
- ], |
|
1019 |
- _msg.Label.KNOWN_DERIVATION_SCHEMES: [ |
|
1020 |
- k for k, v in derivation_schemes.items() if not v |
|
1021 |
- ], |
|
1022 |
- _msg.Label.SUPPORTED_FOREIGN_CONFIGURATION_FORMATS: [ |
|
1023 |
- k for k, v in foreign_configuration_formats.items() if v |
|
1024 |
- ], |
|
1025 |
- _msg.Label.KNOWN_FOREIGN_CONFIGURATION_FORMATS: [ |
|
1026 |
- k for k, v in foreign_configuration_formats.items() if not v |
|
1027 |
- ], |
|
1028 |
- _msg.Label.ENABLED_PEP508_EXTRAS: [ |
|
1029 |
- k for k, v in known_extras.items() if v |
|
1030 |
- ], |
|
1031 |
- } |
|
988 |
+ |
|
989 |
+ |
|
990 |
+def print_version_info_types( |
|
991 |
+ version_info_types: dict[_msg.Label, list[str]], |
|
992 |
+ /, |
|
993 |
+ *, |
|
994 |
+ ctx: click.Context, |
|
995 |
+) -> None: |
|
1032 | 996 |
for message_label, item_list in version_info_types.items(): |
1033 | 997 |
if item_list: |
1034 | 998 |
current_length = len(str(_msg.TranslatedString(message_label))) |
... | ... |
@@ -1038,21 +1002,14 @@ def version_option_callback( |
1038 | 1002 |
space = ' ' |
1039 | 1003 |
punctuation = '.' if i == n else ',' |
1040 | 1004 |
if ( |
1041 |
- current_length |
|
1042 |
- + len(space) |
|
1043 |
- + len(item) |
|
1044 |
- + len(punctuation) |
|
1005 |
+ current_length + len(space) + len(item) + len(punctuation) |
|
1045 | 1006 |
<= VERSION_OUTPUT_WRAPPING_WIDTH |
1046 | 1007 |
): |
1047 |
- current_length += ( |
|
1048 |
- len(space) + len(item) + len(punctuation) |
|
1049 |
- ) |
|
1008 |
+ current_length += len(space) + len(item) + len(punctuation) |
|
1050 | 1009 |
piece = f'{space}{item}{punctuation}' |
1051 | 1010 |
else: |
1052 | 1011 |
space = ' ' |
1053 |
- current_length = ( |
|
1054 |
- len(space) + len(item) + len(punctuation) |
|
1055 |
- ) |
|
1012 |
+ current_length = len(space) + len(item) + len(punctuation) |
|
1056 | 1013 |
piece = f'\n{space}{item}{punctuation}' |
1057 | 1014 |
formatted_item_list_pieces.append(piece) |
1058 | 1015 |
click.echo( |
... | ... |
@@ -1065,10 +1022,118 @@ def version_option_callback( |
1065 | 1022 |
]), |
1066 | 1023 |
color=ctx.color, |
1067 | 1024 |
) |
1025 |
+ |
|
1026 |
+ |
|
1027 |
+def derivepassphrase_version_option_callback( |
|
1028 |
+ ctx: click.Context, |
|
1029 |
+ param: click.Parameter, |
|
1030 |
+ value: bool, # noqa: FBT001 |
|
1031 |
+) -> None: |
|
1032 |
+ if value and not ctx.resilient_parsing: |
|
1033 |
+ common_version_output(ctx, param, value) |
|
1034 |
+ derivation_schemes = {'vault': True} |
|
1035 |
+ supported_subcommands = {'export', 'vault'} |
|
1036 |
+ click.echo() |
|
1037 |
+ version_info_types = { |
|
1038 |
+ _msg.Label.SUPPORTED_DERIVATION_SCHEMES: [ |
|
1039 |
+ k for k, v in derivation_schemes.items() if v |
|
1040 |
+ ], |
|
1041 |
+ _msg.Label.KNOWN_DERIVATION_SCHEMES: [ |
|
1042 |
+ k for k, v in derivation_schemes.items() if not v |
|
1043 |
+ ], |
|
1044 |
+ _msg.Label.SUPPORTED_SUBCOMMANDS: sorted(supported_subcommands), |
|
1045 |
+ } |
|
1046 |
+ print_version_info_types(version_info_types, ctx=ctx) |
|
1068 | 1047 |
ctx.exit() |
1069 | 1048 |
|
1070 | 1049 |
|
1071 |
-def version_option(f: Callable[P, R]) -> Callable[P, R]: |
|
1050 |
+def export_version_option_callback( |
|
1051 |
+ ctx: click.Context, |
|
1052 |
+ param: click.Parameter, |
|
1053 |
+ value: bool, # noqa: FBT001 |
|
1054 |
+) -> None: |
|
1055 |
+ if value and not ctx.resilient_parsing: |
|
1056 |
+ common_version_output(ctx, param, value) |
|
1057 |
+ supported_subcommands = {'vault'} |
|
1058 |
+ foreign_configuration_formats = { |
|
1059 |
+ 'vault storeroom': False, |
|
1060 |
+ 'vault v0.2': False, |
|
1061 |
+ 'vault v0.3': False, |
|
1062 |
+ } |
|
1063 |
+ click.echo() |
|
1064 |
+ version_info_types = { |
|
1065 |
+ _msg.Label.KNOWN_FOREIGN_CONFIGURATION_FORMATS: [ |
|
1066 |
+ k for k, v in foreign_configuration_formats.items() if not v |
|
1067 |
+ ], |
|
1068 |
+ _msg.Label.SUPPORTED_SUBCOMMANDS: sorted(supported_subcommands), |
|
1069 |
+ } |
|
1070 |
+ print_version_info_types(version_info_types, ctx=ctx) |
|
1071 |
+ ctx.exit() |
|
1072 |
+ |
|
1073 |
+ |
|
1074 |
+def export_vault_version_option_callback( |
|
1075 |
+ ctx: click.Context, |
|
1076 |
+ param: click.Parameter, |
|
1077 |
+ value: bool, # noqa: FBT001 |
|
1078 |
+) -> None: |
|
1079 |
+ if value and not ctx.resilient_parsing: |
|
1080 |
+ common_version_output(ctx, param, value) |
|
1081 |
+ foreign_configuration_formats = { |
|
1082 |
+ 'vault storeroom': False, |
|
1083 |
+ 'vault v0.2': False, |
|
1084 |
+ 'vault v0.3': False, |
|
1085 |
+ } |
|
1086 |
+ known_extras = { |
|
1087 |
+ 'export': False, |
|
1088 |
+ } |
|
1089 |
+ try: |
|
1090 |
+ from derivepassphrase.exporter import storeroom, vault_native # noqa: I001,PLC0415 |
|
1091 |
+ |
|
1092 |
+ foreign_configuration_formats[ |
|
1093 |
+ 'vault storeroom' |
|
1094 |
+ ] = not storeroom.STUBBED |
|
1095 |
+ foreign_configuration_formats[ |
|
1096 |
+ 'vault v0.2' |
|
1097 |
+ ] = not vault_native.STUBBED |
|
1098 |
+ foreign_configuration_formats[ |
|
1099 |
+ 'vault v0.3' |
|
1100 |
+ ] = not vault_native.STUBBED |
|
1101 |
+ known_extras['export'] = ( |
|
1102 |
+ not storeroom.STUBBED and not vault_native.STUBBED |
|
1103 |
+ ) |
|
1104 |
+ except ModuleNotFoundError: # pragma: no cover |
|
1105 |
+ pass |
|
1106 |
+ click.echo() |
|
1107 |
+ version_info_types = { |
|
1108 |
+ _msg.Label.SUPPORTED_FOREIGN_CONFIGURATION_FORMATS: [ |
|
1109 |
+ k for k, v in foreign_configuration_formats.items() if v |
|
1110 |
+ ], |
|
1111 |
+ _msg.Label.KNOWN_FOREIGN_CONFIGURATION_FORMATS: [ |
|
1112 |
+ k for k, v in foreign_configuration_formats.items() if not v |
|
1113 |
+ ], |
|
1114 |
+ _msg.Label.ENABLED_PEP508_EXTRAS: [ |
|
1115 |
+ k for k, v in known_extras.items() if v |
|
1116 |
+ ], |
|
1117 |
+ } |
|
1118 |
+ print_version_info_types(version_info_types, ctx=ctx) |
|
1119 |
+ ctx.exit() |
|
1120 |
+ |
|
1121 |
+ |
|
1122 |
+def vault_version_option_callback( |
|
1123 |
+ ctx: click.Context, |
|
1124 |
+ param: click.Parameter, |
|
1125 |
+ value: bool, # noqa: FBT001 |
|
1126 |
+) -> None: |
|
1127 |
+ if value and not ctx.resilient_parsing: |
|
1128 |
+ common_version_output(ctx, param, value) |
|
1129 |
+ ctx.exit() |
|
1130 |
+ |
|
1131 |
+ |
|
1132 |
+def version_option( |
|
1133 |
+ version_option_callback: Callable[ |
|
1134 |
+ [click.Context, click.Parameter, Any], Any |
|
1135 |
+ ], |
|
1136 |
+) -> Callable[[Callable[P, R]], Callable[P, R]]: |
|
1072 | 1137 |
return click.option( |
1073 | 1138 |
'--version', |
1074 | 1139 |
is_flag=True, |
... | ... |
@@ -1077,7 +1142,7 @@ def version_option(f: Callable[P, R]) -> Callable[P, R]: |
1077 | 1142 |
callback=version_option_callback, |
1078 | 1143 |
cls=StandardOption, |
1079 | 1144 |
help=_msg.TranslatedString(_msg.Label.VERSION_OPTION_HELP_TEXT), |
1080 |
- )(f) |
|
1145 |
+ ) |
|
1081 | 1146 |
|
1082 | 1147 |
|
1083 | 1148 |
color_forcing_pseudo_option = click.option( |
... | ... |
@@ -1327,6 +1327,15 @@ class Label(enum.Enum): |
1327 | 1327 |
'Supported foreign configuration formats:', |
1328 | 1328 |
) |
1329 | 1329 |
"""""" |
1330 |
+ SUPPORTED_SUBCOMMANDS = commented( |
|
1331 |
+ 'This is part of the version output, emitting lists of supported ' |
|
1332 |
+ 'subcommands. A comma-separated English list ' |
|
1333 |
+ 'of items follows, with standard English punctuation.', |
|
1334 |
+ )( |
|
1335 |
+ 'Label :: Info Message:: Table row header', |
|
1336 |
+ 'Supported subcommands:', |
|
1337 |
+ ) |
|
1338 |
+ """""" |
|
1330 | 1339 |
CONFIRM_THIS_CHOICE_PROMPT_TEXT = commented( |
1331 | 1340 |
'There is no support for "yes" or "no" in other languages ' |
1332 | 1341 |
'than English, so it is advised that your translation makes it ' |
... | ... |
@@ -58,7 +58,9 @@ VERSION = _internals.VERSION |
58 | 58 |
_msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_03), |
59 | 59 |
), |
60 | 60 |
) |
61 |
-@cli_machinery.version_option |
|
61 |
+@cli_machinery.version_option( |
|
62 |
+ cli_machinery.derivepassphrase_version_option_callback |
|
63 |
+) |
|
62 | 64 |
@cli_machinery.color_forcing_pseudo_option |
63 | 65 |
@cli_machinery.standard_logging_options |
64 | 66 |
@click.pass_context |
... | ... |
@@ -113,7 +115,7 @@ def derivepassphrase(ctx: click.Context, /) -> None: |
113 | 115 |
_msg.TranslatedString(_msg.Label.DERIVEPASSPHRASE_EXPORT_03), |
114 | 116 |
), |
115 | 117 |
) |
116 |
-@cli_machinery.version_option |
|
118 |
+@cli_machinery.version_option(cli_machinery.export_version_option_callback) |
|
117 | 119 |
@cli_machinery.color_forcing_pseudo_option |
118 | 120 |
@cli_machinery.standard_logging_options |
119 | 121 |
@click.pass_context |
... | ... |
@@ -204,7 +206,9 @@ def derivepassphrase_export(ctx: click.Context, /) -> None: |
204 | 206 |
), |
205 | 207 |
cls=cli_machinery.StandardOption, |
206 | 208 |
) |
207 |
-@cli_machinery.version_option |
|
209 |
+@cli_machinery.version_option( |
|
210 |
+ cli_machinery.export_vault_version_option_callback |
|
211 |
+) |
|
208 | 212 |
@cli_machinery.color_forcing_pseudo_option |
209 | 213 |
@cli_machinery.standard_logging_options |
210 | 214 |
@click.argument( |
... | ... |
@@ -610,7 +614,7 @@ def derivepassphrase_export_vault( |
610 | 614 |
), |
611 | 615 |
cls=cli_machinery.CompatibilityOption, |
612 | 616 |
) |
613 |
-@cli_machinery.version_option |
|
617 |
+@cli_machinery.version_option(cli_machinery.vault_version_option_callback) |
|
614 | 618 |
@cli_machinery.color_forcing_pseudo_option |
615 | 619 |
@cli_machinery.standard_logging_options |
616 | 620 |
@click.argument( |
... | ... |
@@ -85,6 +85,7 @@ class VersionOutputData(NamedTuple): |
85 | 85 |
derivation_schemes: dict[str, bool] |
86 | 86 |
foreign_configuration_formats: dict[str, bool] |
87 | 87 |
extras: frozenset[str] |
88 |
+ subcommands: frozenset[str] |
|
88 | 89 |
|
89 | 90 |
|
90 | 91 |
PASSPHRASE_GENERATION_OPTIONS: list[tuple[str, ...]] = [ |
... | ... |
@@ -349,15 +350,15 @@ def parse_version_output( # noqa: C901 |
349 | 350 |
The version output contains two paragraphs. The first paragraph |
350 | 351 |
details the version number, and the version number of any major |
351 | 352 |
libraries in use. The second paragraph details known and supported |
352 |
- passphrase derivation schemes, foreign configuration formats, and |
|
353 |
- PEP 508 package extras. For the schemes and formats, there is |
|
354 |
- a "supported" line for supported items, and a "known" line for known |
|
355 |
- but currently unsupported items (usually because of missing |
|
356 |
- dependencies), either of which may be empty and thus omitted. For |
|
357 |
- extras, only active items are shown, and there is a separate message |
|
358 |
- for the "no extras active" case. Item lists may be spilled across |
|
359 |
- multiple lines, but only at item boundaries, and the continuation |
|
360 |
- lines are then indented. |
|
353 |
+ passphrase derivation schemes, foreign configuration formats, |
|
354 |
+ subcommands and PEP 508 package extras. For the schemes and |
|
355 |
+ formats, there is a "supported" line for supported items, and |
|
356 |
+ a "known" line for known but currently unsupported items (usually |
|
357 |
+ because of missing dependencies), either of which may be empty and |
|
358 |
+ thus omitted. For extras, only active items are shown, and there is |
|
359 |
+ a separate message for the "no extras active" case. Item lists may |
|
360 |
+ be spilled across multiple lines, but only at item boundaries, and |
|
361 |
+ the continuation lines are then indented. |
|
361 | 362 |
|
362 | 363 |
Args: |
363 | 364 |
text: |
... | ... |
@@ -389,8 +390,8 @@ def parse_version_output( # noqa: C901 |
389 | 390 |
if paragraph: # pragma: no branch |
390 | 391 |
paragraphs.append(paragraph.copy()) |
391 | 392 |
paragraph.clear() |
392 |
- assert len(paragraphs) == 2, ( |
|
393 |
- f'expected exactly two lines of version output: {paragraphs!r}' |
|
393 |
+ assert paragraphs, ( |
|
394 |
+ f'expected at least one paragraph of version output: {paragraphs!r}' |
|
394 | 395 |
) |
395 | 396 |
assert prog_name is None or prog_name in paragraphs[0][0], ( |
396 | 397 |
f'first version output line should mention ' |
... | ... |
@@ -400,9 +401,17 @@ def parse_version_output( # noqa: C901 |
400 | 401 |
f'first version output line should mention the version number ' |
401 | 402 |
f'{version}: {paragraphs[0][0]!r}' |
402 | 403 |
) |
403 |
- schemas: dict[str, bool] = {} |
|
404 |
+ schemes: dict[str, bool] = {} |
|
404 | 405 |
formats: dict[str, bool] = {} |
406 |
+ subcommands: set[str] = set() |
|
405 | 407 |
extras: set[str] = set() |
408 |
+ if len(paragraphs) < 2: |
|
409 |
+ return VersionOutputData( |
|
410 |
+ derivation_schemes=schemes, |
|
411 |
+ foreign_configuration_formats=formats, |
|
412 |
+ subcommands=frozenset(subcommands), |
|
413 |
+ extras=frozenset(extras), |
|
414 |
+ ) |
|
406 | 415 |
for line in paragraphs[1]: |
407 | 416 |
line_type, _, value = line.partition(':') |
408 | 417 |
if line_type == line: |
... | ... |
@@ -416,16 +425,23 @@ def parse_version_output( # noqa: C901 |
416 | 425 |
elif line_type == 'Known foreign configuration formats': |
417 | 426 |
formats[item] = False |
418 | 427 |
elif line_type == 'Supported derivation schemes': |
419 |
- schemas[item] = True |
|
428 |
+ schemes[item] = True |
|
420 | 429 |
elif line_type == 'Known derivation schemes': |
421 |
- schemas[item] = False |
|
430 |
+ schemes[item] = False |
|
431 |
+ elif line_type == 'Supported subcommands': |
|
432 |
+ subcommands.add(item) |
|
422 | 433 |
elif line_type == 'PEP 508 extras': |
423 | 434 |
extras.add(item) |
424 | 435 |
else: |
425 | 436 |
raise AssertionError( # noqa: TRY003 |
426 | 437 |
f'Unknown version info line type: {line_type!r}' # noqa: EM102 |
427 | 438 |
) |
428 |
- return VersionOutputData(schemas, formats, frozenset(extras)) |
|
439 |
+ return VersionOutputData( |
|
440 |
+ derivation_schemes=schemes, |
|
441 |
+ foreign_configuration_formats=formats, |
|
442 |
+ subcommands=frozenset(subcommands), |
|
443 |
+ extras=frozenset(extras), |
|
444 |
+ ) |
|
429 | 445 |
|
430 | 446 |
|
431 | 447 |
def bash_format(item: click.shell_completion.CompletionItem) -> str: |
... | ... |
@@ -1451,7 +1467,6 @@ class Parametrize(types.SimpleNamespace): |
1451 | 1467 |
derivepassphrase 0.4.0 |
1452 | 1468 |
Using cryptography 44.0.0 |
1453 | 1469 |
|
1454 |
-Supported derivation schemes: vault. |
|
1455 | 1470 |
Supported foreign configuration formats: vault storeroom, vault v0.2, |
1456 | 1471 |
vault v0.3. |
1457 | 1472 |
PEP 508 extras: export. |
... | ... |
@@ -1459,12 +1474,13 @@ PEP 508 extras: export. |
1459 | 1474 |
'derivepassphrase', |
1460 | 1475 |
'0.4.0', |
1461 | 1476 |
VersionOutputData( |
1462 |
- derivation_schemes={'vault': True}, |
|
1477 |
+ derivation_schemes={}, |
|
1463 | 1478 |
foreign_configuration_formats={ |
1464 | 1479 |
'vault storeroom': True, |
1465 | 1480 |
'vault v0.2': True, |
1466 | 1481 |
'vault v0.3': True, |
1467 | 1482 |
}, |
1483 |
+ subcommands=frozenset(), |
|
1468 | 1484 |
extras=frozenset({'export'}), |
1469 | 1485 |
), |
1470 | 1486 |
id='derivepassphrase-0.4.0-export', |
... | ... |
@@ -1475,6 +1491,7 @@ derivepassphrase 0.5 |
1475 | 1491 |
|
1476 | 1492 |
Supported derivation schemes: vault. |
1477 | 1493 |
Known foreign configuration formats: vault storeroom, vault v0.2, vault v0.3. |
1494 |
+Supported subcommands: export, vault. |
|
1478 | 1495 |
No PEP 508 extras are active. |
1479 | 1496 |
""", |
1480 | 1497 |
'derivepassphrase', |
... | ... |
@@ -1486,6 +1503,7 @@ No PEP 508 extras are active. |
1486 | 1503 |
'vault v0.2': False, |
1487 | 1504 |
'vault v0.3': False, |
1488 | 1505 |
}, |
1506 |
+ subcommands=frozenset({'export', 'vault'}), |
|
1489 | 1507 |
extras=frozenset({}), |
1490 | 1508 |
), |
1491 | 1509 |
id='derivepassphrase-0.5-plain', |
... | ... |
@@ -1506,6 +1524,7 @@ Known derivation schemes: divination, /dev/random, |
1506 | 1524 |
Supported foreign configuration formats: derivepassphrase, nonsense. |
1507 | 1525 |
Known foreign configuration formats: divination v3.141592, |
1508 | 1526 |
/dev/random. |
1527 |
+Supported subcommands: delete-all-files, dump-core. |
|
1509 | 1528 |
PEP 508 extras: annoying-popups, delete-all-files, |
1510 | 1529 |
dump-core-depending-on-the-phase-of-the-moon. |
1511 | 1530 |
|
... | ... |
@@ -1528,6 +1547,7 @@ PEP 508 extras: annoying-popups, delete-all-files, |
1528 | 1547 |
'divination v3.141592': False, |
1529 | 1548 |
'/dev/random': False, |
1530 | 1549 |
}, |
1550 |
+ subcommands=frozenset({'delete-all-files', 'dump-core'}), |
|
1531 | 1551 |
extras=frozenset({ |
1532 | 1552 |
'annoying-popups', |
1533 | 1553 |
'delete-all-files', |
... | ... |
@@ -1778,20 +1798,19 @@ class TestAllCLI: |
1778 | 1798 |
'Expected no color, but found an ANSI control sequence' |
1779 | 1799 |
) |
1780 | 1800 |
|
1781 |
- @Parametrize.COMMAND_NON_EAGER_ARGUMENTS |
|
1782 |
- def test_202_version_option_output( |
|
1801 |
+ def test_202a_derivepassphrase_version_option_output( |
|
1783 | 1802 |
self, |
1784 |
- command: list[str], |
|
1785 |
- non_eager_arguments: list[str], |
|
1786 | 1803 |
) -> None: |
1787 | 1804 |
"""The version output states supported features. |
1788 | 1805 |
|
1789 | 1806 |
The version output is parsed using [`parse_version_output`][]. |
1790 | 1807 |
Format examples can be found in |
1791 |
- [`Parametrize.VERSION_OUTPUT_DATA`][]. |
|
1808 |
+ [`Parametrize.VERSION_OUTPUT_DATA`][]. Specifically, for the |
|
1809 |
+ top-level `derivepassphrase` command, the output should contain |
|
1810 |
+ the known and supported derivation schemes, and a list of |
|
1811 |
+ subcommands. |
|
1792 | 1812 |
|
1793 | 1813 |
""" |
1794 |
- del non_eager_arguments |
|
1795 | 1814 |
runner = click.testing.CliRunner(mix_stderr=False) |
1796 | 1815 |
# TODO(the-13th-letter): Rewrite using parenthesized |
1797 | 1816 |
# with-statements. |
... | ... |
@@ -1806,15 +1825,103 @@ class TestAllCLI: |
1806 | 1825 |
) |
1807 | 1826 |
result_ = runner.invoke( |
1808 | 1827 |
cli.derivepassphrase, |
1809 |
- [*command, '--version'], |
|
1828 |
+ ['--version'], |
|
1810 | 1829 |
catch_exceptions=False, |
1811 | 1830 |
) |
1812 | 1831 |
result = tests.ReadableResult.parse(result_) |
1813 | 1832 |
assert result.clean_exit(empty_stderr=True), 'expected clean exit' |
1814 | 1833 |
assert result.output.strip(), 'expected version output' |
1815 | 1834 |
version_data = parse_version_output(result.output) |
1816 |
- actually_known_formats: dict[str, bool] = {} |
|
1817 | 1835 |
actually_known_schemes = {'vault': True} |
1836 |
+ subcommands = {'export', 'vault'} |
|
1837 |
+ assert version_data.derivation_schemes == actually_known_schemes |
|
1838 |
+ assert not version_data.foreign_configuration_formats |
|
1839 |
+ assert version_data.subcommands == subcommands |
|
1840 |
+ assert not version_data.extras |
|
1841 |
+ |
|
1842 |
+ def test_202b_export_version_option_output( |
|
1843 |
+ self, |
|
1844 |
+ ) -> None: |
|
1845 |
+ """The version output states supported features. |
|
1846 |
+ |
|
1847 |
+ The version output is parsed using [`parse_version_output`][]. |
|
1848 |
+ Format examples can be found in |
|
1849 |
+ [`Parametrize.VERSION_OUTPUT_DATA`][]. Specifically, for the |
|
1850 |
+ `export` command, the output should contain the known foreign |
|
1851 |
+ configuration formats (but not marked as supported), and a list |
|
1852 |
+ of subcommands. |
|
1853 |
+ |
|
1854 |
+ """ |
|
1855 |
+ runner = click.testing.CliRunner(mix_stderr=False) |
|
1856 |
+ # TODO(the-13th-letter): Rewrite using parenthesized |
|
1857 |
+ # with-statements. |
|
1858 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
1859 |
+ with contextlib.ExitStack() as stack: |
|
1860 |
+ monkeypatch = stack.enter_context(pytest.MonkeyPatch.context()) |
|
1861 |
+ stack.enter_context( |
|
1862 |
+ tests.isolated_config( |
|
1863 |
+ monkeypatch=monkeypatch, |
|
1864 |
+ runner=runner, |
|
1865 |
+ ) |
|
1866 |
+ ) |
|
1867 |
+ result_ = runner.invoke( |
|
1868 |
+ cli.derivepassphrase, |
|
1869 |
+ ['export', '--version'], |
|
1870 |
+ catch_exceptions=False, |
|
1871 |
+ ) |
|
1872 |
+ result = tests.ReadableResult.parse(result_) |
|
1873 |
+ assert result.clean_exit(empty_stderr=True), 'expected clean exit' |
|
1874 |
+ assert result.output.strip(), 'expected version output' |
|
1875 |
+ version_data = parse_version_output(result.output) |
|
1876 |
+ actually_known_formats: dict[str, bool] = { |
|
1877 |
+ 'vault storeroom': False, |
|
1878 |
+ 'vault v0.2': False, |
|
1879 |
+ 'vault v0.3': False, |
|
1880 |
+ } |
|
1881 |
+ subcommands = {'vault'} |
|
1882 |
+ assert not version_data.derivation_schemes |
|
1883 |
+ assert ( |
|
1884 |
+ version_data.foreign_configuration_formats |
|
1885 |
+ == actually_known_formats |
|
1886 |
+ ) |
|
1887 |
+ assert version_data.subcommands == subcommands |
|
1888 |
+ assert not version_data.extras |
|
1889 |
+ |
|
1890 |
+ def test_202c_export_vault_version_option_output( |
|
1891 |
+ self, |
|
1892 |
+ ) -> None: |
|
1893 |
+ """The version output states supported features. |
|
1894 |
+ |
|
1895 |
+ The version output is parsed using [`parse_version_output`][]. |
|
1896 |
+ Format examples can be found in |
|
1897 |
+ [`Parametrize.VERSION_OUTPUT_DATA`][]. Specifically, for the |
|
1898 |
+ `export vault` subcommand, the output should contain the |
|
1899 |
+ vault-specific subset of the known or supported foreign |
|
1900 |
+ configuration formats, and a list of available PEP 508 extras. |
|
1901 |
+ |
|
1902 |
+ """ |
|
1903 |
+ runner = click.testing.CliRunner(mix_stderr=False) |
|
1904 |
+ # TODO(the-13th-letter): Rewrite using parenthesized |
|
1905 |
+ # with-statements. |
|
1906 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
1907 |
+ with contextlib.ExitStack() as stack: |
|
1908 |
+ monkeypatch = stack.enter_context(pytest.MonkeyPatch.context()) |
|
1909 |
+ stack.enter_context( |
|
1910 |
+ tests.isolated_config( |
|
1911 |
+ monkeypatch=monkeypatch, |
|
1912 |
+ runner=runner, |
|
1913 |
+ ) |
|
1914 |
+ ) |
|
1915 |
+ result_ = runner.invoke( |
|
1916 |
+ cli.derivepassphrase, |
|
1917 |
+ ['export', 'vault', '--version'], |
|
1918 |
+ catch_exceptions=False, |
|
1919 |
+ ) |
|
1920 |
+ result = tests.ReadableResult.parse(result_) |
|
1921 |
+ assert result.clean_exit(empty_stderr=True), 'expected clean exit' |
|
1922 |
+ assert result.output.strip(), 'expected version output' |
|
1923 |
+ version_data = parse_version_output(result.output) |
|
1924 |
+ actually_known_formats: dict[str, bool] = {} |
|
1818 | 1925 |
actually_enabled_extras: set[str] = set() |
1819 | 1926 |
with contextlib.suppress(ModuleNotFoundError): |
1820 | 1927 |
from derivepassphrase.exporter import storeroom, vault_native # noqa: I001,PLC0415 |
... | ... |
@@ -1826,13 +1933,52 @@ class TestAllCLI: |
1826 | 1933 |
}) |
1827 | 1934 |
if not storeroom.STUBBED and not vault_native.STUBBED: |
1828 | 1935 |
actually_enabled_extras.add('export') |
1936 |
+ assert not version_data.derivation_schemes |
|
1829 | 1937 |
assert ( |
1830 | 1938 |
version_data.foreign_configuration_formats |
1831 | 1939 |
== actually_known_formats |
1832 | 1940 |
) |
1833 |
- assert version_data.derivation_schemes == actually_known_schemes |
|
1941 |
+ assert not version_data.subcommands |
|
1834 | 1942 |
assert version_data.extras == actually_enabled_extras |
1835 | 1943 |
|
1944 |
+ def test_202d_vault_version_option_output( |
|
1945 |
+ self, |
|
1946 |
+ ) -> None: |
|
1947 |
+ """The version output states supported features. |
|
1948 |
+ |
|
1949 |
+ The version output is parsed using [`parse_version_output`][]. |
|
1950 |
+ Format examples can be found in |
|
1951 |
+ [`Parametrize.VERSION_OUTPUT_DATA`][]. Specifically, for the |
|
1952 |
+ vault command, the output should not contain anything beyond the |
|
1953 |
+ first paragraph. |
|
1954 |
+ |
|
1955 |
+ """ |
|
1956 |
+ runner = click.testing.CliRunner(mix_stderr=False) |
|
1957 |
+ # TODO(the-13th-letter): Rewrite using parenthesized |
|
1958 |
+ # with-statements. |
|
1959 |
+ # https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
|
1960 |
+ with contextlib.ExitStack() as stack: |
|
1961 |
+ monkeypatch = stack.enter_context(pytest.MonkeyPatch.context()) |
|
1962 |
+ stack.enter_context( |
|
1963 |
+ tests.isolated_config( |
|
1964 |
+ monkeypatch=monkeypatch, |
|
1965 |
+ runner=runner, |
|
1966 |
+ ) |
|
1967 |
+ ) |
|
1968 |
+ result_ = runner.invoke( |
|
1969 |
+ cli.derivepassphrase, |
|
1970 |
+ ['vault', '--version'], |
|
1971 |
+ catch_exceptions=False, |
|
1972 |
+ ) |
|
1973 |
+ result = tests.ReadableResult.parse(result_) |
|
1974 |
+ assert result.clean_exit(empty_stderr=True), 'expected clean exit' |
|
1975 |
+ assert result.output.strip(), 'expected version output' |
|
1976 |
+ version_data = parse_version_output(result.output) |
|
1977 |
+ assert not version_data.derivation_schemes |
|
1978 |
+ assert not version_data.foreign_configuration_formats |
|
1979 |
+ assert not version_data.subcommands |
|
1980 |
+ assert not version_data.extras |
|
1981 |
+ |
|
1836 | 1982 |
|
1837 | 1983 |
class TestCLI: |
1838 | 1984 |
"""Tests for the `derivepassphrase vault` command-line interface.""" |
1839 | 1985 |