Source code for pycafee.utils.helpers

"""This module concentrates the help functions to run the functions behind the scenes

"""


# Function list:
#
#     - LanguageManagment
#         - get_language(self)
#         - set_language(self, language)
#         - __str__(self)
#         - __repr__(self)
#
#     - AlphaManagement(LanguageManagment)
#         - get_alfa(self)
#         - set_alfa(self, alfa)
#         - __str__(self)
#         - __repr__(self)
#
#
#     - NDigitsManagement(LanguageManagment)
#         - get_n_digits(self)
#         - set_n_digits(self, n_digits)
#         - __str__(self)
#         - __repr__(self)

#     - _change_decimal_separator_x_axis(fig, axes, decimal_separator)
#     - _change_locale(language, decimal_separator=".", local="pt_BR")
#     - _change_locale_back_to_default(default_locale)
#     - _check_blank_space(value, param_name, language)
#     - _check_conflicting_filename(file_name, extension, language)
#     - _check_decimal_separator(decimal_separator, language)
#     - _check_figure_extension(value, param_name, language)
#     - _check_file_exists(file_name)
#     - _check_file_name_is_str(file_name, language)
#     - _check_forbidden_character(value, param_name, language)
#     - _check_plot_design(plot_design, param_name, plot_design_default, plot_design_example, language)
#     - _check_which_density_gaussian_kernal_plot(which, language)
#     - _export_to_csv(df, file_name="my_data", sep=',', language)
#     - _export_to_xlsx(df_list, language, file_name=None, sheet_names=[None,None])
#     - _flat_list_of_lists(my_list, param_name, language)
#     - _raises_when_fit_was_not_applied(func_name, language, name)
#     - _replace_last_occurrence(value, old, new, occurrence)
#     - _sep_checker(sep, language)
#     - _truncate(value, language, decs=None)



#########################################
################ Imports ################
#########################################

###### Standard ######
import locale
import logging
from pathlib import Path
import traceback

###### Third part ######
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

###### Home made ######
from pycafee.database_management import management
from pycafee.utils import general
from pycafee.utils import checkers


###########################################
################ Functions ################
###########################################



# with test, with database, with docstring
[docs]class LanguageManagement: """Instantiates a class for ``language`` management. This class is primarily for internal use. """ def __init__(self, language=None, **kwargs): super().__init__(**kwargs) """Constructs the name of the language Parameters ---------- language : string The abreviation of a language (dafualt None, which means 'en') Notes ----- The method does not allow the input of values that are not of type string and that have lenght higher than 5 (due to the database restrictions) """ all_languages = management._get_all_available_languages() current_default_language = management._get_current_default_language() # Obtendo o idioma padrão # if language is None: self.language = management._get_current_default_language() # Caso queria alterar o valor diretamente ao instanciar a classe else: # verificando se o valor passado é uma string checkers._check_is_str(language, "language", current_default_language) # agora verificando se o valor passado é um idioma válido if language not in all_languages.keys(): all_formated_languages = [f" ---> {lang}" for lang in all_languages] fk_id_function = management._query_func_id("LanguageManagment") messages = management._get_messages(fk_id_function, current_default_language) try: raise ValueError(messages[1][0][0]) except ValueError: msg = [ f"{messages[2][0][0]} '{language}' {messages[2][2][0]}", f"{messages[2][3][0]}", all_formated_languages ] msg = general._flatten_list_of_list_string(msg) msg = list(msg) general._display_n_line_attention(msg) raise else: self.language = language
[docs] def get_language(self): """Returns the current language """ return self.language
[docs] def set_language(self, language): """Changes the current language Parameters ---------- language : ``str`` The language code Notes ----- The ``language`` must be a ``str`` with no more then ``5`` elements. """ all_languages = management._get_all_available_languages() # verificando se o valor passado é uma string checkers._check_is_str(language, "language", self.language) # agora verificando se o valor passado é um idioma válido if language not in all_languages.keys(): all_formated_languages = [f" ---> {lang}" for lang in all_languages] fk_id_function = management._query_func_id("LanguageManagment") messages = management._get_messages(fk_id_function, self.language) try: raise ValueError(messages[1][0][0]) except ValueError: msg = [ f"{messages[2][0][0]} '{language}' {messages[2][2][0]}", f"{messages[2][3][0]}", all_formated_languages ] msg = general._flatten_list_of_list_string(msg) msg = list(msg) general._display_n_line_attention(msg) raise else: self.language = language
def __str__(self): fk_id_function = management._query_func_id("LanguageManagement") messages = management._get_messages(fk_id_function, self.language) return f"{messages[5][0][0]} '{self.language}'" def __repr__(self): return self.language
# with test, with database, with docstring
[docs]class AlphaManagement(LanguageManagement): """Instanciates a class for ``alpha`` managment. This class inherits from :class:`.LanguageManagement` and it is primarily for internal use. """ def __init__(self, alfa=None, **kwargs): super().__init__(**kwargs) """Constructs the significance level value Parameters ---------- alfa : ``float`` The significance level (default is ``None``, which means ``0.05``) Notes ----- This method only allows input of type ``float`` and between ``0.0`` and ``1.0``. """ if alfa is None: self.alfa = 0.05 else: checkers._check_is_float(alfa, "alfa", self.language) checkers._check_data_in_range(alfa, "alfa", 0.0, 1.0, self.language) self.alfa = alfa
[docs] def get_alfa(self): """Returns the current ``alpha`` value """ return self.alfa
[docs] def set_alfa(self, alfa): """Changes the ``alpha`` value Parameters ---------- alfa : ``float`` The new significance level Notes ----- This method only allows input of type ``float`` and between ``0.0`` and ``1.0``. """ checkers._check_is_float(alfa, "alfa", self.language) checkers._check_data_in_range(alfa, "alfa", 0.0, 1.0, self.language) self.alfa = alfa
def __repr__(self): return self.alfa def __str__(self): fk_id_function = management._query_func_id("AlphaManagement") messages = management._get_messages(fk_id_function, self.language) return f"{messages[1][0][0]} '{self.alfa}'"
# with test, with database, with docstring
[docs]class NDigitsManagement(LanguageManagement): """Instanciates a class for ``n_digits`` managment. This class inherits from :class:`.LanguageManagement` and it is primarily for internal use. """ def __init__(self, n_digits=None, **kwargs): super().__init__(**kwargs) """Constructs the n_digits value Parameters ---------- n_digits : ``int`` The maximum number of decimal places that the calculated parameters can have, ``default = 3``. Notes ----- This method only accepts ``int`` values higher than ``0``. """ if n_digits is None: self.n_digits = 3 else: checkers._check_is_integer(n_digits, "n_digits", self.language) checkers._check_is_positive(n_digits, "n_digits", self.language) self.n_digits = n_digits
[docs] def get_n_digits(self): """Returns the ``n_digits`` parameter """ return self.n_digits
[docs] def set_n_digits(self, n_digits): """Sets the ``n_digits`` parameter Parameters ---------- n_digits : ``int`` The maximum number of decimal places to be shown. """ checkers._check_is_integer(n_digits, "n_digits", self.language) checkers._check_is_positive(n_digits, "n_digits", self.language) self.n_digits = n_digits
def __repr__(self): return self.n_digits def __str__(self): fk_id_function = management._query_func_id("NDigitsManagement") messages = management._get_messages(fk_id_function, self.language) return f"{messages[1][0][0]} '{self.n_digits}'"
[docs]class PlotsManagement: """This class just instantiates the default values for ploting and add methods to get/control these default values. It is primarily for internal use. """ def __init__(self, **kwargs): super().__init__(**kwargs) # enviar estes valores para a database e permiter a alteração(?) self.width = 12 self.height = 6 self.export = False self.extension = "png" self.dpi = 100 self.tight = True self.transparent = False self.legend = True self.decimal_separator = "." self.local = "pt_BR" self.legend_label = "data" self.x_label = "data" self.y_label = "data" def _get_default_width(self,width): if width == 'default': width = self.width else: checkers._check_is_float_or_int(width, "width", self.language) return width def _get_default_height(self,height): if height == 'default': height = self.height else: checkers._check_is_float_or_int(height, "height", self.language) return height def _get_default_export(self,export): if export is None: export = self.export else: checkers._check_is_bool(export, "export", self.language) return export def _get_default_extension(self, extension): if extension is None: extension = self.extension else: checkers._check_is_str(extension, "extension", self.language) _check_forbidden_character(extension, "extension", self.language) _check_figure_extension(extension, "extension", self.language) return extension def _get_default_dpi(self,dpi): if dpi is None: dpi = self.dpi else: checkers._check_is_float_or_int(dpi, "dpi", self.language) checkers._check_is_positive(dpi, "dpi", self.language) return dpi def _get_default_tight(self,tight): if tight is None: tight = self.tight else: checkers._check_is_bool(tight, "tight", self.language) return tight def _get_default_transparent(self,transparent): if transparent is None: transparent = self.transparent else: checkers._check_is_bool(transparent, "transparent", self.language) return transparent def _get_default_legend(self,legend): if legend is None: legend = self.legend else: checkers._check_is_bool(legend, "legend", self.language) return legend def _get_default_x_label(self, x_label): if x_label is None: x_label = self.x_label else: checkers._check_is_str(x_label, "x_label", self.language) return x_label def _get_default_y_label(self, y_label): if y_label is None: y_label = self.y_label else: checkers._check_is_str(y_label, "y_label", self.language) return y_label def _get_default_decimal_separator(self, decimal_separator): if decimal_separator is None: decimal_separator = self.decimal_separator else: pass # o controle é feito em outra função return decimal_separator # def _get_default_local(self, local): # if local is None: # local = self.local # else: # pass # o controle é feito em outra função # return local def _get_default_legend_label(self, legend_label): if legend_label is None: legend_label = self.legend_label else: checkers._check_is_str(legend_label, "legend_label", self.language) return legend_label
# with some test, no text, no database, with docstring def _change_decimal_separator_x_axis(fig, axes, decimal_separator): """Esta função altera o separador de casa decimal através da mudança do seu label """ if decimal_separator != ".": new_x_ticks_labels = [] fig.canvas.draw() for text in axes.get_xticklabels(): result = _replace_last_occurrence(text.get_text(), '.', decimal_separator, 1) new_x_ticks_labels.append(result) new_x_ticks = [] for text in axes.get_xticklabels(): result = _replace_last_occurrence(text.get_text(), '.', decimal_separator, 1) new_x_ticks.append(result) axes.set_xticklabels(new_x_ticks_labels) # for text in axes.get_xticklabels(): # temp = text.get_text() return axes else: return axes # with some test, no text, no database, with docstring def _change_decimal_separator_y_axis(fig, axes, decimal_separator): """Esta função altera o separador de casa decimal através da mudança do seu label """ if decimal_separator != ".": new_y_ticks = [] fig.canvas.draw() for text in axes.get_yticklabels(): result = _replace_last_occurrence(text.get_text(), '.', decimal_separator, 1) new_y_ticks.append(result) axes.set_yticklabels(new_y_ticks) for text in axes.get_yticklabels(): temp = text.get_text() return axes else: return axes ## This is current not used due to an issue on google colab ## def _change_locale(language, decimal_separator=".", local="pt_BR"): """This function momentarily changes the decimal separator used in charts. Parameters ---------- decimal_separator : string (default ".") The decimal separator symbol. It can be the dot (default '.') or the comma (','). local : string (default "pt_BR") The alias for the desired locale. Only used if decimal_separator is a comma, setting matplolib's default value. Its only function is to change the decimal separator symbol and should be changed only if the "pt_BR" option is not available. language : ``str`` The language code Notes ----- The parameter 'language' isn't checked if it is a string. Returns ------- default_locale : The user's system default value (string or None) - None if the default values are used - String with the user's system default value, which will be passed to the _change_locale_back_to_default() function to restore the user's default value Notes ----- This function must always be used in conjunction with the _change_locale_back_to_default(default_locale) function. """ # conferindo o local checkers._check_is_str(local, "local", language) # conferindo o decimal_separator checkers._check_is_str(decimal_separator, "decimal_separator", language) current_decimal_separator_available = [".", ","] # querring func_name = "_change_locale" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) if decimal_separator not in current_decimal_separator_available: try: raise ValueError(messages[1][0][0]) except ValueError: general._display_one_line_attention( f"{messages[2][0][0]} 'decimal_separator' {messages[2][2][0]} '{decimal_separator}'", ) raise if decimal_separator == ",": default_locale = locale.getdefaultlocale()[0] try: locale.setlocale(locale.LC_NUMERIC, local) plt.rcParams['axes.formatter.use_locale'] = True except locale.Error: general._display_one_line_attention( f"{messages[3][0][0]} {local} {messages[3][2][0]}" ) # if 'google.colab' in str(get_ipython()): # print('Running on CoLab') # else: # print('Not running on CoLab') raise else: default_locale = None return default_locale ## This is current not used due to an issue on google colab ## # with a test, no text, no database, with docstring def _change_locale_back_to_default(default_locale): """This function restores the local parameter to its default value. Parameters ---------- default_locale : string The default value of locale, which is obtained through the _change_locale() function Notes ----- This function must always be used in conjunction with the _change_locale(decimal_separator=".", local="pt_BR") function. """ if default_locale is not None: locale.setlocale(locale.LC_NUMERIC, default_locale) plt.rcParams['axes.formatter.use_locale'] = False # with tests, with text, with database, with docstring def _check_blank_space(value, param_name, language): """This function checks if a string has white space The function compares the length of 'value' with the length of first element in value.split(). If these lengths are equal, 'value' has no white space. The function does not check if value is a string, and this should be done previously to prevent errors. Parameters ---------- value : string The string to be evaluated param_name : string The param_name language : string The language code Notes ----- The parameter 'param_name' isn't checked if it is a string. The parameter 'language' isn't checked if it is a string. Returns ------- True is value does not have white space Raises ValueError if value has white space """ checkers._check_is_str(value, param_name, language) value_size = len(value) value_split = value.split()[0] value_split_size = len(value_split) if value_size == value_split_size: return True else: func_name = "_check_blank_space" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: raise ValueError(messages[1][0][0]) except ValueError: general._display_one_line_attention( f"{messages[2][0][0]} '{value}' {messages[2][2][0]}", ) raise # with test, with database, with docstring def _check_conflicting_filename(file_name, extension, language): """This function checks if a file exists in the current directory. If it exists, it returns a different name for the file, so as not to overwrite existing files. Paramters --------- file_name : ``str`` The name of the file to be exported, without its extension extension : ``str`` The file extension language : ``str`` The language code Notes ----- The parameter ``file_name`` isn't checked if it is a string. The parameter ``extension`` isn't checked if it is a string. The parameter ``language`` isn't checked if it is a string. If the file_name + extension does not exists in the current directory, the output os file_name + "." + extension If the file_name + extension exists in the current directory, a string ("_n") is inserted at the end od the file_name (where n is a number). Is this is true, the user is wanrned about it. Returns ------- file_name : ``str`` The file name that does not exists in the current directory exitis : ``bool`` Whether the file already exists (``True``) or not (``False``) """ ### Baptism of Fire ### file = file_name + "." + extension # if the file already exists, create a new name for the file file_exists = _check_file_exists(file) if file_exists: exitis = True ### quering ### func_name = "_check_conflicting_filename" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) i = 0 msg_1 = f"{messages[1][0][0]} '{file}' {messages[1][2][0]}" # try to create a new name by adding a number to the end of the name. while file_exists: i += 1 file = file_name + "_" + str(i) + "." + extension file_exists = _check_file_exists(file) file_name = file # warn that the file already exists # warn the user the name of the file to be exported general._display_n_line_warn([ f" {messages[2][0][0]}", msg_1, f"{messages[3][0][0]} '{file_name}'" ]) else: file_name = file exitis = False return exitis, file_name # with tests, with text, with database, with docstring def _check_decimal_separator(decimal_separator, language): """This function checks if decimal_separator is valid Parameters ---------- decimal_separator : ``str`` The value to check if it valied. language : ``str`` The language code Notes ----- The parameter ``param_name`` isn't checked if it is a ``str``. The parameter ``language`` isn't checked if it is a ``str``. The allowed decimal separators are: ".": "dot", ",": "comma", Returns ------- True if decimal_separator is valid. Raises ValueError is decimal_separator is not a valid. """ list_of_allowed = [".", ","] if decimal_separator not in list_of_allowed: ### quering ### func_name = "_check_decimal_separator" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: error = messages[1][0][0] raise ValueError(error) except ValueError: all_formated_characters = [f" ---> '{charcater}'" for charcater in list_of_allowed] msg = [ f"{messages[2][0][0]} '{decimal_separator}' {messages[2][2][0]}", f"{messages[3][0][0]}", all_formated_characters ] flat_list = general._flatten_list_of_list_string(msg) flat_list = list(flat_list) general._display_n_line_attention( flat_list ) raise return True # with test, with text, with database, with docstring def _check_figure_extension(value, param_name, language): """This function checks if 'value' is one of the extensions available for exporting figures using matplotlib. The allowed extensions for matlab version 3.5 are: 'eps' : 'Encapsulated Postscript' 'jpg' : 'Joint Photographic Experts Group' 'jpeg' : 'Joint Photographic Experts Group' 'pdf' : 'Portable Document Format' 'pgf' : 'PGF code for LaTeX' 'png' : 'Portable Network Graphics' 'ps' : 'Postscript' 'raw' : 'Raw RGBA bitmap' 'rgba' : 'Raw RGBA bitmap' 'svg' : 'Scalable Vector Graphics' 'svgz' : 'Scalable Vector Graphics' 'tif' : 'Tagged Image File Format' 'tiff' : 'Tagged Image File Format' However, the options are checked using plt.gcf().canvas.get_supported_filetypes(). Parameters ---------- value : string The value to check if it is a valid extension for figure creation. param_name : string The original name of the parameter passed through the parameter 'value'. language : string The language code Notes ----- The parameter 'param_name' isn't checked if it is a string. The parameter 'language' isn't checked if it is a string. To check the supported extensions on your system, use: >>> from matplotlib import pyplot as plt >>> suported_types = plt.gcf().canvas.get_supported_filetypes() >>> for key, value in suported_types.items(): print(key, ":", value) >>> plt.close() Returns ------- True if 'value' is an allowed extension. Raises ValueError is 'value' is not an allowed extension. """ suported_types = plt.gcf().canvas.get_supported_filetypes() plt.close() # essencial, pois o acima criar uma figura em branco, e caso o código seja ativado vai criar essa fig em branco if value not in suported_types.keys(): ### quering ### func_name = "_check_figure_extension" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: raise ValueError(messages[1][0][0]) except ValueError: extensions_allowed = [] for key, value in suported_types.items(): extensions_allowed.append(f" ---> '{key}': {value}") msg = [ f"{messages[2][0][0]} '{value}' {messages[2][2][0]} '{param_name}' {messages[2][4][0]}!", messages[3][0][0], extensions_allowed ] flat_list = general._flatten_list_of_list_string(msg) flat_list = list(flat_list) general._display_n_line_attention( flat_list ) raise return True # with tests, with no text with no database, with docstring def _check_file_exists(file_name): """This function checks if a file already exists on the current folder Parameters ---------- file_name : string The file name (with extension). Return ------ True if file already exists or False if file does not exists """ file = Path(file_name) if file.exists(): return True else: return False # with tests, with no text with no database, with docstring def _check_file_name_is_str(file_name, language): """This function checks if a variable can be the name of a file, checking if it is of type string and if its size is greater than zero. Parameters ---------- file_name : string language : string The language code Notes ----- The parameter 'language' isn't checked if it is a string. """ if isinstance(file_name, str) == False: ### quering ### func_name = "_check_file_name_is_str" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: raise ValueError(messages[1][0][0]) except ValueError: general._display_one_line_attention( text = f"{messages[2][0][0]} '{str(type(file_name).__name__)}'" ) raise if len(file_name) == 0: func_name = "_check_file_name_is_str" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: raise ValueError(messages[3][0][0]) except ValueError: # "query" general._display_one_line_attention( text = f"{messages[4][0][0]}" ) raise # with tests, with text, with database, with docstring def _check_forbidden_character(value, param_name, language): """This function checks if there are characters that can be problematic for a file name. Parameters ---------- value : string The value to check if it has some espcific characters. param_name : string The original name of the parameter passed through the parameter 'value'. language : string The language code Notes ----- The parameter 'param_name' isn't checked if it is a string. The parameter 'language' isn't checked if it is a string. This function checks if a string contains some characters that can be problematic for saving files. The forbidden characters are: "/": 'forward slash', "<": "less than", ">": "greater than", ":": "colon", "\"": "double quote", "\\": "back slash", "|": "vertical bar", "?": "question mark", "*": "asterisk", ".": "dot", ",": "comma", "[": "left square bracket", "]": "right square bracket", ";": "semicolon", Returns ------- True if value does not have any forbidden. Raises ValueError is value is not a valid string. References ---------- .. [1] https://stackoverflow.com/a/31976060/17872198 .. [2] https://stackoverflow.com/q/1976007/17872198 """ list_of_forbbiden = { "/": 'forward slash', "<": "less than", ">": "greater than", ":": "colon", "\"": "double quote", "\\": "back slash", "|": "vertical bar", "?": "question mark", "*": "asterisk", ".": "dot", ",": "comma", "[": "left square bracket", "]": "right square bracket", ";": "semicolon", } for key in list_of_forbbiden.keys(): if key in value: ### quering ### func_name = "_check_forbidden_character" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: raise ValueError(messages[1][0][0]) except ValueError: list_of_charcater = list(list_of_forbbiden.keys()) all_formated_characters = [f" ---> ' {charcater} '" for charcater in list_of_charcater] msg = [ f"{messages[2][0][0]} '{key}' ({list_of_forbbiden[key]}) {messages[2][2][0]}", f"{messages[3][0][0]}", all_formated_characters ] flat_list = general._flatten_list_of_list_string(msg) flat_list = list(flat_list) general._display_n_line_attention( flat_list ) raise return True # with tests, with text, with database, with docstring def _check_plot_design(plot_design, param_name, plot_design_default, plot_design_example, language): """This function checks if the dictionary passed through the plot_desing parameter is correct. Parameters ---------- plot_design : dict The dictionary to be tested, which is passed by the user param_name : string The name of the parameter being tested plot_design_default : dict A dictionary containing the default values to be compared with the plot_design plot_design_example: dict A dictionary with the same keys as plot_design, but the values are strings that are used as an example. language : string The language code Notes ----- The parameter 'param_name' isn't checked if it is a string. The parameter 'language' isn't checked if it is a string. Returns ------- True if 'plot_design' seems to be corret ValueError if 'plot_design' has something wrong """ # Verificando se plot_design checkers._check_is_dict(plot_design, param_name, language) # lista com as chaves passadas data_keys_list = list(plot_design.keys()) # lista com as chaves necessárias keys_list = list(plot_design_default.keys()) # verificando o dicionário tem as chaves esperadas for chave in keys_list: if chave not in data_keys_list: ### quering ### func_name = "_check_plot_design" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: raise ValueError(messages[1][0][0]) except ValueError: all_formated_keys = [f" ---> '{key}'" for key in keys_list] msg = [ f"{messages[2][0][0]} '{chave}' {messages[2][2][0]}", f"{messages[3][0][0]}", all_formated_keys ] msg = general._flatten_list_of_list_string(msg) msg = list(msg) general._display_n_line_attention(msg) raise # verificando se o número de chaves passadas é correto if len(plot_design.keys()) != len(plot_design_default.keys()): func_name = "_check_plot_design" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: raise ValueError(messages[4][0][0]) except ValueError: all_formated_keys = [f" ---> '{key}'" for key in keys_list] msg = [ f"{messages[5][0][0]} '{len(plot_design_default.keys())}', {messages[5][2][0]} '{len(plot_design.keys())}'.", f"{messages[6][0][0]}", all_formated_keys ] msg = general._flatten_list_of_list_string(msg) msg = list(msg) general._display_n_line_attention(msg) raise # verificando os values # conferindo se todos os values são listas for chave, value in plot_design.items(): func_name = "_check_plot_design" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) if isinstance(value, list) == False: try: raise ValueError(messages[7][0][0]) except ValueError: general._display_one_line_attention( f"{messages[8][0][0]} '{chave}' {messages[8][2][0]} '{type(value).__name__}'" ) raise # verificando o tamanho da lista para cada dict for chave, value in plot_design.items(): if len(plot_design[chave]) != len(plot_design_default[chave]): func_name = "_check_plot_design" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: raise ValueError(messages[9][0][0]) except ValueError: msg = [ f"{messages[10][0][0]} '{chave}' {messages[10][2][0]} {len(plot_design_default[chave])}, {messages[10][4][0]} {len(plot_design[chave])}.", f"{messages[11][0][0]}", f" ---> {plot_design_example[chave]}" ] general._display_n_line_attention(msg) raise # verificando o tipo de cada elemento dentro das listas for (chave, value), (chave_def, value_def) in zip(plot_design.items(), plot_design_default.items()): for i in range(len(value)): func_name = "_check_plot_design" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) if type(value[i]) != type(value_def[i]): try: raise ValueError(messages[12][0][0]) except ValueError: msg = f"{messages[13][0][0]} '{i}' {messages[13][2][0]} '{chave}' {messages[13][4][0]} '{type(value_def[i]).__name__}', {messages[13][6][0]} '{type(value[i]).__name__}'" general._display_one_line_attention( msg ) raise return True # with tests, with text, with database,, with docstring def _check_which_density_gaussian_kernal_plot(which, language): """This function checks if the value passed to the 'which' parameter used to draw the Gaussian density plot is valid. Parameters ---------- which : string A string containing the keys used to draw the kde graph. language : string The language code Notes ----- The parameter 'language' isn't checked if it is a string. Return ------ True if which was considered correct Raise ValueError if it was not considered correct """ which_original = which list_accepted_keys = ["mean", "median", "mode", "all"] # removando espaços em branco which = which.replace(" ", "") # verificando se tem apenas caracteres aceitos list_accepted_letters = ["a", "e", "d", "i", "l", "m", "n", "o", ","] list_which = list(which) for word in list_which: if word not in list_accepted_letters: ### quering ### func_name = "_check_which_density_gaussian_kernal_plot" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: error = messages[1][0][0] raise ValueError(error) except ValueError: msg = [ f"{messages[2][0][0]} '{which}' {messages[2][2][0]}.", f"{messages[3][0][0]}", [f" ---> {chave}" for chave in list_accepted_keys], ] msg = general._flatten_list_of_list_string(msg) msg = list(msg) general._display_n_line_attention(msg) raise which = which.split(",") for value in which: func_name = "_check_which_density_gaussian_kernal_plot" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) if value not in list_accepted_keys: try: error = messages[1][0][0] raise ValueError(error) except ValueError: msg = [ f"{messages[2][0][0]} '{value}' {messages[2][2][0]}.", f"{messages[3][0][0]}", [f" ---> {chave}" for chave in list_accepted_keys], ] msg = general._flatten_list_of_list_string(msg) msg = list(msg) general._display_n_line_attention(msg) raise if "all" in which: func_name = "_check_which_density_gaussian_kernal_plot" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) if len(which) != 1: try: error = messages[4][0][0] raise ValueError(error) except ValueError: general._display_two_line_attention( f"{messages[5][0][0]}", f" ----> '{which_original}'" ) raise return which # with SOME test, with text, with database def _export_to_csv(df, language, file_name="my_data", sep=','): """Export the data to csv file This function is just a wraper around DataFrame.to_csv to export csv files. Parameters ---------- df : pandas.DataFrame The DataFrame with the data to be exported language : string The language code file_name : string The name of the file to be exported, without its extension (default = 'my_data') sep : string of length 1 Field delimiter for the output file (default = ';'). The same parameter of the DataFrame.to_csv pandas method [1]_ Notes ----- The parameter 'language' isn't checked if it is a string. References ---------- .. [1] https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html """ # cheking if the filename is correct _check_file_name_is_str(file_name, language) # checking if a problematic character is present in the filename _check_forbidden_character(file_name, "file_name", language) # adding the '.csv' extension file = file_name + '.csv' # cheking if the sep is valid _sep_checker(sep, language) # cheking if the df is a DataFrame checkers._check_is_data_frame(df, file_name, language) # cheking if the file already exists. If it does, ask the user if wants to replace the file file_exists = _check_file_exists(file) ### querring ### func_name = "_export_to_csv" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) # if the file already exists, create a new name for the file if file_exists: # warn that the file already exists print(f"{messages[1][0][0]} '{file}' {messages[1][2][0]}") i = 0 # try to create a new nine by adding a number to the end of the name. while file_exists: i += 1 file = file_name + "_" + str(i) + ".csv" file_exists = _check_file_exists(file) file_name = file # warn the user the name of the file to be exported print(f" ---> {messages[2][0][0]} '{file_name}'") else: file_name = file_name + '.csv' try: df.to_csv(file_name, encoding='utf-8-sig', index=False, sep=sep) general._display_one_line_success( text = f"{messages[3][0][0]} '{file_name}' {messages[3][2][0]}" ) except PermissionError: # logging.error(traceback.format_exc()) general._display_two_line_attention( text1 = f"{messages[4][0][0]} '{file_name}' {messages[4][2][0]}.", text2 = f"{messages[5][0][0]} '{file_name}' {messages[5][2][0]}" ) raise except FileNotFoundError: # acredito que o problema com subfolder é resolvido com a proibição do / # logging.error(traceback.format_exc()) general._display_two_line_attention( text1 = f"{messages[4][0][0]} '{file_name}' {messages[4][2][0]}.", text2 = f"{messages[6][0][0]}" ) raise return True # with SOME test, with text, with database, with docstring def _export_to_xlsx(df_list, language, file_name=None, sheet_names=[None,None]): """Export the data to .xlsx file This function is just a wraper around DataFrame.to_excel [1]_ to export excel files. Parameters ---------- df_list : list with pandas.DataFrame A list where each element is a DataFrame that will be inserted in a different sheet. The order of DataFrames in this list must match the list of names passed through the sheet_names parameter. language : string The language code file_name : string The name of the file to be exported, without its extension (default = 'my_data') sheetet_names : list (default [None, None]) A list where each element is a string that will be used for each sheet. The order of strings in this list must match the list of DataFrames passed through the df_list parameter. Notes ----- The parameter 'language' isn't checked if it is a string. Returns ------- True if the file is exported ValueError if it was not possible to export the file References ---------- .. [1] https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_excel.html """ checkers._check_is_list(df_list, "df_list", language) for df in df_list: checkers._check_is_data_frame(df, "df", language) if file_name is None: file_name = "sample" else: checkers._check_is_str(file_name, "file_name", language) _check_forbidden_character(file_name, "file_name", language) checkers._check_is_list(sheet_names, "sheet_names", language) for name in sheet_names: checkers._check_is_str(name, "sheet_names", language) ### querring ### func_name = "_export_to_excel" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) # combando nome corretamente file_name = file_name + ".xlsx" # verificando se os dataframes são validos for df in df_list: checkers._check_is_data_frame(df, "df_list", language) ### verificando se o arquivo .xlsx já existe if _check_file_exists(file_name): ## caso exista, obter uma lista com o nome das abas do arquivo # obter os sheet names arquivo = pd.ExcelFile(file_name, engine="openpyxl") # iterar esta lista comparando se os sheet_names já existem nela sheet_alredy_exists = [] # lista vazia para acumular nomes repetidos for sheet in arquivo.sheet_names: # olhando nome por nome dentro de sheet_names if sheet in sheet_names: sheet_alredy_exists.append(sheet) # apendadndo else: pass # caso pelo menos 1 aba já exista, avisar que o nome escolhido será alterado if len(sheet_alredy_exists) > 0: lista_sheet_names = [f" ---> '{sheet}'" for sheet in arquivo.sheet_names] sheet_alredy_exists = [f" ---> '{sheet}'" for sheet in sheet_alredy_exists] msg = [ f"{messages[1][0][0]} '{file_name}' {messages[1][2][0]}", lista_sheet_names, f"{messages[2][0][0]}", sheet_alredy_exists, "\n", f"{messages[3][0][0]}", f"{messages[4][0][0]}", ] msg = general._flatten_list_of_list_string(msg) msg = list(msg) general._display_n_line_attention(msg) arquivo.close() else: pass # é pass pois caso o sheet name já exista, é apenas para avisar que o nome será alterado. É apenas um aviso # caso não tenha nenhum nome conflitante, inserir novas abas no arquivo fornecido try: with pd.ExcelWriter(file_name, mode="a", if_sheet_exists="new") as writer: for i in range(len(df_list)): df_list[i].to_excel(writer, sheet_name=sheet_names[i], index=False, engine="openpyxl") general._display_one_line_success(f"{messages[5][0][0]} '{file_name}' {messages[5][2][0]}") except PermissionError: general._display_two_line_attention( text1 = f"{messages[6][0][0]} '{file_name}' {messages[6][2][0]}", text2 = f"{messages[7][0][0]} '{file_name}' {messages[7][2][0]}" ) raise except FileNotFoundError: # acredito que o problema com subfolder é resolvido com a proibição do / # logging.error(traceback.format_exc()) general._display_two_line_attention( text1 = f"{messages[6][0][0]} '{file_name}' {messages[6][2][0]}", text2 = f"{messages[8][0][0]}" ) raise else: ## caso não exista, criar o arquivo e exportar try: with pd.ExcelWriter(file_name) as writer: for i in range(len(df_list)): df_list[i].to_excel(writer, sheet_name=sheet_names[i], index=False, engine="openpyxl") general._display_one_line_success(f"{messages[5][0][0]} '{file_name}' {messages[5][2][0]}") except PermissionError: general._display_two_line_attention( text1 = f"{messages[6][0][0]} '{file_name}' {messages[6][2][0]}", text2 = f"{messages[7][0][0]} '{file_name}' {messages[7][2][0]}" ) raise except FileNotFoundError: # acredito que o problema com subfolder é resolvido com a proibição do / # logging.error(traceback.format_exc()) general._display_two_line_attention( text1 = f"{messages[6][0][0]} '{file_name}' {messages[6][2][0]}", text2 = f"{messages[8][0][0]}" ) raise return True # with some test, with text, with database def _flat_list_of_lists(my_list, param_name, language): """This function flats a list of lists Parameters ---------- my_list : list of lists The list with lists to be flattened. All inner elements must be a list param_name : string The original name of the parameter passed through the parameter 'my_list'. Notes ----- The parameter 'param_name' isn't checked if it is a string. The parameter 'my_list' isn't checked if it is a list. Returns ------- A flattened list ValueError if 'my_list' does not contain lists in all its elements. """ checkers._check_is_list(my_list, param_name, language) ### quering ### func_name = "_flat_list_of_lists" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) if all(isinstance(element, list) for element in my_list) == False: try: raise ValueError(messages[1][0][0]) except ValueError: # "query" general._display_one_line_attention( text = f"{messages[2][0][0]} {param_name} {messages[2][2][0]}" ) raise return [item for sublist in my_list for item in sublist] # wtih tests, with text, the database is stored on func_name, with docstring def _raises_when_fit_was_not_applied(func_name, language, name): """This function raises error when called Parameters ---------- func_name : ``str`` The name of the function sabed on the database language : ``str`` The language code name : ``str`` The sample name Notes ----- The parameter ``language`` isn't checked if it is a string. The parameter ``name`` isn't checked if it is a string. Returns ------- ``ValueError`` Notes ----- This function must always be used in conjunction with a fit function, where error and messages are at key 1 and 2. """ fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) try: error = messages[1][0][0] raise ValueError(error) except ValueError: general._display_one_line_attention( f"{messages[2][0][0]} {name}", ) raise # with some test, no text, no database, with docstring def _replace_last_occurrence(value, old, new, occurrence): """This function replaces the last ``occurrence`` of ``old`` in ``value`` with the value passed in ``new`` Parameters ---------- value : ``str`` The text to be changed old : ``str`` The character(s) to be replaced new : ``str`` The new characters occurrence : ``int`` The number of occurrences that will be replaced Returns ------- value : ``str`` The changed text References ---------- .. [1] Adapted from mg. rreplace - How to replace the last occurrence of an expression in a string?. Available at: `stackoverflow.com <https://stackoverflow.com/a/2556252/17872198>`_. Access on: 10 May. 2022. """ li = value.rsplit(old, occurrence) return new.join(li) # with tests, with text, with database, with docstring def _sep_checker(sep, language): """This function checks if a value could be used as 'sep' parameter for pandas to_csv function Parameters ---------- sep : string The sep value language : string The language code Notes ----- The parameter 'language' isn't checked if it is a string. Returns ------- True if sep is valid. Raises ValueError is sep is not suitable to be used in pd.to_csv. """ checkers._check_is_str(sep, "sep", language) ### quering ### func_name = "_sep_checker" fk_id_function = management._query_func_id(func_name) messages = management._get_messages(fk_id_function, language, func_name) if len(sep) != 1: try: raise ValueError(messages[1][0][0]) #message except ValueError: general._display_two_line_attention( text1 = f"{messages[2][0][0]} 'sep' {messages[2][2][0]} '{len(sep)}' <--- ({sep})", text2 = f' {messages[3][0][0]}: ---> ";" ' ) raise return True # with tests, without database, with docstring def _truncate(value, language, decs=None): """This function truncates a 'value' with 'decs' decimal places. This function is a wrapper around numpy.trunc() [1]_ adapted with a clever solution for the truncation of decimal places [2]_. Parameters ---------- value : int or float The value to be truncated decs : int or None (default = None) The number of decimal places the value should be truncated language : string The language code Notes ----- The parameter 'language' isn't checked if it is a string. Returns ------- value if value or decs is None, just return the input value elif value is integer, just return the input value else return the value truncated References ---------- .. [1] https://numpy.org/doc/stable/reference/generated/numpy.trunc.html .. [2] The inspiration came from: https://stackoverflow.com/a/46020635/17872198 Examples -------- >>> from easy_stat.utils.helpers import _truncate >>> print(_truncate(0.111, 'en', decs=0)) 0.0 >>> print(_truncate(0.111, 'en', decs=1)) 0.1 >>> print(_truncate(0.111, 'en', decs=2)) 0.11 >>> print(_truncate(0.111, 'en', decs=10)) 0.111 >>> print(_truncate(0.111, 'en', decs=None)) 0.111 >>> print(_truncate(10, 'en', decs=2)) 10 >>> print(_truncate(10, 'en', decs=None)) 10 """ if decs is None or value is None: return value else: checkers._check_is_integer(decs, "decs", language) checkers._check_is_float_or_int(value, "value", language) if isinstance(value, (int, np.uint, np.integer)): return value else: return np.trunc(value*10**decs)/(10**decs) # Death, death, death, death, death, death, death, death, death, Death, death, death https://youtu.be/jRc9dbgiBPI?t=334