From 039f9f69388126a5fc285e7aa1b23c5d519711b8 Mon Sep 17 00:00:00 2001 From: allegroai <> Date: Wed, 9 Nov 2022 11:40:36 +0200 Subject: [PATCH] Return stub object from Task.init() if no clearml.conf file is found --- clearml/backend_api/session/defs.py | 12 ++++++ clearml/backend_api/session/session.py | 10 ++--- clearml/task.py | 55 +++++++++++++++----------- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/clearml/backend_api/session/defs.py b/clearml/backend_api/session/defs.py index d4e7fd78..a9063499 100644 --- a/clearml/backend_api/session/defs.py +++ b/clearml/backend_api/session/defs.py @@ -18,6 +18,7 @@ ENV_DISABLE_VAULT_SUPPORT = EnvEntry('CLEARML_DISABLE_VAULT_SUPPORT', type=bool) ENV_ENABLE_ENV_CONFIG_SECTION = EnvEntry('CLEARML_ENABLE_ENV_CONFIG_SECTION', type=bool) ENV_ENABLE_FILES_CONFIG_SECTION = EnvEntry('CLEARML_ENABLE_FILES_CONFIG_SECTION', type=bool) ENV_DEFERRED_TASK_INIT = EnvEntry('CLEARML_DEFERRED_TASK_INIT', type=bool) +ENV_IGNORE_MISSING_CONFIG = EnvEntry("CLEARML_IGNORE_MISSING_CONFIG", type=bool) """ Experimental option to set the request method for all API requests and auth login. @@ -35,3 +36,14 @@ NOTE: this changes behavior and might cause the experiment to wait for a very long time for a non-responding or mis-configured server """ ENV_API_EXTRA_RETRY_CODES = EnvEntry("CLEARML_API_EXTRA_RETRY_CODES") + + +class MissingConfigError(Exception): + def __init__(self, message=None): + if message is None: + message = ( + "It seems ClearML is not configured on this machine!\n" + "To get started with ClearML, setup your own 'clearml-server' or create a free account at https://app.clear.ml\n" + "Setup instructions can be found here: https://clear.ml/docs/latest/docs" + ) + super().__init__(message) diff --git a/clearml/backend_api/session/session.py b/clearml/backend_api/session/session.py index 31f68353..30d078ff 100644 --- a/clearml/backend_api/session/session.py +++ b/clearml/backend_api/session/session.py @@ -26,7 +26,9 @@ from .defs import ( ENV_DISABLE_VAULT_SUPPORT, ENV_ENABLE_ENV_CONFIG_SECTION, ENV_ENABLE_FILES_CONFIG_SECTION, - ENV_API_EXTRA_RETRY_CODES, ENV_API_DEFAULT_REQ_METHOD, + ENV_API_EXTRA_RETRY_CODES, + ENV_API_DEFAULT_REQ_METHOD, + MissingConfigError ) from .request import Request, BatchRequest # noqa: F401 from .token_manager import TokenManager @@ -175,11 +177,7 @@ class Session(TokenManager): raise ValueError("ClearML host was not set, check your configuration file or environment variable") if not self._offline_mode and (not self.secret_key and not self.access_key and not self.__auth_token): - raise ValueError( - "ClearML configuration could not be found (missing `~/clearml.conf` or environment configuration)\n" - "To get started with ClearML: setup your own `clearml-server`, " - "or create a free account at https://app.clear.ml" - ) + raise MissingConfigError() self._ssl_error_count_verbosity = self.config.get( "api.ssl_error_count_verbosity", self._ssl_error_count_verbosity) diff --git a/clearml/task.py b/clearml/task.py index e66cbf72..648255b6 100644 --- a/clearml/task.py +++ b/clearml/task.py @@ -41,7 +41,7 @@ from .backend_config.defs import get_active_config_file, get_config_file from .backend_api.services import tasks, projects from .backend_api.session.session import ( Session, ENV_ACCESS_KEY, ENV_SECRET_KEY, ENV_HOST, ENV_WEB_HOST, ENV_FILES_HOST, ) -from .backend_api.session.defs import ENV_DEFERRED_TASK_INIT +from .backend_api.session.defs import ENV_DEFERRED_TASK_INIT, ENV_IGNORE_MISSING_CONFIG, MissingConfigError from .backend_interface.metrics import Metrics from .backend_interface.model import Model as BackendModel from .backend_interface.task import Task as _Task @@ -77,7 +77,7 @@ from .binding.jsonargs_bind import PatchJsonArgParse from .binding.frameworks import WeightsFileHandler from .config import ( config, DEV_TASK_NO_REUSE, get_is_master_node, DEBUG_SIMULATE_REMOTE_TASK, DEV_DEFAULT_OUTPUT_URI, - deferred_config, TASK_SET_ITERATION_OFFSET, ) + deferred_config, TASK_SET_ITERATION_OFFSET) from .config import running_remotely, get_remote_task_id from .config.cache import SessionCache from .debugging.log import LoggerRoot @@ -529,16 +529,6 @@ class Task(_Task): # check that we are not a child process, in that case do nothing. # we should not get here unless this is Windows/macOS platform, linux support fork if cls.__is_subprocess(): - class _TaskStub(object): - def __call__(self, *args, **kwargs): - return self - - def __getattr__(self, attr): - return self - - def __setattr__(self, attr, val): - pass - is_sub_process_task_id = cls.__get_master_id_task_id() # we could not find a task ID, revert to old stub behaviour if not is_sub_process_task_id: @@ -598,18 +588,24 @@ class Task(_Task): cls.__update_master_pid_task() # if this is the main process, create the task elif not is_sub_process_task_id: - task = cls._create_dev_task( - default_project_name=project_name, - default_task_name=task_name, - default_task_type=task_type, - tags=tags, - reuse_last_task_id=reuse_last_task_id, - continue_last_task=continue_last_task, - detect_repo=False if ( - isinstance(auto_connect_frameworks, dict) and - not auto_connect_frameworks.get('detect_repository', True)) else True, - auto_connect_streams=auto_connect_streams, - ) + try: + task = cls._create_dev_task( + default_project_name=project_name, + default_task_name=task_name, + default_task_type=task_type, + tags=tags, + reuse_last_task_id=reuse_last_task_id, + continue_last_task=continue_last_task, + detect_repo=False if ( + isinstance(auto_connect_frameworks, dict) and + not auto_connect_frameworks.get('detect_repository', True)) else True, + auto_connect_streams=auto_connect_streams, + ) + except MissingConfigError as e: + if not ENV_IGNORE_MISSING_CONFIG.get(): + raise + getLogger().warning(str(e)) + return _TaskStub() # set defaults if cls._offline_mode: task.output_uri = None @@ -4280,3 +4276,14 @@ class Task(_Task): auto_connect_frameworks={'detect_repository': False}) \ if state['main'] else Task.get_task(task_id=state['id']) self.__dict__ = task.__dict__ + + +class _TaskStub(object): + def __call__(self, *args, **kwargs): + return self + + def __getattr__(self, attr): + return self + + def __setattr__(self, attr, val): + pass