mirror of
https://github.com/clearml/clearml
synced 2025-05-03 20:41:00 +00:00
Fix git diff larger than 500kb , git section will contain warning, and entire git diff will be uploaded as artifact named auxiliary_git_diff
This commit is contained in:
parent
d1744785b1
commit
934771184d
@ -592,6 +592,7 @@ class ScriptInfo(object):
|
|||||||
script_dir = scripts_dir[0]
|
script_dir = scripts_dir[0]
|
||||||
script_path = scripts_path[0]
|
script_path = scripts_path[0]
|
||||||
messages = []
|
messages = []
|
||||||
|
auxiliary_git_diff = None
|
||||||
|
|
||||||
if not plugin:
|
if not plugin:
|
||||||
log.info("No repository found, storing script code instead")
|
log.info("No repository found, storing script code instead")
|
||||||
@ -625,7 +626,10 @@ class ScriptInfo(object):
|
|||||||
messages.append(
|
messages.append(
|
||||||
"======> WARNING! Git diff to large to store "
|
"======> WARNING! Git diff to large to store "
|
||||||
"({}kb), skipping uncommitted changes <======".format(len(diff)//1024))
|
"({}kb), skipping uncommitted changes <======".format(len(diff)//1024))
|
||||||
diff = ''
|
auxiliary_git_diff = diff
|
||||||
|
diff = '# WARNING! git diff too large to store, clear this section to execute without it.\n' \
|
||||||
|
'# full git diff available in Artifacts/auxiliary_git_diff\n' \
|
||||||
|
'# Clear the section before enqueueing Task!\n'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
diff = ''
|
diff = ''
|
||||||
@ -665,7 +669,7 @@ class ScriptInfo(object):
|
|||||||
if not any(script_info.values()):
|
if not any(script_info.values()):
|
||||||
script_info = None
|
script_info = None
|
||||||
|
|
||||||
return (ScriptInfoResult(script=script_info, warning_messages=messages),
|
return (ScriptInfoResult(script=script_info, warning_messages=messages, auxiliary_git_diff=auxiliary_git_diff),
|
||||||
script_requirements)
|
script_requirements)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -724,6 +728,7 @@ class ScriptInfo(object):
|
|||||||
class ScriptInfoResult(object):
|
class ScriptInfoResult(object):
|
||||||
script = attr.ib(default=None)
|
script = attr.ib(default=None)
|
||||||
warning_messages = attr.ib(factory=list)
|
warning_messages = attr.ib(factory=list)
|
||||||
|
auxiliary_git_diff = attr.ib(default=None)
|
||||||
|
|
||||||
|
|
||||||
class _JupyterHistoryLogger(object):
|
class _JupyterHistoryLogger(object):
|
||||||
|
@ -21,6 +21,7 @@ from collections import OrderedDict
|
|||||||
from six.moves.urllib.parse import quote
|
from six.moves.urllib.parse import quote
|
||||||
|
|
||||||
from ...utilities.locks import RLock as FileRLock
|
from ...utilities.locks import RLock as FileRLock
|
||||||
|
from ...binding.artifacts import Artifacts
|
||||||
from ...backend_interface.task.development.worker import DevWorker
|
from ...backend_interface.task.development.worker import DevWorker
|
||||||
from ...backend_api import Session
|
from ...backend_api import Session
|
||||||
from ...backend_api.services import tasks, models, events, projects
|
from ...backend_api.services import tasks, models, events, projects
|
||||||
@ -154,6 +155,7 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin):
|
|||||||
log_to_backend = False
|
log_to_backend = False
|
||||||
self._log_to_backend = log_to_backend
|
self._log_to_backend = log_to_backend
|
||||||
self._setup_log(default_log_to_backend=log_to_backend)
|
self._setup_log(default_log_to_backend=log_to_backend)
|
||||||
|
self._artifacts_manager = Artifacts(self)
|
||||||
|
|
||||||
def _setup_log(self, default_log_to_backend=None, replace_existing=False):
|
def _setup_log(self, default_log_to_backend=None, replace_existing=False):
|
||||||
"""
|
"""
|
||||||
@ -264,6 +266,11 @@ class Task(IdObjectBase, AccessMixin, SetupUploadMixin):
|
|||||||
for msg in result.warning_messages:
|
for msg in result.warning_messages:
|
||||||
self.get_logger().report_text(msg)
|
self.get_logger().report_text(msg)
|
||||||
|
|
||||||
|
# if the git is too large to store on the task, we must store it as artifact:
|
||||||
|
if result.auxiliary_git_diff:
|
||||||
|
self._artifacts_manager.upload_artifact(
|
||||||
|
name='auxiliary_git_diff', artifact_object=result.auxiliary_git_diff)
|
||||||
|
|
||||||
# store original entry point
|
# store original entry point
|
||||||
entry_point = result.script.get('entry_point') if result.script else None
|
entry_point = result.script.get('entry_point') if result.script else None
|
||||||
|
|
||||||
|
@ -161,6 +161,9 @@ class Artifact(object):
|
|||||||
elif self.type == 'JSON':
|
elif self.type == 'JSON':
|
||||||
with open(local_file, 'rt') as f:
|
with open(local_file, 'rt') as f:
|
||||||
self._object = json.load(f)
|
self._object = json.load(f)
|
||||||
|
elif self.type == 'string':
|
||||||
|
with open(local_file, 'rt') as f:
|
||||||
|
self._object = f.read()
|
||||||
elif self.type == 'pickle':
|
elif self.type == 'pickle':
|
||||||
with open(local_file, 'rb') as f:
|
with open(local_file, 'rb') as f:
|
||||||
self._object = pickle.load(f)
|
self._object = pickle.load(f)
|
||||||
@ -316,10 +319,18 @@ class Artifacts(object):
|
|||||||
artifact_path = Path(artifact_object)
|
artifact_path = Path(artifact_object)
|
||||||
if artifact_path.exists():
|
if artifact_path.exists():
|
||||||
artifact_object = artifact_path
|
artifact_object = artifact_path
|
||||||
|
elif '*' in artifact_object or '?' in artifact_object:
|
||||||
|
# hackish, detect wildcard in tr files
|
||||||
|
folder = Path('').joinpath(*artifact_path.parts[:-1])
|
||||||
|
if folder.is_dir() and folder.parts:
|
||||||
|
wildcard = artifact_path.parts[-1]
|
||||||
|
if list(Path(folder).rglob(wildcard)):
|
||||||
|
artifact_object = artifact_path
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
artifact_type_data = tasks.ArtifactTypeData()
|
artifact_type_data = tasks.ArtifactTypeData()
|
||||||
|
artifact_type_data.preview = ''
|
||||||
override_filename_in_uri = None
|
override_filename_in_uri = None
|
||||||
override_filename_ext_in_uri = None
|
override_filename_ext_in_uri = None
|
||||||
uri = None
|
uri = None
|
||||||
@ -367,7 +378,7 @@ class Artifacts(object):
|
|||||||
artifact_type_data.preview = preview
|
artifact_type_data.preview = preview
|
||||||
else:
|
else:
|
||||||
artifact_type_data.preview = '# full json too large to store, storing first {}kb\n{}'.format(
|
artifact_type_data.preview = '# full json too large to store, storing first {}kb\n{}'.format(
|
||||||
len(preview)//1024, preview[:self.max_preview_size_bytes]
|
self.max_preview_size_bytes//1024, preview[:self.max_preview_size_bytes]
|
||||||
)
|
)
|
||||||
|
|
||||||
delete_after_upload = True
|
delete_after_upload = True
|
||||||
@ -428,6 +439,8 @@ class Artifacts(object):
|
|||||||
raise ValueError("Artifact file '{}' could not be found".format(artifact_object.as_posix()))
|
raise ValueError("Artifact file '{}' could not be found".format(artifact_object.as_posix()))
|
||||||
|
|
||||||
override_filename_in_uri = artifact_object.parts[-1]
|
override_filename_in_uri = artifact_object.parts[-1]
|
||||||
|
artifact_type_data.preview = '{} - {}\n'.format(
|
||||||
|
artifact_object, humanfriendly.format_size(artifact_object.stat().st_size))
|
||||||
artifact_object = artifact_object.as_posix()
|
artifact_object = artifact_object.as_posix()
|
||||||
artifact_type = 'custom'
|
artifact_type = 'custom'
|
||||||
artifact_type_data.content_type = mimetypes.guess_type(artifact_object)[0]
|
artifact_type_data.content_type = mimetypes.guess_type(artifact_object)[0]
|
||||||
@ -441,11 +454,38 @@ class Artifacts(object):
|
|||||||
uri = artifact_object
|
uri = artifact_object
|
||||||
artifact_type = 'custom'
|
artifact_type = 'custom'
|
||||||
artifact_type_data.content_type = mimetypes.guess_type(artifact_object)[0]
|
artifact_type_data.content_type = mimetypes.guess_type(artifact_object)[0]
|
||||||
|
elif isinstance(artifact_object, six.string_types):
|
||||||
|
# if we got here, we should store it as text file.
|
||||||
|
artifact_type = 'string'
|
||||||
|
artifact_type_data.content_type = 'text/plain'
|
||||||
|
if len(artifact_object) < self.max_preview_size_bytes:
|
||||||
|
artifact_type_data.preview = artifact_object
|
||||||
|
else:
|
||||||
|
artifact_type_data.preview = '# full text too large to store, storing first {}kb\n{}'.format(
|
||||||
|
self.max_preview_size_bytes//1024, artifact_object[:self.max_preview_size_bytes]
|
||||||
|
)
|
||||||
|
delete_after_upload = True
|
||||||
|
override_filename_ext_in_uri = '.txt'
|
||||||
|
override_filename_in_uri = name + override_filename_ext_in_uri
|
||||||
|
fd, local_filename = mkstemp(prefix=quote(name, safe="") + '.', suffix=override_filename_ext_in_uri)
|
||||||
|
os.close(fd)
|
||||||
|
# noinspection PyBroadException
|
||||||
|
try:
|
||||||
|
with open(local_filename, 'wt') as f:
|
||||||
|
f.write(artifact_object)
|
||||||
|
except Exception as ex:
|
||||||
|
# cleanup and raise exception
|
||||||
|
os.unlink(local_filename)
|
||||||
|
raise
|
||||||
elif auto_pickle:
|
elif auto_pickle:
|
||||||
# if we are here it means we do not know what to do with the object, so we serialize it with pickle.
|
# if we are here it means we do not know what to do with the object, so we serialize it with pickle.
|
||||||
artifact_type = 'pickle'
|
artifact_type = 'pickle'
|
||||||
artifact_type_data.content_type = 'application/pickle'
|
artifact_type_data.content_type = 'application/pickle'
|
||||||
|
# noinspection PyBroadException
|
||||||
|
try:
|
||||||
artifact_type_data.preview = str(artifact_object.__repr__())[:self.max_preview_size_bytes]
|
artifact_type_data.preview = str(artifact_object.__repr__())[:self.max_preview_size_bytes]
|
||||||
|
except Exception:
|
||||||
|
artifact_type_data.preview = ''
|
||||||
delete_after_upload = True
|
delete_after_upload = True
|
||||||
override_filename_ext_in_uri = '.pkl'
|
override_filename_ext_in_uri = '.pkl'
|
||||||
override_filename_in_uri = name + override_filename_ext_in_uri
|
override_filename_in_uri = name + override_filename_ext_in_uri
|
||||||
@ -455,7 +495,7 @@ class Artifacts(object):
|
|||||||
try:
|
try:
|
||||||
with open(local_filename, 'wb') as f:
|
with open(local_filename, 'wb') as f:
|
||||||
pickle.dump(artifact_object, f)
|
pickle.dump(artifact_object, f)
|
||||||
except Exception:
|
except Exception as ex:
|
||||||
# cleanup and raise exception
|
# cleanup and raise exception
|
||||||
os.unlink(local_filename)
|
os.unlink(local_filename)
|
||||||
raise
|
raise
|
||||||
|
@ -152,7 +152,6 @@ class Task(_Task):
|
|||||||
self._connected_parameter_type = None
|
self._connected_parameter_type = None
|
||||||
self._detect_repo_async_thread = None
|
self._detect_repo_async_thread = None
|
||||||
self._resource_monitor = None
|
self._resource_monitor = None
|
||||||
self._artifacts_manager = Artifacts(self)
|
|
||||||
self._calling_filename = None
|
self._calling_filename = None
|
||||||
# register atexit, so that we mark the task as stopped
|
# register atexit, so that we mark the task as stopped
|
||||||
self._at_exit_called = False
|
self._at_exit_called = False
|
||||||
|
Loading…
Reference in New Issue
Block a user