1- # Copyright 2018 Alexey Stepanov aka penguinolog.
1+ # Copyright 2018 - 2019 Alexey Stepanov aka penguinolog.
22
33# Copyright 2016 Mirantis, Inc.
44#
3737from exec_helpers import exceptions
3838from exec_helpers import proc_enums
3939
40+ try :
41+ import lxml .etree # type: ignore # nosec
42+ except ImportError :
43+ lxml = None # pylint: disable=invalid-name
44+
4045if typing .TYPE_CHECKING :
4146 import xml .etree .ElementTree # nosec # noqa # pylint: disable=unused-import
4247
@@ -496,6 +501,8 @@ def __deserialize(self, fmt): # type: (typing.Text) -> typing.Any
496501 return yaml .safe_load (self .stdout_str )
497502 if fmt == "xml" :
498503 return defusedxml .ElementTree .fromstring (bytes (self .stdout_bin ))
504+ if fmt == "lxml" :
505+ return lxml .etree .fromstring (bytes (self .stdout_bin )) # nosec
499506 except Exception :
500507 tmpl = " stdout is not valid {fmt}:\n " "{{stdout!r}}\n " .format (fmt = fmt )
501508 logger .exception (self .cmd + tmpl .format (stdout = self .stdout_str ))
@@ -526,17 +533,32 @@ def stdout_yaml(self): # type: () -> typing.Any
526533
527534 @property
528535 def stdout_xml (self ): # type: () -> xml.etree.ElementTree.Element
529- """YAML from stdout.
536+ """XML from stdout.
530537
531538 :rtype: xml.etree.ElementTree.Element
532539 :raises DeserializeValueError: STDOUT can not be deserialized as XML
533540 """
534541 with self .stdout_lock :
535542 return self .__deserialize (fmt = "xml" ) # type: ignore
536543
544+ @property
545+ def stdout_lxml (self ): # type: () -> "lxml.etree.Element"
546+ """XML from stdout using lxml.
547+
548+ :rtype: lxml.etree.Element
549+ :raises DeserializeValueError: STDOUT can not be deserialized as XML
550+ :raises AttributeError: lxml is not installed
551+
552+ .. note:: Can be insecure.
553+ """
554+ if lxml is None :
555+ raise AttributeError ("lxml is not installed -> attribute is not functional." )
556+ with self .stdout_lock :
557+ return self .__deserialize (fmt = "lxml" )
558+
537559 def __dir__ (self ): # type: () -> typing.List[typing.Text]
538560 """Override dir for IDE and as source for getitem checks."""
539- return [
561+ content = [
540562 "cmd" ,
541563 "stdout" ,
542564 "stderr" ,
@@ -554,6 +576,9 @@ def __dir__(self): # type: () -> typing.List[typing.Text]
554576 "stdout_xml" ,
555577 "lock" ,
556578 ]
579+ if lxml is not None :
580+ content .append ("stdout_lxml" )
581+ return content
557582
558583 def __getitem__ (self , item ): # type: (typing.Union[str, typing.Text]) -> typing.Any
559584 """Dict like get data.
0 commit comments