pyinfra 2.9.1__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.1.dist-info → pyinfra-3.0.dist-info}/METADATA +40 -41
  113. pyinfra-3.0.dist-info/RECORD +167 -0
  114. {pyinfra-2.9.1.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.1.dist-info/RECORD +0 -170
  151. pyinfra-2.9.1.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.1.dist-info → pyinfra-3.0.dist-info}/LICENSE.md +0 -0
  156. {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/top_level.txt +0 -0
@@ -1,19 +1,29 @@
1
+ from __future__ import annotations
2
+
1
3
  import shlex
2
4
  from collections import defaultdict
3
5
  from io import StringIO
6
+ from typing import Callable
4
7
  from urllib.parse import urlparse
5
8
 
9
+ from pyinfra.api import Host, State
6
10
  from pyinfra.facts.files import File
7
11
  from pyinfra.facts.rpm import RpmPackage
12
+ from pyinfra.operations import files
8
13
 
9
14
 
10
- def _package_name(package):
15
+ def _package_name(package: list[str] | str) -> str:
11
16
  if isinstance(package, list):
12
17
  return package[0]
13
18
  return package
14
19
 
15
20
 
16
- def _has_package(package, packages, expand_package_fact=None, match_any=False):
21
+ def _has_package(
22
+ package: str | list[str],
23
+ packages: dict[str, set[str]],
24
+ expand_package_fact: Callable[[str], list[str | list[str]]] | None = None,
25
+ match_any=False,
26
+ ) -> tuple[bool, dict]:
17
27
  def in_packages(pkg_name, pkg_versions):
18
28
  if not pkg_versions:
19
29
  return pkg_name in packages
@@ -21,9 +31,12 @@ def _has_package(package, packages, expand_package_fact=None, match_any=False):
21
31
  version in packages[pkg_name] for version in pkg_versions
22
32
  )
23
33
 
24
- packages_to_check = [package]
34
+ packages_to_check: list[str | list[str]] = [package]
25
35
  if expand_package_fact:
26
- packages_to_check = expand_package_fact(package) or packages_to_check
36
+ if isinstance(package, list):
37
+ packages_to_check = expand_package_fact(package[0]) or packages_to_check
38
+ else:
39
+ packages_to_check = expand_package_fact(package) or packages_to_check
27
40
 
28
41
  package_name_to_versions = defaultdict(set)
29
42
  for pkg in packages_to_check:
@@ -43,16 +56,16 @@ def _has_package(package, packages, expand_package_fact=None, match_any=False):
43
56
 
44
57
 
45
58
  def ensure_packages(
46
- host,
47
- packages,
48
- current_packages,
49
- present,
50
- install_command,
51
- uninstall_command,
59
+ host: Host,
60
+ packages_to_ensure: str | list[str] | None,
61
+ current_packages: dict[str, set[str]],
62
+ present: bool,
63
+ install_command: str,
64
+ uninstall_command: str,
52
65
  latest=False,
53
- upgrade_command=None,
54
- version_join=None,
55
- expand_package_fact=None,
66
+ upgrade_command: str | None = None,
67
+ version_join: str | None = None,
68
+ expand_package_fact: Callable[[str], list[str | list[str]]] | None = None,
56
69
  ):
57
70
  """
58
71
  Handles this common scenario:
@@ -64,7 +77,7 @@ def ensure_packages(
64
77
  + Optionally upgrades packages w/o specified version when present
65
78
 
66
79
  Args:
67
- packages (list): list of packages or package/versions
80
+ packages_to_ensure (list): list of packages or package/versions
68
81
  current_packages (fact): fact returning dict of package names -> version
69
82
  present (bool): whether packages should exist or not
70
83
  install_command (str): command to prefix to list of packages to install
@@ -73,18 +86,21 @@ def ensure_packages(
73
86
  upgrade_command (str): as above for upgrading
74
87
  version_join (str): the package manager specific "joiner", ie ``=`` for \
75
88
  ``<apt_pkg>=<version>``
89
+ expand_package_fact: fact returning packages providing a capability \
90
+ (ie ``yum whatprovides``)
76
91
  """
77
92
 
78
- if packages is None:
93
+ if packages_to_ensure is None:
79
94
  return
95
+ if isinstance(packages_to_ensure, str):
96
+ packages_to_ensure = [packages_to_ensure]
80
97
 
81
- if isinstance(packages, str):
82
- packages = [packages]
98
+ packages: list[str | list[str]] = packages_to_ensure # type: ignore[assignment]
83
99
 
84
100
  if version_join:
85
101
  packages = [
86
102
  package[0] if len(package) == 1 else package
87
- for package in [package.rsplit(version_join, 1) for package in packages]
103
+ for package in [package.rsplit(version_join, 1) for package in packages] # type: ignore[union-attr] # noqa
88
104
  ]
89
105
 
90
106
  diff_packages = []
@@ -140,7 +156,7 @@ def ensure_packages(
140
156
  command = install_command if present else uninstall_command
141
157
 
142
158
  joined_packages = [
143
- version_join.join(package) if isinstance(package, list) else package
159
+ version_join.join(package) if isinstance(package, list) else package # type: ignore[union-attr] # noqa
144
160
  for package in diff_packages
145
161
  ]
146
162
 
@@ -149,20 +165,6 @@ def ensure_packages(
149
165
  " ".join([shlex.quote(pkg) for pkg in joined_packages]),
150
166
  )
151
167
 
152
- for package in diff_packages: # add/remove from current packages
153
- pkg_name = _package_name(package)
154
- version = "unknown"
155
- if isinstance(package, list):
156
- version = package[1]
157
-
158
- if present:
159
- current_packages[pkg_name] = [version]
160
- current_packages.update(diff_expanded_packages.get(pkg_name, {}))
161
- else:
162
- current_packages.pop(pkg_name, None)
163
- for name in diff_expanded_packages.get(pkg_name, {}):
164
- current_packages.pop(name, None)
165
-
166
168
  if latest and upgrade_command and upgrade_packages:
167
169
  yield "{0} {1}".format(
168
170
  upgrade_command,
@@ -170,27 +172,27 @@ def ensure_packages(
170
172
  )
171
173
 
172
174
 
173
- def ensure_rpm(state, host, files, source, present, package_manager_command):
175
+ def ensure_rpm(state: State, host: Host, source: str, present: bool, package_manager_command: str):
174
176
  original_source = source
175
177
 
176
178
  # If source is a url
177
179
  if urlparse(source).scheme:
178
180
  # Generate a temp filename (with .rpm extension to please yum)
179
- temp_filename = "{0}.rpm".format(state.get_temp_filename(source))
181
+ temp_filename = "{0}.rpm".format(host.get_temp_filename(source))
180
182
 
181
183
  # Ensure it's downloaded
182
- yield from files.download(source, temp_filename)
184
+ yield from files.download._inner(src=source, dest=temp_filename)
183
185
 
184
186
  # Override the source with the downloaded file
185
187
  source = temp_filename
186
188
 
187
189
  # Check for file .rpm information
188
- info = host.get_fact(RpmPackage, name=source)
190
+ info = host.get_fact(RpmPackage, package=source)
189
191
  exists = False
190
192
 
191
193
  # We have info!
192
194
  if info:
193
- current_package = host.get_fact(RpmPackage, name=info["name"])
195
+ current_package = host.get_fact(RpmPackage, package=info["name"])
194
196
  if current_package and current_package["version"] == info["version"]:
195
197
  exists = True
196
198
 
@@ -199,8 +201,6 @@ def ensure_rpm(state, host, files, source, present, package_manager_command):
199
201
  # If we had info, always install
200
202
  if info:
201
203
  yield "rpm -i {0}".format(source)
202
- host.create_fact(RpmPackage, kwargs={"name": info["name"]}, data=info)
203
-
204
204
  # This happens if we download the package mid-deploy, so we have no info
205
205
  # but also don't know if it's installed. So check at runtime, otherwise
206
206
  # the install will fail.
@@ -210,8 +210,6 @@ def ensure_rpm(state, host, files, source, present, package_manager_command):
210
210
  # Package exists but we don't want?
211
211
  elif exists and not present:
212
212
  yield "{0} remove -y {1}".format(package_manager_command, info["name"])
213
- host.delete_fact(RpmPackage, kwargs={"name": info["name"]})
214
-
215
213
  else:
216
214
  host.noop(
217
215
  "rpm {0} is {1}".format(
@@ -222,18 +220,16 @@ def ensure_rpm(state, host, files, source, present, package_manager_command):
222
220
 
223
221
 
224
222
  def ensure_yum_repo(
225
- state,
226
- host,
227
- files,
228
- name_or_url,
229
- baseurl,
230
- present,
231
- description,
232
- enabled,
233
- gpgcheck,
234
- gpgkey,
223
+ host: Host,
224
+ name_or_url: str,
225
+ baseurl: str | None,
226
+ present: bool,
227
+ description: str | None,
228
+ enabled: bool,
229
+ gpgcheck: bool,
230
+ gpgkey: str | None,
235
231
  repo_directory="/etc/yum.repos.d/",
236
- type_=None,
232
+ type_: str | None = None,
237
233
  ):
238
234
  url = None
239
235
  url_parts = urlparse(name_or_url)
@@ -247,15 +243,17 @@ def ensure_yum_repo(
247
243
 
248
244
  # If we don't want the repo, just remove any existing file
249
245
  if not present:
250
- yield from files.file(filename, present=False)
246
+ yield from files.file._inner(path=filename, present=False)
251
247
  return
252
248
 
253
249
  # If we're a URL, download the repo if it doesn't exist
254
250
  if url:
255
251
  if not host.get_fact(File, path=filename):
256
- yield from files.download(url, filename)
252
+ yield from files.download._inner(src=url, dest=filename)
257
253
  return
258
254
 
255
+ assert isinstance(baseurl, str)
256
+
259
257
  # Description defaults to name
260
258
  description = description or name_or_url
261
259
 
@@ -276,7 +274,7 @@ def ensure_yum_repo(
276
274
 
277
275
  repo_lines.append("")
278
276
  repo = "\n".join(repo_lines)
279
- repo = StringIO(repo)
277
+ repo_file = StringIO(repo)
280
278
 
281
279
  # Ensure this is the file on the server
282
- yield from files.put(repo, filename)
280
+ yield from files.put._inner(src=repo_file, dest=filename)
@@ -1,58 +1,46 @@
1
+ from __future__ import annotations
2
+
3
+ import shlex
4
+
5
+ from pyinfra.api import Host
6
+
7
+
1
8
  def handle_service_control(
2
- host,
3
- name,
4
- statuses,
5
- formatter,
6
- running,
7
- restarted,
8
- reloaded,
9
- command,
9
+ host: Host,
10
+ name: str,
11
+ statuses: dict[str, bool],
12
+ formatter: str,
13
+ running: bool | None = None,
14
+ restarted: bool | None = None,
15
+ reloaded: bool | None = None,
16
+ command: str | None = None,
10
17
  status_argument="status",
11
18
  ):
12
- status = statuses.get(name, None)
13
-
14
- # If we don't know the status, we need to check if it's up before starting
15
- # and/or restarting/reloading
16
- if status is None:
17
- yield (
18
- "if ({status_command}); then "
19
- "({stop_command}); ({restart_command}); ({reload_command}); "
20
- "else ({start_command}); fi"
21
- ).format(
22
- status_command=formatter.format(name, status_argument),
23
- start_command=(formatter.format(name, "start") if running is True else "true"),
24
- stop_command=(formatter.format(name, "stop") if running is False else "true"),
25
- restart_command=(formatter.format(name, "restart") if restarted else "true"),
26
- reload_command=(formatter.format(name, "reload") if reloaded else "true"),
27
- )
28
- statuses[name] = running
29
-
30
- else:
31
- # Need down but running
32
- if running is False:
33
- if status:
34
- yield formatter.format(name, "stop")
35
- statuses[name] = False
36
- else:
37
- host.noop("service {0} is stopped".format(name))
38
-
39
- # Need running but down
40
- if running is True:
41
- if not status:
42
- yield formatter.format(name, "start")
43
- statuses[name] = True
44
- else:
45
- host.noop("service {0} is running".format(name))
46
-
47
- # Only restart if the service is already running
48
- if restarted and status:
49
- yield formatter.format(name, "restart")
50
-
51
- # Only reload if the service is already reloaded
52
- if reloaded and status:
53
- yield formatter.format(name, "reload")
19
+ is_running = statuses.get(name, None)
20
+
21
+ # Need down but running
22
+ if running is False:
23
+ if is_running:
24
+ yield formatter.format(shlex.quote(name), "stop")
25
+ else:
26
+ host.noop("service {0} is stopped".format(name))
27
+
28
+ # Need running but down
29
+ if running is True:
30
+ if not is_running:
31
+ yield formatter.format(shlex.quote(name), "start")
32
+ else:
33
+ host.noop("service {0} is running".format(name))
34
+
35
+ # Only restart if the service is already running
36
+ if restarted and is_running:
37
+ yield formatter.format(shlex.quote(name), "restart")
38
+
39
+ # Only reload if the service is already reloaded
40
+ if reloaded and is_running:
41
+ yield formatter.format(shlex.quote(name), "reload")
54
42
 
55
43
  # Always execute arbitrary commands as these may or may not rely on the service
56
44
  # being up or down
57
45
  if command:
58
- yield formatter.format(name, command)
46
+ yield formatter.format(shlex.quote(name), command)
@@ -2,13 +2,15 @@
2
2
  Manage OpenVZ containers with ``vzctl``.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from pyinfra import host
6
8
  from pyinfra.api import OperationError, operation
7
9
  from pyinfra.facts.vzctl import OpenvzContainers
8
10
 
9
11
 
10
12
  @operation(is_idempotent=False)
11
- def start(ctid, force=False):
13
+ def start(ctid: str, force=False):
12
14
  """
13
15
  Start OpenVZ containers.
14
16
 
@@ -25,7 +27,7 @@ def start(ctid, force=False):
25
27
 
26
28
 
27
29
  @operation(is_idempotent=False)
28
- def stop(ctid):
30
+ def stop(ctid: str):
29
31
  """
30
32
  Stop OpenVZ containers.
31
33
 
@@ -38,7 +40,7 @@ def stop(ctid):
38
40
 
39
41
 
40
42
  @operation(is_idempotent=False)
41
- def restart(ctid, force=False):
43
+ def restart(ctid: str, force=False):
42
44
  """
43
45
  Restart OpenVZ containers.
44
46
 
@@ -46,12 +48,12 @@ def restart(ctid, force=False):
46
48
  + force: whether to force container start
47
49
  """
48
50
 
49
- yield from stop(ctid)
50
- yield from start(ctid, force=force)
51
+ yield from stop._inner(ctid=ctid)
52
+ yield from start._inner(ctid=ctid, force=force)
51
53
 
52
54
 
53
55
  @operation(is_idempotent=False)
54
- def mount(ctid):
56
+ def mount(ctid: str):
55
57
  """
56
58
  Mount OpenVZ container filesystems.
57
59
 
@@ -62,7 +64,7 @@ def mount(ctid):
62
64
 
63
65
 
64
66
  @operation(is_idempotent=False)
65
- def unmount(ctid):
67
+ def unmount(ctid: str):
66
68
  """
67
69
  Unmount OpenVZ container filesystems.
68
70
 
@@ -73,7 +75,7 @@ def unmount(ctid):
73
75
 
74
76
 
75
77
  @operation(is_idempotent=False)
76
- def delete(ctid):
78
+ def delete(ctid: str):
77
79
  """
78
80
  Delete OpenVZ containers.
79
81
 
@@ -84,7 +86,7 @@ def delete(ctid):
84
86
 
85
87
 
86
88
  @operation(is_idempotent=False)
87
- def create(ctid, template=None):
89
+ def create(ctid: str, template: str | None = None):
88
90
  """
89
91
  Create OpenVZ containers.
90
92
 
@@ -107,7 +109,7 @@ def create(ctid, template=None):
107
109
 
108
110
 
109
111
  @operation(is_idempotent=False)
110
- def set(ctid, save=True, **settings):
112
+ def set(ctid: str, save=True, **settings):
111
113
  """
112
114
  Set OpenVZ container details.
113
115
 
@@ -2,6 +2,8 @@
2
2
  Manage XBPS packages and repositories. Note that XBPS package names are case-sensitive.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from pyinfra import host
6
8
  from pyinfra.api import operation
7
9
  from pyinfra.facts.xbps import XbpsPackages
@@ -18,7 +20,7 @@ def upgrade():
18
20
  yield "xbps-install -y -u"
19
21
 
20
22
 
21
- _upgrade = upgrade # noqa: E305
23
+ _upgrade = upgrade._inner # noqa: E305
22
24
 
23
25
 
24
26
  @operation(is_idempotent=False)
@@ -30,12 +32,12 @@ def update():
30
32
  yield "xbps-install -S"
31
33
 
32
34
 
33
- _update = update # noqa: E305
35
+ _update = update._inner # noqa: E305
34
36
 
35
37
 
36
- @operation
38
+ @operation()
37
39
  def packages(
38
- packages=None,
40
+ packages: str | list[str] | None = None,
39
41
  present=True,
40
42
  update=False,
41
43
  upgrade=False,
pyinfra/operations/yum.py CHANGED
@@ -2,16 +2,17 @@
2
2
  Manage yum packages and repositories. Note that yum package names are case-sensitive.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  from pyinfra import host, state
6
8
  from pyinfra.api import operation
7
9
  from pyinfra.facts.rpm import RpmPackageProvides, RpmPackages
8
10
 
9
- from . import files
10
11
  from .util.packaging import ensure_packages, ensure_rpm, ensure_yum_repo
11
12
 
12
13
 
13
14
  @operation(is_idempotent=False)
14
- def key(src):
15
+ def key(src: str):
15
16
  """
16
17
  Add yum gpg keys with ``rpm``.
17
18
 
@@ -35,15 +36,15 @@ def key(src):
35
36
  yield "rpm --import {0}".format(src)
36
37
 
37
38
 
38
- @operation
39
+ @operation()
39
40
  def repo(
40
- src,
41
+ src: str,
41
42
  present=True,
42
- baseurl=None,
43
- description=None,
43
+ baseurl: str | None = None,
44
+ description: str | None = None,
44
45
  enabled=True,
45
46
  gpgcheck=True,
46
- gpgkey=None,
47
+ gpgkey: str | None = None,
47
48
  ):
48
49
  # NOTE: if updating this docstring also update `dnf.repo`
49
50
  """
@@ -51,7 +52,7 @@ def repo(
51
52
 
52
53
  + src: URL or name for the ``.repo`` file
53
54
  + present: whether the ``.repo`` file should be present
54
- + baseurl: the baseurl of the repo (if ``name`` is not a URL)
55
+ + baseurl: the baseurl of the repo (if ``src`` is not a URL)
55
56
  + description: optional verbose description
56
57
  + enabled: whether this repo is enabled
57
58
  + gpgcheck: whether set ``gpgcheck=1``
@@ -81,9 +82,7 @@ def repo(
81
82
  """
82
83
 
83
84
  yield from ensure_yum_repo(
84
- state,
85
85
  host,
86
- files,
87
86
  src,
88
87
  baseurl,
89
88
  present,
@@ -94,8 +93,8 @@ def repo(
94
93
  )
95
94
 
96
95
 
97
- @operation
98
- def rpm(src, present=True):
96
+ @operation()
97
+ def rpm(src: str, present=True):
99
98
  # NOTE: if updating this docstring also update `dnf.rpm`
100
99
  """
101
100
  Add/remove ``.rpm`` file packages.
@@ -118,7 +117,7 @@ def rpm(src, present=True):
118
117
  )
119
118
  """
120
119
 
121
- yield from ensure_rpm(state, host, files, src, present, "yum")
120
+ yield from ensure_rpm(state, host, src, present, "yum")
122
121
 
123
122
 
124
123
  @operation(is_idempotent=False)
@@ -130,19 +129,19 @@ def update():
130
129
  yield "yum update -y"
131
130
 
132
131
 
133
- _update = update # noqa: E305 (for use below where update is a kwarg)
132
+ _update = update._inner # noqa: E305 (for use below where update is a kwarg)
134
133
 
135
134
 
136
- @operation
135
+ @operation()
137
136
  def packages(
138
- packages=None,
137
+ packages: str | list[str] | None = None,
139
138
  present=True,
140
139
  latest=False,
141
140
  update=False,
142
141
  clean=False,
143
142
  nobest=False,
144
- extra_install_args=None,
145
- extra_uninstall_args=None,
143
+ extra_install_args: str | None = None,
144
+ extra_uninstall_args: str | None = None,
146
145
  ):
147
146
  """
148
147
  Install/remove/update yum packages & updates.
@@ -207,8 +206,5 @@ def packages(
207
206
  upgrade_command="yum update -y",
208
207
  version_join="=",
209
208
  latest=latest,
210
- expand_package_fact=lambda package: host.get_fact(
211
- RpmPackageProvides,
212
- name=package,
213
- ),
209
+ expand_package_fact=lambda package: host.get_fact(RpmPackageProvides, package=package),
214
210
  )
@@ -1,15 +1,16 @@
1
+ from __future__ import annotations
2
+
1
3
  from pyinfra import host, state
2
4
  from pyinfra.api import operation
3
5
  from pyinfra.facts.rpm import RpmPackages
4
6
 
5
- from . import files
6
7
  from .util.packaging import ensure_packages, ensure_rpm, ensure_yum_repo
7
8
  from .yum import key as yum_key
8
9
 
9
10
  key = yum_key
10
11
 
11
12
 
12
- @operation
13
+ @operation()
13
14
  def repo(
14
15
  src,
15
16
  baseurl=None,
@@ -56,9 +57,7 @@ def repo(
56
57
  """
57
58
 
58
59
  yield from ensure_yum_repo(
59
- state,
60
60
  host,
61
- files,
62
61
  src,
63
62
  baseurl,
64
63
  present,
@@ -71,7 +70,7 @@ def repo(
71
70
  )
72
71
 
73
72
 
74
- @operation
73
+ @operation()
75
74
  def rpm(src, present=True):
76
75
  # NOTE: if updating this docstring also update `dnf.rpm`
77
76
  """
@@ -94,7 +93,7 @@ def rpm(src, present=True):
94
93
  )
95
94
  """
96
95
 
97
- yield from ensure_rpm(state, host, files, src, present, "zypper --non-interactive")
96
+ yield from ensure_rpm(state, host, src, present, "zypper --non-interactive")
98
97
 
99
98
 
100
99
  @operation(is_idempotent=False)
@@ -106,20 +105,20 @@ def update():
106
105
  yield "zypper update -y"
107
106
 
108
107
 
109
- _update = update # noqa: E305 (for use below where update is a kwarg)
108
+ _update = update._inner # noqa: E305 (for use below where update is a kwarg)
110
109
 
111
110
 
112
- @operation
111
+ @operation()
113
112
  def packages(
114
- packages=None,
113
+ packages: str | list[str] | None = None,
115
114
  present=True,
116
115
  latest=False,
117
116
  update=False,
118
117
  clean=False,
119
- extra_global_install_args=None,
120
- extra_install_args=None,
121
- extra_global_uninstall_args=None,
122
- extra_uninstall_args=None,
118
+ extra_global_install_args: str | None = None,
119
+ extra_install_args: str | None = None,
120
+ extra_global_uninstall_args: str | None = None,
121
+ extra_uninstall_args: str | None = None,
123
122
  ):
124
123
  """
125
124
  Install/remove/update zypper packages & updates.
pyinfra/version.py CHANGED
@@ -1,6 +1,9 @@
1
1
  try:
2
- from pkg_resources import get_distribution
2
+ try:
3
+ from importlib_metadata import version
4
+ except ImportError:
5
+ from importlib.metadata import version
3
6
 
4
- __version__ = get_distribution("pyinfra").version
7
+ __version__ = version("pyinfra")
5
8
  except Exception:
6
9
  __version__ = "unknown"