Skip to content

Commit f618551

Browse files
committed
xml is also optional
Signed-off-by: Aleksei Stepanov <penguinolog@gmail.com>
1 parent 161200c commit f618551

File tree

7 files changed

+25
-12
lines changed

7 files changed

+25
-12
lines changed

CI_REQUIREMENTS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
lxml!=3.7.0
33
PyYAML>=3.12
44
ruamel.yaml
5+
defusedxml # PSF

README.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ or call command and wait for return code, but without timeout processing.
3030

3131
In the most cases, we are need just simple SSH client with comfortable API for calls, calls via SSH proxy and checking return code/stderr.
3232
This library offers this functionality with connection memorizing, deadlock free polling and friendly result objects
33-
(with inline decoding of YAML, JSON, binary or just strings).
33+
(with inline decoding of XML Element tree, YAML, JSON, binary or just strings).
3434
In addition this library offers the same API for subprocess calls, but with specific limitation: no parallel calls
3535
(for protection from race conditions).
3636

@@ -223,11 +223,11 @@ Execution result object has a set of useful properties:
223223

224224
* `stdout_json` - STDOUT decoded as JSON.
225225

226-
* `stdout_yaml` - STDOUT decoded as YAML. Accessible only if PyYAML or ruamel.YAML library installed.
226+
* `stdout_yaml` - STDOUT decoded as YAML. Accessible only if PyYAML or ruamel.YAML library installed. (Option ``yaml``)
227227

228-
* `stdout_xml` - STDOUT decoded as XML to `ElementTree` using `defusedxml` library.
228+
* `stdout_xml` - STDOUT decoded as XML to `ElementTree` using `defusedxml` library. Accessible only if `defusedxml` library installed. (Option ``xml``)
229229

230-
* `stdout_lxml` - STDOUT decoded as XML to `ElementTree` using `lxml` library. Accessible only if lxml library installed. Can be insecure.
230+
* `stdout_lxml` - STDOUT decoded as XML to `ElementTree` using `lxml` library. Accessible only if `lxml` library installed. (Option ``lxml``) Can be insecure.
231231

232232
* `timestamp` -> `typing.Optional(datetime.datetime)`. Timestamp for received exit code.
233233

doc/source/ExecResult.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ API: ExecResult
154154

155155
:rtype: xml.etree.ElementTree.Element
156156
:raises DeserializeValueError: STDOUT can not be deserialized as XML
157+
:raises AttributeError: defusedxml is not installed
157158

158159
.. py:attribute:: stdout_lxml
159160

exec_helpers/exec_result.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@
2424
import logging
2525
import threading
2626
import typing
27-
import xml.etree.ElementTree # nosec # for typing only
28-
29-
# External Dependencies
30-
import defusedxml.ElementTree # type: ignore
3127

3228
# Exec-Helpers Implementation
3329
from exec_helpers import exceptions
@@ -42,13 +38,19 @@
4238
import ruamel.yaml as ruamel_yaml # type: ignore
4339
except ImportError:
4440
ruamel_yaml = None # pylint: disable=invalid-name
45-
41+
try:
42+
import defusedxml.ElementTree # type: ignore
43+
except ImportError:
44+
defusedxml = None # pylint: disable=invalid-name
4645
try:
4746
# noinspection PyPackageRequirements
4847
import lxml.etree # type: ignore # nosec
4948
except ImportError:
5049
lxml = None # pylint: disable=invalid-name
5150

51+
if typing.TYPE_CHECKING:
52+
import xml.etree.ElementTree # nosec # for typing only
53+
5254
LOGGER: logging.Logger = logging.getLogger(__name__)
5355

5456

@@ -551,12 +553,15 @@ def stdout_yaml(self) -> typing.Any:
551553
return self.__deserialize(fmt="yaml")
552554

553555
@property
554-
def stdout_xml(self) -> xml.etree.ElementTree.Element:
556+
def stdout_xml(self) -> "xml.etree.ElementTree.Element":
555557
"""XML from stdout.
556558
557559
:rtype: xml.etree.ElementTree.Element
558560
:raises DeserializeValueError: STDOUT can not be deserialized as XML
561+
:raises AttributeError: defusedxml is not installed
559562
"""
563+
if defusedxml is None:
564+
raise AttributeError("defusedxml is not installed -> attribute is not functional by security reasons.")
560565
with self.stdout_lock:
561566
return self.__deserialize(fmt="xml") # type: ignore
562567

@@ -591,11 +596,12 @@ def __dir__(self) -> typing.List[str]:
591596
"stdout_lines",
592597
"stderr_lines",
593598
"stdout_json",
594-
"stdout_xml",
595599
"lock",
596600
]
597601
if yaml is not None or ruamel_yaml is not None:
598602
content.append("stdout_yaml")
603+
if defusedxml is not None:
604+
content.append("stdout_xml")
599605
if lxml is not None:
600606
content.append("stdout_lxml")
601607
return content

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@ threaded>=2.0 # Apache-2.0
55
advanced-descriptors>=1.0 # Apache-2.0
66
typing >= 3.6 ; python_version < "3.7" # PSF
77
psutil >= 5.0 # BSD
8-
defusedxml # PSF

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ def get_simple_vars_from_src(src):
259259
use_scm_version={'write_to': 'exec_helpers/_version.py'},
260260
install_requires=REQUIRED,
261261
extras_require={
262+
"xml": ["defusedxml"],
262263
"lxml": ["lxml!=3.7.0"],
263264
"yaml": ["PyYAML>=3.12"],
264265
},

test/test_exec_result.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
import ruamel.yaml as ruamel_yaml
3535
except ImportError:
3636
ruamel_yaml = None
37+
try:
38+
import defusedxml.ElementTree
39+
except ImportError:
40+
defusedxml = None
3741
try:
3842
import lxml.etree
3943
except ImportError:
@@ -274,6 +278,7 @@ def test_indexed_lines_access(self):
274278
with self.assertRaises(TypeError):
275279
_ = result.stdout_lines[1, "aaa"] # noqa
276280

281+
@unittest.skipIf(defusedxml is None, "defusedxml is not installed")
277282
def test_stdout_xml(self):
278283
result = exec_helpers.ExecResult(
279284
"test",

0 commit comments

Comments
 (0)