3131from robotframework_reportportal .variables import Variables
3232
3333logger = logging .getLogger (__name__ )
34- VARIABLE_PATTERN = r'^\s*\${[^}]*}\s*=\s*'
34+ VARIABLE_PATTERN = re .compile (r'^\s*\${[^}]*}\s*=\s*' )
35+ IMAGE_PATTERN = re .compile (
36+ r'</td></tr><tr><td colspan="\d+"><a href="[^"]+"(?: target="_blank")?>'
37+ r'<img src="([^"]+)" width="\d+(?:px|pt)?"/?></a>' )
38+
39+ DEFAULT_BINARY_FILE_TYPE = 'application/octet-stream'
3540TRUNCATION_SIGN = "...'"
3641
3742
@@ -98,7 +103,7 @@ def __init__(self) -> None:
98103 self ._service = None
99104 self ._variables = None
100105
101- def _build_msg_struct (self , message : Dict ) -> LogMessage :
106+ def _build_msg_struct (self , message : Dict [ str , Any ] ) -> LogMessage :
102107 """Check if the given message comes from our custom logger or not.
103108
104109 :param message: Message passed by the Robot Framework
@@ -110,6 +115,44 @@ def _build_msg_struct(self, message: Dict) -> LogMessage:
110115 msg .level = message ['level' ]
111116 if not msg .launch_log :
112117 msg .item_id = getattr (self .current_item , 'rp_item_id' , None )
118+
119+ message_str = msg .message
120+ if is_binary (message_str ):
121+ variable_match = VARIABLE_PATTERN .search (message_str )
122+ if variable_match :
123+ # Treat as partial binary data
124+ msg_content = message_str [variable_match .end ():]
125+ # remove trailing `'"...`, add `...'`
126+ msg .message = (message_str [variable_match .start ():variable_match .end ()]
127+ + str (msg_content .encode ('utf-8' ))[:- 5 ] + TRUNCATION_SIGN )
128+ else :
129+ # Do not log full binary data, since it's usually corrupted
130+ content_type = guess_content_type_from_bytes (_unescape (message_str , 128 ))
131+ msg .message = (f'Binary data of type "{ content_type } " logging skipped, as it was processed as text and'
132+ ' hence corrupted.' )
133+ msg .level = 'WARN'
134+ elif message .get ('html' , 'no' ) == 'yes' :
135+ image_match = IMAGE_PATTERN .match (message_str )
136+ if image_match :
137+ image_path = image_match .group (1 )
138+ msg .message = f'Image attached: { image_path } '
139+ if os .path .exists (image_path ):
140+ image_type_by_name = guess_type (image_path )[0 ]
141+ with open (image_path , 'rb' ) as fh :
142+ image_data = fh .read ()
143+ image_type_by_data = guess_content_type_from_bytes (image_data )
144+ if image_type_by_name and image_type_by_data and image_type_by_name != image_type_by_data :
145+ logger .warning (
146+ f'Image type mismatch: type by file name "{ image_type_by_name } " '
147+ f'!= type by file content "{ image_type_by_data } "' )
148+ mime_type = DEFAULT_BINARY_FILE_TYPE
149+ else :
150+ mime_type = image_type_by_name or image_type_by_data or DEFAULT_BINARY_FILE_TYPE
151+ msg .attachment = {
152+ 'name' : os .path .basename (image_path ),
153+ 'data' : image_data ,
154+ 'mime' : mime_type
155+ }
113156 return msg
114157
115158 def _add_current_item (self , item : Union [Keyword , Launch , Suite , Test ]) -> None :
@@ -132,20 +175,6 @@ def log_message(self, message: Dict) -> None:
132175 :param message: Message passed by the Robot Framework
133176 """
134177 msg = self ._build_msg_struct (message )
135- if is_binary (msg .message ):
136- variable_match = re .search (VARIABLE_PATTERN , msg .message )
137- if variable_match :
138- # Treat as partial binary data
139- msg_content = msg .message [variable_match .end ():]
140- # remove trailing `'"...`, add `...'`
141- msg .message = (msg .message [variable_match .start ():variable_match .end ()]
142- + str (msg_content .encode ('utf-8' ))[:- 5 ] + TRUNCATION_SIGN )
143- else :
144- # Do not log full binary data, since it's usually corrupted
145- content_type = guess_content_type_from_bytes (_unescape (msg .message , 128 ))
146- msg .message = (f'Binary data of type "{ content_type } " logging skipped, as it was processed as text and'
147- ' hence corrupted.' )
148- msg .level = 'WARN'
149178 logger .debug (f'ReportPortal - Log Message: { message } ' )
150179 self .service .log (message = msg )
151180
@@ -161,7 +190,7 @@ def log_message_with_image(self, msg: Dict, image: str):
161190 mes .attachment = {
162191 'name' : os .path .basename (image ),
163192 'data' : fh .read (),
164- 'mime' : guess_type (image )[0 ] or 'application/octet-stream'
193+ 'mime' : guess_type (image )[0 ] or DEFAULT_BINARY_FILE_TYPE
165194 }
166195 logger .debug (f'ReportPortal - Log Message with Image: { mes } { image } ' )
167196 self .service .log (message = mes )
0 commit comments