coveralls: ## Pull Request Test Coverage Report for [Build 128](https://coveralls.io/builds/17142361)

* **17** of **17**   **(100.0%)**  changed or added relevant lines in **3** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage remained the same at **100.0%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/17142361/badge)](https://coveralls.io/builds/17142361) |
| :-- | --: |
| Change from base [Build 127](https://coveralls.io/builds/17054024): |  0.0% |
| Covered Lines: | 945 |
| Relevant Lines: | 945 |

---
##### 💛  - [Coveralls](https://coveralls.io)

coveralls: ## Pull Request Test Coverage Report for [Build 128](https://coveralls.io/builds/17142361)

* **17** of **17**   **(100.0%)**  changed or added relevant lines in **3** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage remained the same at **100.0%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/17142361/badge)](https://coveralls.io/builds/17142361) |
| :-- | --: |
| Change from base [Build 127](https://coveralls.io/builds/17054024): |  0.0% |
| Covered Lines: | 945 |
| Relevant Lines: | 945 |

---
##### 💛  - [Coveralls](https://coveralls.io)

coveralls: ## Pull Request Test Coverage Report for [Build 128](https://coveralls.io/builds/17142361)

* **17** of **17**   **(100.0%)**  changed or added relevant lines in **3** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage remained the same at **100.0%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/17142361/badge)](https://coveralls.io/builds/17142361) |
| :-- | --: |
| Change from base [Build 127](https://coveralls.io/builds/17054024): |  0.0% |
| Covered Lines: | 945 |
| Relevant Lines: | 945 |

---
##### 💛  - [Coveralls](https://coveralls.io)

diff --git a/doc/source/exceptions.rst b/doc/source/exceptions.rst
index d558cae..5d50d24 100644
--- a/doc/source/exceptions.rst
+++ b/doc/source/exceptions.rst
@@ -14,13 +14,45 @@ API: exceptions
 
     Deserialize impossible.
 
-.. py:exception:: ExecHelperTimeoutError(ExecHelperError)
+.. py:exception:: ExecCalledProcessError(ExecHelperError)
+
+    Base class for process call errors.
+
+.. py:exception:: ExecHelperTimeoutError(ExecCalledProcessError)
 
     Execution timeout.
 
-.. py:exception:: ExecCalledProcessError(ExecHelperError)
+    .. versionchanged:: 1.3.0 provide full result and timeout inside.
+    .. versionchanged:: 1.3.0 subclass ExecCalledProcessError
 
-    Base class for process call errors.
+    .. py:method:: __init__(self, result, timeout)
+
+        Exception for error on process calls.
+
+        :param result: execution result
+        :type result: exec_result.ExecResult
+        :param timeout: timeout for command
+        :type timeout: typing.Union[int, float]
+
+    .. py:attribute:: timeout
+
+        ``int``
+
+    .. py:attribute:: result
+
+        Execution result
+
+        :rtype: ExecResult
+
+    .. py:attribute:: stdout
+
+        ``typing.Text``
+        stdout string or brief string
+
+    .. py:attribute:: stderr
+
+        ``typing.Text``
+        stdout string or brief string
 
 .. py:exception:: CalledProcessError(ExecCalledProcessError)
 
@@ -60,12 +92,12 @@ API: exceptions
 
     .. py:attribute:: stdout
 
-        ``typing.Any``
+        ``typing.Text``
         stdout string or brief string
 
     .. py:attribute:: stderr
 
-        ``typing.Any``
+        ``typing.Text``
         stdout string or brief string
 
 .. py:exception:: ParallelCallExceptions(ExecCalledProcessError)
diff --git a/exec_helpers/_ssh_client_base.py b/exec_helpers/_ssh_client_base.py
index 65395bc..f0ce5b5 100644
--- a/exec_helpers/_ssh_client_base.py
+++ b/exec_helpers/_ssh_client_base.py
@@ -735,7 +735,7 @@ class SSHClientBase(six.with_metaclass(_MemorizedSSH, _api.ExecHelper)):
             timeout=timeout
         )
         self.logger.debug(wait_err_msg)
-        raise exceptions.ExecHelperTimeoutError(wait_err_msg)
+        raise exceptions.ExecHelperTimeoutError(result=result, timeout=timeout)
 
     def execute_through_host(
         self,
diff --git a/exec_helpers/exceptions.py b/exec_helpers/exceptions.py
index 07d2cb4..fc01aa7 100644
--- a/exec_helpers/exceptions.py
+++ b/exec_helpers/exceptions.py
@@ -21,6 +21,7 @@ from __future__ import unicode_literals
 import typing  # noqa  # pylint: disable=unused-import
 
 from exec_helpers import proc_enums
+from exec_helpers import _log_templates
 
 __all__ = (
     'ExecHelperError',
@@ -44,16 +45,58 @@ class DeserializeValueError(ExecHelperError, ValueError):
     __slots__ = ()
 
 
-class ExecHelperTimeoutError(ExecHelperError):
-    """Execution timeout."""
+class ExecCalledProcessError(ExecHelperError):
+    """Base class for process call errors."""
 
     __slots__ = ()
 
 
-class ExecCalledProcessError(ExecHelperError):
-    """Base class for process call errors."""
+class ExecHelperTimeoutError(ExecCalledProcessError):
+    """Execution timeout.
 
-    __slots__ = ()
+    .. versionchanged:: 1.3.0 provide full result and timeout inside.
+    .. versionchanged:: 1.3.0 subclass ExecCalledProcessError
+    """
+
+    __slots__ = (
+        'result',
+        'timeout',
+    )
+
+    def __init__(
+        self,
+        result,  # type: exec_result.ExecResult
+        timeout,  # type: typing.Union[int, float]
+    ):  # type: (...) -> None
+        """Exception for error on process calls.
+
+        :param result: execution result
+        :type result: exec_result.ExecResult
+        :param timeout: timeout for command
+        :type timeout: typing.Union[int, float]
+        """
+        self.result = result
+        self.timeout = timeout
+        message = _log_templates.CMD_WAIT_ERROR.format(
+            result=result,
+            timeout=timeout
+        )
+        super(ExecHelperTimeoutError, self).__init__(message)
+
+    @property
+    def cmd(self):  # type: () -> str
+        """Failed command."""
+        return self.result.cmd
+
+    @property
+    def stdout(self):  # type: () -> typing.Text
+        """Command stdout."""
+        return self.result.stdout_str
+
+    @property
+    def stderr(self):  # type: () -> typing.Text
+        """Command stderr."""
+        return self.result.stderr_str
 
 
 class CalledProcessError(ExecCalledProcessError):
@@ -74,9 +117,7 @@ class CalledProcessError(ExecCalledProcessError):
         :param result: execution result
         :type result: exec_result.ExecResult
         :param expected: expected return codes
-        :type expected: typing.Optional[
-            typing.List[typing.Union[int, proc_enums.ExitCodes]]
-        ]
+        :type expected: typing.Optional[typing.List[typing.Union[int, proc_enums.ExitCodes]]]
 
         .. versionchanged:: 1.1.1 - provide full result
         """
@@ -89,7 +130,7 @@ class CalledProcessError(ExecCalledProcessError):
             "\tSTDOUT:\n"
             "{result.stdout_brief}\n"
             "\tSTDERR:\n{result.stderr_brief}".format(
-                result=result,
+                result=self.result,
                 expected=self.expected
             )
         )
diff --git a/exec_helpers/exceptions.pyi b/exec_helpers/exceptions.pyi
index 4a22763..1f4558b 100644
--- a/exec_helpers/exceptions.pyi
+++ b/exec_helpers/exceptions.pyi
@@ -7,13 +7,32 @@ class ExecHelperError(Exception):
 class DeserializeValueError(ExecHelperError, ValueError):
     ...
 
-class ExecHelperTimeoutError(ExecHelperError):
-    ...
 
 class ExecCalledProcessError(ExecHelperError):
     ...
 
 
+class ExecHelperTimeoutError(ExecCalledProcessError):
+
+    result: exec_result.ExecResult = ...
+    timeout: int = ...
+
+    def __init__(
+        self,
+        result: exec_result.ExecResult,
+        timeout: typing.Union[int, float],
+    ) -> None: ...
+
+    @property
+    def cmd(self) -> str: ...
+
+    @property
+    def stdout(self) -> typing.Text: ...
+
+    @property
+    def stderr(self) -> typing.Text: ...
+
+
 class CalledProcessError(ExecCalledProcessError):
 
     result: exec_result.ExecResult = ...
diff --git a/exec_helpers/subprocess_runner.py b/exec_helpers/subprocess_runner.py
index 8b79cc2..b36a05c 100644
--- a/exec_helpers/subprocess_runner.py
+++ b/exec_helpers/subprocess_runner.py
@@ -269,7 +269,7 @@ class Subprocess(six.with_metaclass(SingletonMeta, _api.ExecHelper)):
             timeout=timeout
         )
         logger.debug(wait_err_msg)
-        raise exceptions.ExecHelperTimeoutError(wait_err_msg)
+        raise exceptions.ExecHelperTimeoutError(result=result, timeout=timeout)
 
     def execute_async(
         self,

Timeout error object should contain execution result and timeout for the future processing
Currently `ExecHelperTimeoutError` contains only message and inherited from `ExecHelperError` while used in single call scenarios only.
Need to re-inherit `ExecHelperError` and provide result + timeout + properties access to cmd, stdout_str and stderr_str.
diff --git a/test/test_ssh_client.py b/test/test_ssh_client.py
index 9119773..f02a68f 100644
--- a/test/test_ssh_client.py
+++ b/test/test_ssh_client.py
@@ -1028,10 +1028,15 @@ class TestExecute(unittest.TestCase):
 
         logger.reset_mock()
 
-        with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
+        with self.assertRaises(exec_helpers.ExecHelperTimeoutError) as cm:
             # noinspection PyTypeChecker
             ssh.execute(command=command, verbose=False, timeout=0.2)
 
+        self.assertEqual(cm.exception.timeout, 0.2)
+        self.assertEqual(cm.exception.cmd, command)
+        self.assertEqual(cm.exception.stdout, stdout_str)
+        self.assertEqual(cm.exception.stderr, stderr_str)
+
         execute_async.assert_called_once_with(command, verbose=False)
         chan.assert_has_calls((mock.call.status_event.is_set(), ))
 
diff --git a/test/test_subprocess_runner.py b/test/test_subprocess_runner.py
index 04555c7..18d508d 100644
--- a/test/test_subprocess_runner.py
+++ b/test/test_subprocess_runner.py
@@ -233,10 +233,15 @@ class TestSubprocessRunner(unittest.TestCase):
 
         # noinspection PyTypeChecker
 
-        with self.assertRaises(exec_helpers.ExecHelperTimeoutError):
+        with self.assertRaises(exec_helpers.ExecHelperTimeoutError) as cm:
             # noinspection PyTypeChecker
             runner.execute(command, timeout=0.2)
 
+        self.assertEqual(cm.exception.timeout, 0.2)
+        self.assertEqual(cm.exception.cmd, command)
+        self.assertEqual(cm.exception.stdout, exp_result.stdout_str)
+        self.assertEqual(cm.exception.stderr, exp_result.stderr_str)
+
         popen.assert_has_calls((
             mock.call(
                 args=[command],

pip install -e .
parse_log_pytest_v2
requirements.txt
pytest pytest-cov pytest-html pytest-sugar
apt-get update apt-get install -y gcc
3.6
requirements.txt CI_REQUIREMENTS.txt build_requirements.txt
pytest -vv -s -p no:django -p no:ipdb
advanced-descriptors==3.0.9.post0
attrs==22.2.0
bcrypt==4.0.1
certifi==2021.5.30
cffi==1.15.1
coverage==6.2
cryptography==40.0.2
Cython==3.0.12
-e git+https://github.com/python-useful-helpers/exec-helpers.git@814d435b7eda2b00fa1559d5a94103f1e888ab52#egg=exec_helpers
importlib-metadata==4.8.3
iniconfig==1.1.1
mock==5.2.0
packaging==21.3
paramiko==3.5.1
pluggy==1.0.0
py==1.11.0
pycparser==2.21
PyNaCl==1.5.0
pyparsing==3.1.4
pytest==7.0.1
pytest-cov==4.0.0
pytest-html==3.2.0
pytest-metadata==1.11.0
pytest-sugar==0.9.6
PyYAML==6.0.1
six==1.17.0
tenacity==8.2.2
termcolor==1.1.0
threaded==4.1.0
tomli==1.2.3
typing_extensions==4.1.1
zipp==3.6.0

name: exec-helpers
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - advanced-descriptors==3.0.9.post0
      - attrs==22.2.0
      - bcrypt==4.0.1
      - cffi==1.15.1
      - coverage==6.2
      - cryptography==40.0.2
      - cython==3.0.12
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - mock==5.2.0
      - packaging==21.3
      - paramiko==3.5.1
      - pluggy==1.0.0
      - py==1.11.0
      - pycparser==2.21
      - pynacl==1.5.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - pytest-html==3.2.0
      - pytest-metadata==1.11.0
      - pytest-sugar==0.9.6
      - pyyaml==6.0.1
      - six==1.17.0
      - tenacity==8.2.2
      - termcolor==1.1.0
      - threaded==4.1.0
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - zipp==3.6.0
prefix: /opt/conda/envs/exec-helpers

test/test_ssh_client.py::TestExecute::test_025_execute_timeout_fail test/test_subprocess_runner.py::TestSubprocessRunner::test_004_execute_timeout_fail
test/test_ssh_client.py::TestExecute::test_001_execute_async test/test_ssh_client.py::TestExecute::test_002_execute_async_pty test/test_ssh_client.py::TestExecute::test_003_execute_async_no_stdout_stderr test/test_ssh_client.py::TestExecute::test_004_execute_async_sudo test/test_ssh_client.py::TestExecute::test_005_execute_async_with_sudo_enforce test/test_ssh_client.py::TestExecute::test_006_execute_async_with_no_sudo_enforce test/test_ssh_client.py::TestExecute::test_007_execute_async_with_sudo_none_enforce test/test_ssh_client.py::TestExecute::test_008_execute_async_sudo_password test/test_ssh_client.py::TestExecute::test_009_execute_async_verbose test/test_ssh_client.py::TestExecute::test_010_execute_async_mask_command test/test_ssh_client.py::TestExecute::test_011_check_stdin_str test/test_ssh_client.py::TestExecute::test_012_check_stdin_bytes test/test_ssh_client.py::TestExecute::test_013_check_stdin_bytearray test/test_ssh_client.py::TestExecute::test_014_check_stdin_closed test/test_ssh_client.py::TestExecute::test_015_keepalive test/test_ssh_client.py::TestExecute::test_016_no_keepalive test/test_ssh_client.py::TestExecute::test_017_keepalive_enforced test/test_ssh_client.py::TestExecute::test_018_no_keepalive_enforced test/test_ssh_client.py::TestExecute::test_019_execute test/test_ssh_client.py::TestExecute::test_020_execute_verbose test/test_ssh_client.py::TestExecute::test_021_execute_no_stdout test/test_ssh_client.py::TestExecute::test_022_execute_no_stderr test/test_ssh_client.py::TestExecute::test_023_execute_no_stdout_stderr test/test_ssh_client.py::TestExecute::test_024_execute_timeout test/test_ssh_client.py::TestExecute::test_026_execute_mask_command test/test_ssh_client.py::TestExecute::test_027_execute_together test/test_ssh_client.py::TestExecute::test_028_execute_together_exceptions test/test_ssh_client.py::TestExecute::test_029_check_call test/test_ssh_client.py::TestExecute::test_030_check_call_expected test/test_ssh_client.py::TestExecute::test_031_check_stderr test/test_ssh_client.py::TestExecuteThrowHost::test_01_execute_through_host_no_creds test/test_ssh_client.py::TestExecuteThrowHost::test_02_execute_through_host_auth test/test_ssh_client.py::TestExecuteThrowHost::test_03_execute_through_host_get_pty test/test_ssh_client.py::TestSftp::test_download test/test_ssh_client.py::TestSftp::test_exists test/test_ssh_client.py::TestSftp::test_isdir test/test_ssh_client.py::TestSftp::test_isfile test/test_ssh_client.py::TestSftp::test_mkdir test/test_ssh_client.py::TestSftp::test_open test/test_ssh_client.py::TestSftp::test_rm_rf test/test_ssh_client.py::TestSftp::test_stat test/test_ssh_client.py::TestSftp::test_upload_dir test/test_ssh_client.py::TestSftp::test_upload_file test/test_subprocess_runner.py::TestSubprocessRunner::test_001_call test/test_subprocess_runner.py::TestSubprocessRunner::test_002_call_verbose test/test_subprocess_runner.py::TestSubprocessRunner::test_003_context_manager test/test_subprocess_runner.py::TestSubprocessRunner::test_004_check_stdin_str test/test_subprocess_runner.py::TestSubprocessRunner::test_005_check_stdin_bytes test/test_subprocess_runner.py::TestSubprocessRunner::test_005_execute_no_stdout test/test_subprocess_runner.py::TestSubprocessRunner::test_006_check_stdin_bytearray test/test_subprocess_runner.py::TestSubprocessRunner::test_006_execute_no_stderr test/test_subprocess_runner.py::TestSubprocessRunner::test_007_check_stdin_fail_broken_pipe test/test_subprocess_runner.py::TestSubprocessRunner::test_007_execute_no_stdout_stderr test/test_subprocess_runner.py::TestSubprocessRunner::test_008_check_stdin_fail_closed_win test/test_subprocess_runner.py::TestSubprocessRunner::test_008_execute_mask_global test/test_subprocess_runner.py::TestSubprocessRunner::test_009_check_stdin_fail_write test/test_subprocess_runner.py::TestSubprocessRunner::test_009_execute_mask_local test/test_subprocess_runner.py::TestSubprocessRunner::test_010_check_stdin_fail_close_pipe test/test_subprocess_runner.py::TestSubprocessRunner::test_011_check_stdin_fail_close_pipe_win test/test_subprocess_runner.py::TestSubprocessRunner::test_012_check_stdin_fail_close test/test_subprocess_runner.py::TestSubprocessRunner::test_013_execute_timeout_done test/test_subprocess_runner.py::TestSubprocessRunnerHelpers::test_001_check_call test/test_subprocess_runner.py::TestSubprocessRunnerHelpers::test_002_check_call_expected test/test_subprocess_runner.py::TestSubprocessRunnerHelpers::test_003_check_stderr
doc/source/exceptions.rst exec_helpers/subprocess_runner.py exec_helpers/_ssh_client_base.py exec_helpers/exceptions.pyi exec_helpers/exceptions.py
doc/source/exceptions.rst exec_helpers/subprocess_runner.py exec_helpers/_ssh_client_base.py exec_helpers/exceptions.pyi exec_helpers/exceptions.py