Skip to content

Commit 1fb7829

Browse files
committed
Improved code base
1 parent 0d96d1e commit 1fb7829

2 files changed

Lines changed: 78 additions & 50 deletions

File tree

codext/__common__.py

Lines changed: 76 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
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"]
3232
CODECS_REGISTRY = None
3333
MASKS = {
3434
'a': printable,
@@ -52,10 +52,10 @@
5252
s2i = 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)
351369
codecs.add_map = add_map
352370

@@ -374,6 +392,14 @@ def examples(encoding_regex, number=10):
374392
codecs.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+
377403
def remove(encoding):
378404
""" Remove all search functions matching the input encoding name from codext's local registry. """
379405
tbr = []

codext/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
lookup = codecs.lookup
1717
open = codecs.open
1818

19+
list = list_encodings # not included in __all__ because of shadow name
20+
1921

2022
reset()
2123

0 commit comments

Comments
 (0)