2727
2828
2929__all__ = ["add" , "add_map" , "b" , "clear" , "codecs" , "decode" , "encode" , "ensure_str" , "examples" ,
30- "generate_strings_from_regex" , "get_alphabet_from_mask" , "handle_error" , "lookup " , "maketrans" , "re " ,
31- "register" , "remove" , "reset" , "s2i" , "search" , "MASKS" , "PY3" ]
30+ "generate_strings_from_regex" , "get_alphabet_from_mask" , "handle_error" , "list_encodings " , "lookup " ,
31+ "maketrans" , "re" , " register" , "remove" , "reset" , "s2i" , "search" , "MASKS" , "PY3" ]
3232CODECS_REGISTRY = None
3333MASKS = {
3434 'a' : printable ,
5252s2i = lambda s : int (codecs .encode (s , "base16" ), 16 )
5353
5454
55- def add (ename , encode = None , decode = None , pattern = None , text = True , add_to_codecs = False ):
55+ def add (ename , encode = None , decode = None , pattern = None , text = True , add_to_codecs = False , ** kwargs ):
5656 """
5757 This adds a new codec to the codecs module setting its encode and/or decode functions, eventually dynamically naming
58- the encoding with a pattern and with file handling (if text is True) .
58+ the encoding with a pattern and with file handling.
5959
6060 :param ename: encoding name
6161 :param encode: encoding function or None
@@ -72,39 +72,13 @@ def add(ename, encode=None, decode=None, pattern=None, text=True, add_to_codecs=
7272 raise ValueError ("Bad 'decode' function" )
7373 if not encode and not decode :
7474 raise ValueError ("At least one en/decoding function must be defined" )
75+ glob = currentframe ().f_back .f_globals
7576 # search function for the new encoding
7677 def getregentry (encoding ):
7778 if encoding != ename and not (pattern and re .match (pattern , encoding )):
7879 return
7980 fenc , fdec , name = encode , decode , encoding
8081 # prepare CodecInfo input arguments
81- class Codec (codecs .Codec ):
82- def encode (self , input , errors = "strict" ):
83- if fenc is None :
84- raise NotImplementedError
85- return fenc (input , errors )
86-
87- def decode (self , input , errors = "strict" ):
88- if fdec is None :
89- raise NotImplementedError
90- return fdec (input , errors )
91-
92- class IncrementalEncoder (codecs .IncrementalEncoder ):
93- def encode (self , input , final = False ):
94- if fenc is None :
95- raise NotImplementedError
96- return b (fenc (input , self .errors )[0 ])
97-
98- class IncrementalDecoder (codecs .IncrementalDecoder ):
99- def decode (self , input , final = False ):
100- if fdec is None :
101- raise NotImplementedError
102- return ensure_str (fdec (input , self .errors )[0 ])
103-
104- incrementalencoder = IncrementalEncoder
105- incrementaldecoder = IncrementalDecoder
106- streamwriter = None
107- streamreader = None
10882 if pattern :
10983 m = re .match (pattern , encoding )
11084 try :
@@ -127,27 +101,54 @@ def decode(self, input, final=False):
127101 if fdec :
128102 fdec = fix_inout_formats (fdec )
129103
130- if text :
131-
132- class StreamWriter (Codec , codecs .StreamWriter ):
133- charbuffertype = bytes
134-
135- class StreamReader (Codec , codecs .StreamReader ):
136- charbuffertype = bytes
104+ class Codec (codecs .Codec ):
105+ def encode (self , input , errors = "strict" ):
106+ if fenc is None :
107+ raise NotImplementedError
108+ return fenc (input , errors )
137109
138- streamwriter = StreamWriter
139- streamreader = StreamReader
110+ def decode (self , input , errors = "strict" ):
111+ if fdec is None :
112+ raise NotImplementedError
113+ return fdec (input , errors )
114+
115+ class IncrementalEncoder (codecs .IncrementalEncoder ):
116+ def encode (self , input , final = False ):
117+ if fenc is None :
118+ raise NotImplementedError
119+ return b (fenc (input , self .errors )[0 ])
120+
121+ class IncrementalDecoder (codecs .IncrementalDecoder ):
122+ def decode (self , input , final = False ):
123+ if fdec is None :
124+ raise NotImplementedError
125+ return ensure_str (fdec (input , self .errors )[0 ])
126+
127+ class StreamWriter (Codec , codecs .StreamWriter ):
128+ charbuffertype = bytes
129+
130+ class StreamReader (Codec , codecs .StreamReader ):
131+ charbuffertype = bytes
140132
141- return codecs .CodecInfo (
133+ ci = codecs .CodecInfo (
142134 name = name ,
143135 encode = Codec ().encode ,
144136 decode = Codec ().decode ,
145- incrementalencoder = incrementalencoder ,
146- incrementaldecoder = incrementaldecoder ,
147- streamwriter = streamwriter ,
148- streamreader = streamreader ,
137+ incrementalencoder = IncrementalEncoder ,
138+ incrementaldecoder = IncrementalDecoder ,
139+ streamwriter = StreamWriter ,
140+ streamreader = StreamReader ,
149141 _is_text_encoding = text ,
150142 )
143+ ci .parameters = kwargs
144+ ci .parameters ['name' ] = ename
145+ ci .parameters ['add_to_codecs' ] = add_to_codecs
146+ ci .parameters ['pattern' ] = pattern
147+ ci .parameters ['text' ] = text
148+ ci .parameters ['type' ] = kwargs .get ('type' , glob ['__file__' ].split (os .path .sep )[- 2 ].rstrip ("s" ))
149+ ci .parameters ['examples' ] = kwargs .get ('examples' , glob .get ('__examples__' ))
150+ return ci
151+
151152 getregentry .__name__ = re .sub (r"[\s\-]" , "_" , ename )
152153 getregentry .__pattern__ = pattern
153154 register (getregentry , add_to_codecs )
@@ -190,9 +191,10 @@ def _wrapper(param):
190191 param MUST be an int, otherwise for the first case it could clash with a character of the encoding map)
191192 2. otherwise handle it as a new encoding character map "ABC" translates to ".-/" for morse
192193 """
194+ p = param
193195 if isinstance (encmap , FunctionType ):
194- mapdict = encmap (param )
195- param = None
196+ mapdict = encmap (p )
197+ p = None
196198 else :
197199 mapdict = encmap
198200 if isinstance (mapdict , dict ):
@@ -201,8 +203,7 @@ def _wrapper(param):
201203 smapdict = {k : v for k , v in mapdict [0 ].items ()}
202204 else :
203205 raise ValueError ("Bad mapping dictionary or list of mapping dictionaries" )
204- if param is not None :
205- p = param
206+ if p is not None :
206207 # case 1: param is empty string
207208 if p == "" :
208209 if isinstance (mapdict , list ):
@@ -332,7 +333,7 @@ def __get_value(token, position, case_changed=False):
332333 if len (bs ) > 0 :
333334 tmp += "[" + bs + "]"
334335 r = tmp + lsep
335- return r [:len (r )- len (lsep )], len (text )
336+ return r [:len (r )- len (lsep )], len (b ( text ) )
336337 return code
337338 if re .search (r"\([^(?:)]" , kwargs .get ('pattern' , "" )) is None :
338339 # in this case, there is no capturing group for parametrization
@@ -347,6 +348,23 @@ def __get_value(token, position, case_changed=False):
347348 encexc = "{}EncodeError" .format (name )
348349 exec ("class {}(ValueError): pass" .format (encexc ), glob )
349350 # now use the generic add() function
351+ kwargs ['type' ] = glob ['__file__' ].split (os .path .sep )[- 2 ].rstrip ("s" )
352+ kwargs ['examples' ] = kwargs .get ('examples' , glob .get ('__examples__' ))
353+ kwargs ['encmap' ] = encmap
354+ kwargs ['repl_char' ] = repl_char
355+ kwargs ['sep' ] = sep
356+ kwargs ['ignore_case' ] = ignore_case
357+ kwargs ['no_error' ] = no_error
358+ kwargs ['binary' ] = binary
359+ try :
360+ if isinstance (encmap , dict ):
361+ smapdict = {k : v for k , v in encmap .items ()}
362+ elif isinstance (encmap , list ) and isinstance (encmap [0 ], dict ):
363+ smapdict = {k : v for k , v in encmap [0 ].items ()}
364+ kwargs ['repl_minlen' ] = i = max (1 , min (map (len , set (smapdict .values ()) - {'' })))
365+ kwargs ['repl_minlen_b' ] = max (1 , min (map (len , map (b , set (smapdict .values ()) - {'' }))))
366+ except :
367+ pass
350368 add (ename , __generic_code (glob [encexc ]), __generic_code (glob [decexc ], True ), ** kwargs )
351369codecs .add_map = add_map
352370
@@ -374,6 +392,14 @@ def examples(encoding_regex, number=10):
374392codecs .examples = examples
375393
376394
395+ def list_encodings ():
396+ """ Get a list of codext's added encodings from the local registry. """
397+ enc = []
398+ for search_function in __codecs_registry :
399+ enc .append (search_function .__name__ )
400+ return enc
401+
402+
377403def remove (encoding ):
378404 """ Remove all search functions matching the input encoding name from codext's local registry. """
379405 tbr = []
0 commit comments