pyinfra 3.0b4__tar.gz → 3.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. pyinfra-3.0.1/CHANGELOG.md +73 -0
  2. {pyinfra-3.0b4/pyinfra.egg-info → pyinfra-3.0.1}/PKG-INFO +1 -5
  3. {pyinfra-3.0b4 → pyinfra-3.0.1}/README.md +0 -4
  4. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/facts.py +7 -50
  5. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/util.py +1 -1
  6. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/ssh.py +3 -3
  7. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/sshuserclient/client.py +1 -1
  8. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/apk.py +5 -2
  9. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/apt.py +13 -7
  10. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/brew.py +26 -13
  11. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/bsdinit.py +7 -6
  12. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/cargo.py +4 -3
  13. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/choco.py +6 -4
  14. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/deb.py +12 -5
  15. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/dnf.py +9 -6
  16. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/docker.py +13 -6
  17. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/files.py +3 -3
  18. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/gem.py +5 -2
  19. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/git.py +14 -21
  20. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/gpg.py +2 -1
  21. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/hardware.py +17 -11
  22. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/launchd.py +5 -2
  23. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/lxd.py +6 -2
  24. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/mysql.py +7 -6
  25. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/npm.py +2 -1
  26. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/openrc.py +6 -2
  27. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/pacman.py +7 -3
  28. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/pkg.py +3 -1
  29. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/pkgin.py +5 -2
  30. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/postgres.py +3 -1
  31. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/rpm.py +12 -9
  32. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/runit.py +4 -2
  33. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/selinux.py +12 -4
  34. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/server.py +80 -51
  35. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/snap.py +6 -2
  36. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/systemd.py +10 -5
  37. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/sysvinit.py +2 -1
  38. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/upstart.py +5 -2
  39. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/vzctl.py +6 -4
  40. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/xbps.py +5 -2
  41. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/yum.py +8 -5
  42. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/zypper.py +7 -4
  43. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/apt.py +5 -0
  44. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/selinux.py +1 -1
  45. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/server.py +1 -1
  46. {pyinfra-3.0b4 → pyinfra-3.0.1/pyinfra.egg-info}/PKG-INFO +1 -5
  47. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra.egg-info/SOURCES.txt +1 -0
  48. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/__main__.py +2 -3
  49. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/inventory.py +13 -11
  50. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/main.py +10 -9
  51. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api_facts.py +2 -2
  52. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_cli/test_cli.py +0 -1
  53. pyinfra-3.0.1/tests/test_cli/test_cli_inventory.py +66 -0
  54. pyinfra-3.0b4/CHANGELOG.md +0 -29
  55. {pyinfra-3.0b4 → pyinfra-3.0.1}/LICENSE.md +0 -0
  56. {pyinfra-3.0b4 → pyinfra-3.0.1}/MANIFEST.in +0 -0
  57. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/__init__.py +0 -0
  58. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/__main__.py +0 -0
  59. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/__init__.py +0 -0
  60. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/arguments.py +0 -0
  61. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/arguments_typed.py +0 -0
  62. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/command.py +0 -0
  63. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/config.py +0 -0
  64. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/connect.py +0 -0
  65. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/connectors.py +0 -0
  66. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/deploy.py +0 -0
  67. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/exceptions.py +0 -0
  68. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/host.py +0 -0
  69. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/inventory.py +0 -0
  70. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/operation.py +0 -0
  71. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/operations.py +0 -0
  72. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/api/state.py +0 -0
  73. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/__init__.py +0 -0
  74. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/base.py +0 -0
  75. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/chroot.py +0 -0
  76. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/docker.py +0 -0
  77. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/dockerssh.py +0 -0
  78. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/local.py +0 -0
  79. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/ssh_util.py +0 -0
  80. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/sshuserclient/__init__.py +0 -0
  81. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/sshuserclient/config.py +0 -0
  82. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/terraform.py +0 -0
  83. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/util.py +0 -0
  84. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/connectors/vagrant.py +0 -0
  85. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/context.py +0 -0
  86. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/__init__.py +0 -0
  87. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/iptables.py +0 -0
  88. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/pip.py +0 -0
  89. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/postgresql.py +0 -0
  90. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/util/__init__.py +0 -0
  91. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/util/databases.py +0 -0
  92. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/util/packaging.py +0 -0
  93. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/facts/util/win_files.py +0 -0
  94. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/local.py +0 -0
  95. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/__init__.py +0 -0
  96. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/apk.py +0 -0
  97. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/brew.py +0 -0
  98. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/bsdinit.py +0 -0
  99. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/cargo.py +0 -0
  100. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/choco.py +0 -0
  101. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/dnf.py +0 -0
  102. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/docker.py +0 -0
  103. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/files.py +0 -0
  104. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/gem.py +0 -0
  105. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/git.py +0 -0
  106. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/iptables.py +0 -0
  107. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/launchd.py +0 -0
  108. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/lxd.py +0 -0
  109. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/mysql.py +0 -0
  110. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/npm.py +0 -0
  111. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/openrc.py +0 -0
  112. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/pacman.py +0 -0
  113. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/pip.py +0 -0
  114. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/pkg.py +0 -0
  115. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/pkgin.py +0 -0
  116. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/postgres.py +0 -0
  117. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/postgresql.py +0 -0
  118. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/puppet.py +0 -0
  119. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/python.py +0 -0
  120. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/runit.py +0 -0
  121. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/snap.py +0 -0
  122. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/ssh.py +0 -0
  123. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/systemd.py +0 -0
  124. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/sysvinit.py +0 -0
  125. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/upstart.py +0 -0
  126. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/util/__init__.py +0 -0
  127. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/util/docker.py +0 -0
  128. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/util/files.py +0 -0
  129. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/util/packaging.py +0 -0
  130. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/util/service.py +0 -0
  131. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/vzctl.py +0 -0
  132. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/xbps.py +0 -0
  133. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/yum.py +0 -0
  134. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/operations/zypper.py +0 -0
  135. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/progress.py +0 -0
  136. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/py.typed +0 -0
  137. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra/version.py +0 -0
  138. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra.egg-info/dependency_links.txt +0 -0
  139. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra.egg-info/entry_points.txt +0 -0
  140. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra.egg-info/requires.txt +0 -0
  141. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra.egg-info/top_level.txt +0 -0
  142. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/__init__.py +0 -0
  143. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/commands.py +0 -0
  144. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/exceptions.py +0 -0
  145. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/log.py +0 -0
  146. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/prints.py +0 -0
  147. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/util.py +0 -0
  148. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyinfra_cli/virtualenv.py +0 -0
  149. {pyinfra-3.0b4 → pyinfra-3.0.1}/pyproject.toml +0 -0
  150. {pyinfra-3.0b4 → pyinfra-3.0.1}/setup.cfg +0 -0
  151. {pyinfra-3.0b4 → pyinfra-3.0.1}/setup.py +0 -0
  152. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/__init__.py +0 -0
  153. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api.py +0 -0
  154. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api_arguments.py +0 -0
  155. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api_command.py +0 -0
  156. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api_config.py +0 -0
  157. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api_deploys.py +0 -0
  158. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api_host.py +0 -0
  159. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api_inventory.py +0 -0
  160. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api_operations.py +0 -0
  161. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_api/test_api_util.py +0 -0
  162. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_cli/__init__.py +0 -0
  163. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_cli/test_cli_deploy.py +0 -0
  164. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_cli/test_cli_exceptions.py +0 -0
  165. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_cli/test_cli_util.py +0 -0
  166. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_cli/test_context_objects.py +0 -0
  167. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_cli/util.py +0 -0
  168. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/__init__.py +0 -0
  169. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/test_chroot.py +0 -0
  170. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/test_docker.py +0 -0
  171. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/test_dockerssh.py +0 -0
  172. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/test_local.py +0 -0
  173. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/test_ssh.py +0 -0
  174. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/test_sshuserclient.py +0 -0
  175. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/test_terraform.py +0 -0
  176. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/test_util.py +0 -0
  177. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_connectors/test_vagrant.py +0 -0
  178. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_facts.py +0 -0
  179. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_global_arguments.py +0 -0
  180. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_operations.py +0 -0
  181. {pyinfra-3.0b4 → pyinfra-3.0.1}/tests/test_operations_utils.py +0 -0
@@ -0,0 +1,73 @@
1
+ # v3.0.1
2
+
3
+ - Switch to `command -v` not `which` in `server.Which` fact (@lemmi)
4
+ - Fix detection of xbps in `server.packages` operation (@romain-dartigues)
5
+ - Fix argument typo in operations doc (@scoufman)
6
+ - Add expanded note about detected changes + hidden side effects during execution
7
+ - Fix missing global arguments in group data files
8
+ - Fix `--group-data` CLI argument behaviour
9
+ - Remove unused/dead `--quiet` flag
10
+
11
+ # v3.0
12
+
13
+ Welcome to pyinfra v3! This version is the biggest overhaul of pyinfra since it was created back in 2015. Most v2 deployment code should be automatically compatible, but as always be aware. Major changes:
14
+
15
+ ### Runtime operation execution
16
+
17
+ pyinfra now executes operations at runtime, rather than pre-generating commands. Although the change isn't noticeable this fixes an entire class of bugs and confusion. See the [limitations](https://docs.pyinfra.com/en/2.x/deploy-process.html#limitations) section in the v2 docs. All of those issues are now a thing of the past.
18
+
19
+ This represents a huge overhaul of pyinfra's internals and should be a huge improvement for users.
20
+
21
+ Care has been taken to reduce the overhead of this change which still supports the same diffs and change proposal mechanism.
22
+
23
+ ### CLI flow & prompts
24
+
25
+ The pyinfra CLI will now prompt (instead of ignore, or immediately exit) when problems are encountered, allowing the user to choose to continue. Additionally an approval step is added before executing changes (this can be skipped with `-y` or setting the `PYINFRA_YES` environment variable).
26
+
27
+ ### Extendable connectors API, typing overhaul
28
+
29
+ v3 of pyinfra includes for the first time a (mostly) typed internal API with proper support for IDE linting. There's a whole new connectors API that provides a framework for building new connectors.
30
+
31
+ ### Breaking changes
32
+
33
+ - Rename `_use_sudo_password` argument to `_sudo_password`
34
+ - Remove `winrm` connector and `windows*` operations/facts, moving to [`pyinfra-windows`](https://github.com/pyinfra-dev/pyinfra-windows)
35
+ - The deploy decorator must now be called, ie used as `@deploy()`, and is now typed
36
+ - Remove broken Ansible inventory connector
37
+
38
+ ### Operations & Facts
39
+
40
+ - Add `docker.container`, `docker.image`, `docker.volume`, `docker.network` & `docker.prune` operations (@apecnascimento)
41
+ - Add `runit.service` operation and `RunitStatus` fact (@lemmi)
42
+ - Add `TmpDir` fact
43
+ - Add `services` argument to systemd facts for filtering
44
+ - Add type hints for all the operations (@stone-w4tch3r)
45
+ - Lowercase pip packages properly (PEP-0426)
46
+ - Rename `postgresql` -> `postgres` operations & facts (old ones still work)
47
+ - Improve IP/MAC parsing in `NetworkDevices` fact (@sudoBash418)
48
+ - Enable getting `Home` fact for other users (@matthijskooijman)
49
+ - Use users correct home directory in `server.user_authorized_keys` operation (@matthijskooijman)
50
+ - Fix `destination`/`not_destination` arguments in `iptables.rule` operation
51
+ - Fix remote dirs when executing from Windows in `files.sync` operation (@Renerick)
52
+ - Fix quoting of systemd unit names (@martenlienen)
53
+
54
+ ### Other Changes
55
+
56
+ - Add new `_if` global argument to control operation execution at runtime
57
+ - Add `--debug-all` flag to set debug logging for all packages
58
+ - Retry SSH connections on failure (configurable, see [SSH connector](https://docs.pyinfra.com/en/3.x/connectors/ssh.html#available-data)) (@fwiesel)
59
+ - Documentation typo fixes (@szepeviktor, @sudoBash418)
60
+ - Fix handling of binary files in Docker connector (@matthijskooijman)
61
+ - Add `will_change` attribute and `did_change` context manager to `OperationMeta`
62
+ - Replace use of `pkg_resources` with `importlib.metadata` (@diazona)
63
+ - Fix identifying Python inventory files as modules (@martenlienen)
64
+ - Fix typed arguments order (@cdleonard)
65
+ - Check that fact commands don't take global arguments (@martenlienen)
66
+
67
+ # v2.x
68
+
69
+ [See this file in the `2.x` branch](https://github.com/Fizzadar/pyinfra/blob/2.x/CHANGELOG.md).
70
+
71
+ # v1.x
72
+
73
+ [See this file in the `1.x` branch](https://github.com/Fizzadar/pyinfra/blob/1.x/CHANGELOG.md).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyinfra
3
- Version: 3.0b4
3
+ Version: 3.0.1
4
4
  Summary: pyinfra automates/provisions/manages/deploys infrastructure.
5
5
  Home-page: https://pyinfra.com
6
6
  Author: Nick / Fizzadar
@@ -92,10 +92,6 @@ Requires-Dist: redbaron; extra == "dev"
92
92
  </a>
93
93
  </p>
94
94
 
95
- <p>
96
- <strong>Note: this is the v3 branch, which is currently in beta. <a href="https://docs.pyinfra.com/en/next">See the docs for v3</a>. If needed the <a href="https://github.com/pyinfra-dev/pyinfra/tree/2.x/">2.x branch is here</a>, but is in bugfix only mode.</strong>
97
- </p>
98
-
99
95
  <p>
100
96
  pyinfra turns Python code into shell commands and runs them on your servers. Execute ad-hoc commands and write declarative operations. Target SSH servers, local machine and Docker containers. Fast and scales from one server to thousands. Think <code>ansible</code> but Python instead of YAML, and a lot faster.
101
97
  </p>
@@ -4,10 +4,6 @@
4
4
  </a>
5
5
  </p>
6
6
 
7
- <p>
8
- <strong>Note: this is the v3 branch, which is currently in beta. <a href="https://docs.pyinfra.com/en/next">See the docs for v3</a>. If needed the <a href="https://github.com/pyinfra-dev/pyinfra/tree/2.x/">2.x branch is here</a>, but is in bugfix only mode.</strong>
9
- </p>
10
-
11
7
  <p>
12
8
  pyinfra turns Python code into shell commands and runs them on your servers. Execute ad-hoc commands and write declarative operations. Target SSH servers, local machine and Docker containers. Fast and scales from one server to thousands. Think <code>ansible</code> but Python instead of YAML, and a lot faster.
13
9
  </p>
@@ -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",
@@ -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(
@@ -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,
@@ -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
 
@@ -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"
@@ -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
 
@@ -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
@@ -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)
@@ -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", "")
@@ -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(
@@ -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
 
@@ -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):
@@ -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(
@@ -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
 
@@ -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
@@ -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"