From 0c91ea777e2faff2f28f67c4ce60716fe88de940 Mon Sep 17 00:00:00 2001 From: Grigori Fursin Date: Tue, 23 Apr 2024 19:19:05 +0200 Subject: [PATCH 1/3] - added utils.compare_versions to check min version requirements for automations and entries - removed outdated convert_path (https://github.com/mlcommons/ck/issues/1219) --- cm/CHANGES.md | 3 + cm/cmind/utils.py | 77 ++++++++++++++++++- cm/docs/KB/ML.md | 1 - cm/docs/KB/MLOps.md | 1 - cm/docs/README.md | 1 - cm/docs/architecture.md | 1 - cm/docs/conventions.md | 1 - cm/docs/enhancements.md | 55 ------------- .../example-modular-image-classification.md | 1 - cm/docs/installation.md | 1 - cm/docs/motivation.md | 1 - cm/docs/specification.md | 1 - cm/docs/tutorial-concept.md | 1 - cm/docs/tutorial-modular-mlperf.md | 1 - cm/docs/tutorial-scripts.md | 1 - cm/setup.py | 2 +- 16 files changed, 79 insertions(+), 70 deletions(-) delete mode 100644 cm/docs/KB/ML.md delete mode 100644 cm/docs/KB/MLOps.md delete mode 100644 cm/docs/README.md delete mode 100644 cm/docs/architecture.md delete mode 100644 cm/docs/conventions.md delete mode 100644 cm/docs/enhancements.md delete mode 100644 cm/docs/example-modular-image-classification.md delete mode 100644 cm/docs/installation.md delete mode 100644 cm/docs/motivation.md delete mode 100644 cm/docs/specification.md delete mode 100644 cm/docs/tutorial-concept.md delete mode 100644 cm/docs/tutorial-modular-mlperf.md delete mode 100644 cm/docs/tutorial-scripts.md diff --git a/cm/CHANGES.md b/cm/CHANGES.md index e24b5070f1..90de8bc108 100644 --- a/cm/CHANGES.md +++ b/cm/CHANGES.md @@ -3,6 +3,9 @@ - added "cmind.utils.debug_here" function to attach remote Python debugger and tested with Visual Studio Code. - added test to avoid checking out CM repo that was not pulled + - added utils.safe_load_json to return empty dict if file doesn't exist + - added utils.compare_versions to check min version requirements for automations and entries + - removed outdated convert_path (https://github.com/mlcommons/ck/issues/1219) ## V2.1.2 - added support for deps on other CM repos diff --git a/cm/cmind/utils.py b/cm/cmind/utils.py index a12908b5d8..e920efc650 100644 --- a/cm/cmind/utils.py +++ b/cm/cmind/utils.py @@ -138,6 +138,37 @@ def save_json_or_yaml(file_name, meta, sort_keys=False, encoding = 'utf8'): return {'return':ERROR_UNKNOWN_FILE_EXTENSION, 'error':'unknown file extension'} +########################################################################### +def safe_load_json(path, file_name='', encoding='utf8'): + """ + Load JSON file if exists, otherwise return empty dict + + Args: + (CM input dict): + + file_name (str): file name + (encoding) (str): file encoding ('utf8' by default) + + Returns: + (CM return dict): + + * return (int): return code == 0 if no error and >0 if error + * (error) (str): error string if return>0 + + * meta (dict): meta from the file + + """ + + path_to_file = os.path.join(path, file_name) if file_name == '' or path != file_name else path + + meta = {} + + r = load_json(path_to_file, check_if_exists, encoding) + if r['return'] == 0: + meta = r['meta'] + + return {'return':0, 'meta': meta} + ########################################################################### def load_json(file_name, check_if_exists = False, encoding='utf8'): """ @@ -173,8 +204,7 @@ def load_json(file_name, check_if_exists = False, encoding='utf8'): except Exception as e: return {'return':4, 'error': format(e)} - return {'return':0, - 'meta': meta} + return {'return':0, 'meta': meta} ########################################################################### def save_json(file_name, meta={}, indent=2, sort_keys=True, encoding = 'utf8'): @@ -1679,3 +1709,46 @@ def breakpoint(self): # Go up outside this function to continue debugging (F11 in VS) return debugpy + +############################################################################## +def compare_versions(version1, version2): + """ + Compare versions + + Args: + + version1 (str): version 1 + version2 (str): version 2 + + Returns: + comparison (int): 1 - version 1 > version 2 + 0 - version 1 == version 2 + -1 - version 1 < version 2 + """ + + version1 = i['version1'] + version2 = i['version2'] + + l_version1 = version1.split('.') + l_version2 = version2.split('.') + + # 3.9.6 vs 3.9 + # 3.9 vs 3.9.6 + + i_version1 = [int(v) if v.isdigit() else v for v in l_version1] + i_version2 = [int(v) if v.isdigit() else v for v in l_version2] + + comparison = 0 + + for index in range(max(len(i_version1), len(i_version2))): + v1 = i_version1[index] if index < len(i_version1) else 0 + v2 = i_version2[index] if index < len(i_version2) else 0 + + if v1 > v2: + comparison = 1 + break + elif v1 < v2: + comparison = -1 + break + + return {'return':0, 'comparison': comparison} diff --git a/cm/docs/KB/ML.md b/cm/docs/KB/ML.md deleted file mode 100644 index 5c53e92b88..0000000000 --- a/cm/docs/KB/ML.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../../docs/misc/ML.md). diff --git a/cm/docs/KB/MLOps.md b/cm/docs/KB/MLOps.md deleted file mode 100644 index b033570be7..0000000000 --- a/cm/docs/KB/MLOps.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../../docs/misc/MLOps.md). diff --git a/cm/docs/README.md b/cm/docs/README.md deleted file mode 100644 index b6a4629573..0000000000 --- a/cm/docs/README.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/README.md). diff --git a/cm/docs/architecture.md b/cm/docs/architecture.md deleted file mode 100644 index c3a747097a..0000000000 --- a/cm/docs/architecture.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/specs/cm-tool-architecture.md). diff --git a/cm/docs/conventions.md b/cm/docs/conventions.md deleted file mode 100644 index b6a4629573..0000000000 --- a/cm/docs/conventions.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/README.md). diff --git a/cm/docs/enhancements.md b/cm/docs/enhancements.md deleted file mode 100644 index 5cd1c1a460..0000000000 --- a/cm/docs/enhancements.md +++ /dev/null @@ -1,55 +0,0 @@ -# Enhancements - -## Automation scripts - -* [Planned developments for 2022]( https://github.com/mlcommons/ck/issues/189 ) -* ~[Prototyping major automations for MLOps and DevOps](https://github.com/mlcommons/ck/issues/245)~ - -## Ideas - -### Making CM scripts completely deterministic - -Script starts with a "state" dict (with "env" inside) -and must produce an updated "state" dict deterministically -to run the final command (CMD) - -If "state" contains all the required information, -script just runs the final command. - -If something is missing in the "state", script and dependencies -must fill in all missing info on a given platform. - -CM input to the script finds a given script -and updates the "state" uniqely. For example ---version --version_max for get-python3 will update the following variable in the state: - -* CM_PYTHON_VERSION -* CM_PYTHON_VERSION_MAX - -This means that we can either use state from the start and update it manually -or use local input to the script that will again update the state -before finding and running the script ... - -My feeling is that it will simplify the current flow. - -### Speeding up search action - -In the CK1, we used explicit indexing of all entries using .cm directories. -Such mechanism provided a very fast search but it was not very user friendly: -if a user forgot to add .cm to Git or Zip, the search function was broken. - -In the CM (aka CK2), we have decided to simplify the overall architecture and removed -explicit indexing by default. Now, CM will be searching recursively for entries -based on UID and alias in their meta description (_cm.yaml | _cm.json). - -We want to add implicit indexing later similar to Git to let CM auto-index repositories. - -### Using sub-folders for automations (scripts) - -(from Arjun) Can we also add support for putting CM scripts inside a folder? -This will mean CM to recursively scan the script directory for all sub folders -having "_cm.json". I was considering a use case of C programs for Computer -Science subjects being organized as CM scripts (for better -reproducibility) and having them organized as sub folders -(algorithm-lab, os-lab etc) will be better. - diff --git a/cm/docs/example-modular-image-classification.md b/cm/docs/example-modular-image-classification.md deleted file mode 100644 index 7aa51679e6..0000000000 --- a/cm/docs/example-modular-image-classification.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/tutorials/modular-image-classification.md). diff --git a/cm/docs/installation.md b/cm/docs/installation.md deleted file mode 100644 index db9888b90b..0000000000 --- a/cm/docs/installation.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/installation.md). diff --git a/cm/docs/motivation.md b/cm/docs/motivation.md deleted file mode 100644 index b6a4629573..0000000000 --- a/cm/docs/motivation.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/README.md). diff --git a/cm/docs/specification.md b/cm/docs/specification.md deleted file mode 100644 index be7c74b17e..0000000000 --- a/cm/docs/specification.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/specification.md). diff --git a/cm/docs/tutorial-concept.md b/cm/docs/tutorial-concept.md deleted file mode 100644 index 7a091dddcf..0000000000 --- a/cm/docs/tutorial-concept.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/tutorials/concept.md). diff --git a/cm/docs/tutorial-modular-mlperf.md b/cm/docs/tutorial-modular-mlperf.md deleted file mode 100644 index 7a681da130..0000000000 --- a/cm/docs/tutorial-modular-mlperf.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/tutorials/modular-mlperf.md). diff --git a/cm/docs/tutorial-scripts.md b/cm/docs/tutorial-scripts.md deleted file mode 100644 index 1b4024c292..0000000000 --- a/cm/docs/tutorial-scripts.md +++ /dev/null @@ -1 +0,0 @@ -Moved [here](../../docs/tutorials/scripts.md). diff --git a/cm/setup.py b/cm/setup.py index 0031a5d527..6a1c26a856 100644 --- a/cm/setup.py +++ b/cm/setup.py @@ -2,7 +2,7 @@ import sys import re -from setuptools import find_packages, setup, convert_path +from setuptools import find_packages, setup try: from setuptools.command.install import install From 1b8dba8a1d3a19a633073f8669bae15ba9142c46 Mon Sep 17 00:00:00 2001 From: Grigori Fursin Date: Tue, 23 Apr 2024 19:57:30 +0200 Subject: [PATCH 2/3] check "min_cm_version" in CM automations and CM scripts (use _cm.yaml or _cm.json) --- cm/CHANGES.md | 4 +++- cm/cmind/__init__.py | 2 +- cm/cmind/core.py | 10 ++++++++++ cm/cmind/utils.py | 40 +++++++++++++++++++++++++++++++++++----- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/cm/CHANGES.md b/cm/CHANGES.md index 90de8bc108..375eed55bf 100644 --- a/cm/CHANGES.md +++ b/cm/CHANGES.md @@ -1,4 +1,4 @@ -## V2.1.2.1 +## V2.1.3 - fixed detection of a CM artifact using 'cm info .' when inside virtual env entries. - added "cmind.utils.debug_here" function to attach remote Python debugger and tested with Visual Studio Code. @@ -6,6 +6,8 @@ - added utils.safe_load_json to return empty dict if file doesn't exist - added utils.compare_versions to check min version requirements for automations and entries - removed outdated convert_path (https://github.com/mlcommons/ck/issues/1219) + - added utils.check_if_true_yes_on (https://github.com/mlcommons/ck/issues/1216) + - check "min_cm_version" in CM automations and CM scripts (use _cm.yaml or _cm.json) ## V2.1.2 - added support for deps on other CM repos diff --git a/cm/cmind/__init__.py b/cm/cmind/__init__.py index 03bcd9c1bf..571f1707e0 100644 --- a/cm/cmind/__init__.py +++ b/cm/cmind/__init__.py @@ -1,4 +1,4 @@ -__version__ = "2.1.2.1" +__version__ = "2.1.3" from cmind.core import access from cmind.core import error diff --git a/cm/cmind/core.py b/cm/cmind/core.py index 7ca3a52f42..a008597cd5 100644 --- a/cm/cmind/core.py +++ b/cm/cmind/core.py @@ -584,6 +584,16 @@ def access(self, i, out = None): i['parsed_artifact'] = r['cm_object'] + # Check min CM version requirement + min_cm_version = automation_meta.get('min_cm_version','').strip() + if min_cm_version != '': + from cmind import __version__ as current_cm_version + comparison = utils.compare_versions(current_cm_version, min_cm_version) + if comparison < 0: + return {'return':1, 'error':'CM automation requires CM version >= {} while current CM version is {} - please update using "pip install cmind -U"'.format(min_cm_version, current_cm_version)} + + + # Call automation action action_addr=getattr(initialized_automation, action) diff --git a/cm/cmind/utils.py b/cm/cmind/utils.py index e920efc650..21e52952d6 100644 --- a/cm/cmind/utils.py +++ b/cm/cmind/utils.py @@ -163,7 +163,7 @@ def safe_load_json(path, file_name='', encoding='utf8'): meta = {} - r = load_json(path_to_file, check_if_exists, encoding) + r = load_json(path_to_file, check_if_exists=True, encoding=encoding) if r['return'] == 0: meta = r['meta'] @@ -1726,9 +1726,6 @@ def compare_versions(version1, version2): -1 - version 1 < version 2 """ - version1 = i['version1'] - version2 = i['version2'] - l_version1 = version1.split('.') l_version2 = version2.split('.') @@ -1751,4 +1748,37 @@ def compare_versions(version1, version2): comparison = -1 break - return {'return':0, 'comparison': comparison} + return comparison + +############################################################################## +def check_if_true_yes_on(env, key): + """ + Universal check if str(env.get(key, '')).lower() in ['true', 'yes', 'on']: + + Args: + + env (dict): dictionary + key (str): key + + Returns: + True if str(env.get(key, '')).lower() in ['true', 'yes', 'on']: + """ + + return str(env.get(key, '')).lower() in ['true', 'yes', 'on'] + +############################################################################## +def check_if_none_false_no_off(env, key): + """ + Universal check if str(env.get(key, '')).lower() in ['false', 'no', 'off']: + + Args: + + env (dict): dictionary + key (str): key + + Returns: + True if str(env.get(key, '')).lower() in ['false', 'no', 'off']: + """ + + return str(env.get(key, '')).lower() in ['none', 'false', 'no', 'off'] + From f574aed684e884f6cc108ab0ebb659194083d113 Mon Sep 17 00:00:00 2001 From: Grigori Fursin Date: Tue, 23 Apr 2024 19:58:00 +0200 Subject: [PATCH 3/3] CM v2.2.0 release --- cm/CHANGES.md | 2 +- cm/cmind/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cm/CHANGES.md b/cm/CHANGES.md index 375eed55bf..0c09942878 100644 --- a/cm/CHANGES.md +++ b/cm/CHANGES.md @@ -1,4 +1,4 @@ -## V2.1.3 +## V2.2.0 - fixed detection of a CM artifact using 'cm info .' when inside virtual env entries. - added "cmind.utils.debug_here" function to attach remote Python debugger and tested with Visual Studio Code. diff --git a/cm/cmind/__init__.py b/cm/cmind/__init__.py index 571f1707e0..1bd8ddb448 100644 --- a/cm/cmind/__init__.py +++ b/cm/cmind/__init__.py @@ -1,4 +1,4 @@ -__version__ = "2.1.3" +__version__ = "2.2.0" from cmind.core import access from cmind.core import error