python/vmaf/core/result_store.py (77 lines of code) (raw):
import os
import hashlib
import ast
import shutil
import pandas as pd
from vmaf.config import VmafConfig
from vmaf.core.asset import Asset
from vmaf.core.result import Result
from vmaf.tools.misc import make_parent_dirs_if_nonexist
__copyright__ = "Copyright 2016-2020, Netflix, Inc."
__license__ = ("BSD"
"+Patent")
class ResultStore(object):
"""
Provide capability to save and load a Result.
"""
pass
class SqliteResultStore(ResultStore):
"""
persist result by a SQLite engine that save/load result.
"""
pass
class FileSystemResultStore(ResultStore):
"""
persist result by a simple file system that save/load result in a directory.
The directory has multiple subdirectories, each corresponding to an Executor
(e.g. a VMAF feature extractor, or a NO19 feature extractor, or a
VMAF quality runner, or an SSIM quality runner). Each subdirectory contains
multiple files, each file stores dataframe for an asset, and has file name
str(asset).
"""
def __init__(self, logger=None,
result_store_dir=VmafConfig.file_result_store_path()
):
self.logger = logger
self.result_store_dir = result_store_dir
def save(self, result):
result_file_path = self._get_result_file_path(result)
try:
make_parent_dirs_if_nonexist(result_file_path)
except OSError as e:
print('make_parent_dirs_if_nonexist {path} fails: {e}'.format(path=result_file_path, e=str(e)))
self.save_result(result, result_file_path)
def save_workfile(self, result: Result, workfile_path: str, suffix: str):
result_file_path = self._get_result_file_path(result)
try:
make_parent_dirs_if_nonexist(result_file_path)
except OSError as e:
print('make_parent_dirs_if_nonexist {path} fails: {e}'.format(path=result_file_path, e=str(e)))
shutil.copyfile(workfile_path, result_file_path + suffix)
def load(self, asset, executor_id):
result_file_path = self._get_result_file_path2(asset, executor_id)
if not os.path.isfile(result_file_path):
return None
result = self.load_result(result_file_path, asset.__class__)
return result
def has_workfile(self, asset: Asset, executor_id: str, suffix: str) -> bool:
result_file_path = self._get_result_file_path2(asset, executor_id)
return os.path.isfile(result_file_path + suffix)
@staticmethod
def save_result(result, result_file_path):
with open(result_file_path, "wt") as result_file:
result_file.write(str(result.to_dataframe().to_dict()))
@staticmethod
def load_result(result_file_path, AssetClass=Asset):
with open(result_file_path, "rt") as result_file:
df = pd.DataFrame.from_dict(ast.literal_eval(result_file.read()))
result = Result.from_dataframe(df, AssetClass)
return result
def delete(self, asset, executor_id):
result_file_path = self._get_result_file_path2(asset, executor_id)
if os.path.isfile(result_file_path):
os.remove(result_file_path)
def delete_workfile(self, asset, executor_id, suffix: str):
result_file_path = self._get_result_file_path2(asset, executor_id)
workfile_path = result_file_path + suffix
if os.path.isfile(workfile_path):
os.remove(workfile_path)
def clean_up(self):
"""
WARNING: RMOVE ENTIRE RESULT STORE, USE WITH CAUTION!!!
:return:
"""
import shutil
if os.path.isdir(self.result_store_dir):
shutil.rmtree(self.result_store_dir)
def _get_result_file_path(self, result):
return self._get_result_file_path2(result.asset, result.executor_id)
def _get_result_file_path2(self, asset, executor_id):
str_to_hash = str(asset).encode("utf-8")
return "{dir}/{executor_id}/{dataset}/{content_id}/{str}".format(
dir=self.result_store_dir, executor_id=executor_id,
dataset=asset.dataset,
content_id=asset.content_id,
str=hashlib.sha1(str_to_hash).hexdigest())