transcrypto 1.3.0__py3-none-any.whl → 1.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,13 +10,15 @@ Notes on the layout (quick mental model):
10
10
 
11
11
  isprime, primegen, mersenne
12
12
  gcd, xgcd, and grouped mod inv|div|exp|poly|lagrange|crt
13
- random bits|int|bytes|prime, hash sha256|sha512|file
13
+ random bits|int|bytes|prime
14
+ hash sha256|sha512|file
14
15
  aes key frompass, aes encrypt|decrypt (GCM), aes ecb encrypt|decrypt
15
16
  rsa new|encrypt|decrypt|sign|verify|rawencrypt|rawdecrypt|rawsign|rawverify
16
17
  elgamal shared|new|encrypt|decrypt|sign|verify|rawencrypt|rawdecrypt|rawsign|rawverify
17
18
  dsa shared|new|sign|verify|rawsign|rawverify
18
19
  bid new|verify
19
20
  sss new|shares|recover|rawshares|rawrecover|rawverify
21
+ doc md
20
22
  """
21
23
 
22
24
  from __future__ import annotations
@@ -27,7 +29,7 @@ import glob
27
29
  import logging
28
30
  # import pdb
29
31
  import sys
30
- from typing import Any, Iterable, Sequence
32
+ from typing import Any, Iterable
31
33
 
32
34
  from . import base, modmath, rsa, sss, elgamal, dsa, aes
33
35
 
@@ -119,179 +121,6 @@ def _LoadObj(path: str, password: str | None, expect: type, /) -> Any:
119
121
  return obj
120
122
 
121
123
 
122
- def _FlagNames(a: argparse.Action, /) -> list[str]:
123
- # Positional args have empty 'option_strings'; otherwise use them (e.g., ['-v','--verbose'])
124
- if a.option_strings:
125
- return list(a.option_strings)
126
- if a.nargs:
127
- if isinstance(a.metavar, str) and a.metavar:
128
- # e.g., nargs=2, metavar='FILE'
129
- return [a.metavar]
130
- if isinstance(a.metavar, tuple):
131
- # e.g., nargs=2, metavar=('FILE1', 'FILE2')
132
- return list(a.metavar)
133
- # Otherwise, it’s a positional arg with no flags, so return the destination name
134
- return [a.dest]
135
-
136
-
137
- def _ActionIsSubparser(a: argparse.Action, /) -> bool:
138
- return isinstance(a, argparse._SubParsersAction) # type: ignore[attr-defined] # pylint: disable=protected-access
139
-
140
-
141
- def _FormatDefault(a: argparse.Action, /) -> str:
142
- if a.default is argparse.SUPPRESS:
143
- return ''
144
- if isinstance(a.default, bool):
145
- return ' (default: on)' if a.default else ''
146
- if a.default in (None, '', 0, False):
147
- return ''
148
- return f' (default: {a.default})'
149
-
150
-
151
- def _FormatChoices(a: argparse.Action, /) -> str:
152
- return f' choices: {list(a.choices)}' if getattr(a, 'choices', None) else '' # type:ignore
153
-
154
-
155
- def _FormatType(a: argparse.Action, /) -> str:
156
- t: Any | None = getattr(a, 'type', None)
157
- if t is None:
158
- return ''
159
- # Show clean type names (int, str, float); for callables, just say 'custom'
160
- return f' type: {t.__name__ if hasattr(t, "__name__") else "custom"}'
161
-
162
-
163
- def _FormatNArgs(a: argparse.Action, /) -> str:
164
- return f' nargs: {a.nargs}' if getattr(a, 'nargs', None) not in (None, 0) else ''
165
-
166
-
167
- def _RowsForActions(actions: Sequence[argparse.Action], /) -> list[tuple[str, str]]:
168
- rows: list[tuple[str, str]] = []
169
- for a in actions:
170
- if _ActionIsSubparser(a):
171
- continue
172
- # skip the built-in help action; it’s implied
173
- if getattr(a, 'help', '') == argparse.SUPPRESS or isinstance(a, argparse._HelpAction): # type: ignore[attr-defined] # pylint: disable=protected-access
174
- continue
175
- flags: str = ', '.join(_FlagNames(a))
176
- meta: str = ''.join(
177
- (_FormatType(a), _FormatNArgs(a), _FormatChoices(a), _FormatDefault(a))).strip()
178
- desc: str = (a.help or '').strip()
179
- if meta:
180
- desc = f'{desc} [{meta}]' if desc else f'[{meta}]'
181
- rows.append((flags, desc))
182
- return rows
183
-
184
-
185
- def _MarkdownTable(
186
- rows: Sequence[tuple[str, str]],
187
- headers: tuple[str, str] = ('Option/Arg', 'Description'), /) -> str:
188
- if not rows:
189
- return ''
190
- out: list[str] = ['| ' + headers[0] + ' | ' + headers[1] + ' |', '|---|---|']
191
- for left, right in rows:
192
- out.append(f'| `{left}` | {right} |')
193
- return '\n'.join(out)
194
-
195
-
196
- def _WalkSubcommands(
197
- parser: argparse.ArgumentParser, path: list[str] | None = None, /) -> list[
198
- tuple[list[str], argparse.ArgumentParser, Any]]:
199
- path = path or []
200
- items: list[tuple[list[str], argparse.ArgumentParser, Any]] = []
201
- # sub_action = None
202
- name: str
203
- sp: argparse.ArgumentParser
204
- for action in parser._actions: # type: ignore[attr-defined] # pylint: disable=protected-access
205
- if _ActionIsSubparser(action):
206
- # sub_action = a # type: ignore[assignment]
207
- for name, sp in action.choices.items(): # type:ignore
208
- items.append((path + [name], sp, action)) # type:ignore
209
- items.extend(_WalkSubcommands(sp, path + [name])) # type:ignore
210
- return items
211
-
212
-
213
- def _HelpText(sub_parser: argparse.ArgumentParser, parent_sub_action: Any, /) -> str:
214
- if parent_sub_action is not None:
215
- for choice_action in parent_sub_action._choices_actions: # type: ignore # pylint: disable=protected-access
216
- if choice_action.dest == sub_parser.prog.split()[-1]:
217
- return choice_action.help or ''
218
- return ''
219
-
220
-
221
- def _GenerateCLIMarkdown() -> str: # pylint: disable=too-many-locals
222
- """Return a Markdown doc section that reflects the current _BuildParser() tree.
223
-
224
- Will treat epilog strings as examples, splitting on '$$' to get multiple examples.
225
- """
226
- parser: argparse.ArgumentParser = _BuildParser()
227
- assert parser.prog == 'poetry run transcrypto', 'should never happen: module name changed?'
228
- prog: str = 'transcrypto' # no '.py' needed because poetry run has an alias
229
- lines: list[str] = ['']
230
- # Header + global flags
231
- lines.append('## Command-Line Interface\n')
232
- lines.append(
233
- f'`{prog}` is a command-line utility that provides access to all core functionality '
234
- 'described in this documentation. It serves as a convenient wrapper over the Python APIs, '
235
- 'enabling **cryptographic operations**, **number theory functions**, **secure randomness '
236
- 'generation**, **hashing**, **AES**, **RSA**, **El-Gamal**, **DSA**, **bidding**, **SSS**, '
237
- 'and other utilities without writing code.\n')
238
- lines.append('Invoke with:\n')
239
- lines.append('```bash')
240
- lines.append(f'poetry run {prog} <command> [sub-command] [options...]')
241
- lines.append('```\n')
242
- # Global options table
243
- global_rows: list[tuple[str, str]] = _RowsForActions(parser._actions) # type: ignore[attr-defined] # pylint: disable=protected-access
244
- if global_rows:
245
- lines.append('### Global Options\n')
246
- lines.append(_MarkdownTable(global_rows))
247
- lines.append('')
248
- # Top-level commands summary
249
- lines.append('### Top-Level Commands\n')
250
- # Find top-level subparsers to list available commands
251
- top_subs: list[argparse.Action] = [a for a in parser._actions if _ActionIsSubparser(a)] # type: ignore[attr-defined] # pylint: disable=protected-access
252
- for action in top_subs:
253
- for name, sp in action.choices.items(): # type: ignore[union-attr]
254
- help_text: str = (sp.description or ' '.join(i.strip() for i in sp.format_usage().splitlines())).strip() # type:ignore
255
- short: str = (sp.help if hasattr(sp, 'help') else '') or '' # type:ignore
256
- help_text = short or help_text # type:ignore
257
- help_text = help_text.replace('usage: ', '').strip() # type:ignore
258
- lines.append(f'- **`{name}`** — `{help_text}`')
259
- lines.append('')
260
- if parser.epilog:
261
- lines.append('```bash')
262
- lines.append(parser.epilog)
263
- lines.append('```\n')
264
- # Detailed sections per (sub)command
265
- for path, sub_parser, parent_sub_action in _WalkSubcommands(parser):
266
- if len(path) == 1:
267
- lines.append('---\n') # horizontal rule between top-level commands
268
- header: str = ' '.join(path)
269
- lines.append(f'###{"" if len(path) == 1 else "#"} `{header}`') # (header level 3 or 4)
270
- # Usage block
271
- help_text = _HelpText(sub_parser, parent_sub_action)
272
- if help_text:
273
- lines.append(f'\n{help_text}')
274
- usage: str = sub_parser.format_usage().replace('usage: ', '').strip()
275
- lines.append('\n```bash')
276
- lines.append(str(usage))
277
- lines.append('```\n')
278
- # Options/args table
279
- rows: list[tuple[str, str]] = _RowsForActions(sub_parser._actions) # type: ignore[attr-defined] # pylint: disable=protected-access
280
- if rows:
281
- lines.append(_MarkdownTable(rows))
282
- lines.append('')
283
- # Examples (if any) - stored in epilog argument
284
- epilog: str = sub_parser.epilog.strip() if sub_parser.epilog else ''
285
- if epilog:
286
- lines.append('**Example:**\n')
287
- lines.append('```bash')
288
- for epilog_line in epilog.split('$$'):
289
- lines.append(f'$ poetry run {prog} {epilog_line.strip()}')
290
- lines.append('```\n')
291
- # join all lines as the markdown string
292
- return '\n'.join(lines)
293
-
294
-
295
124
  def _BuildParser() -> argparse.ArgumentParser: # pylint: disable=too-many-statements,too-many-locals
296
125
  """Construct the CLI argument parser (kept in sync with the docs)."""
297
126
  # ========================= main parser ==========================================================
@@ -740,7 +569,7 @@ def _BuildParser() -> argparse.ArgumentParser: # pylint: disable=too-many-state
740
569
  'decrypt',
741
570
  help='Decrypt `ciphertext` with private key.',
742
571
  epilog=('--b64 --out-bin -p rsa-key.priv rsa decrypt -a eHl6 -- '
743
- 'AO6knI6xwq6TGR…Qy22jiFhXi1eQ== \nabcde'))
572
+ 'AO6knI6xwq6TGR…Qy22jiFhXi1eQ==\nabcde'))
744
573
  p_rsa_dec_safe.add_argument('ciphertext', type=str, help='Ciphertext to decrypt')
745
574
  p_rsa_dec_safe.add_argument(
746
575
  '-a', '--aad', type=str, default='',
@@ -1109,9 +938,7 @@ def _BuildParser() -> argparse.ArgumentParser: # pylint: disable=too-many-state
1109
938
  doc_sub.add_parser(
1110
939
  'md',
1111
940
  help='Emit Markdown docs for the CLI (see README.md section "Creating a New Version").',
1112
- epilog=('doc md > CLI.md\n'
1113
- '$ ./tools/inject_md_includes.py\n'
1114
- 'inject: README.md updated with included content'))
941
+ epilog='doc md > transcrypto.md\n<<saves file>>')
1115
942
 
1116
943
  return parser
1117
944
 
@@ -1604,7 +1431,14 @@ def main(argv: list[str] | None = None, /) -> int: # pylint: disable=invalid-na
1604
1431
  args.doc_command.lower().strip() if getattr(args, 'doc_command', '') else '')
1605
1432
  match doc_command:
1606
1433
  case 'md':
1607
- print(_GenerateCLIMarkdown())
1434
+ print(base.GenerateCLIMarkdown(
1435
+ 'transcrypto', _BuildParser(), description=(
1436
+ '`transcrypto` is a command-line utility that provides access to all core '
1437
+ 'functionality described in this documentation. It serves as a convenient '
1438
+ 'wrapper over the Python APIs, enabling **cryptographic operations**, '
1439
+ '**number theory functions**, **secure randomness generation**, **hashing**, '
1440
+ '**AES**, **RSA**, **El-Gamal**, **DSA**, **bidding**, **SSS**, '
1441
+ 'and other utilities without writing code.')))
1608
1442
  case _:
1609
1443
  raise NotImplementedError()
1610
1444