# Path: astroNN/config.py
# def config_path(flag=None):
# def magic_num_reader():
# def multiprocessing_flag_reader():
# def envvar_warning_flag_reader():
# def custom_model_path_reader():
# def cpu_gpu_reader():
# def cpu_gpu_check():
# def tf_patch():
# def tf_unpatch():
# def __tf_patches(method='patch'):
#     def __master_patch(path, diffpatch):
# MAGIC_NUMBER = magic_num_reader()
# MULTIPROCESS_FLAG = multiprocessing_flag_reader()
# ENVVAR_WARN_FLAG = envvar_warning_flag_reader()
# CUSTOM_MODEL_PATH = custom_model_path_reader()
# 
# Path: astroNN/config.py
# def cpu_gpu_check():
#     fallback_cpu, limit_gpu_mem = cpu_gpu_reader()
#     if fallback_cpu is True:
#         cpu_fallback()
#     if isinstance(limit_gpu_mem, float) is True:
#         gpu_memory_manage(ratio=limit_gpu_mem)
#     else:
#         gpu_memory_manage()
# 
# Path: astroNN/shared/warnings.py
# def deprecated(func):
#     """
#     This is a decorator which can be used to mark functions
#     as deprecated. It will result in a warning being emitted
#     when the function is used.
#     """
# 
#     @functools.wraps(func)
#     def new_func(*args, **kwargs):
#         if inspect.isclass(func):
#             warnings.warn(f"The use of class {func.__name__}() is deprecated. It will be removed in future",
#                           category=DeprecationWarning, stacklevel=2)
#         else:
#             warnings.warn(f"Call to function {func.__name__}() is deprecated. It will be removed in future",
#                           category=DeprecationWarning, stacklevel=2)
#         return func(*args, **kwargs)
# 
#     return new_func
# 
# Path: astroNN/shared/nn_tools.py
# def folder_runnum():
#     """
#     To get the smallest available folder name without replacing the existing folder
# 
#     :return: folder name
#     :rtype: str
#     :History: 2017-Nov-25 - Written - Henry Leung (University of Toronto)
#     """
#     now = datetime.datetime.now()
#     runnum = 1
#     while True:
#         folder_name = f'astroNN_{now.month:0{2}d}{now.day:0{2}d}_run{runnum:0{3}d}'
#         if not os.path.exists(folder_name):
#             break
#         else:
#             runnum += 1
# 
#     return folder_name
# 
# Path: astroNN/shared/dict_tools.py
# def dict_np_to_dict_list(input_dict):
#     """
#     Convert a dict of numpy array to a dict of list
#     """
#     input_dict = copy.copy(input_dict)
#     if type(input_dict) is dict:
#         for name in list(input_dict.keys()):
#             input_dict.update({name: input_dict[name].tolist()})
#         return input_dict
#     else:
#         return input_dict.tolist()
# 
# def list_to_dict(names, arrs):
#     """
#     Matching a list of array with names
#     """
#     # TODO: need detailed test
#     if type(arrs) is list:
#         final_dict = {}
#         if len(names) == len(arrs):
#             for name, arr in zip(names, arrs):
#                 final_dict.update({name: arr})
#         elif len(arrs):
#             for name in names:
#                 final_dict.update({name: arrs[0]})
#         else:
#             raise IndexError(f"names has a length of {len(names)} but arrs has a  length of {len(arrs)}")
#         return final_dict
#     elif type(arrs) is np.ndarray and len(names) == 1:
#         return {names[0]: arrs}
#     elif type(arrs) is np.ndarray and len(names) > 1:
#         final_dict = {}
#         for name in names:
#             final_dict.update({name: arrs})
#         return final_dict
#     else:
#         return arrs


from distutils.log import warn
from abc import ABC, abstractmethod
from tensorflow import keras as tfk
from packaging import version
from astroNN.config import _astroNN_MODEL_NAME
from astroNN.config import cpu_gpu_check
from astroNN.shared.warnings import deprecated
from astroNN.shared.nn_tools import folder_runnum
from astroNN.shared.dict_tools import dict_np_to_dict_list, list_to_dict
import os
import sys
import time
import warnings
import numpy as np
import pylab as plt
import tensorflow as tf
import astroNN
                    self._labels_shape.update({name: (labels[name].shape[1], labels[name].shape[2], labels[name].shape[3])})

        print(f'Number of Training Data: {self.num_train}, Number of Validation Data: {self.val_num}')

        return input_data, labels

    def pre_testing_checklist_master(self, input_data):
        if type(input_data) is not dict:
            input_data = {self.input_names[0]: np.atleast_2d(input_data)}
        else:
            for name in input_data.keys():
                input_data.update({name: np.atleast_2d(input_data[name])})
        return input_data

    def post_training_checklist_master(self):
        pass

    def save(self, name=None, model_plot=False):
        """
        Save the model to disk

        :param name: Folder name to be saved
        :type name: string
        :param model_plot: True to plot model too
        :type model_plot: boolean
        :return: A saved folder on disk
        """
        self.has_model_check()
        # Only generate a folder automatically if no name provided
        if self.folder_name is None and name is None:

# Path: astroNN/config.py
# def config_path(flag=None):
# def magic_num_reader():
# def multiprocessing_flag_reader():
# def envvar_warning_flag_reader():
# def custom_model_path_reader():
# def cpu_gpu_reader():
# def cpu_gpu_check():
# def tf_patch():
# def tf_unpatch():
# def __tf_patches(method='patch'):
#     def __master_patch(path, diffpatch):
# MAGIC_NUMBER = magic_num_reader()
# MULTIPROCESS_FLAG = multiprocessing_flag_reader()
# ENVVAR_WARN_FLAG = envvar_warning_flag_reader()
# CUSTOM_MODEL_PATH = custom_model_path_reader()
# 
# Path: astroNN/config.py
# def cpu_gpu_check():
#     fallback_cpu, limit_gpu_mem = cpu_gpu_reader()
#     if fallback_cpu is True:
#         cpu_fallback()
#     if isinstance(limit_gpu_mem, float) is True:
#         gpu_memory_manage(ratio=limit_gpu_mem)
#     else:
#         gpu_memory_manage()
# 
# Path: astroNN/shared/warnings.py
# def deprecated(func):
#     """
#     This is a decorator which can be used to mark functions
#     as deprecated. It will result in a warning being emitted
#     when the function is used.
#     """
# 
#     @functools.wraps(func)
#     def new_func(*args, **kwargs):
#         if inspect.isclass(func):
#             warnings.warn(f"The use of class {func.__name__}() is deprecated. It will be removed in future",
#                           category=DeprecationWarning, stacklevel=2)
#         else:
#             warnings.warn(f"Call to function {func.__name__}() is deprecated. It will be removed in future",
#                           category=DeprecationWarning, stacklevel=2)
#         return func(*args, **kwargs)
# 
#     return new_func
# 
# Path: astroNN/shared/nn_tools.py
# def folder_runnum():
#     """
#     To get the smallest available folder name without replacing the existing folder
# 
#     :return: folder name
#     :rtype: str
#     :History: 2017-Nov-25 - Written - Henry Leung (University of Toronto)
#     """
#     now = datetime.datetime.now()
#     runnum = 1
#     while True:
#         folder_name = f'astroNN_{now.month:0{2}d}{now.day:0{2}d}_run{runnum:0{3}d}'
#         if not os.path.exists(folder_name):
#             break
#         else:
#             runnum += 1
# 
#     return folder_name
# 
# Path: astroNN/shared/dict_tools.py
# def dict_np_to_dict_list(input_dict):
#     """
#     Convert a dict of numpy array to a dict of list
#     """
#     input_dict = copy.copy(input_dict)
#     if type(input_dict) is dict:
#         for name in list(input_dict.keys()):
#             input_dict.update({name: input_dict[name].tolist()})
#         return input_dict
#     else:
#         return input_dict.tolist()
# 
# def list_to_dict(names, arrs):
#     """
#     Matching a list of array with names
#     """
#     # TODO: need detailed test
#     if type(arrs) is list:
#         final_dict = {}
#         if len(names) == len(arrs):
#             for name, arr in zip(names, arrs):
#                 final_dict.update({name: arr})
#         elif len(arrs):
#             for name in names:
#                 final_dict.update({name: arrs[0]})
#         else:
#             raise IndexError(f"names has a length of {len(names)} but arrs has a  length of {len(arrs)}")
#         return final_dict
#     elif type(arrs) is np.ndarray and len(names) == 1:
#         return {names[0]: arrs}
#     elif type(arrs) is np.ndarray and len(names) > 1:
#         final_dict = {}
#         for name in names:
#             final_dict.update({name: arrs})
#         return final_dict
#     else:
#         return arrs


# Path: astroNN/models/base_master_nn.py
from distutils.log import warn
from abc import ABC, abstractmethod
from tensorflow import keras as tfk
from packaging import version
from astroNN.config import _astroNN_MODEL_NAME
from astroNN.config import cpu_gpu_check
from astroNN.shared.warnings import deprecated
from astroNN.shared.nn_tools import folder_runnum
from astroNN.shared.dict_tools import dict_np_to_dict_list, list_to_dict
import os
import sys
import time
import warnings
import numpy as np
import pylab as plt
import tensorflow as tf
import astroNN

                    self._labels_shape.update({name: (labels[name].shape[1], labels[name].shape[2], labels[name].shape[3])})

        print(f'Number of Training Data: {self.num_train}, Number of Validation Data: {self.val_num}')

        return input_data, labels

    def pre_testing_checklist_master(self, input_data):
        if type(input_data) is not dict:
            input_data = {self.input_names[0]: np.atleast_2d(input_data)}
        else:
            for name in input_data.keys():
                input_data.update({name: np.atleast_2d(input_data[name])})
        return input_data

    def post_training_checklist_master(self):
        pass

    def save(self, name=None, model_plot=False):
        """
        Save the model to disk

        :param name: Folder name to be saved
        :type name: string
        :param model_plot: True to plot model too
        :type model_plot: boolean
        :return: A saved folder on disk
        """
        self.has_model_check()
        # Only generate a folder automatically if no name provided
        if self.folder_name is None and name is None:

            self.folder_name = folder_runnum()