pyinfra 3.0b4__py2.py3-none-any.whl → 3.0.1__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 (54) hide show
  1. pyinfra/api/facts.py +7 -50
  2. pyinfra/api/util.py +1 -1
  3. pyinfra/connectors/ssh.py +3 -3
  4. pyinfra/connectors/sshuserclient/client.py +1 -1
  5. pyinfra/facts/apk.py +5 -2
  6. pyinfra/facts/apt.py +13 -7
  7. pyinfra/facts/brew.py +26 -13
  8. pyinfra/facts/bsdinit.py +7 -6
  9. pyinfra/facts/cargo.py +4 -3
  10. pyinfra/facts/choco.py +6 -4
  11. pyinfra/facts/deb.py +12 -5
  12. pyinfra/facts/dnf.py +9 -6
  13. pyinfra/facts/docker.py +13 -6
  14. pyinfra/facts/files.py +3 -3
  15. pyinfra/facts/gem.py +5 -2
  16. pyinfra/facts/git.py +14 -21
  17. pyinfra/facts/gpg.py +2 -1
  18. pyinfra/facts/hardware.py +17 -11
  19. pyinfra/facts/launchd.py +5 -2
  20. pyinfra/facts/lxd.py +6 -2
  21. pyinfra/facts/mysql.py +7 -6
  22. pyinfra/facts/npm.py +2 -1
  23. pyinfra/facts/openrc.py +6 -2
  24. pyinfra/facts/pacman.py +7 -3
  25. pyinfra/facts/pkg.py +3 -1
  26. pyinfra/facts/pkgin.py +5 -2
  27. pyinfra/facts/postgres.py +3 -1
  28. pyinfra/facts/rpm.py +12 -9
  29. pyinfra/facts/runit.py +4 -2
  30. pyinfra/facts/selinux.py +12 -4
  31. pyinfra/facts/server.py +80 -51
  32. pyinfra/facts/snap.py +6 -2
  33. pyinfra/facts/systemd.py +10 -5
  34. pyinfra/facts/sysvinit.py +2 -1
  35. pyinfra/facts/upstart.py +5 -2
  36. pyinfra/facts/vzctl.py +6 -4
  37. pyinfra/facts/xbps.py +5 -2
  38. pyinfra/facts/yum.py +8 -5
  39. pyinfra/facts/zypper.py +7 -4
  40. pyinfra/operations/apt.py +5 -0
  41. pyinfra/operations/selinux.py +1 -1
  42. pyinfra/operations/server.py +1 -1
  43. {pyinfra-3.0b4.dist-info → pyinfra-3.0.1.dist-info}/METADATA +1 -5
  44. {pyinfra-3.0b4.dist-info → pyinfra-3.0.1.dist-info}/RECORD +54 -53
  45. pyinfra_cli/__main__.py +2 -3
  46. pyinfra_cli/inventory.py +13 -11
  47. pyinfra_cli/main.py +10 -9
  48. tests/test_api/test_api_facts.py +2 -2
  49. tests/test_cli/test_cli.py +0 -1
  50. tests/test_cli/test_cli_inventory.py +66 -0
  51. {pyinfra-3.0b4.dist-info → pyinfra-3.0.1.dist-info}/LICENSE.md +0 -0
  52. {pyinfra-3.0b4.dist-info → pyinfra-3.0.1.dist-info}/WHEEL +0 -0
  53. {pyinfra-3.0b4.dist-info → pyinfra-3.0.1.dist-info}/entry_points.txt +0 -0
  54. {pyinfra-3.0b4.dist-info → pyinfra-3.0.1.dist-info}/top_level.txt +0 -0
pyinfra/api/facts.py CHANGED
@@ -14,18 +14,7 @@ import inspect
14
14
  import re
15
15
  from inspect import getcallargs
16
16
  from socket import error as socket_error, timeout as timeout_error
17
- from typing import (
18
- TYPE_CHECKING,
19
- Any,
20
- Callable,
21
- Generic,
22
- Iterable,
23
- Optional,
24
- Type,
25
- TypeVar,
26
- Union,
27
- cast,
28
- )
17
+ from typing import TYPE_CHECKING, Any, Callable, Generic, Iterable, Optional, Type, TypeVar, cast
29
18
 
30
19
  import click
31
20
  import gevent
@@ -38,7 +27,6 @@ from pyinfra.api.util import (
38
27
  get_kwargs_str,
39
28
  log_error_or_warning,
40
29
  log_host_command_error,
41
- make_hash,
42
30
  print_host_combined_output,
43
31
  )
44
32
  from pyinfra.connectors.util import CommandOutput
@@ -66,11 +54,12 @@ class FactBase(Generic[T]):
66
54
 
67
55
  abstract: bool = True
68
56
 
69
- shell_executable: Optional[str] = None
57
+ shell_executable: str | None = None
70
58
 
71
- requires_command: Optional[str] = None
59
+ command: Callable[..., str | StringCommand]
72
60
 
73
- command: Union[str, Callable]
61
+ def requires_command(self, *args, **kwargs) -> str | None:
62
+ return None
74
63
 
75
64
  def __init_subclass__(cls) -> None:
76
65
  super().__init_subclass__()
@@ -113,8 +102,7 @@ class ShortFactBase(Generic[T]):
113
102
  module_name = cls.__module__.replace("pyinfra.facts.", "")
114
103
  cls.name = f"{module_name}.{cls.__name__}"
115
104
 
116
- @staticmethod
117
- def process_data(data):
105
+ def process_data(self, data):
118
106
  return data
119
107
 
120
108
 
@@ -130,30 +118,6 @@ def _make_command(command_attribute, host_args):
130
118
  return command_attribute
131
119
 
132
120
 
133
- def _get_executor_kwargs(
134
- state: "State",
135
- host: "Host",
136
- override_kwargs: Optional[dict[str, Any]] = None,
137
- override_kwarg_keys: Optional[list[str]] = None,
138
- ):
139
- if override_kwargs is None:
140
- override_kwargs = {}
141
- if override_kwarg_keys is None:
142
- override_kwarg_keys = []
143
-
144
- # Use the current operation global kwargs, or generate defaults
145
- global_kwargs = host.current_op_global_arguments
146
- if not global_kwargs:
147
- global_kwargs, _ = pop_global_arguments({}, state, host)
148
-
149
- # Apply any current op kwargs that *weren't* found in the overrides
150
- override_kwargs.update(
151
- {key: value for key, value in global_kwargs.items() if key not in override_kwarg_keys},
152
- )
153
-
154
- return {key: value for key, value in override_kwargs.items() if key in CONNECTOR_ARGUMENT_KEYS}
155
-
156
-
157
121
  def _handle_fact_kwargs(state, host, cls, args, kwargs):
158
122
  args = args or []
159
123
  kwargs = kwargs or {}
@@ -296,7 +260,7 @@ def _get_fact(
296
260
  log_host_command_error(
297
261
  host,
298
262
  e,
299
- timeout=global_kwargs["_timeout"],
263
+ timeout=global_kwargs.get("_timeout"),
300
264
  )
301
265
 
302
266
  stdout_lines, stderr_lines = output.stdout_lines, output.stderr_lines
@@ -346,13 +310,6 @@ def _get_fact(
346
310
  return data
347
311
 
348
312
 
349
- def _get_fact_hash(state: "State", host: "Host", cls, args, kwargs):
350
- if issubclass(cls, ShortFactBase):
351
- cls = cls.fact
352
- fact_kwargs, executor_kwargs = _handle_fact_kwargs(state, host, cls, args, kwargs)
353
- return make_hash((cls, fact_kwargs, executor_kwargs))
354
-
355
-
356
313
  def get_host_fact(
357
314
  state: "State",
358
315
  host: "Host",
pyinfra/api/util.py CHANGED
@@ -241,7 +241,7 @@ def log_error_or_warning(
241
241
  )
242
242
 
243
243
 
244
- def log_host_command_error(host: "Host", e: Exception, timeout: int = 0) -> None:
244
+ def log_host_command_error(host: "Host", e: Exception, timeout: int | None = 0) -> None:
245
245
  if isinstance(e, timeout_error):
246
246
  logger.error(
247
247
  "{0}{1}".format(
pyinfra/connectors/ssh.py CHANGED
@@ -123,7 +123,7 @@ class SSHConnector(BaseConnector):
123
123
 
124
124
  hosts = (
125
125
  ["my-host-1.net", "my-host-2.net"],
126
- {"ssh_username": "ssh-user"},
126
+ {"ssh_user": "ssh-user"},
127
127
  )
128
128
 
129
129
  Multiple hosts with different SSH usernames:
@@ -131,8 +131,8 @@ class SSHConnector(BaseConnector):
131
131
  .. code:: python
132
132
 
133
133
  hosts = [
134
- ("my-host-1.net", {"ssh_username": "ssh-user"}),
135
- ("my-host-2.net", {"ssh_username": "other-user"}),
134
+ ("my-host-1.net", {"ssh_user": "ssh-user"}),
135
+ ("my-host-2.net", {"ssh_user": "other-user"}),
136
136
  ]
137
137
  """
138
138
 
@@ -124,7 +124,7 @@ class SSHClient(ParamikoClient):
124
124
  original idea at http://bitprophet.org/blog/2012/11/05/gateway-solutions/.
125
125
  """
126
126
 
127
- def connect(
127
+ def connect( # type: ignore[override]
128
128
  self,
129
129
  hostname,
130
130
  _pyinfra_ssh_forward_agent=None,
pyinfra/facts/apk.py CHANGED
@@ -18,8 +18,11 @@ class ApkPackages(FactBase):
18
18
  }
19
19
  """
20
20
 
21
- command = "apk list --installed"
22
- requires_command = "apk"
21
+ def command(self) -> str:
22
+ return "apk list --installed"
23
+
24
+ def requires_command(self) -> str:
25
+ return "apk"
23
26
 
24
27
  default = dict
25
28
 
pyinfra/facts/apt.py CHANGED
@@ -52,11 +52,14 @@ class AptSources(FactBase):
52
52
  ]
53
53
  """
54
54
 
55
- command = make_cat_files_command(
56
- "/etc/apt/sources.list",
57
- "/etc/apt/sources.list.d/*.list",
58
- )
59
- requires_command = "apt" # if apt installed, above should exist
55
+ def command(self) -> str:
56
+ return make_cat_files_command(
57
+ "/etc/apt/sources.list",
58
+ "/etc/apt/sources.list.d/*.list",
59
+ )
60
+
61
+ def requires_command(self) -> str:
62
+ return "apt" # if apt installed, above should exist
60
63
 
61
64
  default = list
62
65
 
@@ -86,5 +89,8 @@ class AptKeys(GpgFactBase):
86
89
  """
87
90
 
88
91
  # This requires both apt-key *and* apt-key itself requires gpg
89
- command = "! command -v gpg || apt-key list --with-colons"
90
- requires_command = "apt-key"
92
+ def command(self) -> str:
93
+ return "! command -v gpg || apt-key list --with-colons"
94
+
95
+ def requires_command(self) -> str:
96
+ return "apt-key"
pyinfra/facts/brew.py CHANGED
@@ -37,18 +37,22 @@ class BrewVersion(FactBase):
37
37
 
38
38
  """
39
39
 
40
- command = "brew --version"
41
- requires_command = "brew"
40
+ def command(self) -> str:
41
+ return "brew --version"
42
+
43
+ def requires_command(self) -> str:
44
+ return "brew"
42
45
 
43
46
  @staticmethod
44
47
  def default():
45
48
  return [0, 0, 0]
46
49
 
47
50
  def process(self, output):
48
- m = VERSION_MATCHER.match(output[0])
51
+ out = list(output)[0]
52
+ m = VERSION_MATCHER.match(out)
49
53
  if m is not None:
50
54
  return [int(m.group(key)) for key in ["major", "minor", "patch"]]
51
- logger.warning("could not parse version string from brew: %s", output[0])
55
+ logger.warning("could not parse version string from brew: %s", out)
52
56
  return self.default()
53
57
 
54
58
 
@@ -63,8 +67,11 @@ class BrewPackages(FactBase):
63
67
  }
64
68
  """
65
69
 
66
- command = "brew list --versions"
67
- requires_command = "brew"
70
+ def command(self) -> str:
71
+ return "brew list --versions"
72
+
73
+ def requires_command(self) -> str:
74
+ return "brew"
68
75
 
69
76
  default = dict
70
77
 
@@ -83,11 +90,14 @@ class BrewCasks(BrewPackages):
83
90
  }
84
91
  """
85
92
 
86
- command = (
87
- r'if brew --version | grep -q -e "Homebrew\ +(1\.|2\.[0-5]).*" 1>/dev/null;'
88
- r"then brew cask list --versions; else brew list --cask --versions; fi"
89
- )
90
- requires_command = "brew"
93
+ def command(self) -> str:
94
+ return (
95
+ r'if brew --version | grep -q -e "Homebrew\ +(1\.|2\.[0-5]).*" 1>/dev/null;'
96
+ r"then brew cask list --versions; else brew list --cask --versions; fi"
97
+ )
98
+
99
+ def requires_command(self) -> str:
100
+ return "brew"
91
101
 
92
102
 
93
103
  class BrewTaps(FactBase):
@@ -95,8 +105,11 @@ class BrewTaps(FactBase):
95
105
  Returns a list of brew taps.
96
106
  """
97
107
 
98
- command = "brew tap"
99
- requires_command = "brew"
108
+ def command(self) -> str:
109
+ return "brew tap"
110
+
111
+ def requires_command(self) -> str:
112
+ return "brew"
100
113
 
101
114
  default = list
102
115
 
pyinfra/facts/bsdinit.py CHANGED
@@ -9,11 +9,12 @@ class RcdStatus(InitdStatus):
9
9
  BSD init scripts are well behaved and as such their output can be trusted.
10
10
  """
11
11
 
12
- command = """
13
- for SERVICE in `find /etc/rc.d /usr/local/etc/rc.d -type f`; do
14
- $SERVICE status 2> /dev/null || $SERVICE check 2> /dev/null
15
- echo "`basename $SERVICE`=$?"
16
- done
17
- """
12
+ def command(self) -> str:
13
+ return """
14
+ for SERVICE in `find /etc/rc.d /usr/local/etc/rc.d -type f`; do
15
+ $SERVICE status 2> /dev/null || $SERVICE check 2> /dev/null
16
+ echo "`basename $SERVICE`=$?"
17
+ done
18
+ """
18
19
 
19
20
  default = dict
pyinfra/facts/cargo.py CHANGED
@@ -22,10 +22,11 @@ class CargoPackages(FactBase):
22
22
 
23
23
  default = dict
24
24
 
25
- requires_command = "cargo"
26
-
27
- def command(self):
25
+ def command(self) -> str:
28
26
  return "cargo install --list"
29
27
 
28
+ def requires_command(self) -> str:
29
+ return "cargo"
30
+
30
31
  def process(self, output):
31
32
  return parse_packages(CARGO_REGEX, output)
pyinfra/facts/choco.py CHANGED
@@ -18,7 +18,9 @@ class ChocoPackages(FactBase):
18
18
  }
19
19
  """
20
20
 
21
- command = "choco list"
21
+ def command(self) -> str:
22
+ return "choco list"
23
+
22
24
  shell_executable = "ps"
23
25
 
24
26
  default = dict
@@ -32,8 +34,8 @@ class ChocoVersion(FactBase):
32
34
  Returns the choco (Chocolatey) version.
33
35
  """
34
36
 
35
- command = "choco --version"
37
+ def command(self) -> str:
38
+ return "choco --version"
36
39
 
37
- @staticmethod
38
- def process(output):
40
+ def process(self, output):
39
41
  return "".join(output).replace("\n", "")
pyinfra/facts/deb.py CHANGED
@@ -16,8 +16,11 @@ class DebArch(FactBase):
16
16
  Returns the architecture string used in apt repository sources, eg ``amd64``.
17
17
  """
18
18
 
19
- command = "dpkg --print-architecture"
20
- requires_command = "dpkg"
19
+ def command(self) -> str:
20
+ return "dpkg --print-architecture"
21
+
22
+ def requires_command(self) -> str:
23
+ return "dpkg"
21
24
 
22
25
 
23
26
  class DebPackages(FactBase):
@@ -31,8 +34,11 @@ class DebPackages(FactBase):
31
34
  }
32
35
  """
33
36
 
34
- command = "dpkg -l"
35
- requires_command = "dpkg"
37
+ def command(self) -> str:
38
+ return "dpkg -l"
39
+
40
+ def requires_command(self) -> str:
41
+ return "dpkg"
36
42
 
37
43
  default = dict
38
44
 
@@ -55,7 +61,8 @@ class DebPackage(FactBase):
55
61
  "version": r"^Version:\s+({0})$".format(DEB_PACKAGE_VERSION_REGEX),
56
62
  }
57
63
 
58
- requires_command = "dpkg"
64
+ def requires_command(self, package) -> str:
65
+ return "dpkg"
59
66
 
60
67
  def command(self, package):
61
68
  return "! test -e {0} && (dpkg -s {0} 2>/dev/null || true) || dpkg -I {0}".format(
pyinfra/facts/dnf.py CHANGED
@@ -23,12 +23,15 @@ class DnfRepositories(FactBase):
23
23
  ]
24
24
  """
25
25
 
26
- command = make_cat_files_command(
27
- "/etc/dnf.conf",
28
- "/etc/dnf.repos.d/*.repo",
29
- "/etc/yum.repos.d/*.repo",
30
- )
31
- requires_command = "dnf"
26
+ def command(self) -> str:
27
+ return make_cat_files_command(
28
+ "/etc/dnf.conf",
29
+ "/etc/dnf.repos.d/*.repo",
30
+ "/etc/yum.repos.d/*.repo",
31
+ )
32
+
33
+ def requires_command(self) -> str:
34
+ return "dnf"
32
35
 
33
36
  default = list
34
37
 
pyinfra/facts/docker.py CHANGED
@@ -9,7 +9,9 @@ class DockerFactBase(FactBase):
9
9
  abstract = True
10
10
 
11
11
  docker_type: str
12
- requires_command = "docker"
12
+
13
+ def requires_command(self, *args, **kwargs) -> str:
14
+ return "docker"
13
15
 
14
16
  def process(self, output):
15
17
  output = "".join(output)
@@ -21,7 +23,8 @@ class DockerSystemInfo(DockerFactBase):
21
23
  Returns ``docker system info`` output in JSON format.
22
24
  """
23
25
 
24
- command = 'docker system info --format="{{json .}}"'
26
+ def command(self) -> str:
27
+ return 'docker system info --format="{{json .}}"'
25
28
 
26
29
 
27
30
  # All Docker objects
@@ -33,7 +36,8 @@ class DockerContainers(DockerFactBase):
33
36
  Returns ``docker inspect`` output for all Docker containers.
34
37
  """
35
38
 
36
- command = "docker container inspect `docker ps -qa`"
39
+ def command(self) -> str:
40
+ return "docker container inspect `docker ps -qa`"
37
41
 
38
42
 
39
43
  class DockerImages(DockerFactBase):
@@ -41,7 +45,8 @@ class DockerImages(DockerFactBase):
41
45
  Returns ``docker inspect`` output for all Docker images.
42
46
  """
43
47
 
44
- command = "docker image inspect `docker images -q`"
48
+ def command(self) -> str:
49
+ return "docker image inspect `docker images -q`"
45
50
 
46
51
 
47
52
  class DockerNetworks(DockerFactBase):
@@ -49,7 +54,8 @@ class DockerNetworks(DockerFactBase):
49
54
  Returns ``docker inspect`` output for all Docker networks.
50
55
  """
51
56
 
52
- command = "docker network inspect `docker network ls -q`"
57
+ def command(self) -> str:
58
+ return "docker network inspect `docker network ls -q`"
53
59
 
54
60
 
55
61
  # Single Docker objects
@@ -93,7 +99,8 @@ class DockerVolumes(DockerFactBase):
93
99
  Returns ``docker inspect`` output for all Docker volumes.
94
100
  """
95
101
 
96
- command = "docker volume inspect `docker volume ls -q`"
102
+ def command(self) -> str:
103
+ return "docker volume inspect `docker volume ls -q`"
97
104
 
98
105
 
99
106
  class DockerVolume(DockerSingleMixin):
pyinfra/facts/files.py CHANGED
@@ -312,8 +312,7 @@ class FindFilesBase(FactBase):
312
312
  default = list
313
313
  type_flag: str
314
314
 
315
- @staticmethod
316
- def process(output):
315
+ def process(self, output):
317
316
  return output
318
317
 
319
318
  def command(self, path, quote_path=True):
@@ -353,7 +352,8 @@ class Flags(FactBase):
353
352
  Returns a list of the file flags set for the specified file or directory.
354
353
  """
355
354
 
356
- requires_command = "chflags" # don't try to retrieve them if we can't set them
355
+ def requires_command(self, path) -> str:
356
+ return "chflags" # don't try to retrieve them if we can't set them
357
357
 
358
358
  def command(self, path):
359
359
  return make_formatted_string_command(
pyinfra/facts/gem.py CHANGED
@@ -18,8 +18,11 @@ class GemPackages(FactBase):
18
18
  }
19
19
  """
20
20
 
21
- command = "gem list --local"
22
- requires_command = "gem"
21
+ def command(self) -> str:
22
+ return "gem list --local"
23
+
24
+ def requires_command(self) -> str:
25
+ return "gem"
23
26
 
24
27
  default = dict
25
28
 
pyinfra/facts/git.py CHANGED
@@ -5,32 +5,29 @@ import re
5
5
  from pyinfra.api.facts import FactBase
6
6
 
7
7
 
8
- class GitBranch(FactBase):
9
- requires_command = "git"
8
+ class GitFactBase(FactBase):
9
+ def requires_command(self, *args, **kwargs) -> str:
10
+ return "git"
10
11
 
11
- @staticmethod
12
- def command(repo):
12
+
13
+ class GitBranch(GitFactBase):
14
+ def command(self, repo) -> str:
13
15
  return "! test -d {0} || (cd {0} && git describe --all)".format(repo)
14
16
 
15
- @staticmethod
16
- def process(output):
17
+ def process(self, output):
17
18
  return re.sub(r"(heads|tags)/", r"", "\n".join(output))
18
19
 
19
20
 
20
- class GitConfig(FactBase):
21
+ class GitConfig(GitFactBase):
21
22
  default = dict
22
23
 
23
- requires_command = "git"
24
-
25
- @staticmethod
26
- def command(repo=None):
24
+ def command(self, repo=None) -> str:
27
25
  if repo is None:
28
26
  return "git config --global -l || true"
29
27
 
30
28
  return "! test -d {0} || (cd {0} && git config --local -l)".format(repo)
31
29
 
32
- @staticmethod
33
- def process(output):
30
+ def process(self, output):
34
31
  items: dict[str, list[str]] = {}
35
32
 
36
33
  for line in output:
@@ -40,19 +37,15 @@ class GitConfig(FactBase):
40
37
  return items
41
38
 
42
39
 
43
- class GitTrackingBranch(FactBase):
44
- requires_command = "git"
45
-
46
- @staticmethod
47
- def command(repo):
40
+ class GitTrackingBranch(GitFactBase):
41
+ def command(self, repo) -> str:
48
42
  return r"! test -d {0} || (cd {0} && git status --branch --porcelain)".format(repo)
49
43
 
50
- @staticmethod
51
- def process(output):
44
+ def process(self, output):
52
45
  if not output:
53
46
  return None
54
47
 
55
- m = re.search(r"\.{3}(\S+)\b", output[0])
48
+ m = re.search(r"\.{3}(\S+)\b", list(output)[0])
56
49
  if m:
57
50
  return m.group(1)
58
51
  return None
pyinfra/facts/gpg.py CHANGED
@@ -8,7 +8,8 @@ from pyinfra.api import FactBase
8
8
  class GpgFactBase(FactBase):
9
9
  abstract = True
10
10
 
11
- requires_command = "gpg"
11
+ def requires_command(self, *args, **kwargs) -> str:
12
+ return "gpg"
12
13
 
13
14
  key_record_type = "pub"
14
15
  subkey_record_type = "sub"
pyinfra/facts/hardware.py CHANGED
@@ -5,17 +5,17 @@ import re
5
5
  from pyinfra.api import FactBase, ShortFactBase
6
6
 
7
7
 
8
- class Cpus(FactBase):
8
+ class Cpus(FactBase[int]):
9
9
  """
10
10
  Returns the number of CPUs on this server.
11
11
  """
12
12
 
13
- command = "getconf NPROCESSORS_ONLN 2> /dev/null || getconf _NPROCESSORS_ONLN"
13
+ def command(self) -> str:
14
+ return "getconf NPROCESSORS_ONLN 2> /dev/null || getconf _NPROCESSORS_ONLN"
14
15
 
15
- @staticmethod
16
- def process(output):
16
+ def process(self, output):
17
17
  try:
18
- return int(output[0])
18
+ return int(list(output)[0])
19
19
  except ValueError:
20
20
  pass
21
21
 
@@ -25,11 +25,13 @@ class Memory(FactBase):
25
25
  Returns the memory installed in this server, in MB.
26
26
  """
27
27
 
28
- command = "vmstat -s"
29
- requires_command = "vmstat"
28
+ def requires_command(self) -> str:
29
+ return "vmstat"
30
+
31
+ def command(self) -> str:
32
+ return "vmstat -s"
30
33
 
31
- @staticmethod
32
- def process(output):
34
+ def process(self, output):
33
35
  data = {}
34
36
 
35
37
  for line in output:
@@ -75,10 +77,12 @@ class BlockDevices(FactBase):
75
77
  }
76
78
  """
77
79
 
78
- command = "df"
79
80
  regex = r"([a-zA-Z0-9\/\-_]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]{1,3})%\s+([a-zA-Z\/0-9\-_]+)" # noqa: E501
80
81
  default = dict
81
82
 
83
+ def command(self) -> str:
84
+ return "df"
85
+
82
86
  def process(self, output):
83
87
  devices = {}
84
88
 
@@ -170,9 +174,11 @@ class NetworkDevices(FactBase):
170
174
  }
171
175
  """
172
176
 
173
- command = "ip addr show 2> /dev/null || ifconfig -a"
174
177
  default = dict
175
178
 
179
+ def command(self) -> str:
180
+ return "ip addr show 2> /dev/null || ifconfig -a"
181
+
176
182
  # Definition of valid interface names for Linux:
177
183
  # https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/core/dev.c?h=v5.1.3#n1020
178
184
  def process(self, output):
pyinfra/facts/launchd.py CHANGED
@@ -8,8 +8,11 @@ class LaunchdStatus(FactBase):
8
8
  Returns a dict of name -> status for launchd managed services.
9
9
  """
10
10
 
11
- command = "launchctl list"
12
- requires_command = "launchctl"
11
+ def command(self) -> str:
12
+ return "launchctl list"
13
+
14
+ def requires_command(self) -> str:
15
+ return "launchctl"
13
16
 
14
17
  default = dict
15
18
 
pyinfra/facts/lxd.py CHANGED
@@ -10,11 +10,15 @@ class LxdContainers(FactBase):
10
10
  Returns a list of running LXD containers
11
11
  """
12
12
 
13
- command = "lxc list --format json --fast"
14
- requires_command = "lxc"
13
+ def command(self) -> str:
14
+ return "lxc list --format json --fast"
15
+
16
+ def requires_command(self) -> str:
17
+ return "lxc"
15
18
 
16
19
  default = list
17
20
 
18
21
  def process(self, output):
22
+ output = list(output)
19
23
  assert len(output) == 1
20
24
  return json.loads(output[0])