python (3.11.7)
       1  from .core import encode, decode, alabel, ulabel, IDNAError
       2  import codecs
       3  import re
       4  from typing import Tuple, Optional
       5  
       6  _unicode_dots_re = re.compile('[\u002e\u3002\uff0e\uff61]')
       7  
       8  class ESC[4;38;5;81mCodec(ESC[4;38;5;149mcodecsESC[4;38;5;149m.ESC[4;38;5;149mCodec):
       9  
      10      def encode(self, data: str, errors: str = 'strict') -> Tuple[bytes, int]:
      11          if errors != 'strict':
      12              raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
      13  
      14          if not data:
      15              return b"", 0
      16  
      17          return encode(data), len(data)
      18  
      19      def decode(self, data: bytes, errors: str = 'strict') -> Tuple[str, int]:
      20          if errors != 'strict':
      21              raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
      22  
      23          if not data:
      24              return '', 0
      25  
      26          return decode(data), len(data)
      27  
      28  class ESC[4;38;5;81mIncrementalEncoder(ESC[4;38;5;149mcodecsESC[4;38;5;149m.ESC[4;38;5;149mBufferedIncrementalEncoder):
      29      def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[str, int]:  # type: ignore
      30          if errors != 'strict':
      31              raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
      32  
      33          if not data:
      34              return "", 0
      35  
      36          labels = _unicode_dots_re.split(data)
      37          trailing_dot = ''
      38          if labels:
      39              if not labels[-1]:
      40                  trailing_dot = '.'
      41                  del labels[-1]
      42              elif not final:
      43                  # Keep potentially unfinished label until the next call
      44                  del labels[-1]
      45                  if labels:
      46                      trailing_dot = '.'
      47  
      48          result = []
      49          size = 0
      50          for label in labels:
      51              result.append(alabel(label))
      52              if size:
      53                  size += 1
      54              size += len(label)
      55  
      56          # Join with U+002E
      57          result_str = '.'.join(result) + trailing_dot  # type: ignore
      58          size += len(trailing_dot)
      59          return result_str, size
      60  
      61  class ESC[4;38;5;81mIncrementalDecoder(ESC[4;38;5;149mcodecsESC[4;38;5;149m.ESC[4;38;5;149mBufferedIncrementalDecoder):
      62      def _buffer_decode(self, data: str, errors: str, final: bool) -> Tuple[str, int]:  # type: ignore
      63          if errors != 'strict':
      64              raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
      65  
      66          if not data:
      67              return ('', 0)
      68  
      69          labels = _unicode_dots_re.split(data)
      70          trailing_dot = ''
      71          if labels:
      72              if not labels[-1]:
      73                  trailing_dot = '.'
      74                  del labels[-1]
      75              elif not final:
      76                  # Keep potentially unfinished label until the next call
      77                  del labels[-1]
      78                  if labels:
      79                      trailing_dot = '.'
      80  
      81          result = []
      82          size = 0
      83          for label in labels:
      84              result.append(ulabel(label))
      85              if size:
      86                  size += 1
      87              size += len(label)
      88  
      89          result_str = '.'.join(result) + trailing_dot
      90          size += len(trailing_dot)
      91          return (result_str, size)
      92  
      93  
      94  class ESC[4;38;5;81mStreamWriter(ESC[4;38;5;149mCodec, ESC[4;38;5;149mcodecsESC[4;38;5;149m.ESC[4;38;5;149mStreamWriter):
      95      pass
      96  
      97  
      98  class ESC[4;38;5;81mStreamReader(ESC[4;38;5;149mCodec, ESC[4;38;5;149mcodecsESC[4;38;5;149m.ESC[4;38;5;149mStreamReader):
      99      pass
     100  
     101  
     102  def getregentry() -> codecs.CodecInfo:
     103      # Compatibility as a search_function for codecs.register()
     104      return codecs.CodecInfo(
     105          name='idna',
     106          encode=Codec().encode,  # type: ignore
     107          decode=Codec().decode,  # type: ignore
     108          incrementalencoder=IncrementalEncoder,
     109          incrementaldecoder=IncrementalDecoder,
     110          streamwriter=StreamWriter,
     111          streamreader=StreamReader,
     112      )