wolfhece.PyParams ================= .. py:module:: wolfhece.PyParams .. autoapi-nested-parse:: Author: HECE - University of Liege, Pierre Archambeau Date: 2024 Copyright (c) 2024 University of Liege. All rights reserved. This script and its content are protected by copyright law. Unauthorized copying or distribution of this file, via any medium, is strictly prohibited. Module Contents --------------- .. py:data:: _ .. py:data:: PARAM_TRUE :value: '.True.' .. py:data:: PARAM_FALSE :value: '.False.' .. py:data:: PREFIX_DEFAULT :value: 'def' .. py:class:: Type_Param(*args, **kwds) Bases: :py:obj:`enum.Enum` .. autoapi-inheritance-diagram:: wolfhece.PyParams.Type_Param :parts: 1 :private-bases: Enum to define the type of a parameter Strings are also used by Fortran Code -- modify with care .. py:attribute:: Integer_or_Float :value: 'Integer_or_Float' .. py:attribute:: Integer :value: 'Integer' .. py:attribute:: Logical :value: 'Logical' .. py:attribute:: Float :value: 'Float' .. py:attribute:: File :value: 'File' .. py:attribute:: Directory :value: 'Directory' .. py:attribute:: Color :value: 'Color' .. py:attribute:: Fontname :value: 'Fontname' .. py:attribute:: String :value: 'String' .. py:attribute:: Empty :value: '' .. py:attribute:: Double :value: 'Double' .. py:attribute:: Real :value: 'Real' .. py:class:: key_Param(*args, **kwds) Bases: :py:obj:`enum.Enum` .. autoapi-inheritance-diagram:: wolfhece.PyParams.key_Param :parts: 1 :private-bases: Enum to define the keys of a parameter .. py:attribute:: NAME :value: 'name' .. py:attribute:: TYPE :value: 'type' .. py:attribute:: VALUE :value: 'value' .. py:attribute:: COMMENT :value: 'comment' .. py:attribute:: ADDED_JSON :value: 'added_json' .. py:class:: Buttons(*args, **kwds) Bases: :py:obj:`enum.Enum` .. autoapi-inheritance-diagram:: wolfhece.PyParams.Buttons :parts: 1 :private-bases: Enum to define the buttons .. py:attribute:: Load :value: 'Load' .. py:attribute:: Save :value: 'Save' .. py:attribute:: Apply :value: 'Apply' .. py:attribute:: Reload :value: 'Reload' .. py:function:: new_json(values: dict = None, fullcomment: str = '') -> dict Create a new JSON string from values and fullcomment :param values : values to store in the JSON string - dict of key:value - value must be integer :param fullcomment : full comment to store in the JSON string - str - can be multiline with .. py:function:: new_infos_incr(groupname: str = None, paramname: str = 'nb', min: int = 1, max: int = 100) -> tuple[str] Create a new string for an incrementable group or parameter :param groupname : name of the reference group (optional) -- if ommitted, the reference group is in the same group as the parameter :param paramname : name of the reference parameter :param min : minimum value :param max : maximum value .. py:function:: search_type(chain: str) -> Type_Param recherche du typage dans une chaîne de caractères .. py:class:: Wolf_Param(parent: wx.Window = None, title: str = 'Default Title', w: int = 500, h: int = 800, ontop: bool = False, to_read: bool = True, filename: str = '', withbuttons: bool = True, DestroyAtClosing: bool = True, toShow: bool = True, init_GUI: bool = True, force_even_if_same_default: bool = False, toolbar: bool = True) Bases: :py:obj:`wx.Frame` .. autoapi-inheritance-diagram:: wolfhece.PyParams.Wolf_Param :parts: 1 :private-bases: **FR** Gestion des paramètres au format WOLF. **Fichier texte** Les fichiers '.param' sont des fichiers texte contenant des paramètres de type nom=valeur et compatibles avec les codes Fortran. L'extension '.param.default' est utilisée pour stocker les paramètres par défaut. Une autre extension est possible mais un fichier '.default' sera créé automatiquement si ce fichier n'existe pas. Le séparateur (nom, valeur, commentaire) est la tabulation ' '. Aucun autre caractère ne doit être utilisé comme séparateur. Les groupes sont définis par un nom suivi de ':'. Cela signifie que ':' ne peut pas être utilisé dans un nom de paramètre. Les lignes débutant par '%' sont des commentaires. Il est possible d'ajouter du code JSON dans un commentaire. Pour cela, il faut ajouter '%json' au début de la ligne suivi d'un dictionnaire (e.g. %json{"Values":{'key1':1, 'key2':2}, "Full_Comment":"fullcomment"} ). **Organisation Python** L'objet Python est basé sur des dictionnaires Python. Un dictionnaire par groupe de paramètres. Les paramètres sont donc stockés dans un dictionnaire de dictionnaires. Le premier niveau est le nom du groupe, le second niveau est le nom du paramètre. Les paramètres disposent des clés suivantes : - name : nom du paramètre (str) - type : type du paramètre (str) -- see Type_Param - value : valeur du paramètre (str) -- peut être converti dynamiquement en int, float, bool, str, ... sur base du type - comment : commentaire du paramètre (str) -- helpful to understand the parameter - added_json : dictionnaire contenant des informations supplémentaires (optionnel) -- permet de stocker des informations supplémentaires sur le paramètre (ex : valeurs possibles, commentaires étendus, ...) **Dictionnaires** Il existe un dictionnaire de valeurs par défaut "myparams_default". Pour l'interaction Python-Fortran, c'est le Fortran qui écrit ces paramètres. Il existe un dictionnaire de paramètres actifs "myparams". Il est utilisé pour stocker les paramètres modifiés par l'utilisateur. Normalement, seuls les paramètres modifiés par l'utilisateur sont stockés dans ce dictionnaire et sont écrits sur disque. **Groupe/Paramètre incrémentable** Il est également possible de définir des groupes ou des paramètres incrémentables. Pour cela, dans le nom du groupe/paramètre, il faut ajouter, à l'emplacement souhaité du **numéro** du groupe/paramètre, des informations entre '$...$' : - groupname : nom du groupe (uniquement pour groupe incrémentable) - paramname : nom du paramètre contenant le nombre de groupe/paramètre - min : valeur minimale - max : valeur maximale Le nombre de groupes est ainsi défini par le couple (key:value) = (groupname:paramname). Le nombre de groupes doit donc être logiquement positionné dans un groupe distinct. Le nombre de paramètres est ainsi défini par le paramètre "paramname" qui est attendu dans le groupe contenant le paramètre incrémentable. Le nombre de groupes/paramètres est un entier compris entre 'min' et 'max'. Les informations génériques sont stockées dans les dictionnaires "myIncGroup" et "myIncParam". **UI** Une interface graphique est disponible pour modifier les paramètres. Elle est basée sur "wxPython" et la classe "wxPropertyGrid". L'attribut wx_exists permet de savoir si wxPython est en cours d'excution ou non. **Accès aux données** Les paramètres sont accessibles via la procédure __getitem__ en fournissant un tuple (groupname, paramname). Il est possible de modifier un paramètre via la procédure __setitem__. Il est possible : - d'ajoutrer un groupe via la procédure add_group. Pour un groupe incrémentabe, le nom doit contenir les infos génériques entre '$...$'. - d'ajouter un paramètre ou un paramètre incrémentable via la procédure addparam : - pour un paramètre classique en choisissant le dictionnaire cible ['All', 'Default', 'Active', 'IncGroup', ''] - '' == 'Active' - 'All' == 'Default' + 'Active' - 'IncGroup' pour ajouter un paramètre au template du groupe incrémentable --> sera dupliqué lors de la MAJ du nompbre réel de groupes - pour un paramètre incrémentable, en fournissant les données nécessaires dans une chaîne $n(refname,min,max)$ ou $n(groupname,refname,min,max)$ - si le groupe visé n'existe pas, il sera créé si toutes les infos sont disponibles. - d'ajouter seulement un paramètre incrémentable via la procédure add_IncParam. **EN** Management of parameters in WOLF format. **Text File** '.param' files are text files containing parameters in the name=value format and compatible with Fortran codes. The '.param.default' extension is used to store default parameters. Another extension is possible, but a '.default' file will be automatically created if this file does not exist. The separator (name, value, comment) is the tab character ' '. No other character should be used as a separator. Groups are defined by a name followed by ':'. This means that ':' cannot be used in a parameter name. Lines starting with '%' are comments. It is possible to add JSON code in a comment. To do this, add '%json' at the beginning of the line followed by a dictionary (e.g., %json{"Values":{'key1':1, 'key2':2}, "Full_Comment":"fullcomment"}). **Python Organization** The Python object is based on Python dictionaries. One dictionary per parameter group. Therefore, parameters are stored in a dictionary of dictionaries. The first level is the group name, and the second level is the parameter name. Parameters have the following keys: - name: parameter name (str) - type: parameter type (str) -- see Type_Param - value: parameter value (str) -- can be dynamically converted to int, float, bool, str, ... based on the type - comment: parameter comment (str) -- helpful to understand the parameter - added_json: dictionary containing additional information (optional) -- used to store additional information about the parameter (e.g., possible values, extended comments, ...) **Dictionaries** There is a default values dictionary "myparams_default." For Python-Fortran interaction, Fortran writes these parameters. There is an active parameters dictionary "myparams." It is used to store parameters modified by the user. Normally, only parameters modified by the user are stored in this dictionary and written to disk. **Incrementable Group/Parameter** It is also possible to define incrementable groups or parameters. To do this, in the group/parameter name, add information between '$...$' at the desired **number** location of the group/parameter: - groupname: group name (only for incrementable group) - paramname: parameter name containing the group/parameter number - min: minimum value - max: maximum value The number of groups is defined by the (key:value) pair (groupname:paramname). The number of groups must logically be positioned in a distinct group. The number of parameters is defined by the "paramname" parameter expected in the group containing the incrementable parameter. The number of groups/parameters is an integer between 'min' and 'max'. Generic information is stored in the "myIncGroup" and "myIncParam" dictionaries. **UI** A graphical interface is available to modify parameters. It is based on "wxPython" and the "wxPropertyGrid" class. The wx_exists attribute indicates whether wxPython is currently running or not. **Data Access** Parameters are accessible via the __getitem__ method by providing a tuple (groupname, paramname). It is possible to modify a parameter via the __setitem__ method. It is possible to: - add a group via the add_group method. For an incrementable group, the name must contain generic information between '$...$'. - add a parameter or an incrementable parameter via the addparam method: - for a regular parameter by choosing the target dictionary ['All', 'Default', 'Active', 'IncGroup', ''] - '' == 'Active' - 'All' == 'Default' + 'Active' - 'IncGroup' to add a parameter to the template of the incrementable group --> will be duplicated when updating the actual number of groups - for an incrementable parameter, by providing the necessary data in a string $n(refname,min,max)$ or $n(groupname,refname,min,max)$ - if the targeted group does not exist, it will be created if all information is available. - only add an incrementable parameter via the add_IncParam method. .. py:attribute:: filename :type: str .. py:attribute:: myparams :type: dict[str, dict] .. py:attribute:: myparams_default :type: dict[str, dict] .. py:attribute:: myIncGroup :type: dict .. py:attribute:: myIncParam :type: dict .. py:attribute:: prop :type: wx.propgrid.PropertyGridManager .. py:attribute:: wx_exists :type: bool .. py:attribute:: update_incr_at_every_change :value: True .. py:attribute:: _callback :type: function :value: None .. py:attribute:: _callbackdestroy :type: function :value: None .. py:attribute:: show_in_active_if_default :value: False .. py:attribute:: sizer :value: None .. py:property:: has_prop :type: bool Return True if the property grid is available .. py:property:: has_gui :type: bool Return True if the own GUI is available .. py:method:: ensure_prop(wxparent=None, show_in_active_if_default: bool = False, height: int = 600) Ensure that the property grid is available .. py:method:: ensure_gui(title: str = 'Default Title', w: int = 500, h: int = 800, ontop: bool = False, to_read: bool = True, withbuttons: bool = True, DestroyAtClosing: bool = True, toShow: bool = True, full_style: bool = False) Ensure that the GUI is available .. py:method:: copy() Return a deep copy of the object .. py:method:: is_like(other: Wolf_Param) -> bool Test if the object is like another object .. py:method:: diff(other: Wolf_Param, exclude_incremental: bool = False) -> dict Return the differences between two objects .. py:method:: set_callbacks(callback_update, callback_destroy) Set the callbacks for the update and destroy events .. py:method:: get_nb_groups() -> tuple[int, int] Return the number of groups in active and default parameters .. py:method:: get_nb_params(group: str) -> tuple[int, int] Return the number of parameters in a group in active and default parameters .. py:method:: get_nb_inc_params() -> int Return the number of incrementable parameters .. py:method:: get_nb_inc_groups() -> int Return the number of incrementable groups .. py:method:: get_group_keys() -> list[str] Return the keys of the active parameters .. py:method:: get_default_group_keys() -> list[str] Return the keys of the default parameters .. py:method:: get_param_keys(group: str) -> list[str] Return the keys of the active parameters .. py:property:: callback Return the callback function .. py:property:: callbackdestroy Return the callback function .. py:method:: _set_gui(parent: wx.Window = None, title: str = 'Default Title', w: int = 500, h: int = 800, ontop: bool = False, to_read: bool = True, withbuttons: bool = True, DestroyAtClosing: bool = True, toShow: bool = True, full_style=False, toolbar: bool = True) Set the GUI if wxPython is running Gui is based on wxPropertyGridManager. On the left, there is a group of buttons to load, save, apply or reload the parameters. On the right, there is the wxPropertyGridManager for the default and active parameters. Active parameters are displayed in bold. To activate a parameter, double-click on it in the default tab. It will be copied to the active tab and the value will be modifiable. :param parent : parent frame :param title : title of the frame :param w : width of the frame :param h : height of the frame :param ontop : if True, the frame will be on top of all other windows :param to_read : if True, the file will be read :param withbuttons : if True, buttons will be displayed :param DestroyAtClosing : if True, the frame will be destroyed when closed :param toShow : if True, the frame will be displayed :param full_style : if True, the full style of the PropertyGridManager will be displayed even if ontop is True .. py:method:: _set_only_prop(wxparent) Set only the property grid .. py:method:: hide_selected_buttons(to_hide: list[Buttons] = [Buttons.Load, Buttons.Save, Buttons.Reload]) Mask selected buttons - Default conserve only 'Apply change' .. py:method:: OnDblClick(event: wx.MouseEvent) Double-click event handler to add a parameter to the active tab or reset to default value. Gestion du double-click pour ajouter des éléments ou remise à valeur par défaut. .. py:method:: OnClose(event: wx.MouseEvent) Close event of the frame .. py:method:: SavetoFile(event: wx.MouseEvent) sauvegarde dans le fichier texte .. py:method:: Save(filename: str = '') Save the parameters in a file .. py:method:: Reload(event: wx.MouseEvent) relecture du fichier sur base du nom déjà connu .. py:method:: LoadFromFile(event: wx.MouseEvent) Load parameters from file .. py:method:: _get_prop_names(page: wx.propgrid.PropertyGridPage) -> list[str] Return the names of the properties in a page .. py:method:: _is_in_propperty_page(page: wx.propgrid.PropertyGridPage, group: str, param: str = '') -> bool Test if a parameter is in a page .. py:method:: ApplytoMemory(event: wx.MouseEvent) Transfert des données en mémoire --> remplissage des dictionnaires .. py:property:: page_active :type: wx.propgrid.PropertyGridPage Return the active page .. py:property:: page_default :type: wx.propgrid.PropertyGridPage Return the default page .. py:method:: _Apply1ParamtoMemory(group: str, param_name: str, isIncrementable: bool = False, genGroup: str = '', genParam: str = '') Routine interne de MAJ d'un paramètre :param group : nom du groupe :param param_name : nom du paramètre :param isIncrementable : True si le paramètre est incrémentable :param genGroup : generic name of an incrementable group :param genParam : generic name of an incrementable param .. py:method:: position(position) Position the frame .. py:method:: Populate(sorted_groups: bool = False) Filling the property management object based on dictionaries Use default AND active parameters Useful only if wxPython is running .. py:method:: _insert_elem_to_page(page: wx.propgrid.PropertyGridPage, group: str, param: dict, param_def: dict = None, prefix: str = '') Insert an element to a page .. py:method:: _insert_with_type_based_on_value(page: wx.propgrid.PropertyGridPage, group: str, param: dict, prefix: str = '') .. py:method:: _add_with_type_based_on_value(page: wx.propgrid.PropertyGridPage, group: str, param: dict, prefix: str = '') .. py:method:: _add_elem_to_page(page: wx.propgrid.PropertyGridPage, group: str, param: dict, param_def: dict = None, prefix: str = '') Add an element to a page .. py:method:: PopulateOnePage() Filling the property management object based on dictionaries Use ONLY active parameters Useful only if wxPython is running -- e.g. class "PyDraw" .. py:method:: check_default_file(filename: str) Check if a default file exists .. py:method:: ReadFile(*args) Lecture d'un fichier .param et remplissage des dictionnaires myparams et myparams_default .. py:method:: fill_from_strings(chain: str, chaindefault: str = None) Fill the dictionaries from a string .. py:method:: ParseFile(myparamsline: list[str], todict: dict) Parsing the file to find groups and parameters and filling a dictionary Each parameter is stored in a dictionary associated to the upper group. 'add_group' is used to add a group in the dictionary 'todict'. 'groupname' will be there sanitized (strip, decoded if iteratable...) to be used in '_add_param_from_str'. myparamsline format: ['groupname1:', 'param1', 'param2', 'groupname2:', 'param1', ...] .. py:method:: _CreateDefaultFile() Create a default file .. py:method:: _Extract_IncrInfo(nameStr: str) -> tuple[str, list[str, str, int, int]] Extract the information of an incrementable group or param The name of an incrementable group or param is of the form: $n(group, param, min, max)$ .. py:method:: apply_changes_to_memory(verbosity: bool = True) Transfert des données en mémoire sans wx --> remplissage des dictionnaires .. py:method:: save_automatically_to_file() Sauvegarde dans le fichier texte sans wx.Event FIXME weird message caused by the dialog box in log messages. .. py:method:: Clear() Clear all the parameters .. py:method:: add_group(groupname: str, todict: dict = None) -> tuple[str, dict] Add a group in the dictionary 'todict' if provided or in the IncGroup dictionary return sanitized groupname and dictionnary attached to the group .. py:method:: _add_param_in_dict(group: dict, name: str, value: Union[float, int, str] = '', type: Type_Param = None, comment: str = '', jsonstr: str = None) -> dict .. py:method:: _new_IncParam_dict(groupname, refgroupname, refparamname, min_value, max_value) -> dict Create a new dictionary for an incrementable parameter .. py:method:: _add_param_from_str(param: str, groupname: str, groupdict: dict, seperator: str = '\t') Add a parameter from a complex string .. py:method:: addparam(groupname: str = '', name: str = '', value: Union[float, int, str] = '', type: Type_Param = None, comment: str = '', jsonstr: str = None, whichdict: Literal['All', 'Default', 'Active', 'IncGroup', ''] = '') Add or update a parameter :param groupname : groupe in which the new param will be strored - If it does not exist, it will be created :param name : param's name - If it does not exist, it will be created :param value : param'a value :param type : type -> will influence the GUI :param comment : param's comment -- helpful to understand the parameter :param jsonstr : string containing JSON data -- used in GUI param whichdict : where to store the param -- Default, Active or All, or IncGroup if the param is part of an incrementable group jsonstr can be a dict i.e. '{"Values":{choice1:1, choice2:2, choice3:3}, "Full_Comment":'Yeah baby !'}' Return 0 if OK, -1 if the group is incrementable and not created, -2 if the group does not exist .. py:method:: add_param(groupname: str = '', name: str = '', value: Union[float, int, str] = '', type: Type_Param = None, comment: str = '', jsonstr: str = None, whichdict: Literal['All', 'Default', 'Active', 'IncGroup', ''] = '') alias of addparam .. py:method:: is_in_active(group: str, name: str = None) -> bool Return True if the parameter is in the active parameters .. py:method:: is_in_default(group: str, name: str = None) -> bool Return True if the parameter is in the default parameters .. py:method:: is_in(group: str, name: str = None, whichdict: Literal['All', 'Default', 'Active', 'IncGroup', ''] = 'Active') -> bool Return True if the parameter is in the whichdict parameters .. py:method:: get_param_dict(group: str, name: str) -> dict[str, Union[str, int, float, bool, tuple[int, int, int]]] Returns the parameter dict if found, otherwise None obj .. py:method:: get_type(group: str, name: str) -> Type_Param Returns the type of the parameter if found, otherwise None obj .. py:method:: value_as_type(value, type, bool_as_int: bool = False, color_as: Union[int, str, float] = int) Convert the value to the right type .. py:method:: get_param(group: str, name: str, default_value=None) Returns the value of the parameter if found, otherwise None obj used in __getitem__ .. py:method:: _get_param_def(group: str, name: str, default_value=None) Returns the default value of the parameter if found, otherwise None obj .. py:method:: get_group(group: str) -> dict Return the group dictionnary if found, otherwise None obj Check the active parameters first, then the default parameters Used in __getitem__ .. py:method:: get_help(group: str, name: str) -> list[str, str] Return the help string if found, otherwise None obj :return: [comment, full_comment] .. py:method:: get_json_values(group: str, name: str) -> dict Return the 'values' in json string if found, otherwise None obj .. py:method:: _detect_type_from_value(value: Union[float, int, str, bool, tuple[int, int, int]]) -> Type_Param Detect the type from the value .. py:method:: change_param(group: str, name: str, value: Union[float, int, str, bool]) Modify the value of the parameter if found, otherwise None obj .. py:method:: update_incremental_groups_params(update_groups=True, update_params=True) Update the incremental groups and parameters .. py:method:: isIncrementable_group(group: Union[str, dict]) -> bool Return True if the group is incrementable .. py:method:: isIncrementable_param(param: Union[str, dict]) -> bool Return True if the group is incrementable .. py:method:: add_IncGroup(group: str, min: int, max: int, refGroup: str, refParam: str) .. py:method:: _update_IncGroup(withGUI: bool = False) Mise à jour des groupes inctrémmentables: Les groupes existants dans les paramètres courants seront sauvés dans le dicionnaire myIncGroup avec son incrément associé. Tout groupe sauvé avec le même incrément sera écrasé. Si le nombre associé au groupe est plus grand que désiré, tous les groupes en surplus seront sauvés dans dans le dicionnaire myIncGroup mais supprimé du dictionnaire de paramètre courant. S'il n'y a pas assez de groupe dans les paramètres courant, on les ajoute avec les valeurs sauvées, sinon avec des valeurs par défaut. Also check the max and min values .. py:method:: add_IncParam(group: str, name: str, value: Union[float, int, str], comment: str, type: Type_Param, min: int = 0, max: int = 0, refParam: str = None, refGroup: str = None, added_json: str = None) Ajout d'un paramètre incrémentable :param group: nom du groupe :param name: nom du paramètre :param value: valeur du paramètre :param comment: commentaire du paramètre :param type: type du paramètre :param min: valeur minimale :param max: valeur maximale :param refParam: nom du paramètre contenant le nombre de paramètres - doit être dans le même groupe .. py:method:: _update_IncParam(withGUI: bool = False) Mise à jour des paramètres inctrémmentables: Les paramètres existants dans les paramètres courants seront sauvés dans le dicionnaire myIncParam avec son incrément associé. Tout groupe sauvé avec le même incrément sera écrasé. Si le nombre associé au groupe est plus grand que désiré, tous les groupe en surplus seront sauvé dans dans le dicionnaire myIncParam mais supprimé du dictionnaire de paramètre courant. S'il n'y a pas assez de groupe dans les paramètres courant, on les ajoute avec les valeurs sauvées, sinon avec des valeurs par défaut. Also check the max and min values .. py:method:: _Update_OneIncParam(curIncParam: str, curGroup: str, genGroup: str, withGUI: bool = False) Routine interne de mise à jour d'un seul paramétre incrémentable :param curIncParam : nom du paramètre incrémentable - contient $n$ à remplacer par le numéro :param curGroup : nom du groupe de référence - ! peut être un groupe icrémentable ! :param genGroup : nom du groupe générique dans lequel sont stockés les informations sur le paramètre (key, value, min, max, ...) :param withGUI : True si on est en mode GUI .. py:data:: test