pyinfra 2.9.2__py2.py3-none-any.whl → 3.0__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 (156) hide show
  1. pyinfra/api/__init__.py +3 -0
  2. pyinfra/api/arguments.py +265 -253
  3. pyinfra/api/arguments_typed.py +80 -0
  4. pyinfra/api/command.py +68 -53
  5. pyinfra/api/config.py +139 -32
  6. pyinfra/api/connect.py +1 -1
  7. pyinfra/api/connectors.py +7 -26
  8. pyinfra/api/deploy.py +21 -52
  9. pyinfra/api/exceptions.py +33 -8
  10. pyinfra/api/facts.py +102 -137
  11. pyinfra/api/host.py +150 -82
  12. pyinfra/api/inventory.py +21 -25
  13. pyinfra/api/operation.py +240 -198
  14. pyinfra/api/operations.py +102 -148
  15. pyinfra/api/state.py +137 -79
  16. pyinfra/api/util.py +79 -86
  17. pyinfra/connectors/base.py +147 -0
  18. pyinfra/connectors/chroot.py +160 -169
  19. pyinfra/connectors/docker.py +220 -237
  20. pyinfra/connectors/dockerssh.py +231 -253
  21. pyinfra/connectors/local.py +196 -208
  22. pyinfra/connectors/ssh.py +530 -613
  23. pyinfra/connectors/ssh_util.py +114 -0
  24. pyinfra/connectors/sshuserclient/client.py +5 -3
  25. pyinfra/connectors/terraform.py +86 -65
  26. pyinfra/connectors/util.py +211 -137
  27. pyinfra/connectors/vagrant.py +60 -53
  28. pyinfra/context.py +4 -2
  29. pyinfra/facts/apk.py +2 -0
  30. pyinfra/facts/apt.py +2 -0
  31. pyinfra/facts/brew.py +2 -0
  32. pyinfra/facts/bsdinit.py +2 -0
  33. pyinfra/facts/cargo.py +2 -0
  34. pyinfra/facts/choco.py +2 -0
  35. pyinfra/facts/deb.py +7 -2
  36. pyinfra/facts/dnf.py +2 -0
  37. pyinfra/facts/docker.py +19 -0
  38. pyinfra/facts/files.py +47 -32
  39. pyinfra/facts/gem.py +2 -0
  40. pyinfra/facts/git.py +3 -1
  41. pyinfra/facts/gpg.py +3 -1
  42. pyinfra/facts/hardware.py +34 -24
  43. pyinfra/facts/iptables.py +5 -3
  44. pyinfra/facts/launchd.py +2 -0
  45. pyinfra/facts/lxd.py +2 -0
  46. pyinfra/facts/mysql.py +13 -6
  47. pyinfra/facts/npm.py +1 -0
  48. pyinfra/facts/openrc.py +2 -0
  49. pyinfra/facts/pacman.py +6 -2
  50. pyinfra/facts/pip.py +2 -0
  51. pyinfra/facts/pkg.py +2 -0
  52. pyinfra/facts/pkgin.py +2 -0
  53. pyinfra/facts/postgres.py +168 -0
  54. pyinfra/facts/postgresql.py +6 -160
  55. pyinfra/facts/rpm.py +12 -9
  56. pyinfra/facts/runit.py +68 -0
  57. pyinfra/facts/selinux.py +3 -1
  58. pyinfra/facts/server.py +80 -36
  59. pyinfra/facts/snap.py +2 -0
  60. pyinfra/facts/systemd.py +31 -12
  61. pyinfra/facts/sysvinit.py +10 -10
  62. pyinfra/facts/upstart.py +2 -0
  63. pyinfra/facts/util/packaging.py +7 -4
  64. pyinfra/facts/vzctl.py +2 -0
  65. pyinfra/facts/xbps.py +2 -0
  66. pyinfra/facts/yum.py +2 -0
  67. pyinfra/facts/zypper.py +2 -0
  68. pyinfra/local.py +4 -5
  69. pyinfra/operations/apk.py +6 -4
  70. pyinfra/operations/apt.py +46 -65
  71. pyinfra/operations/brew.py +17 -22
  72. pyinfra/operations/bsdinit.py +9 -7
  73. pyinfra/operations/cargo.py +4 -2
  74. pyinfra/operations/choco.py +4 -2
  75. pyinfra/operations/dnf.py +19 -23
  76. pyinfra/operations/docker.py +339 -0
  77. pyinfra/operations/files.py +188 -386
  78. pyinfra/operations/gem.py +4 -2
  79. pyinfra/operations/git.py +24 -53
  80. pyinfra/operations/iptables.py +29 -35
  81. pyinfra/operations/launchd.py +6 -7
  82. pyinfra/operations/lxd.py +8 -13
  83. pyinfra/operations/mysql.py +62 -81
  84. pyinfra/operations/npm.py +9 -2
  85. pyinfra/operations/openrc.py +6 -4
  86. pyinfra/operations/pacman.py +7 -8
  87. pyinfra/operations/pip.py +25 -24
  88. pyinfra/operations/pkg.py +4 -2
  89. pyinfra/operations/pkgin.py +6 -4
  90. pyinfra/operations/postgres.py +349 -0
  91. pyinfra/operations/postgresql.py +18 -379
  92. pyinfra/operations/puppet.py +3 -1
  93. pyinfra/operations/python.py +8 -19
  94. pyinfra/operations/runit.py +182 -0
  95. pyinfra/operations/selinux.py +47 -44
  96. pyinfra/operations/server.py +111 -127
  97. pyinfra/operations/snap.py +4 -4
  98. pyinfra/operations/ssh.py +20 -33
  99. pyinfra/operations/systemd.py +19 -15
  100. pyinfra/operations/sysvinit.py +9 -16
  101. pyinfra/operations/upstart.py +9 -7
  102. pyinfra/operations/util/__init__.py +12 -0
  103. pyinfra/operations/util/docker.py +177 -0
  104. pyinfra/operations/util/files.py +24 -16
  105. pyinfra/operations/util/packaging.py +55 -57
  106. pyinfra/operations/util/service.py +39 -51
  107. pyinfra/operations/vzctl.py +12 -10
  108. pyinfra/operations/xbps.py +6 -4
  109. pyinfra/operations/yum.py +18 -22
  110. pyinfra/operations/zypper.py +12 -13
  111. pyinfra/version.py +5 -2
  112. {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/METADATA +40 -41
  113. pyinfra-3.0.dist-info/RECORD +167 -0
  114. {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/WHEEL +1 -1
  115. pyinfra-3.0.dist-info/entry_points.txt +11 -0
  116. pyinfra_cli/__main__.py +4 -3
  117. pyinfra_cli/commands.py +7 -2
  118. pyinfra_cli/exceptions.py +78 -42
  119. pyinfra_cli/inventory.py +40 -6
  120. pyinfra_cli/log.py +17 -3
  121. pyinfra_cli/main.py +133 -90
  122. pyinfra_cli/prints.py +95 -127
  123. pyinfra_cli/util.py +62 -29
  124. tests/test_api/test_api.py +2 -0
  125. tests/test_api/test_api_arguments.py +13 -13
  126. tests/test_api/test_api_deploys.py +28 -29
  127. tests/test_api/test_api_facts.py +60 -98
  128. tests/test_api/test_api_operations.py +101 -201
  129. tests/test_cli/test_cli.py +18 -49
  130. tests/test_cli/test_cli_deploy.py +11 -37
  131. tests/test_cli/test_cli_exceptions.py +50 -19
  132. tests/test_cli/util.py +1 -1
  133. tests/test_connectors/test_chroot.py +6 -6
  134. tests/test_connectors/test_docker.py +4 -4
  135. tests/test_connectors/test_dockerssh.py +38 -50
  136. tests/test_connectors/test_local.py +11 -12
  137. tests/test_connectors/test_ssh.py +105 -93
  138. tests/test_connectors/test_terraform.py +9 -15
  139. tests/test_connectors/test_util.py +24 -46
  140. tests/test_connectors/test_vagrant.py +7 -7
  141. pyinfra/api/operation.pyi +0 -117
  142. pyinfra/connectors/ansible.py +0 -171
  143. pyinfra/connectors/mech.py +0 -186
  144. pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
  145. pyinfra/connectors/winrm.py +0 -320
  146. pyinfra/facts/windows.py +0 -366
  147. pyinfra/facts/windows_files.py +0 -90
  148. pyinfra/operations/windows.py +0 -59
  149. pyinfra/operations/windows_files.py +0 -551
  150. pyinfra-2.9.2.dist-info/RECORD +0 -170
  151. pyinfra-2.9.2.dist-info/entry_points.txt +0 -14
  152. tests/test_connectors/test_ansible.py +0 -64
  153. tests/test_connectors/test_mech.py +0 -126
  154. tests/test_connectors/test_winrm.py +0 -76
  155. {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/LICENSE.md +0 -0
  156. {pyinfra-2.9.2.dist-info → pyinfra-3.0.dist-info}/top_level.txt +0 -0
pyinfra/api/exceptions.py CHANGED
@@ -4,15 +4,28 @@ class PyinfraError(Exception):
4
4
  """
5
5
 
6
6
 
7
- class NoMoreHostsError(PyinfraError):
7
+ class ConnectError(PyinfraError):
8
8
  """
9
- Exception raised when pyinfra runs out of hosts (they all failed).
9
+ Exception raised when connecting fails.
10
10
  """
11
11
 
12
12
 
13
- class ConnectError(PyinfraError):
13
+ class FactError(PyinfraError):
14
14
  """
15
- Exception raised when connecting fails.
15
+ Exception raised during fact gathering staging if a fact is unable to
16
+ generate output/change state.
17
+ """
18
+
19
+
20
+ class FactTypeError(FactError, TypeError):
21
+ """
22
+ Exception raised when a fact is passed invalid argument types.
23
+ """
24
+
25
+
26
+ class FactValueError(FactError, ValueError):
27
+ """
28
+ Exception raised when a fact is passed invalid argument values.
16
29
  """
17
30
 
18
31
 
@@ -47,19 +60,31 @@ class InventoryError(PyinfraError):
47
60
  """
48
61
 
49
62
 
50
- class NoConnectorError(PyinfraError, TypeError):
63
+ class NoConnectorError(PyinfraError, ValueError):
51
64
  """
52
65
  Raised when a requested connector is missing.
53
66
  """
54
67
 
55
68
 
56
- class NoHostError(PyinfraError, TypeError):
69
+ class NoHostError(PyinfraError, KeyError):
57
70
  """
58
71
  Raised when an inventory is missing a host.
59
72
  """
60
73
 
61
74
 
62
- class NoGroupError(PyinfraError, TypeError):
75
+ class NoGroupError(PyinfraError, KeyError):
76
+ """
77
+ Raised when an inventory is missing a group.
78
+ """
79
+
80
+
81
+ class ConnectorDataTypeError(PyinfraError, TypeError):
82
+ """
83
+ Raised when host connector data has invalid types.
84
+ """
85
+
86
+
87
+ class ArgumentTypeError(PyinfraError, TypeError):
63
88
  """
64
- Raise when an inventory is missing a group.
89
+ Raised when global arguments are passed with invalid types.
65
90
  """
pyinfra/api/facts.py CHANGED
@@ -8,10 +8,24 @@ it's possible to call facts on hosts out of context (ie give me the IP of this
8
8
  other host B while I operate on this host A).
9
9
  """
10
10
 
11
+ from __future__ import annotations
12
+
13
+ import inspect
11
14
  import re
12
15
  from inspect import getcallargs
13
16
  from socket import error as socket_error, timeout as timeout_error
14
- from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Type, Union
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
+ )
15
29
 
16
30
  import click
17
31
  import gevent
@@ -19,7 +33,7 @@ from paramiko import SSHException
19
33
 
20
34
  from pyinfra import logger
21
35
  from pyinfra.api import StringCommand
22
- from pyinfra.api.arguments import pop_global_arguments
36
+ from pyinfra.api.arguments import all_global_arguments, pop_global_arguments
23
37
  from pyinfra.api.util import (
24
38
  get_kwargs_str,
25
39
  log_error_or_warning,
@@ -27,11 +41,11 @@ from pyinfra.api.util import (
27
41
  make_hash,
28
42
  print_host_combined_output,
29
43
  )
30
- from pyinfra.connectors.util import split_combined_output
44
+ from pyinfra.connectors.util import CommandOutput
31
45
  from pyinfra.context import ctx_host, ctx_state
32
46
  from pyinfra.progress import progress_spinner
33
47
 
34
- from .arguments import get_executor_kwarg_keys
48
+ from .arguments import CONNECTOR_ARGUMENT_KEYS
35
49
 
36
50
  if TYPE_CHECKING:
37
51
  from pyinfra.api.host import Host
@@ -44,14 +58,10 @@ SU_REGEXES = (
44
58
  )
45
59
 
46
60
 
47
- class FactNameMeta(type):
48
- def __init__(cls, name: str, bases, attrs, **kwargs):
49
- super().__init__(name, bases, attrs, **kwargs)
50
- module_name = cls.__module__.replace("pyinfra.facts.", "")
51
- cls.name = f"{module_name}.{cls.__name__}"
61
+ T = TypeVar("T")
52
62
 
53
63
 
54
- class FactBase(metaclass=FactNameMeta):
64
+ class FactBase(Generic[T]):
55
65
  name: str
56
66
 
57
67
  abstract: bool = True
@@ -62,23 +72,47 @@ class FactBase(metaclass=FactNameMeta):
62
72
 
63
73
  command: Union[str, Callable]
64
74
 
75
+ def __init_subclass__(cls) -> None:
76
+ super().__init_subclass__()
77
+ module_name = cls.__module__.replace("pyinfra.facts.", "")
78
+ cls.name = f"{module_name}.{cls.__name__}"
79
+
80
+ # Check that fact's `command` method does not inadvertently take a global
81
+ # argument, most commonly `name`.
82
+ if hasattr(cls, "command") and callable(cls.command):
83
+ command_args = set(inspect.signature(cls.command).parameters.keys())
84
+ global_args = set([name for name, _ in all_global_arguments()])
85
+ command_global_args = command_args & global_args
86
+
87
+ if len(command_global_args) > 0:
88
+ names = ", ".join(command_global_args)
89
+ raise TypeError(f"{cls.name}'s arguments {names} are reserved for global arguments")
90
+
65
91
  @staticmethod
66
- def default():
92
+ def default() -> T:
67
93
  """
68
94
  Set the default attribute to be a type (eg list/dict).
69
95
  """
70
96
 
71
- @staticmethod
72
- def process(output):
73
- return "\n".join(output)
97
+ return cast(T, None)
98
+
99
+ def process(self, output: Iterable[str]) -> T:
100
+ # NOTE: TypeVar does not support a default, so we have to cast this str -> T
101
+ return cast(T, "\n".join(output))
74
102
 
75
103
  def process_pipeline(self, args, output):
76
104
  return {arg: self.process([output[i]]) for i, arg in enumerate(args)}
77
105
 
78
106
 
79
- class ShortFactBase(metaclass=FactNameMeta):
107
+ class ShortFactBase(Generic[T]):
108
+ name: str
80
109
  fact: Type[FactBase]
81
110
 
111
+ def __init_subclass__(cls) -> None:
112
+ super().__init_subclass__()
113
+ module_name = cls.__module__.replace("pyinfra.facts.", "")
114
+ cls.name = f"{module_name}.{cls.__name__}"
115
+
82
116
  @staticmethod
83
117
  def process_data(data):
84
118
  return data
@@ -99,8 +133,8 @@ def _make_command(command_attribute, host_args):
99
133
  def _get_executor_kwargs(
100
134
  state: "State",
101
135
  host: "Host",
102
- override_kwargs: Optional[Dict[str, Any]] = None,
103
- override_kwarg_keys: Optional[List[str]] = None,
136
+ override_kwargs: Optional[dict[str, Any]] = None,
137
+ override_kwarg_keys: Optional[list[str]] = None,
104
138
  ):
105
139
  if override_kwargs is None:
106
140
  override_kwargs = {}
@@ -108,7 +142,7 @@ def _get_executor_kwargs(
108
142
  override_kwarg_keys = []
109
143
 
110
144
  # Use the current operation global kwargs, or generate defaults
111
- global_kwargs = host.current_op_global_kwargs
145
+ global_kwargs = host.current_op_global_arguments
112
146
  if not global_kwargs:
113
147
  global_kwargs, _ = pop_global_arguments({}, state, host)
114
148
 
@@ -117,43 +151,32 @@ def _get_executor_kwargs(
117
151
  {key: value for key, value in global_kwargs.items() if key not in override_kwarg_keys},
118
152
  )
119
153
 
120
- return {
121
- key: value for key, value in override_kwargs.items() if key in get_executor_kwarg_keys()
122
- }
154
+ return {key: value for key, value in override_kwargs.items() if key in CONNECTOR_ARGUMENT_KEYS}
123
155
 
124
156
 
125
157
  def _handle_fact_kwargs(state, host, cls, args, kwargs):
126
158
  args = args or []
127
159
  kwargs = kwargs or {}
128
160
 
129
- # TODO: this is here to avoid popping stuff accidentally, this is horrible! Change the
130
- # pop function to return the clean kwargs to avoid the indirect mutation.
131
- kwargs = kwargs.copy()
161
+ # Start with a (shallow) copy of current operation kwargs if any
162
+ ctx_kwargs = (host.current_op_global_arguments or {}).copy()
163
+ # Update with the input kwargs (overrides)
164
+ ctx_kwargs.update(kwargs)
132
165
 
133
- # Get the defaults *and* overrides by popping from kwargs, executor kwargs passed
134
- # into get_fact override everything else (applied below).
135
- override_kwargs, override_kwarg_keys = pop_global_arguments(
136
- kwargs,
166
+ # Pop executor kwargs, pass remaining
167
+ global_kwargs, _ = pop_global_arguments(
168
+ ctx_kwargs,
137
169
  state=state,
138
170
  host=host,
139
- keys_to_check=get_executor_kwarg_keys(),
140
- )
141
-
142
- executor_kwargs = _get_executor_kwargs(
143
- state,
144
- host,
145
- override_kwargs=override_kwargs,
146
- override_kwarg_keys=override_kwarg_keys,
147
171
  )
148
172
 
149
- fact_kwargs = {}
173
+ fact_kwargs = {key: value for key, value in kwargs.items() if key not in global_kwargs}
150
174
 
151
- if args or kwargs:
152
- assert not isinstance(cls.command, str)
175
+ if args or fact_kwargs:
153
176
  # Merges args & kwargs into a single kwargs dictionary
154
- fact_kwargs = getcallargs(cls().command, *args, **kwargs)
177
+ fact_kwargs = getcallargs(cls().command, *args, **fact_kwargs)
155
178
 
156
- return fact_kwargs, executor_kwargs
179
+ return fact_kwargs, global_kwargs
157
180
 
158
181
 
159
182
  def get_facts(state: "State", *args, **kwargs):
@@ -181,14 +204,12 @@ def get_facts(state: "State", *args, **kwargs):
181
204
  def get_fact(
182
205
  state: "State",
183
206
  host: "Host",
184
- cls: Type[FactBase],
207
+ cls: type[FactBase],
185
208
  args: Optional[Any] = None,
186
209
  kwargs: Optional[Any] = None,
187
210
  ensure_hosts: Optional[Any] = None,
188
211
  apply_failed_hosts: bool = True,
189
- fact_hash: Optional[Any] = None,
190
- use_cache: bool = True,
191
- ):
212
+ ) -> Any:
192
213
  if issubclass(cls, ShortFactBase):
193
214
  return get_short_facts(
194
215
  state,
@@ -198,40 +219,32 @@ def get_fact(
198
219
  kwargs=kwargs,
199
220
  ensure_hosts=ensure_hosts,
200
221
  apply_failed_hosts=apply_failed_hosts,
201
- fact_hash=fact_hash,
202
- use_cache=use_cache,
203
222
  )
204
223
 
205
- with host.facts_lock:
206
- if use_cache and fact_hash and fact_hash in host.facts:
207
- return host.facts[fact_hash]
208
-
209
- return _get_fact(
210
- state,
211
- host,
212
- cls,
213
- args,
214
- kwargs,
215
- ensure_hosts,
216
- apply_failed_hosts,
217
- fact_hash,
218
- )
224
+ return _get_fact(
225
+ state,
226
+ host,
227
+ cls,
228
+ args,
229
+ kwargs,
230
+ ensure_hosts,
231
+ apply_failed_hosts,
232
+ )
219
233
 
220
234
 
221
235
  def _get_fact(
222
236
  state: "State",
223
237
  host: "Host",
224
- cls: Type[FactBase],
225
- args: Optional[List] = None,
226
- kwargs: Optional[Dict] = None,
238
+ cls: type[FactBase],
239
+ args: Optional[list] = None,
240
+ kwargs: Optional[dict] = None,
227
241
  ensure_hosts: Optional[Any] = None,
228
242
  apply_failed_hosts: bool = True,
229
- fact_hash: Optional[Any] = None,
230
- ):
243
+ ) -> Any:
231
244
  fact = cls()
232
245
  name = fact.name
233
246
 
234
- fact_kwargs, executor_kwargs = _handle_fact_kwargs(state, host, cls, args, kwargs)
247
+ fact_kwargs, global_kwargs = _handle_fact_kwargs(state, host, cls, args, kwargs)
235
248
 
236
249
  kwargs_str = get_kwargs_str(fact_kwargs)
237
250
  logger.debug(
@@ -247,14 +260,9 @@ def _get_fact(
247
260
  raise_exceptions=True,
248
261
  )
249
262
 
250
- ignore_errors = (host.current_op_global_kwargs or {}).get(
251
- "ignore_errors",
252
- state.config.IGNORE_ERRORS,
253
- )
254
-
255
263
  # Facts can override the shell (winrm powershell vs cmd support)
256
264
  if fact.shell_executable:
257
- executor_kwargs["shell_executable"] = fact.shell_executable
265
+ global_kwargs["_shell_executable"] = fact.shell_executable
258
266
 
259
267
  command = _make_command(fact.command, fact_kwargs)
260
268
  requires_command = _make_command(fact.requires_command, fact_kwargs)
@@ -271,40 +279,42 @@ def _get_fact(
271
279
  )
272
280
 
273
281
  status = False
274
- stdout = []
275
- combined_output_lines = []
282
+ output = CommandOutput([])
283
+
284
+ executor_kwargs = {
285
+ key: value for key, value in global_kwargs.items() if key in CONNECTOR_ARGUMENT_KEYS
286
+ }
276
287
 
277
288
  try:
278
- status, combined_output_lines = host.run_shell_command(
289
+ status, output = host.run_shell_command(
279
290
  command,
280
291
  print_output=state.print_fact_output,
281
292
  print_input=state.print_fact_input,
282
- return_combined_output=True,
283
293
  **executor_kwargs,
284
294
  )
285
295
  except (timeout_error, socket_error, SSHException) as e:
286
296
  log_host_command_error(
287
297
  host,
288
298
  e,
289
- timeout=executor_kwargs["timeout"],
299
+ timeout=global_kwargs["_timeout"],
290
300
  )
291
301
 
292
- stdout, stderr = split_combined_output(combined_output_lines)
302
+ stdout_lines, stderr_lines = output.stdout_lines, output.stderr_lines
293
303
 
294
304
  data = fact.default()
295
305
 
296
306
  if status:
297
- if stdout:
298
- data = fact.process(stdout)
299
- elif stderr:
307
+ if stdout_lines:
308
+ data = fact.process(stdout_lines)
309
+ elif stderr_lines:
300
310
  # If we have error output and that error is sudo or su stating the user
301
311
  # does not exist, do not fail but instead return the default fact value.
302
312
  # This allows for users that don't currently but may be created during
303
313
  # other operations.
304
- first_line = stderr[0]
305
- if executor_kwargs["sudo_user"] and re.match(SUDO_REGEX, first_line):
314
+ first_line = stderr_lines[0]
315
+ if executor_kwargs["_sudo_user"] and re.match(SUDO_REGEX, first_line):
306
316
  status = True
307
- if executor_kwargs["su_user"] and any(re.match(regex, first_line) for regex in SU_REGEXES):
317
+ if executor_kwargs["_su_user"] and any(re.match(regex, first_line) for regex in SU_REGEXES):
308
318
  status = True
309
319
 
310
320
  if status:
@@ -321,20 +331,18 @@ def _get_fact(
321
331
  logger.debug(log_message)
322
332
  else:
323
333
  if not state.print_fact_output:
324
- print_host_combined_output(host, combined_output_lines)
334
+ print_host_combined_output(host, output)
325
335
 
326
336
  log_error_or_warning(
327
337
  host,
328
- ignore_errors,
338
+ global_kwargs["_ignore_errors"],
329
339
  description=("could not load fact: {0} {1}").format(name, get_kwargs_str(fact_kwargs)),
330
340
  )
331
341
 
332
342
  # Check we've not failed
333
- if not status and not ignore_errors and apply_failed_hosts:
343
+ if apply_failed_hosts and not status and not global_kwargs["_ignore_errors"]:
334
344
  state.fail_hosts({host})
335
345
 
336
- if fact_hash:
337
- host.facts[fact_hash] = data
338
346
  return data
339
347
 
340
348
 
@@ -349,50 +357,7 @@ def get_host_fact(
349
357
  state: "State",
350
358
  host: "Host",
351
359
  cls,
352
- args: Optional[List] = None,
353
- kwargs: Optional[Dict] = None,
354
- ):
355
- fact_hash = _get_fact_hash(state, host, cls, args, kwargs)
356
- return get_fact(state, host, cls, args=args, kwargs=kwargs, fact_hash=fact_hash)
357
-
358
-
359
- def reload_host_fact(
360
- state: "State",
361
- host: "Host",
362
- cls,
363
- args: Optional[List] = None,
364
- kwargs: Optional[Dict] = None,
365
- ):
366
- fact_hash = _get_fact_hash(state, host, cls, args, kwargs)
367
- return get_fact(
368
- state,
369
- host,
370
- cls,
371
- args=args,
372
- kwargs=kwargs,
373
- fact_hash=fact_hash,
374
- use_cache=False,
375
- )
376
-
377
-
378
- def create_host_fact(
379
- state: "State",
380
- host: "Host",
381
- cls,
382
- data,
383
- args: Optional[List] = None,
384
- kwargs: Optional[Dict] = None,
385
- ):
386
- fact_hash = _get_fact_hash(state, host, cls, args, kwargs)
387
- host.facts[fact_hash] = data
388
-
389
-
390
- def delete_host_fact(
391
- state: "State",
392
- host: "Host",
393
- cls,
394
- args: Optional[List] = None,
395
- kwargs: Optional[Dict] = None,
396
- ):
397
- fact_hash = _get_fact_hash(state, host, cls, args, kwargs)
398
- host.facts.pop(fact_hash, None)
360
+ args: Optional[Iterable] = None,
361
+ kwargs: Optional[dict] = None,
362
+ ) -> Any:
363
+ return get_fact(state, host, cls, args=args, kwargs=kwargs)