shelltastic 0.4.3__tar.gz → 0.4.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {shelltastic-0.4.3 → shelltastic-0.4.4}/PKG-INFO +1 -1
  2. {shelltastic-0.4.3 → shelltastic-0.4.4}/pyproject.toml +1 -1
  3. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/backend/default/remote.py +6 -0
  4. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/display.py +14 -19
  5. {shelltastic-0.4.3 → shelltastic-0.4.4}/LICENSE +0 -0
  6. {shelltastic-0.4.3 → shelltastic-0.4.4}/README.md +0 -0
  7. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/__init__.py +0 -0
  8. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/backend/__init__.py +0 -0
  9. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/backend/base.py +0 -0
  10. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/backend/default/__init__.py +0 -0
  11. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/backend/default/common.py +0 -0
  12. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/backend/default/local.py +0 -0
  13. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/enum.py +0 -0
  14. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/exception.py +0 -0
  15. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/frontend/__init__.py +0 -0
  16. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/frontend/common.py +0 -0
  17. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/frontend/git.py +0 -0
  18. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/frontend/scp.py +0 -0
  19. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/frontend/shell.py +0 -0
  20. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/host.py +0 -0
  21. {shelltastic-0.4.3 → shelltastic-0.4.4}/src/shelltastic/result.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shelltastic
3
- Version: 0.4.3
3
+ Version: 0.4.4
4
4
  Summary: A fantastic shell command runner for python
5
5
  Author: Bearmine
6
6
  License-Expression: MPL-2.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "shelltastic"
3
- version = "0.4.3"
3
+ version = "0.4.4"
4
4
  description = "A fantastic shell command runner for python"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING
6
6
 
7
7
  from shelltastic.backend.base import RemoteShellBackend
8
8
  from shelltastic.backend.default.common import CommonDefaultBackend
9
+ from shelltastic.enum import CaptureMode
9
10
  from shelltastic.exception import ShellException, SSHConnectionError
10
11
 
11
12
  if TYPE_CHECKING:
@@ -44,6 +45,11 @@ class DefaultRemoteBackend(CommonDefaultBackend, RemoteShellBackend):
44
45
  if subshell:
45
46
  cmd = shlex.join(["bash", "-c", cmd])
46
47
 
48
+ # If we're redirecting stderr to stdout,
49
+ # add the same redirect inside the ssh command.
50
+ if kwargs.get("stderr") == CaptureMode.STDOUT:
51
+ cmd = cmd + " 2>&1"
52
+
47
53
  # cd into cwd first if cwd is set
48
54
  if cwd:
49
55
  cmd = shlex.join(["cd", str(cwd)]) + " && " + cmd
@@ -1,43 +1,41 @@
1
1
  import logging
2
2
  import sys
3
+ import threading
3
4
  from abc import ABC, abstractmethod
4
5
 
5
6
  from shelltastic.enum import DisplayMode
6
7
 
7
8
  LOGGER = logging.getLogger(__name__)
8
9
 
10
+ _io_display_lock = threading.RLock()
11
+
9
12
 
10
13
  class IODisplay(ABC):
11
- @abstractmethod
12
14
  def printbytes(self, line: bytes):
13
- raise NotImplementedError
15
+ with _io_display_lock:
16
+ self._emit_line(line.decode().rstrip())
14
17
 
15
- @abstractmethod
16
18
  def printline(self, msg: object, *args: object):
19
+ with _io_display_lock:
20
+ self._emit_line(msg, *args)
21
+
22
+ @abstractmethod
23
+ def _emit_line(self, msg: object, *args: object):
17
24
  raise NotImplementedError
18
25
 
19
26
 
20
27
  class DevNullDisplay(IODisplay):
21
- def printbytes(self, line: bytes):
22
- pass
23
-
24
- def printline(self, msg, *args):
28
+ def _emit_line(self, msg: object, *args: object):
25
29
  pass
26
30
 
27
31
 
28
32
  class StdoutDisplay(IODisplay):
29
- def printbytes(self, line: bytes):
30
- print(line.decode(), end="", flush=True)
31
-
32
- def printline(self, msg, *args):
33
+ def _emit_line(self, msg: object, *args: object):
33
34
  print(str(msg) % args, flush=True)
34
35
 
35
36
 
36
37
  class StderrDisplay(IODisplay):
37
- def printbytes(self, line: bytes):
38
- print(line.decode(), end="", file=sys.stderr, flush=True)
39
-
40
- def printline(self, msg, *args):
38
+ def _emit_line(self, msg: object, *args: object):
41
39
  print(str(msg) % args, file=sys.stderr, flush=True)
42
40
 
43
41
 
@@ -46,10 +44,7 @@ class LogDisplay(IODisplay):
46
44
  super().__init__()
47
45
  self.log_level = log_level
48
46
 
49
- def printbytes(self, line: bytes):
50
- LOGGER.log(self.log_level, line.decode().rstrip(), stacklevel=2)
51
-
52
- def printline(self, msg: object, *args: object):
47
+ def _emit_line(self, msg: object, *args: object):
53
48
  LOGGER.log(self.log_level, msg, *args, stacklevel=2)
54
49
 
55
50
 
File without changes
File without changes