Source code for pyquickhelper.filehelper.transfer_api
"""
API to move files
:githublink:`%|py|5`
"""
import json
import hashlib
from io import StringIO
from ..loghelper.flog import noLOG
from ..loghelper.convert_helper import str2datetime, datetime2str
[docs]class TransferAPI_FileInfo:
"""
Keeps tracks of transferred files.
:githublink:`%|py|15`
"""
[docs] def __init__(self, name, pieces, last_update):
"""
Information about a transferred file.
:param name: name of the file
:param pieces: list of pieces contributing to the file
:param last_update: last_update
:githublink:`%|py|24`
"""
self.name = name
self.pieces = pieces
self.last_update = last_update
[docs] def __str__(self):
"""
usual
:githublink:`%|py|32`
"""
mes = "[%s,#%d,%s]" % (self.name, len(self.pieces), self.last_update)
return mes
[docs] def add_piece(self, piece):
"""
Adds a piece.
:param piece: add piece
:githublink:`%|py|41`
"""
self.pieces.append(piece)
[docs] @staticmethod
def read_json(s):
"""
Retrieves information from a :epkg:`json` string.
:githublink:`%|py|48`
"""
st = StringIO(s)
js = json.load(st)
js[2] = str2datetime(js[2])
return TransferAPI_FileInfo(*js)
[docs] def to_json(self):
"""
Serializes this class info JSON.
:githublink:`%|py|57`
"""
li = [self.name, self.pieces, datetime2str(self.last_update)]
return json.dumps(li)
[docs]class TransferAPI:
"""
Defines an API to transfer files over a remote location.
:githublink:`%|py|65`
"""
[docs] def __init__(self, fLOG=noLOG):
"""
:param fLOG: logging function
:githublink:`%|py|70`
"""
self.fLOG = fLOG if fLOG else noLOG
[docs] def transfer(self, path, data):
"""
It assumes a data holds in memory,
tansfer data to path.
:param data: bytes
:param path: path to remove location
:return: boolean
:githublink:`%|py|81`
"""
raise NotImplementedError()
[docs] def retrieve(self, path, exc=True):
"""
Retrieves data from path.
:param path: remove location
:param exc: keep exception
:return: data
:githublink:`%|py|91`
"""
raise NotImplementedError()
[docs] def retrieve_mapping(self, decrypt):
"""
Returns the mapping.
:param decrypt: decrypt function
:return: list of key,value pair
:githublink:`%|py|100`
"""
m = self.retrieve("__mapping__", exc=False)
if m is None:
return {}
else:
return TransferAPI.bytes2mapping(m)
[docs] def transfer_mapping(self, mapping, encrypt, filename=None):
"""
Transfers the mapping.
:param mapping: mapping
:param encrypt: encryption function
:param filename: local filename
:return: boolean
:githublink:`%|py|115`
"""
b = TransferAPI.mapping2bytes(mapping)
if filename is not None:
with open(filename, "wb") as f:
f.write(b)
return self.transfer("__mapping__", b)
[docs] @staticmethod
def mapping2bytes(mapping):
"""
Serializes a mapping.
:param mapping: dictionary { str, :class:`TransferAPI_FileInfo <pyquickhelper.filehelper.transfer_api.TransferAPI_FileInfo>` }
:return: bytes
:githublink:`%|py|129`
"""
rows = []
for k, v in sorted(mapping.items()):
r = "{0}\t{1}".format(k, v.to_json())
rows.append(r)
return "\n".join(rows).encode()
[docs] @staticmethod
def bytes2mapping(byt):
"""
Deserializes a mapping.
:param byt: bytes
:return: dictionary { str, :class:`TransferAPI_FileInfo <pyquickhelper.filehelper.transfer_api.TransferAPI_FileInfo>` }
:githublink:`%|py|143`
"""
lines = byt.decode().split("\n")
res = {}
for line in lines:
spl = line.split("\t")
res[spl[0]] = TransferAPI_FileInfo.read_json("\n".join(spl[1:]))
return res
[docs] @staticmethod
def checksum_md5(data):
"""
Computes MD5 for a file.
:param data: some data
:return: string
:githublink:`%|py|158`
"""
zero = hashlib.md5()
zero.update(data)
return zero.hexdigest()
[docs] def get_remote_path(self, data, name, piece=0):
"""
Produces a remote path.
:param data: binary data to transfer (to be hashed)
:param name: local name
:param piece: pieces
:return: remote path
*~ hash of everything*
:githublink:`%|py|173`
"""
m1 = TransferAPI.checksum_md5(name.encode() + str(piece).encode())
m2 = TransferAPI.checksum_md5(data)
return m1 + "_" + m2
[docs]class MockTransferAPI(TransferAPI):
"""
Class used for unit test purposes, simple key, value storage.
:githublink:`%|py|182`
"""
[docs] def __init__(self, fLOG=noLOG):
"""
:param fLOG: logging function
:githublink:`%|py|187`
"""
TransferAPI.__init__(self, fLOG)
self._storage = {}
[docs] def transfer(self, path, data):
"""
It assumes a data holds in memory,
tansfer data to path.
:param data: bytes
:param path: path to remove location
:return: boolean
:githublink:`%|py|199`
"""
self._storage[path] = data
return True
[docs] def retrieve(self, path, exc=True):
"""
Retrieves data from path.
:param path: remove location
:param exc: keep exception
:return: data
:githublink:`%|py|210`
"""
if exc:
return self._storage[path]
else:
try:
return self._storage[path]
except KeyError:
return None