codekingpro/portable-devtools
115k
1import codecs2from typing import Any, Optional, Tuple3 4from .core import IDNAError, _unicode_dots_re, alabel, decode, encode, ulabel5 6 7class Codec(codecs.Codec):8 """Stateless IDNA 2008 codec.9 10 Implements the :class:`codecs.Codec` protocol so that the whole-domain11 encoder (:func:`idna.encode`) and decoder (:func:`idna.decode`) are12 accessible through the standard codec machinery as ``"idna2008"``.13 14 Only the ``"strict"`` error handler is supported; any other handler15 raises :exc:`~idna.IDNAError`.16 """17 18 def encode(self, data: str, errors: str = "strict") -> Tuple[bytes, int]: # ty: ignore[invalid-method-override]19 if errors != "strict":20 raise IDNAError(f'Unsupported error handling "{errors}"')21 22 if not data:23 return b"", 024 25 return encode(data), len(data)26 27 def decode(self, data: bytes, errors: str = "strict") -> Tuple[str, int]: # ty: ignore[invalid-method-override]28 if errors != "strict":29 raise IDNAError(f'Unsupported error handling "{errors}"')30 31 if not data:32 return "", 033 34 return decode(data), len(data)35 36 37class IncrementalEncoder(codecs.BufferedIncrementalEncoder):38 """Incremental IDNA 2008 encoder.39 40 Buffers a partial trailing label across calls until either the next41 label separator is seen or ``final=True``, so that streamed input is42 encoded one whole label at a time. Any of the four Unicode label43 separators (``U+002E``, ``U+3002``, ``U+FF0E``, ``U+FF61``) ends a44 label; the result always uses ``U+002E`` as the separator.45 46 Only the ``"strict"`` error handler is supported.47 """48 49 def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[bytes, int]: # ty: ignore[invalid-method-override]50 if errors != "strict":51 raise IDNAError(f'Unsupported error handling "{errors}"')52 53 if not data:54 return b"", 055 56 labels = _unicode_dots_re.split(data)57 trailing_dot = b""58 if labels:59 if not labels[-1]:60 trailing_dot = b"."61 del labels[-1]62 elif not final:63 # Keep potentially unfinished label until the next call64 del labels[-1]65 if labels:66 trailing_dot = b"."67 68 result = []69 size = 070 for label in labels:71 result.append(alabel(label))72 if size:73 size += 174 size += len(label)75 76 # Join with U+002E77 result_bytes = b".".join(result) + trailing_dot78 size += len(trailing_dot)79 return result_bytes, size80 81 82class IncrementalDecoder(codecs.BufferedIncrementalDecoder):83 """Incremental IDNA 2008 decoder.84 85 Buffers a partial trailing label across calls until either the next86 label separator is seen or ``final=True``, so that streamed input is87 decoded one whole label at a time.88 89 Only the ``"strict"`` error handler is supported.90 """91 92 def _buffer_decode(self, data: Any, errors: str, final: bool) -> Tuple[str, int]: # ty: ignore[invalid-method-override]93 if errors != "strict":94 raise IDNAError(f'Unsupported error handling "{errors}"')95 96 if not data:97 return ("", 0)98 99 if not isinstance(data, str):100 data = str(data, "ascii")101 102 labels = _unicode_dots_re.split(data)103 trailing_dot = ""104 if labels:105 if not labels[-1]:106 trailing_dot = "."107 del labels[-1]108 elif not final:109 # Keep potentially unfinished label until the next call110 del labels[-1]111 if labels:112 trailing_dot = "."113 114 result = []115 size = 0116 for label in labels:117 result.append(ulabel(label))118 if size:119 size += 1120 size += len(label)121 122 result_str = ".".join(result) + trailing_dot123 size += len(trailing_dot)124 return (result_str, size)125 126 127class StreamWriter(Codec, codecs.StreamWriter):128 pass129 130 131class StreamReader(Codec, codecs.StreamReader):132 pass133 134 135def search_function(name: str) -> Optional[codecs.CodecInfo]:136 """Codec search function registered with :mod:`codecs`.137 138 Returns a :class:`codecs.CodecInfo` for the ``"idna2008"`` codec name139 so that ``str.encode("idna2008")`` and ``bytes.decode("idna2008")``140 invoke the IDNA 2008 codec defined in this module.141 142 :param name: The codec name being looked up.143 :returns: A :class:`codecs.CodecInfo` instance if ``name`` is144 ``"idna2008"``, otherwise ``None``.145 """146 if name != "idna2008":147 return None148 return codecs.CodecInfo(149 name=name,150 encode=Codec().encode,151 decode=Codec().decode, # type: ignore152 incrementalencoder=IncrementalEncoder,153 incrementaldecoder=IncrementalDecoder,154 streamwriter=StreamWriter,155 streamreader=StreamReader,156 )157 158 159codecs.register(search_function)160 