Skip to content

Commit f4c163f

Browse files
authored
Show warning if particular target is not present for removal (#145)
* prevent showing error while removing particular cache * update gh action workflow * added enums for error and warning * show multiple warning messages coming out of the scripts
1 parent 3221902 commit f4c163f

File tree

6 files changed

+171
-4
lines changed

6 files changed

+171
-4
lines changed

.github/workflows/test-mlc-core-actions.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ jobs:
245245
246246
- name: Test for rm cache - invalid cache entry tags(test succeeds if command fails)
247247
run: |
248-
! mlc rm cache --tags=sample,invalid,tags
248+
mlc rm cache --tags=sample,invalid,tags
249249
250250
- name: Test for rm cache when the cache folder is empty(only for mlc rm cache without specifying particular script)
251251
run: |

docs/error_codes.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Error and Warning Codes in MLCFlow
2+
3+
MLCFlow uses a standardized system for error and warning codes to provide consistent error handling across the framework. This document explains the error code system and how to use it.
4+
5+
## Overview
6+
7+
The error code system consists of two main components:
8+
9+
1. **WarningCode(1000-1007)**: Enum class for warning codes (return = 0, with warning_code field)
10+
2. **ErrorCode(2000-2007)**: Enum class for error codes (return > 0)
11+
<!--
12+
## Error Code Structure
13+
14+
Error codes are organized by category:
15+
16+
- **General errors (1000-1099)**: Common errors that can occur in any part of the system
17+
- **Script errors (1100-1199)**: Errors specific to script execution and management
18+
- **Repository errors (1200-1299)**: Errors related to repository operations
19+
- **Cache errors (1300-1399)**: Errors related to cache operations
20+
21+
## Warning Code Structure
22+
23+
Warning codes follow a similar structure:
24+
25+
- **General warnings (2000-99)**: Common warnings that can occur in any part of the system
26+
- **Script warnings (2100-2199)**: Warnings specific to script execution and management
27+
- **Repository warnings (2200-2299)**: Warnings related to repository operations
28+
- **Cache warnings (2300-2399)**: Warnings related to cache operations -->
29+
30+
## Usage
31+
32+
### In MLCFlow Framework
33+
34+
When returning an error:
35+
36+
```python
37+
from mlc.error_codes import ErrorCode, get_error_message
38+
39+
return {'return': ErrorCode.UNSUPPORTED_OS.code, 'error': get_error_message(ErrorCode.UNSUPPORTED_OS.description)}
40+
```
41+
42+
When returning a warning:
43+
44+
```python
45+
from mlc.error_codes import WarningCode, get_warning_message
46+
47+
return {'return': 0, 'warning_code': WarningCode.ELEVATED_PERMISSION_NEEDED.code, 'warning': get_warning_message(WarningCode.ELEVATED_PERMISSION_NEEDED.description)}
48+
```
49+
50+
### In Scripts
51+
52+
When checking for errors or warnings:
53+
54+
```python
55+
from mlc.error_codes import is_warning_code
56+
57+
result = mlc_cache.access({'action': 'rm', 'target': 'cache', 'tags': cache_rm_tags, 'f': True})
58+
if result['return'] != 0 and not is_warning_code(result['return']):
59+
# Handle error
60+
return result
61+
```
62+
63+
## Helper Functions
64+
65+
The error code system provides several helper functions:
66+
67+
- `get_error_message(error_code)`: Get the description for an error code
68+
- `get_warning_message(warning_code)`: Get the description for a warning code
69+
- `is_warning_code(code)`: Check if a code is a warning code
70+
- `is_error_code(code)`: Check if a code is an error code
71+
- `get_code_type(code)`: Get the type of a code (error, warning, or unknown)
72+
73+
## Adding New Error or Warning Codes
74+
75+
To add a new error or warning code, update the appropriate enum class in `mlc/error_codes.py`:
76+
77+
```python
78+
# For a new error code
79+
NEW_ERROR = (2008, "Description of the new error")
80+
81+
# For a new warning code
82+
NEW_WARNING = (1007, "Description of the new warning")
83+
```
84+
85+
Make sure to follow the category structure and use the next available code in the appropriate range.

mlc/action.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .index import Index
1414
from .repo import Repo
1515
from .item import Item
16+
from .error_codes import WarningCode
1617

1718
# Base class for actions
1819
class Action:
@@ -340,9 +341,10 @@ def rm(self, i):
340341
# Do not error out if fetch_all is used
341342
if inp.get("fetch_all", False) == True:
342343
logger.warning(f"{target_name} is empty! nothing to be cleared!")
343-
return {"return": 0}
344+
return {"return": 0, "warnings": [{"code": WarningCode.EMPTY_TARGET.code, "description": f"{target_name} is empty! nothing to be cleared!"}]}
344345
else:
345-
return {'return': 16, 'error': f'No {target_name} found for {inp}'}
346+
logger.warning(f"No {target_name} found for {inp}")
347+
return {'return': 0, "warnings": [{"code": WarningCode.EMPTY_TARGET.code, "description": f"No {target_name} found for {inp}"}]}
346348
elif len(res['list']) > 1:
347349
logger.info(f"More than 1 {target_name} found for {inp}:")
348350
if not i.get('all'):

mlc/error_codes.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from enum import Enum, auto
2+
3+
class ErrorCode(Enum):
4+
"""Enum class for error codes in MLCFlow"""
5+
# General errors (2000-2007)
6+
AUTOMATION_SCRIPT_NOT_FOUND = (2000, "The specified automation script was not found")
7+
PATH_DOES_NOT_EXIST = (2001, "Provided path does not exists")
8+
FILE_NOT_FOUND = (2002, "Required file was not found")
9+
PERMISSION_DENIED = (2003, "Insufficient permission to execute the script")
10+
IO_Error = (2004, "File I/O operation failed")
11+
AUTOMATION_CUSTOM_ERROR = (2005, "Custom error triggered by the script")
12+
UNSUPPORTED_OS = (2006, "The Operating System is not supported by the script")
13+
MISSING_ENV_VARIABLE = (2007, "Required environment variables are missing")
14+
15+
def __init__(self, code, description):
16+
self.code = code
17+
self.description = description
18+
19+
class WarningCode(Enum):
20+
"""Enum class for warning codes in MLCFlow"""
21+
# General warnings (1000-1007)
22+
IO_WARNING = (1000, "File I/O operation warning")
23+
AUTOMATION_SCRIPT_NOT_TESTED = (1001, "the script is not tested on the current operatinig system or is in a development state")
24+
AUTOMATION_SCRIPT_SKIPPED = (1002, "The script has been skipped during execution")
25+
AUTOMATION_CUSTOM_ERROR = (1003, "Custom warning triggered by the script")
26+
NON_INTERACTIVE_ENV = (1004, "Non interactive environment detected")
27+
ELEVATED_PERMISSION_NEEDED = (1005, "Elevated permission needed")
28+
EMPTY_TARGET = (1006, "The specified target is empty")
29+
30+
def __init__(self, code, description):
31+
self.code = code
32+
self.description = description
33+
34+
def get_error_info(error_code):
35+
"""Get the error message for a given error code"""
36+
try:
37+
return {"error_code": ErrorCode(error_code).code, "error_message": ErrorCode(error_code).description}
38+
except ValueError:
39+
return f"Unknown error code: {error_code}"
40+
41+
def get_warning_info(warning_code):
42+
"""Get the warning message for a given warning code"""
43+
try:
44+
return {"warning_code": WarningCode(warning_code).code, "warning_message": WarningCode(warning_code).description}
45+
except ValueError:
46+
return f"Unknown warning code: {warning_code}"
47+
48+
def is_warning_code(code):
49+
"""Check if a given code is a warning code"""
50+
try:
51+
# Check if code is in warning range (2000-2399)
52+
if 2000 <= code <= 2399:
53+
WarningCode(code)
54+
return True
55+
return False
56+
except ValueError:
57+
return False
58+
59+
def is_error_code(code):
60+
"""Check if a given code is an error code"""
61+
try:
62+
# Check if code is in error range (1000-1399)
63+
if 1000 <= code <= 1399:
64+
ErrorCode(code)
65+
return True
66+
return False
67+
except ValueError:
68+
return False
69+
70+
def get_code_type(code):
71+
"""Get the type of a code (error or warning)"""
72+
if is_error_code(code):
73+
return "error"
74+
elif is_warning_code(code):
75+
return "warning"
76+
else:
77+
return "unknown"

mlc/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ def process_console_output(res, target, action, run_args):
9797
else:
9898
for item in res['list']:
9999
logger.info(f"""Item path: {item.path}""")
100+
if "warnings" in res:
101+
logger.warning(f"{len(res['warnings'])} warning(s) found during the execution of the mlc command.")
102+
for warning in res["warnings"]:
103+
logger.warning(f"Warning code: {warning['code']}, Discription: {warning['description']}")
100104

101105
if default_parent is None:
102106
default_parent = Action()

mlc/script_action.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ def call_script_module_function(self, function_name, run_args):
224224
module_path = os.path.join(script_path, "module.py")
225225
module = self.dynamic_import_module(module_path)
226226

227-
228227
# Check if ScriptAutomation is defined in the module
229228
if hasattr(module, 'ScriptAutomation'):
230229
automation_instance = module.ScriptAutomation(self, module_path)

0 commit comments

Comments
 (0)