44"""
55import argparse
66import sys
7+ from difflib import get_close_matches
8+ from encodings import normalize_encoding
9+ from encodings .aliases import aliases
710from getpass import getpass
11+ from importlib import import_module
812
13+ from . import __common__
914from .__common__ import *
1015from .__common__ import PERS_MACROS_FILE
1116from .compose import QUESTIONS , report as compose_report
@@ -90,6 +95,30 @@ def __ask(question, given=None):
9095 print (f" please answer with a number from 1 to { len (choices )} " , file = sys .stderr )
9196
9297
98+ def __show (name ):
99+ """ Describe a codec, an encoding or a macro: its name, its category, its module and the docstring of this module,
100+ which documents the codec ; a macro is described by its chain of encodings. """
101+ ci = lookup (name )
102+ if isinstance (ci , CodecMacro ):
103+ pers = name in __common__ .PERS_MACROS
104+ chain = (__common__ .PERS_MACROS if pers else __common__ .MACROS )[name ]
105+ return f"macro : { name } ({ f'personal, in { PERS_MACROS_FILE } ' if pers else 'embedded' } )\n " \
106+ f"chain : { ' · ' .join (chain )} "
107+ p = ci .parameters
108+ codec , cat , module = p .get ('name' , ci .name ), p .get ('category' ), p .get ('module' )
109+ # the native codecs are documented by their module from the encodings package (e.g. encodings.cp500)
110+ if cat == "native" :
111+ n = normalize_encoding (ci .name ).lower ()
112+ module = f"encodings.{ aliases .get (n , n )} "
113+ try :
114+ doc = (import_module (module ).__doc__ or "" ).strip ()
115+ except (ImportError , TypeError , ValueError ):
116+ doc = ""
117+ lines = [f"codec : { codec } ({ cat } )" ] + ([f"encoding : { name } " ] if name != codec else []) + \
118+ [f"module : { module } " , "" , doc or "No description available." ]
119+ return "\n " .join (lines )
120+
121+
93122def main ():
94123 class _CustomFormatter (argparse .RawTextHelpFormatter ):
95124 def __init__ (self , prog , ** kwargs ):
@@ -121,6 +150,8 @@ def _format_action_invocation(self, action):
121150 "echo -en \" test\" | codext encode base64 gzip | codext guess gzip -c base" ,
122151 "codext compose" ,
123152 "codext compose -a alphanumeric -l 4 -k mysecret -m mychain -n" ,
153+ "codext show rle" ,
154+ "codext show base64-url rot-13 example-macro" ,
124155 ])
125156 kw = {'formatter_class' : _CustomFormatter }
126157 parser = argparse .ArgumentParser (prog = "codext" , description = descr , epilog = examples , ** kw )
@@ -218,6 +249,8 @@ def _format_action_invocation(self, action):
218249 compose .add_argument ("-s" , "--seed" , type = int , help = "seed for drawing the chain (default: random)" )
219250 compose .add_argument ("-x" , "--expansion" , choices = list (QUESTIONS [2 ]['choices' ]),
220251 help = "how many times larger than the input the output may be (default: 5)" )
252+ show = sparsers .add_parser ("show" , help = "show the documentation of codecs, encodings or macros" )
253+ show .add_argument ("encoding" , nargs = "+" , help = "names of codecs, encodings or macros" )
221254 search = sparsers .add_parser ("search" , help = "search for codecs" )
222255 search .add_argument ("pattern" , nargs = "+" , help = "encoding pattern to search" )
223256 listi = sparsers .add_parser ("list" , help = "list items" )
@@ -241,6 +274,20 @@ def _format_action_invocation(self, action):
241274 results .extend (codecs .search (enc ))
242275 print (", " .join (results ) or "No encoding found" )
243276 return 0
277+ # show the documentation of codecs, encodings or macros
278+ elif args .command == "show" :
279+ status , out = 0 , []
280+ for name in args .encoding :
281+ try :
282+ out .append (__show (name ))
283+ except LookupError as e :
284+ status = 1
285+ similar = get_close_matches (name , list_encodings () + list_macros (), 5 , .7 )
286+ print (f"codext: { str (e )[0 ].lower ()} { str (e )[1 :]} " +
287+ (f" (similar: { ', ' .join (similar )} )" if similar else "" ), file = sys .stderr )
288+ if out :
289+ print (("\n \n " + "-" * 80 + "\n \n " ).join (out ))
290+ return status
244291 # add/remove macros (not requiring to input a file or text)
245292 elif args .command == "add-macro" :
246293 add_macro (args .name , * args .encoding )
0 commit comments