Skip to content

Commit

Permalink
xml is also optional
Browse files Browse the repository at this point in the history
Signed-off-by: Aleksei Stepanov <penguinolog@gmail.com>
  • Loading branch information
penguinolog committed May 23, 2019
1 parent 161200c commit f618551
Show file tree
Hide file tree
Showing 7 changed files with 25 additions and 12 deletions.
1 change: 1 addition & 0 deletions CI_REQUIREMENTS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
lxml!=3.7.0
PyYAML>=3.12
ruamel.yaml
defusedxml # PSF
8 changes: 4 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ or call command and wait for return code, but without timeout processing.

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.
This library offers this functionality with connection memorizing, deadlock free polling and friendly result objects
(with inline decoding of YAML, JSON, binary or just strings).
(with inline decoding of XML Element tree, YAML, JSON, binary or just strings).
In addition this library offers the same API for subprocess calls, but with specific limitation: no parallel calls
(for protection from race conditions).

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

* `stdout_json` - STDOUT decoded as JSON.

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

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

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

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

Expand Down
1 change: 1 addition & 0 deletions doc/source/ExecResult.rst
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ API: ExecResult

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

.. py:attribute:: stdout_lxml
Expand Down
20 changes: 13 additions & 7 deletions exec_helpers/exec_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@
import logging
import threading
import typing
import xml.etree.ElementTree # nosec # for typing only

# External Dependencies
import defusedxml.ElementTree # type: ignore

# Exec-Helpers Implementation
from exec_helpers import exceptions
Expand All @@ -42,13 +38,19 @@
import ruamel.yaml as ruamel_yaml # type: ignore
except ImportError:
ruamel_yaml = None # pylint: disable=invalid-name

try:
import defusedxml.ElementTree # type: ignore
except ImportError:
defusedxml = None # pylint: disable=invalid-name
try:
# noinspection PyPackageRequirements
import lxml.etree # type: ignore # nosec
except ImportError:
lxml = None # pylint: disable=invalid-name

if typing.TYPE_CHECKING:
import xml.etree.ElementTree # nosec # for typing only

LOGGER: logging.Logger = logging.getLogger(__name__)


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

@property
def stdout_xml(self) -> xml.etree.ElementTree.Element:
def stdout_xml(self) -> "xml.etree.ElementTree.Element":
"""XML from stdout.
:rtype: xml.etree.ElementTree.Element
:raises DeserializeValueError: STDOUT can not be deserialized as XML
:raises AttributeError: defusedxml is not installed
"""
if defusedxml is None:
raise AttributeError("defusedxml is not installed -> attribute is not functional by security reasons.")
with self.stdout_lock:
return self.__deserialize(fmt="xml") # type: ignore

Expand Down Expand Up @@ -591,11 +596,12 @@ def __dir__(self) -> typing.List[str]:
"stdout_lines",
"stderr_lines",
"stdout_json",
"stdout_xml",
"lock",
]
if yaml is not None or ruamel_yaml is not None:
content.append("stdout_yaml")
if defusedxml is not None:
content.append("stdout_xml")
if lxml is not None:
content.append("stdout_lxml")
return content
Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ threaded>=2.0 # Apache-2.0
advanced-descriptors>=1.0 # Apache-2.0
typing >= 3.6 ; python_version < "3.7" # PSF
psutil >= 5.0 # BSD
defusedxml # PSF
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ def get_simple_vars_from_src(src):
use_scm_version={'write_to': 'exec_helpers/_version.py'},
install_requires=REQUIRED,
extras_require={
"xml": ["defusedxml"],
"lxml": ["lxml!=3.7.0"],
"yaml": ["PyYAML>=3.12"],
},
Expand Down
5 changes: 5 additions & 0 deletions test/test_exec_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
import ruamel.yaml as ruamel_yaml
except ImportError:
ruamel_yaml = None
try:
import defusedxml.ElementTree
except ImportError:
defusedxml = None
try:
import lxml.etree
except ImportError:
Expand Down Expand Up @@ -274,6 +278,7 @@ def test_indexed_lines_access(self):
with self.assertRaises(TypeError):
_ = result.stdout_lines[1, "aaa"] # noqa

@unittest.skipIf(defusedxml is None, "defusedxml is not installed")
def test_stdout_xml(self):
result = exec_helpers.ExecResult(
"test",
Expand Down

0 comments on commit f618551

Please sign in to comment.