Fix when the message is :current process ...100%,convert not finished Fix When special characters in the tag, the output image file is incompletetags/v1.1.0
| @@ -29,20 +29,19 @@ from mindinsight.datavisual.proto_files import lazy_read_pb2 | |||||
| from mindinsight.datavisual.data_access.file_handler import FileHandler | from mindinsight.datavisual.data_access.file_handler import FileHandler | ||||
| from mindinsight.datavisual.data_transform.summary_parser.image_writer import ImageWriter | from mindinsight.datavisual.data_transform.summary_parser.image_writer import ImageWriter | ||||
| from mindinsight.datavisual.data_transform.summary_parser.scalar_writer import ScalarWriter | from mindinsight.datavisual.data_transform.summary_parser.scalar_writer import ScalarWriter | ||||
| from mindinsight.datavisual.data_transform.ms_data_loader import _SummaryParser | |||||
| from mindinsight.utils.exceptions import UnknownError | |||||
| HEADER_SIZE = 8 | HEADER_SIZE = 8 | ||||
| CRC_STR_SIZE = 4 | CRC_STR_SIZE = 4 | ||||
| MAX_EVENT_STRING = 500000000 | MAX_EVENT_STRING = 500000000 | ||||
| SCALAR = 'scalar_value' | SCALAR = 'scalar_value' | ||||
| IMAGE = 'image' | IMAGE = 'image' | ||||
| INFO_INTERVAL = 10 | |||||
| class EventParser(): | class EventParser(): | ||||
| """Parse summary file and save it to csv file and image.""" | """Parse summary file and save it to csv file and image.""" | ||||
| def __init__(self, summary_dir, output): | |||||
| self._summary_dir = summary_dir | |||||
| def __init__(self, summary_file, output): | |||||
| self.summary_file = summary_file | |||||
| self._output = output | self._output = output | ||||
| self._scalar_writer = ScalarWriter(self._output) | self._scalar_writer = ScalarWriter(self._output) | ||||
| self._image_writer = ImageWriter(FileHandler.join(self._output, IMAGE)) | self._image_writer = ImageWriter(FileHandler.join(self._output, IMAGE)) | ||||
| @@ -54,52 +53,28 @@ class EventParser(): | |||||
| def parse(self): | def parse(self): | ||||
| """Load summary file and parse file content.""" | """Load summary file and parse file content.""" | ||||
| try: | |||||
| if not (self._check_filepath() and self._check_create_filepath( | |||||
| self._output) and self._check_create_filepath(FileHandler.join(self._output, IMAGE))): | |||||
| return | |||||
| summary_parser = _SummaryParser(self._summary_dir) | |||||
| summary_files = summary_parser.filter_files(os.listdir(self._summary_dir)) | |||||
| summary_file_handler = FileHandler(self.summary_file, 'rb') | |||||
| if not summary_files: | |||||
| parse_summary_logger.error('Path %s has no summary file.', self._summary_dir) | |||||
| return | |||||
| self._file_size = os.path.getsize(self.summary_file) | |||||
| # when current parsed size bigger than self._process_info, print process | |||||
| self._process_info = self._file_size // INFO_INTERVAL | |||||
| summary_files = summary_parser.sort_files(summary_files) | |||||
| parse_summary_logger.info("Loading %s.", self.summary_file) | |||||
| result = self._load(summary_file_handler) | |||||
| filename = summary_files[-1] | |||||
| file_path = FileHandler.join(self._summary_dir, filename) | |||||
| parse_summary_logger.info("Writing scalar.csv") | |||||
| self._scalar_writer.write() | |||||
| if not os.access(file_path, os.R_OK): | |||||
| parse_summary_logger.error('Path %s is not accessible, please check the file-authority.', file_path) | |||||
| return | |||||
| self._summary_file_handler = FileHandler(file_path, 'rb') | |||||
| self._file_size = os.path.getsize(file_path) | |||||
| # when current parsed size bigger than self._process_info, print process | |||||
| self._process_info = self._file_size // 10 | |||||
| parse_summary_logger.info("loading %s", file_path) | |||||
| result = self._load(self._summary_file_handler) | |||||
| self._scalar_writer.write() | |||||
| warning = '' | |||||
| if not self._scalar_check: | |||||
| warning = warning + " the summary file contains no scalar value" | |||||
| if not self._image_check: | |||||
| warning = warning + " the summary file contains no image" | |||||
| if result: | |||||
| if warning: | |||||
| parse_summary_logger.warning(warning) | |||||
| parse_summary_logger.info("parsing summary file finished") | |||||
| except Exception as ex: | |||||
| parse_summary_logger.error("Parse summary file failed, detail: %r", str(ex)) | |||||
| raise UnknownError(str(ex)) | |||||
| warning = '' | |||||
| if not self._scalar_check: | |||||
| warning = warning + " the summary file contains no scalar value." | |||||
| if not self._image_check: | |||||
| warning = warning + " the summary file contains no image." | |||||
| if result: | |||||
| if warning: | |||||
| parse_summary_logger.warning(warning) | |||||
| parse_summary_logger.info("Finished loading %s.", self.summary_file) | |||||
| def _load(self, file_handler): | def _load(self, file_handler): | ||||
| """ | """ | ||||
| @@ -154,6 +129,7 @@ class EventParser(): | |||||
| parse_summary_logger.error("Check header size and crc, record truncated at offset %s, file_path=%s.", | parse_summary_logger.error("Check header size and crc, record truncated at offset %s, file_path=%s.", | ||||
| file_handler.offset, file_handler.file_path) | file_handler.offset, file_handler.file_path) | ||||
| return None | return None | ||||
| if not crc32.CheckValueAgainstData(header_crc_str, header_str, HEADER_SIZE): | if not crc32.CheckValueAgainstData(header_crc_str, header_str, HEADER_SIZE): | ||||
| raise exceptions.CRCFailedError() | raise exceptions.CRCFailedError() | ||||
| @@ -176,9 +152,9 @@ class EventParser(): | |||||
| raise exceptions.CRCFailedError() | raise exceptions.CRCFailedError() | ||||
| self._current += HEADER_SIZE + 2 * CRC_STR_SIZE + event_len | self._current += HEADER_SIZE + 2 * CRC_STR_SIZE + event_len | ||||
| if self._current >= self._process_info: | if self._current >= self._process_info: | ||||
| parse_summary_logger.info("current process: %d/%d, %d%%", self._current, self._file_size, | |||||
| parse_summary_logger.info("Current parsing process: %d/%d, %d%%.", self._current, self._file_size, | |||||
| 100 * self._current // self._file_size) | 100 * self._current // self._file_size) | ||||
| self._process_info += self._file_size // 10 | |||||
| self._process_info += self._file_size // INFO_INTERVAL | |||||
| return event_str | return event_str | ||||
| def _event_parse(self, event_str): | def _event_parse(self, event_str): | ||||
| @@ -219,27 +195,3 @@ class EventParser(): | |||||
| self._image_writer.add((tag, step, value.image.encoded_image)) | self._image_writer.add((tag, step, value.image.encoded_image)) | ||||
| self._image_writer.write() | self._image_writer.write() | ||||
| self._image_check = True | self._image_check = True | ||||
| def _check_filepath(self): | |||||
| """Check file path existence, accessible and available""" | |||||
| if os.path.exists(self._summary_dir): | |||||
| if not os.path.isdir(self._summary_dir): | |||||
| parse_summary_logger.error('Path of summary directory is not a valid directory.') | |||||
| return False | |||||
| if not os.access(self._summary_dir, os.R_OK | os.X_OK): | |||||
| parse_summary_logger.error('Path %s is not accessible, please check the file-authority.', | |||||
| self._summary_dir) | |||||
| return True | |||||
| parse_summary_logger.error('Path of summary directory not exists.') | |||||
| return False | |||||
| def _check_create_filepath(self, filepath): | |||||
| """Check file path existence, accessible and available, if not exist create the file""" | |||||
| permissions = os.R_OK | os.W_OK | os.X_OK | |||||
| os.umask(permissions << 3 | permissions) | |||||
| if os.path.exists(filepath): | |||||
| parse_summary_logger.error('Path %s has already existed, please choose a new output path.', filepath) | |||||
| return False | |||||
| mode = permissions << 6 | |||||
| os.makedirs(filepath, mode=mode) | |||||
| return True | |||||
| @@ -18,7 +18,7 @@ Image Writer. | |||||
| This module write scalar into a csv file. | This module write scalar into a csv file. | ||||
| """ | """ | ||||
| import os | import os | ||||
| import re | |||||
| from urllib.parse import quote | |||||
| from mindinsight.datavisual.data_transform.summary_parser.writer import Writer | from mindinsight.datavisual.data_transform.summary_parser.writer import Writer | ||||
| @@ -47,9 +47,7 @@ class ImageWriter(Writer): | |||||
| def write(self): | def write(self): | ||||
| """Write file.""" | """Write file.""" | ||||
| for i in range(len(self._image_data)): | for i in range(len(self._image_data)): | ||||
| tag = self._image_data[i][0] | |||||
| tag = tag.replace('/', '_') | |||||
| tag = re.sub(r'[^a-zA-Z0-9_]+', '', tag) | |||||
| tag = quote(self._image_data[i][0], safe="") | |||||
| with os.fdopen(os.open("{}/{}_{}.png".format(self._file_path, tag, self._image_data[i][1]), | with os.fdopen(os.open("{}/{}_{}.png".format(self._file_path, tag, self._image_data[i][1]), | ||||
| os.O_WRONLY | os.O_CREAT, 0o600), 'wb') as fp: | os.O_WRONLY | os.O_CREAT, 0o600), 'wb') as fp: | ||||
| fp.write(self._image_data[i][2]) | fp.write(self._image_data[i][2]) | ||||
| @@ -46,6 +46,7 @@ class ScalarWriter(Writer): | |||||
| def write(self): | def write(self): | ||||
| """Write file.""" | """Write file.""" | ||||
| with os.fdopen(os.open('{}/scalar.csv'.format(self._file_path), os.O_WRONLY | os.O_CREAT, 0o600), 'w') as fp: | |||||
| with os.fdopen(os.open('{}/scalar.csv'.format(self._file_path), os.O_WRONLY | os.O_CREAT, 0o600), 'w', | |||||
| encoding='utf-8') as fp: | |||||
| writer = csv.writer(fp, dialect='excel') | writer = csv.writer(fp, dialect='excel') | ||||
| writer.writerows(self._scalar_data) | writer.writerows(self._scalar_data) | ||||
| @@ -19,12 +19,32 @@ import os | |||||
| import datetime | import datetime | ||||
| from mindinsight.utils.command import BaseCommand | from mindinsight.utils.command import BaseCommand | ||||
| from mindinsight.utils.exceptions import UnknownError | |||||
| from mindinsight.datavisual.common.log import parse_summary_logger | |||||
| from mindinsight.datavisual.data_access.file_handler import FileHandler | |||||
| from mindinsight.datavisual.data_transform.ms_data_loader import _SummaryParser | |||||
| from mindinsight.datavisual.data_transform.summary_parser.event_parser import EventParser | from mindinsight.datavisual.data_transform.summary_parser.event_parser import EventParser | ||||
| class FilepathAction(argparse.Action): | |||||
| class FileDirAction(argparse.Action): | |||||
| """File directory action class definition.""" | """File directory action class definition.""" | ||||
| @staticmethod | |||||
| def check_path(file_path): | |||||
| """ | |||||
| Check argument for file path. | |||||
| Args: | |||||
| file_path (str): File path. | |||||
| """ | |||||
| if file_path.startswith('~'): | |||||
| file_path = os.path.realpath(os.path.expanduser(file_path)) | |||||
| if not file_path.startswith('/'): | |||||
| file_path = os.path.realpath(FileHandler.join(os.getcwd(), file_path)) | |||||
| return os.path.realpath(file_path) | |||||
| def __call__(self, parser_in, namespace, values, option_string=None): | def __call__(self, parser_in, namespace, values, option_string=None): | ||||
| """ | """ | ||||
| Inherited __call__ method from argparse.Action. | Inherited __call__ method from argparse.Action. | ||||
| @@ -35,17 +55,10 @@ class FilepathAction(argparse.Action): | |||||
| values (object): Argument values with type depending on argument definition. | values (object): Argument values with type depending on argument definition. | ||||
| option_string (str): Optional string for specific argument name. Default: None. | option_string (str): Optional string for specific argument name. Default: None. | ||||
| """ | """ | ||||
| summary_dir = values | |||||
| if summary_dir.startswith('~'): | |||||
| summary_dir = os.path.realpath(os.path.expanduser(summary_dir)) | |||||
| summary_dir = self.check_path(values) | |||||
| if not summary_dir.startswith('/'): | |||||
| summary_dir = os.path.realpath(os.path.join(os.getcwd(), summary_dir)) | |||||
| summary_dir = os.path.realpath(summary_dir) | |||||
| setattr(namespace, self.dest, summary_dir) | setattr(namespace, self.dest, summary_dir) | ||||
| class OutputDirAction(argparse.Action): | class OutputDirAction(argparse.Action): | ||||
| """File directory action class definition.""" | """File directory action class definition.""" | ||||
| @@ -59,14 +72,8 @@ class OutputDirAction(argparse.Action): | |||||
| values (object): Argument values with type depending on argument definition. | values (object): Argument values with type depending on argument definition. | ||||
| option_string (str): Optional string for specific argument name. Default: None. | option_string (str): Optional string for specific argument name. Default: None. | ||||
| """ | """ | ||||
| output = values | |||||
| if output.startswith('~'): | |||||
| output = os.path.realpath(os.path.expanduser(output)) | |||||
| output = FileDirAction.check_path(values) | |||||
| if not output.startswith('/'): | |||||
| output = os.path.realpath(os.path.join(os.getcwd(), output)) | |||||
| output = os.path.realpath(output) | |||||
| setattr(namespace, self.dest, output) | setattr(namespace, self.dest, output) | ||||
| @@ -83,10 +90,11 @@ class Command(BaseCommand): | |||||
| Args: | Args: | ||||
| parser (ArgumentParser): Specify parser to which arguments are added. | parser (ArgumentParser): Specify parser to which arguments are added. | ||||
| """ | """ | ||||
| parser.add_argument( | parser.add_argument( | ||||
| '--summary-dir', | '--summary-dir', | ||||
| type=str, | type=str, | ||||
| action=FilepathAction, | |||||
| action=FileDirAction, | |||||
| default=os.path.realpath(os.getcwd()), | default=os.path.realpath(os.getcwd()), | ||||
| help=""" | help=""" | ||||
| Optional, specify path for summary file directory. | Optional, specify path for summary file directory. | ||||
| @@ -110,7 +118,87 @@ class Command(BaseCommand): | |||||
| Args: | Args: | ||||
| args (Namespace): Parsed arguments to hold customized parameters. | args (Namespace): Parsed arguments to hold customized parameters. | ||||
| """ | """ | ||||
| date_time = datetime.datetime.now().strftime('output_%Y%m%d_%H%M%S_%f') | |||||
| date_time = os.path.join(args.output, date_time) | |||||
| eventparser = EventParser(args.summary_dir, date_time) | |||||
| eventparser.parse() | |||||
| try: | |||||
| date_time = datetime.datetime.now().strftime('output_%Y%m%d_%H%M%S_%f') | |||||
| output_filename = os.path.join(args.output, date_time) | |||||
| summary_dir = args.summary_dir | |||||
| if not self._check_dirpath(summary_dir): | |||||
| return | |||||
| summary_parser = _SummaryParser(summary_dir) | |||||
| summary_files = summary_parser.filter_files(os.listdir(summary_dir)) | |||||
| if not summary_files: | |||||
| parse_summary_logger.error('Path %s has no summary file.', summary_dir) | |||||
| return | |||||
| summary_files = summary_parser.sort_files(summary_files) | |||||
| filename = summary_files[-1] | |||||
| summary_file = FileHandler.join(summary_dir, filename) | |||||
| if not (self._check_filepath(summary_file) and self._check_create_filepath( | |||||
| output_filename) and self._check_create_filepath(FileHandler.join(output_filename, 'image'))): | |||||
| return | |||||
| eventparser = EventParser(summary_file, output_filename) | |||||
| eventparser.parse() | |||||
| except Exception as ex: | |||||
| parse_summary_logger.error("Parse summary file failed, detail: %r.", str(ex)) | |||||
| raise UnknownError(str(ex)) | |||||
| @staticmethod | |||||
| def _check_filepath(filepath): | |||||
| """ | |||||
| Check file path existence, accessible and available | |||||
| Args: | |||||
| filepath (str): File path. | |||||
| """ | |||||
| if os.path.exists(filepath): | |||||
| if not os.path.isfile(filepath): | |||||
| parse_summary_logger.error('Summary file %s is not a valid file.', filepath) | |||||
| return False | |||||
| if not os.access(filepath, os.R_OK): | |||||
| parse_summary_logger.error('Path %s is not accessible, please check the file-authority.', filepath) | |||||
| return True | |||||
| parse_summary_logger.error('Summary file %s not exists.', filepath) | |||||
| return False | |||||
| @staticmethod | |||||
| def _check_dirpath(filepath): | |||||
| """ | |||||
| Check file path existence, accessible and available | |||||
| Args: | |||||
| filepath (str): File path. | |||||
| """ | |||||
| if os.path.exists(filepath): | |||||
| if not os.path.isdir(filepath): | |||||
| parse_summary_logger.error('Summary directory %s is not a valid directory.', filepath) | |||||
| return False | |||||
| if not os.access(filepath, os.R_OK | os.X_OK): | |||||
| parse_summary_logger.error('Path %s is not accessible, please check the file-authority.', filepath) | |||||
| return True | |||||
| parse_summary_logger.error('Summary directory %s not exists.', filepath) | |||||
| return False | |||||
| @staticmethod | |||||
| def _check_create_filepath(filepath): | |||||
| """ | |||||
| Check file path existence, accessible and available, if not exist create the file | |||||
| Args: | |||||
| filepath (str): File path. | |||||
| """ | |||||
| permissions = os.R_OK | os.W_OK | os.X_OK | |||||
| os.umask(permissions << 3 | permissions) | |||||
| if os.path.exists(filepath): | |||||
| parse_summary_logger.error('Path %s has already existed, please choose a new output path.', filepath) | |||||
| return False | |||||
| mode = permissions << 6 | |||||
| os.makedirs(filepath, mode=mode) | |||||
| return True | |||||