pyinfra 3.2__py2.py3-none-any.whl → 3.3__py2.py3-none-any.whl

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 (88) hide show
  1. pyinfra/api/arguments_typed.py +4 -5
  2. pyinfra/api/command.py +22 -3
  3. pyinfra/api/config.py +5 -2
  4. pyinfra/api/facts.py +3 -0
  5. pyinfra/api/host.py +10 -4
  6. pyinfra/api/operation.py +2 -1
  7. pyinfra/api/state.py +1 -1
  8. pyinfra/connectors/base.py +34 -8
  9. pyinfra/connectors/chroot.py +7 -2
  10. pyinfra/connectors/docker.py +7 -2
  11. pyinfra/connectors/dockerssh.py +7 -2
  12. pyinfra/connectors/local.py +7 -2
  13. pyinfra/connectors/ssh.py +9 -2
  14. pyinfra/connectors/sshuserclient/client.py +16 -0
  15. pyinfra/connectors/sshuserclient/config.py +2 -0
  16. pyinfra/connectors/terraform.py +1 -1
  17. pyinfra/connectors/util.py +13 -9
  18. pyinfra/context.py +9 -2
  19. pyinfra/facts/apk.py +5 -0
  20. pyinfra/facts/apt.py +9 -1
  21. pyinfra/facts/brew.py +13 -0
  22. pyinfra/facts/bsdinit.py +3 -0
  23. pyinfra/facts/cargo.py +5 -0
  24. pyinfra/facts/choco.py +6 -0
  25. pyinfra/facts/crontab.py +6 -1
  26. pyinfra/facts/deb.py +10 -0
  27. pyinfra/facts/dnf.py +5 -0
  28. pyinfra/facts/docker.py +10 -0
  29. pyinfra/facts/efibootmgr.py +5 -0
  30. pyinfra/facts/files.py +19 -1
  31. pyinfra/facts/flatpak.py +7 -0
  32. pyinfra/facts/freebsd.py +75 -0
  33. pyinfra/facts/gem.py +5 -0
  34. pyinfra/facts/git.py +9 -0
  35. pyinfra/facts/gpg.py +7 -0
  36. pyinfra/facts/hardware.py +13 -0
  37. pyinfra/facts/iptables.py +9 -1
  38. pyinfra/facts/launchd.py +5 -0
  39. pyinfra/facts/lxd.py +5 -0
  40. pyinfra/facts/mysql.py +8 -0
  41. pyinfra/facts/npm.py +5 -0
  42. pyinfra/facts/openrc.py +8 -0
  43. pyinfra/facts/opkg.py +12 -0
  44. pyinfra/facts/pacman.py +9 -1
  45. pyinfra/facts/pip.py +5 -0
  46. pyinfra/facts/pipx.py +8 -0
  47. pyinfra/facts/pkg.py +4 -0
  48. pyinfra/facts/pkgin.py +5 -0
  49. pyinfra/facts/podman.py +7 -0
  50. pyinfra/facts/postgres.py +8 -2
  51. pyinfra/facts/rpm.py +11 -0
  52. pyinfra/facts/runit.py +7 -0
  53. pyinfra/facts/selinux.py +16 -0
  54. pyinfra/facts/server.py +49 -3
  55. pyinfra/facts/snap.py +7 -0
  56. pyinfra/facts/systemd.py +5 -0
  57. pyinfra/facts/sysvinit.py +4 -0
  58. pyinfra/facts/upstart.py +5 -0
  59. pyinfra/facts/util/__init__.py +4 -1
  60. pyinfra/facts/vzctl.py +5 -0
  61. pyinfra/facts/xbps.py +6 -1
  62. pyinfra/facts/yum.py +5 -0
  63. pyinfra/facts/zfs.py +19 -2
  64. pyinfra/facts/zypper.py +5 -0
  65. pyinfra/operations/apt.py +10 -3
  66. pyinfra/operations/docker.py +48 -44
  67. pyinfra/operations/files.py +47 -1
  68. pyinfra/operations/freebsd/__init__.py +12 -0
  69. pyinfra/operations/freebsd/freebsd_update.py +70 -0
  70. pyinfra/operations/freebsd/pkg.py +219 -0
  71. pyinfra/operations/freebsd/service.py +116 -0
  72. pyinfra/operations/freebsd/sysrc.py +92 -0
  73. pyinfra/operations/opkg.py +5 -5
  74. pyinfra/operations/postgres.py +99 -16
  75. pyinfra/operations/server.py +6 -4
  76. pyinfra/operations/util/docker.py +44 -22
  77. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/LICENSE.md +1 -1
  78. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/METADATA +25 -24
  79. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/RECORD +88 -82
  80. pyinfra_cli/exceptions.py +5 -0
  81. pyinfra_cli/log.py +3 -0
  82. pyinfra_cli/main.py +9 -8
  83. pyinfra_cli/prints.py +1 -1
  84. pyinfra_cli/virtualenv.py +1 -1
  85. tests/test_connectors/test_ssh.py +302 -182
  86. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/WHEEL +0 -0
  87. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/entry_points.txt +0 -0
  88. {pyinfra-3.2.dist-info → pyinfra-3.3.dist-info}/top_level.txt +0 -0
@@ -10,6 +10,7 @@ from os import environ, path
10
10
  import paramiko.config
11
11
  from gevent.subprocess import CalledProcessError, check_call
12
12
  from paramiko import SSHConfig as ParamikoSSHConfig
13
+ from typing_extensions import override
13
14
 
14
15
  from pyinfra import logger
15
16
 
@@ -95,6 +96,7 @@ class SSHConfig(ParamikoSSHConfig):
95
96
  https://github.com/paramiko/paramiko/pull/1194
96
97
  """
97
98
 
99
+ @override
98
100
  def parse(self, file_obj):
99
101
  file_obj = _expand_include_statements(file_obj)
100
102
  return super().parse(file_obj)
@@ -9,7 +9,7 @@ from .base import BaseConnector
9
9
 
10
10
 
11
11
  @memoize
12
- def show_warning():
12
+ def show_warning() -> None:
13
13
  logger.warning("The @terraform connector is in beta!")
14
14
 
15
15
 
@@ -198,14 +198,18 @@ def execute_command_with_sudo_retry(
198
198
  ) -> tuple[int, CommandOutput]:
199
199
  return_code, output = execute_command()
200
200
 
201
+ # If we failed look for a sudo password prompt line and re-submit using the sudo password. Look
202
+ # at all lines here in case anything else gets printed, eg in:
203
+ # https://github.com/pyinfra-dev/pyinfra/issues/1292
201
204
  if return_code != 0 and output and output.combined_lines:
202
- last_line = output.combined_lines[-1].line
203
- if last_line.strip() == "sudo: a password is required":
204
- # If we need a password, ask the user for it and attach to the host
205
- # internal connector data for use when executing future commands.
206
- sudo_password = getpass("{0}sudo password: ".format(host.print_prefix))
207
- host.connector_data["prompted_sudo_password"] = sudo_password
208
- return_code, output = execute_command()
205
+ for line in reversed(output.combined_lines):
206
+ if line.line.strip() == "sudo: a password is required":
207
+ # If we need a password, ask the user for it and attach to the host
208
+ # internal connector data for use when executing future commands.
209
+ sudo_password = getpass("{0}sudo password: ".format(host.print_prefix))
210
+ host.connector_data["prompted_sudo_password"] = sudo_password
211
+ return_code, output = execute_command()
212
+ break
209
213
 
210
214
  return return_code, output
211
215
 
@@ -232,7 +236,7 @@ def remove_any_sudo_askpass_file(host) -> None:
232
236
 
233
237
 
234
238
  @memoize
235
- def _show_use_su_login_warning():
239
+ def _show_use_su_login_warning() -> None:
236
240
  logger.warning(
237
241
  (
238
242
  "Using `use_su_login` may not work: "
@@ -304,7 +308,7 @@ def make_unix_command(
304
308
  _sudo=False,
305
309
  _sudo_user=None,
306
310
  _use_sudo_login=False,
307
- _sudo_password=False,
311
+ _sudo_password="",
308
312
  _sudo_askpass_path=None,
309
313
  _preserve_sudo_env=False,
310
314
  # Doas config
pyinfra/context.py CHANGED
@@ -10,6 +10,7 @@ from types import ModuleType
10
10
  from typing import TYPE_CHECKING
11
11
 
12
12
  from gevent.local import local
13
+ from typing_extensions import override
13
14
 
14
15
  if TYPE_CHECKING:
15
16
  from pyinfra.api.config import Config
@@ -26,22 +27,25 @@ class ContextObject:
26
27
  _container_cls = container
27
28
  _base_cls: ModuleType
28
29
 
29
- def __init__(self):
30
+ def __init__(self) -> None:
30
31
  self._container = self._container_cls()
31
32
  self._container.module = None
32
33
 
33
34
  def _get_module(self):
34
35
  return self._container.module
35
36
 
37
+ @override
36
38
  def __repr__(self):
37
39
  return "ContextObject({0}):{1}".format(
38
40
  self._base_cls.__name__,
39
41
  repr(self._get_module()),
40
42
  )
41
43
 
44
+ @override
42
45
  def __str__(self):
43
46
  return str(self._get_module())
44
47
 
48
+ @override
45
49
  def __dir__(self):
46
50
  return dir(self._base_cls)
47
51
 
@@ -50,6 +54,7 @@ class ContextObject:
50
54
  return getattr(self._base_cls, key)
51
55
  return getattr(self._get_module(), key)
52
56
 
57
+ @override
53
58
  def __setattr__(self, key, value):
54
59
  if key in ("_container", "_base_cls"):
55
60
  return super().__setattr__(key, value)
@@ -65,9 +70,11 @@ class ContextObject:
65
70
  def __len__(self):
66
71
  return len(self._get_module())
67
72
 
73
+ @override
68
74
  def __eq__(self, other):
69
75
  return self._get_module() == other
70
76
 
77
+ @override
71
78
  def __hash__(self):
72
79
  return hash(self._get_module())
73
80
 
@@ -89,7 +96,7 @@ class ContextManager:
89
96
  def set_base(self, module):
90
97
  self.context._base_cls = module
91
98
 
92
- def reset(self):
99
+ def reset(self) -> None:
93
100
  self.context._container.module = None
94
101
 
95
102
  def isset(self):
pyinfra/facts/apk.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from pyinfra.api import FactBase
4
6
 
5
7
  from .util.packaging import parse_packages
@@ -20,13 +22,16 @@ class ApkPackages(FactBase):
20
22
  }
21
23
  """
22
24
 
25
+ @override
23
26
  def command(self) -> str:
24
27
  return "apk list --installed"
25
28
 
29
+ @override
26
30
  def requires_command(self) -> str:
27
31
  return "apk"
28
32
 
29
33
  default = dict
30
34
 
35
+ @override
31
36
  def process(self, output):
32
37
  return parse_packages(APK_REGEX, output)
pyinfra/facts/apt.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import re
4
4
 
5
- from typing_extensions import TypedDict
5
+ from typing_extensions import TypedDict, override
6
6
 
7
7
  from pyinfra.api import FactBase
8
8
 
@@ -76,17 +76,20 @@ class AptSources(FactBase):
76
76
  ]
77
77
  """
78
78
 
79
+ @override
79
80
  def command(self) -> str:
80
81
  return make_cat_files_command(
81
82
  "/etc/apt/sources.list",
82
83
  "/etc/apt/sources.list.d/*.list",
83
84
  )
84
85
 
86
+ @override
85
87
  def requires_command(self) -> str:
86
88
  return "apt" # if apt installed, above should exist
87
89
 
88
90
  default = list
89
91
 
92
+ @override
90
93
  def process(self, output):
91
94
  repos = []
92
95
 
@@ -113,9 +116,11 @@ class AptKeys(GpgFactBase):
113
116
  """
114
117
 
115
118
  # This requires both apt-key *and* apt-key itself requires gpg
119
+ @override
116
120
  def command(self) -> str:
117
121
  return "! command -v gpg || apt-key list --with-colons"
118
122
 
123
+ @override
119
124
  def requires_command(self) -> str:
120
125
  return "apt-key"
121
126
 
@@ -132,13 +137,16 @@ class SimulateOperationWillChange(FactBase[AptSimulationDict]):
132
137
  Simulate an 'apt-get' operation and try to detect if any changes would be performed.
133
138
  """
134
139
 
140
+ @override
135
141
  def command(self, command: str) -> str:
136
142
  # LC_ALL=C: Ensure the output is in english, as we want to parse it
137
143
  return "LC_ALL=C " + noninteractive_apt(f"{command} --dry-run")
138
144
 
145
+ @override
139
146
  def requires_command(self, command: str) -> str:
140
147
  return "apt-get"
141
148
 
149
+ @override
142
150
  def process(self, output) -> AptSimulationDict:
143
151
  # We are looking for a line similar to
144
152
  # "3 upgraded, 0 newly installed, 0 to remove and 0 not upgraded."
pyinfra/facts/brew.py CHANGED
@@ -2,6 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  import re
4
4
 
5
+ from typing_extensions import override
6
+
5
7
  from pyinfra import logger
6
8
  from pyinfra.api import FactBase
7
9
 
@@ -37,9 +39,11 @@ class BrewVersion(FactBase):
37
39
 
38
40
  """
39
41
 
42
+ @override
40
43
  def command(self) -> str:
41
44
  return "brew --version"
42
45
 
46
+ @override
43
47
  def requires_command(self) -> str:
44
48
  return "brew"
45
49
 
@@ -47,6 +51,7 @@ class BrewVersion(FactBase):
47
51
  def default():
48
52
  return [0, 0, 0]
49
53
 
54
+ @override
50
55
  def process(self, output):
51
56
  out = list(output)[0]
52
57
  m = VERSION_MATCHER.match(out)
@@ -67,14 +72,17 @@ class BrewPackages(FactBase):
67
72
  }
68
73
  """
69
74
 
75
+ @override
70
76
  def command(self) -> str:
71
77
  return "brew list --versions"
72
78
 
79
+ @override
73
80
  def requires_command(self) -> str:
74
81
  return "brew"
75
82
 
76
83
  default = dict
77
84
 
85
+ @override
78
86
  def process(self, output):
79
87
  return parse_packages(BREW_REGEX, output)
80
88
 
@@ -90,12 +98,14 @@ class BrewCasks(BrewPackages):
90
98
  }
91
99
  """
92
100
 
101
+ @override
93
102
  def command(self) -> str:
94
103
  return (
95
104
  r'if brew --version | grep -q -e "Homebrew\ +(1\.|2\.[0-5]).*" 1>/dev/null;'
96
105
  r"then brew cask list --versions; else brew list --cask --versions; fi"
97
106
  )
98
107
 
108
+ @override
99
109
  def requires_command(self) -> str:
100
110
  return "brew"
101
111
 
@@ -105,13 +115,16 @@ class BrewTaps(FactBase):
105
115
  Returns a list of brew taps.
106
116
  """
107
117
 
118
+ @override
108
119
  def command(self) -> str:
109
120
  return "brew tap"
110
121
 
122
+ @override
111
123
  def requires_command(self) -> str:
112
124
  return "brew"
113
125
 
114
126
  default = list
115
127
 
128
+ @override
116
129
  def process(self, output):
117
130
  return output
pyinfra/facts/bsdinit.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from .sysvinit import InitdStatus
4
6
 
5
7
 
@@ -9,6 +11,7 @@ class RcdStatus(InitdStatus):
9
11
  BSD init scripts are well behaved and as such their output can be trusted.
10
12
  """
11
13
 
14
+ @override
12
15
  def command(self) -> str:
13
16
  return """
14
17
  for SERVICE in `find /etc/rc.d /usr/local/etc/rc.d -type f`; do
pyinfra/facts/cargo.py CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from typing_extensions import override
6
+
5
7
  from pyinfra.api import FactBase
6
8
 
7
9
  from .util.packaging import parse_packages
@@ -22,11 +24,14 @@ class CargoPackages(FactBase):
22
24
 
23
25
  default = dict
24
26
 
27
+ @override
25
28
  def command(self) -> str:
26
29
  return "cargo install --list"
27
30
 
31
+ @override
28
32
  def requires_command(self) -> str:
29
33
  return "cargo"
30
34
 
35
+ @override
31
36
  def process(self, output):
32
37
  return parse_packages(CARGO_REGEX, output)
pyinfra/facts/choco.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from pyinfra.api import FactBase
4
6
 
5
7
  from .util.packaging import parse_packages
@@ -18,6 +20,7 @@ class ChocoPackages(FactBase):
18
20
  }
19
21
  """
20
22
 
23
+ @override
21
24
  def command(self) -> str:
22
25
  return "choco list"
23
26
 
@@ -25,6 +28,7 @@ class ChocoPackages(FactBase):
25
28
 
26
29
  default = dict
27
30
 
31
+ @override
28
32
  def process(self, output):
29
33
  return parse_packages(CHOCO_REGEX, output)
30
34
 
@@ -34,8 +38,10 @@ class ChocoVersion(FactBase):
34
38
  Returns the choco (Chocolatey) version.
35
39
  """
36
40
 
41
+ @override
37
42
  def command(self) -> str:
38
43
  return "choco --version"
39
44
 
45
+ @override
40
46
  def process(self, output):
41
47
  return "".join(output).replace("\n", "")
pyinfra/facts/crontab.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import re
2
2
  from typing import Dict, List, Optional, TypedDict, Union
3
3
 
4
- from typing_extensions import NotRequired
4
+ from typing_extensions import NotRequired, override
5
5
 
6
6
  from pyinfra.api import FactBase
7
7
  from pyinfra.api.util import try_int
@@ -70,6 +70,7 @@ class CrontabFile:
70
70
  def __getitem__(self, item) -> Optional[CrontabDict]:
71
71
  return self.get(item)
72
72
 
73
+ @override
73
74
  def __repr__(self):
74
75
  return f"CrontabResult({self.commands})"
75
76
 
@@ -91,6 +92,7 @@ class CrontabFile:
91
92
  )
92
93
  return "\n".join(lines)
93
94
 
95
+ @override
94
96
  def __str__(self):
95
97
  return "\n".join(self.format_item(item) for item in self.commands)
96
98
 
@@ -139,14 +141,17 @@ class Crontab(FactBase[CrontabFile]):
139
141
 
140
142
  default = CrontabFile
141
143
 
144
+ @override
142
145
  def requires_command(self, user=None) -> str:
143
146
  return "crontab"
144
147
 
148
+ @override
145
149
  def command(self, user=None):
146
150
  if user:
147
151
  return "crontab -l -u {0} || true".format(user)
148
152
  return "crontab -l || true"
149
153
 
154
+ @override
150
155
  def process(self, output):
151
156
  crons = CrontabFile()
152
157
  current_comments = []
pyinfra/facts/deb.py CHANGED
@@ -3,6 +3,8 @@ from __future__ import annotations
3
3
  import re
4
4
  import shlex
5
5
 
6
+ from typing_extensions import override
7
+
6
8
  from pyinfra.api import FactBase
7
9
 
8
10
  from .util.packaging import parse_packages
@@ -16,9 +18,11 @@ class DebArch(FactBase):
16
18
  Returns the architecture string used in apt repository sources, eg ``amd64``.
17
19
  """
18
20
 
21
+ @override
19
22
  def command(self) -> str:
20
23
  return "dpkg --print-architecture"
21
24
 
25
+ @override
22
26
  def requires_command(self) -> str:
23
27
  return "dpkg"
24
28
 
@@ -34,9 +38,11 @@ class DebPackages(FactBase):
34
38
  }
35
39
  """
36
40
 
41
+ @override
37
42
  def command(self) -> str:
38
43
  return "dpkg -l"
39
44
 
45
+ @override
40
46
  def requires_command(self) -> str:
41
47
  return "dpkg"
42
48
 
@@ -47,6 +53,7 @@ class DebPackages(FactBase):
47
53
  DEB_PACKAGE_VERSION_REGEX,
48
54
  )
49
55
 
56
+ @override
50
57
  def process(self, output):
51
58
  return parse_packages(self.regex, output)
52
59
 
@@ -61,14 +68,17 @@ class DebPackage(FactBase):
61
68
  "version": r"^Version:\s+({0})$".format(DEB_PACKAGE_VERSION_REGEX),
62
69
  }
63
70
 
71
+ @override
64
72
  def requires_command(self, package) -> str:
65
73
  return "dpkg"
66
74
 
75
+ @override
67
76
  def command(self, package):
68
77
  return "! test -e {0} && (dpkg -s {0} 2>/dev/null || true) || dpkg -I {0}".format(
69
78
  shlex.quote(package)
70
79
  )
71
80
 
81
+ @override
72
82
  def process(self, output):
73
83
  data = {}
74
84
 
pyinfra/facts/dnf.py CHANGED
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from pyinfra.api import FactBase
4
6
 
5
7
  from .util import make_cat_files_command
@@ -23,6 +25,7 @@ class DnfRepositories(FactBase):
23
25
  ]
24
26
  """
25
27
 
28
+ @override
26
29
  def command(self) -> str:
27
30
  return make_cat_files_command(
28
31
  "/etc/dnf.conf",
@@ -30,10 +33,12 @@ class DnfRepositories(FactBase):
30
33
  "/etc/yum.repos.d/*.repo",
31
34
  )
32
35
 
36
+ @override
33
37
  def requires_command(self) -> str:
34
38
  return "dnf"
35
39
 
36
40
  default = list
37
41
 
42
+ @override
38
43
  def process(self, output):
39
44
  return parse_yum_repositories(output)
pyinfra/facts/docker.py CHANGED
@@ -8,6 +8,8 @@ from __future__ import annotations
8
8
 
9
9
  import json
10
10
 
11
+ from typing_extensions import override
12
+
11
13
  from pyinfra.api import FactBase
12
14
 
13
15
 
@@ -16,9 +18,11 @@ class DockerFactBase(FactBase):
16
18
 
17
19
  docker_type: str
18
20
 
21
+ @override
19
22
  def requires_command(self, *args, **kwargs) -> str:
20
23
  return "docker"
21
24
 
25
+ @override
22
26
  def process(self, output):
23
27
  output = "".join(output)
24
28
  return json.loads(output)
@@ -29,6 +33,7 @@ class DockerSystemInfo(DockerFactBase):
29
33
  Returns ``docker system info`` output in JSON format.
30
34
  """
31
35
 
36
+ @override
32
37
  def command(self) -> str:
33
38
  return 'docker system info --format="{{json .}}"'
34
39
 
@@ -42,6 +47,7 @@ class DockerContainers(DockerFactBase):
42
47
  Returns ``docker inspect`` output for all Docker containers.
43
48
  """
44
49
 
50
+ @override
45
51
  def command(self) -> str:
46
52
  return "docker container inspect `docker ps -qa`"
47
53
 
@@ -51,6 +57,7 @@ class DockerImages(DockerFactBase):
51
57
  Returns ``docker inspect`` output for all Docker images.
52
58
  """
53
59
 
60
+ @override
54
61
  def command(self) -> str:
55
62
  return "docker image inspect `docker images -q`"
56
63
 
@@ -60,6 +67,7 @@ class DockerNetworks(DockerFactBase):
60
67
  Returns ``docker inspect`` output for all Docker networks.
61
68
  """
62
69
 
70
+ @override
63
71
  def command(self) -> str:
64
72
  return "docker network inspect `docker network ls -q`"
65
73
 
@@ -69,6 +77,7 @@ class DockerNetworks(DockerFactBase):
69
77
 
70
78
 
71
79
  class DockerSingleMixin(DockerFactBase):
80
+ @override
72
81
  def command(self, object_id):
73
82
  return "docker {0} inspect {1} 2>&- || true".format(
74
83
  self.docker_type,
@@ -105,6 +114,7 @@ class DockerVolumes(DockerFactBase):
105
114
  Returns ``docker inspect`` output for all Docker volumes.
106
115
  """
107
116
 
117
+ @override
108
118
  def command(self) -> str:
109
119
  return "docker volume inspect `docker volume ls -q`"
110
120
 
@@ -2,6 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  from typing import Any, Dict, Iterable, List, Optional, Tuple, TypedDict
4
4
 
5
+ from typing_extensions import override
6
+
5
7
  from pyinfra.api import FactBase
6
8
 
7
9
  BootEntry = Tuple[bool, str]
@@ -37,14 +39,17 @@ class EFIBootMgr(FactBase[Optional[EFIBootMgrInfoDict]]):
37
39
  }
38
40
  """
39
41
 
42
+ @override
40
43
  def requires_command(self, *args: Any, **kwargs: Any) -> str:
41
44
  return "efibootmgr"
42
45
 
46
+ @override
43
47
  def command(self) -> str:
44
48
  # FIXME: Use '|| true' to properly handle the case where
45
49
  # 'efibootmgr' is run on a non-UEFI system
46
50
  return "efibootmgr || true"
47
51
 
52
+ @override
48
53
  def process(self, output: Iterable[str]) -> Optional[EFIBootMgrInfoDict]:
49
54
  # This parsing code closely follows the printing code of efibootmgr
50
55
  # at <https://github.com/rhboot/efibootmgr/blob/main/src/efibootmgr.c#L2020-L2048>