Source code for compress.string_encoding
# -*- coding: utf-8 -*-
"""
string encoding is a technique to convert arbitrary binary data to string
based encoding binary, which is easily to represent string.
"""
import inspect
import base64
import binascii
_example_data = ("Hello World" * 1000).encode("utf-8")
[docs]class EncodingAlgorithm:
"""
Base encoding algorithm class.
"""
name = None
@classmethod
def validate_implement(cls):
encoded_data = cls.encode(_example_data)
decoded_data = cls.decode(encoded_data)
assert _example_data == decoded_data
@staticmethod
def encode(data, **kwargs): # pragma: no cover
raise NotImplementedError
@staticmethod
def decode(data, **kwargs): # pragma: no cover
raise NotImplementedError
class EncodingAlgorithmsMeta(type):
def __new__(cls, name, bases, attrs):
klass = super(EncodingAlgorithmsMeta, cls) \
.__new__(cls, name, bases, attrs)
_mapper = dict()
_algorithm_list = list()
_algorithm_class_list = list()
for key, value in attrs.items():
if inspect.isclass(value):
if issubclass(value, EncodingAlgorithm):
algo_name = key
algo_class = value
try:
algo_class.validate_implement()
except: # pragma: no cover
continue
algo_class.name = algo_class.__name__
_mapper[key] = {
"_encode": algo_class.encode,
"_decode": algo_class.decode,
}
_algorithm_list.append(algo_name)
_algorithm_class_list.append(algo_class)
_algorithm_list.sort()
klass._mapper = _mapper
klass._algorithm_list = _algorithm_list
klass._algorithm_set = set(_algorithm_list)
klass._algorithm_class_list = _algorithm_class_list
return klass
[docs]class EncodingAlgorithms(metaclass=EncodingAlgorithmsMeta):
"""
Collection of string encoding algorithms.
Example::
EncodingAlgorithms.Base64
`Comparison of encoding schemes
<http://www.tenminutetutor.com/data-formats/binary-encoding/comparison-of-encoding-schemes/>`_
"""
_algorithm_list = list()
"""All available algorithm name list.
"""
_algorithm_set = set()
"""All available algorithm name set.
"""
_algorithm_class_list = list()
"""All available algorithm class list.
"""
[docs] class HexString(EncodingAlgorithm):
"""
Data increase 100%.
Doc: https://docs.python.org/2/library/binascii.html#binascii.hexlify
"""
@staticmethod
def encode(data, **kwargs):
return binascii.hexlify(data)
@staticmethod
def decode(data, **kwargs):
return binascii.unhexlify(data)
[docs] class Base32(EncodingAlgorithm):
"""
Data increase 60%.
"""
@staticmethod
def encode(data, **kwargs):
return base64.b32encode(data)
@staticmethod
def decode(data, **kwargs):
return base64.b32decode(data)
[docs] class Base64(EncodingAlgorithm):
"""
Data increase 33%.
"""
@staticmethod
def encode(data, **kwargs):
return base64.b64encode(data)
@staticmethod
def decode(data, **kwargs):
return base64.b64decode(data)
[docs] class Base85(EncodingAlgorithm): # pragma: no cover
"""
Data increase 20%.
"""
@staticmethod
def encode(data, **kwargs):
return base64.b85encode(data)
@staticmethod
def decode(data, **kwargs):
return base64.b85decode(data)
[docs]class Encoder:
"""
String encoder utility class.
Example::
>>> binary_data = ("hello world" * 100).encode("utf-8")
>>> encoder = Encoder().use_base64()
>>> encoder.encode(binary_data)
...
>>> encoder.decode(binary_data)
...
"""
def __init__(self,
algorithm=None,
**kwargs):
self.use(algorithm)
[docs] def use(self, algo=None):
"""
Use specified string encoding algorithm.
:param algo: str or :class:`EncodingAlgorithm`.
"""
if algo is None:
return self
try:
algo_name = algo.__name__ # if it is a class
except AttributeError:
algo_name = algo # if it is a string
if algo_name in EncodingAlgorithms._algorithm_set:
self._encode = EncodingAlgorithms._mapper[algo_name]["_encode"]
self._decode = EncodingAlgorithms._mapper[algo_name]["_decode"]
return self
else:
raise ValueError(
"algorithm has to be one of "
"%r" % EncodingAlgorithms._algorithm_list
)
[docs] def use_hex(self):
"""
Use hex string algorithm.
"""
return self.use(EncodingAlgorithms.HexString)
[docs] def use_base32(self):
"""
Use base32 algorithm.
"""
return self.use(EncodingAlgorithms.Base32)
[docs] def use_base64(self):
"""
Use base64 algorithm.
"""
return self.use(EncodingAlgorithms.Base64)
[docs] def use_base85(self): # pragma: no cover
"""
Use base85 algorithm.
"""
return self.use(EncodingAlgorithms.Base85)
def _encode(self, data, **kwargs):
"""
The real encode method will be called.
"""
raise NotImplementedError
def _decode(self, data, **kwargs):
"""
The real decode method will be called.
"""
raise NotImplementedError
[docs] def encode(self, data, **kwargs):
"""
Encode binary data to string based binary binary.
:return: string encoded binary data.
"""
return self._encode(data, **kwargs)
[docs] def decode(self, data, **kwargs):
"""
Decode string encoded binary data.
:return: original binary data.
"""
return self._decode(data, **kwargs)