extracted current storing process to SettingsFileHandler

This commit is contained in:
iLLiCiTiT 2020-12-11 16:07:47 +01:00
parent 5d9fb93558
commit de92f0a8d3
3 changed files with 248 additions and 172 deletions

View file

@ -1,5 +1,24 @@
import os
import json
import logging
from abc import ABCMeta, abstractmethod
import six
import pype
from .constants import (
M_OVERRIDEN_KEY,
M_ENVIRONMENT_KEY,
M_DYNAMIC_KEY_LABEL,
M_POP_KEY,
METADATA_KEYS,
SYSTEM_SETTINGS_KEY,
ENVIRONMENTS_KEY,
PROJECT_SETTINGS_KEY,
PROJECT_ANATOMY_KEY
)
JSON_EXC = getattr(json.decoder, "JSONDecodeError", ValueError)
@six.add_metaclass(ABCMeta)
@ -87,3 +106,192 @@ class SettingsHandler:
"""
pass
class SettingsFileHandler(SettingsHandler):
def __init__(self):
self.log = logging.getLogger("SettingsFileHandler")
# Folder where studio overrides are stored
studio_overrides_dir = os.getenv("PYPE_PROJECT_CONFIGS")
if not studio_overrides_dir:
studio_overrides_dir = os.path.dirname(os.path.dirname(
os.path.abspath(pype.__file__)
))
system_settings_path = os.path.join(
studio_overrides_dir, SYSTEM_SETTINGS_KEY + ".json"
)
# File where studio's default project overrides are stored
project_settings_filename = PROJECT_SETTINGS_KEY + ".json"
project_settings_path = os.path.join(
studio_overrides_dir, project_settings_filename
)
project_anatomy_filename = PROJECT_ANATOMY_KEY + ".json"
project_anatomy_path = os.path.join(
studio_overrides_dir, project_anatomy_filename
)
self.studio_overrides_dir = studio_overrides_dir
self.system_settings_path = system_settings_path
self.project_settings_filename = project_settings_filename
self.project_anatomy_filename = project_anatomy_filename
self.project_settings_path = project_settings_path
self.project_anatomy_path = project_anatomy_path
def load_json_file(self, fpath):
# Load json data
try:
with open(fpath, "r") as opened_file:
return json.load(opened_file)
except JSON_EXC:
self.log.warning(
"File has invalid json format \"{}\"".format(fpath),
exc_info=True
)
return {}
def path_to_project_settings(self, project_name):
if not project_name:
return self.project_settings_path
return os.path.join(
self.studio_overrides_dir,
project_name,
self.project_settings_filename
)
def path_to_project_anatomy(self, project_name):
if not project_name:
return self.project_anatomy_path
return os.path.join(
self.studio_overrides_dir,
project_name,
self.project_anatomy_filename
)
def save_studio_settings(self, data):
"""Save studio overrides of system settings.
Do not use to store whole system settings data with defaults but only
it's overrides with metadata defining how overrides should be applied
in load function. For loading should be used function
`studio_system_settings`.
Args:
data(dict): Data of studio overrides with override metadata.
"""
dirpath = os.path.dirname(self.system_settings_path)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
self.log.debug(
"Saving studio overrides. Output path: {}".format(
self.system_settings_path
)
)
with open(self.system_settings_path, "w") as file_stream:
json.dump(data, file_stream, indent=4)
def save_project_settings(self, project_name, overrides):
"""Save studio overrides of project settings.
Data are saved for specific project or as defaults for all projects.
Do not use to store whole project settings data with defaults but only
it's overrides with metadata defining how overrides should be applied
in load function. For loading should be used function
`get_studio_project_settings_overrides` for global project settings
and `get_project_settings_overrides` for project specific settings.
Args:
project_name(str, null): Project name for which overrides are
or None for global settings.
data(dict): Data of project overrides with override metadata.
"""
project_overrides_json_path = self.path_to_project_settings(
project_name
)
dirpath = os.path.dirname(project_overrides_json_path)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
self.log.debug(
"Saving overrides of project \"{}\". Output path: {}".format(
project_name, project_overrides_json_path
)
)
with open(project_overrides_json_path, "w") as file_stream:
json.dump(overrides, file_stream, indent=4)
def save_project_anatomy(self, project_name, anatomy_data):
"""Save studio overrides of project anatomy data.
Args:
project_name(str, null): Project name for which overrides are
or None for global settings.
data(dict): Data of project overrides with override metadata.
"""
project_anatomy_json_path = self.path_to_project_anatomy(project_name)
dirpath = os.path.dirname(project_anatomy_json_path)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
self.log.debug(
"Saving anatomy of project \"{}\". Output path: {}".format(
project_name, project_anatomy_json_path
)
)
with open(project_anatomy_json_path, "w") as file_stream:
json.dump(anatomy_data, file_stream, indent=4)
def get_studio_system_settings_overrides(self):
"""Studio overrides of system settings."""
if os.path.exists(self.system_settings_path):
return self.load_json_file(self.system_settings_path)
return {}
def get_studio_project_settings_overrides(self):
"""Studio overrides of default project settings."""
if os.path.exists(self.project_settings_path):
return self.load_json_file(self.project_settings_path)
return {}
def get_studio_project_anatomy_overrides(self):
"""Studio overrides of default project anatomy data."""
if os.path.exists(self.project_anatomy_path):
return self.load_json_file(self.project_anatomy_path)
return {}
def get_project_settings_overrides(self, project_name):
"""Studio overrides of project settings for specific project.
Args:
project_name(str): Name of project for which data should be loaded.
Returns:
dict: Only overrides for entered project, may be empty dictionary.
"""
path_to_json = self.path_to_project_settings(project_name)
if not os.path.exists(path_to_json):
return {}
return self.load_json_file(path_to_json)
def get_project_anatomy_overrides(self, project_name):
"""Studio overrides of project anatomy for specific project.
Args:
project_name(str): Name of project for which data should be loaded.
Returns:
dict: Only overrides for entered project, may be empty dictionary.
"""
if not project_name:
return {}
path_to_json = self.path_to_project_anatomy(project_name)
if not os.path.exists(path_to_json):
return {}
return self.load_json_file(path_to_json)

View file

@ -15,6 +15,8 @@ from .constants import (
PROJECT_SETTINGS_KEY,
PROJECT_ANATOMY_KEY
)
from .handlers import (
SettingsFileHandler
)
log = logging.getLogger(__name__)
@ -29,6 +31,9 @@ DEFAULTS_DIR = os.path.join(os.path.dirname(__file__), "defaults")
# Variable where cache of default settings are stored
_DEFAULT_SETTINGS = None
# Handler of studio overrides
SETTINGS_HANDLER = SettingsFileHandler()
class DuplicatedEnvGroups(Exception):
def __init__(self, duplicated):
@ -220,150 +225,6 @@ def subkey_merge(_dict, value, keys):
return _dict
def path_to_project_settings(project_name):
if not project_name:
return PROJECT_SETTINGS_PATH
return os.path.join(
STUDIO_OVERRIDES_PATH,
project_name,
PROJECT_SETTINGS_FILENAME
)
def path_to_project_anatomy(project_name):
if not project_name:
return PROJECT_ANATOMY_PATH
return os.path.join(
STUDIO_OVERRIDES_PATH,
project_name,
PROJECT_ANATOMY_FILENAME
)
def save_studio_settings(data):
"""Save studio overrides of system settings.
Do not use to store whole system settings data with defaults but only it's
overrides with metadata defining how overrides should be applied in load
function. For loading should be used function `studio_system_settings`.
Args:
data(dict): Data of studio overrides with override metadata.
"""
dirpath = os.path.dirname(SYSTEM_SETTINGS_PATH)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
print("Saving studio overrides. Output path: {}".format(
SYSTEM_SETTINGS_PATH
))
with open(SYSTEM_SETTINGS_PATH, "w") as file_stream:
json.dump(data, file_stream, indent=4)
def save_project_settings(project_name, overrides):
"""Save studio overrides of project settings.
Data are saved for specific project or as defaults for all projects.
Do not use to store whole project settings data with defaults but only it's
overrides with metadata defining how overrides should be applied in load
function. For loading should be used function
`get_studio_project_settings_overrides` for global project settings
and `get_project_settings_overrides` for project specific settings.
Args:
project_name(str, null): Project name for which overrides are
or None for global settings.
data(dict): Data of project overrides with override metadata.
"""
project_overrides_json_path = path_to_project_settings(project_name)
dirpath = os.path.dirname(project_overrides_json_path)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
print("Saving overrides of project \"{}\". Output path: {}".format(
project_name, project_overrides_json_path
))
with open(project_overrides_json_path, "w") as file_stream:
json.dump(overrides, file_stream, indent=4)
def save_project_anatomy(project_name, anatomy_data):
"""Save studio overrides of project anatomy data.
Args:
project_name(str, null): Project name for which overrides are
or None for global settings.
data(dict): Data of project overrides with override metadata.
"""
project_anatomy_json_path = path_to_project_anatomy(project_name)
dirpath = os.path.dirname(project_anatomy_json_path)
if not os.path.exists(dirpath):
os.makedirs(dirpath)
print("Saving anatomy of project \"{}\". Output path: {}".format(
project_name, project_anatomy_json_path
))
with open(project_anatomy_json_path, "w") as file_stream:
json.dump(anatomy_data, file_stream, indent=4)
def get_studio_system_settings_overrides():
"""Studio overrides of system settings."""
if os.path.exists(SYSTEM_SETTINGS_PATH):
return load_json_file(SYSTEM_SETTINGS_PATH)
return {}
def get_studio_project_settings_overrides():
"""Studio overrides of default project settings."""
if os.path.exists(PROJECT_SETTINGS_PATH):
return load_json_file(PROJECT_SETTINGS_PATH)
return {}
def get_studio_project_anatomy_overrides():
"""Studio overrides of default project anatomy data."""
if os.path.exists(PROJECT_ANATOMY_PATH):
return load_json_file(PROJECT_ANATOMY_PATH)
return {}
def get_project_settings_overrides(project_name):
"""Studio overrides of project settings for specific project.
Args:
project_name(str): Name of project for which data should be loaded.
Returns:
dict: Only overrides for entered project, may be empty dictionary.
"""
path_to_json = path_to_project_settings(project_name)
if not os.path.exists(path_to_json):
return {}
return load_json_file(path_to_json)
def get_project_anatomy_overrides(project_name):
"""Studio overrides of project anatomy for specific project.
Args:
project_name(str): Name of project for which data should be loaded.
Returns:
dict: Only overrides for entered project, may be empty dictionary.
"""
if not project_name:
return {}
path_to_json = path_to_project_anatomy(project_name)
if not os.path.exists(path_to_json):
return {}
return load_json_file(path_to_json)
def merge_overrides(source_dict, override_dict):
"""Merge data from override_dict to source_dict."""
@ -397,7 +258,7 @@ def apply_overrides(source_data, override_data):
def get_system_settings(clear_metadata=True):
"""System settings with applied studio overrides."""
default_values = get_default_settings()[SYSTEM_SETTINGS_KEY]
studio_values = get_studio_system_settings_overrides()
studio_values = SETTINGS_HANDLER.get_studio_system_settings_overrides()
result = apply_overrides(default_values, studio_values)
if clear_metadata:
clear_metadata_from_settings(result)
@ -407,7 +268,7 @@ def get_system_settings(clear_metadata=True):
def get_default_project_settings(clear_metadata=True):
"""Project settings with applied studio's default project overrides."""
default_values = get_default_settings()[PROJECT_SETTINGS_KEY]
studio_values = get_studio_project_settings_overrides()
studio_values = SETTINGS_HANDLER.get_studio_project_settings_overrides()
result = apply_overrides(default_values, studio_values)
if clear_metadata:
clear_metadata_from_settings(result)
@ -417,7 +278,7 @@ def get_default_project_settings(clear_metadata=True):
def get_default_anatomy_settings(clear_metadata=True):
"""Project anatomy data with applied studio's default project overrides."""
default_values = get_default_settings()[PROJECT_ANATOMY_KEY]
studio_values = get_studio_project_anatomy_overrides()
studio_values = SETTINGS_HANDLER.get_studio_project_anatomy_overrides()
result = apply_overrides(default_values, studio_values)
if clear_metadata:
clear_metadata_from_settings(result)
@ -433,7 +294,9 @@ def get_anatomy_settings(project_name, clear_metadata=True):
)
studio_overrides = get_default_anatomy_settings(False)
project_overrides = get_project_anatomy_overrides(project_name)
project_overrides = SETTINGS_HANDLER.get_project_anatomy_overrides(
project_name
)
result = apply_overrides(studio_overrides, project_overrides)
if clear_metadata:
@ -450,7 +313,9 @@ def get_project_settings(project_name, clear_metadata=True):
)
studio_overrides = get_default_project_settings(False)
project_overrides = get_project_settings_overrides(project_name)
project_overrides = SETTINGS_HANDLER.get_project_settings_overrides(
project_name
)
result = apply_overrides(studio_overrides, project_overrides)
if clear_metadata:

View file

@ -9,21 +9,11 @@ from pype.settings.constants import (
)
from pype.settings.lib import (
DEFAULTS_DIR,
SETTINGS_HANDLER,
reset_default_settings,
get_default_settings,
get_studio_system_settings_overrides,
get_studio_project_settings_overrides,
get_studio_project_anatomy_overrides,
get_project_settings_overrides,
get_project_anatomy_overrides,
save_studio_settings,
save_project_settings,
save_project_anatomy,
apply_overrides,
find_environments,
DuplicatedEnvGroups
@ -370,7 +360,7 @@ class SystemWidget(SettingsCategoryWidget):
if not self.duplicated_env_group_validation(overrides=values):
return
save_studio_settings(values)
SETTINGS_HANDLER.save_studio_settings(values)
def update_values(self):
default_values = lib.convert_data_to_gui_data({
@ -382,8 +372,11 @@ class SystemWidget(SettingsCategoryWidget):
if self._hide_studio_overrides:
system_values = lib.NOT_SET
else:
studio_system_overrides = (
SETTINGS_HANDLER.get_studio_system_settings_overrides()
)
system_values = lib.convert_overrides_to_gui_data(
{self.main_schema_key: get_studio_system_settings_overrides()}
{self.main_schema_key: studio_system_overrides}
)
for input_field in self.input_fields:
@ -547,8 +540,12 @@ class ProjectWidget(SettingsCategoryWidget):
_project_anatomy = lib.NOT_SET
self.is_overidable = False
else:
_project_overrides = get_project_settings_overrides(project_name)
_project_anatomy = get_project_anatomy_overrides(project_name)
_project_overrides = (
SETTINGS_HANDLER.get_project_settings_overrides(project_name)
)
_project_anatomy = (
SETTINGS_HANDLER.get_project_anatomy_overrides(project_name)
)
self.is_overidable = True
overrides = {self.main_schema_key: {
@ -582,11 +579,15 @@ class ProjectWidget(SettingsCategoryWidget):
# Saving overrides data
project_overrides_data = output_data.get(PROJECT_SETTINGS_KEY, {})
save_project_settings(self.project_name, project_overrides_data)
SETTINGS_HANDLER.save_project_settings(
self.project_name, project_overrides_data
)
# Saving anatomy data
project_anatomy_data = output_data.get(PROJECT_ANATOMY_KEY, {})
save_project_anatomy(self.project_name, project_anatomy_data)
SETTINGS_HANDLER.save_project_anatomy(
self.project_name, project_anatomy_data
)
def update_values(self):
if self.project_name is not None:
@ -602,14 +603,16 @@ class ProjectWidget(SettingsCategoryWidget):
if self._hide_studio_overrides:
studio_values = lib.NOT_SET
else:
project_settings_value = (
SETTINGS_HANDLER.get_studio_project_settings_overrides()
)
project_anatomy_value = (
SETTINGS_HANDLER.get_studio_project_anatomy_overrides()
)
studio_values = lib.convert_overrides_to_gui_data({
self.main_schema_key: {
PROJECT_SETTINGS_KEY: (
get_studio_project_settings_overrides()
),
PROJECT_ANATOMY_KEY: (
get_studio_project_anatomy_overrides()
)
PROJECT_SETTINGS_KEY: project_settings_value,
PROJECT_ANATOMY_KEY: project_anatomy_value
}
})