pyinfra 2.9.2__tar.gz → 3.0__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 (215) hide show
  1. pyinfra-3.0/CHANGELOG.md +63 -0
  2. {pyinfra-2.9.2/pyinfra.egg-info → pyinfra-3.0}/PKG-INFO +72 -15
  3. {pyinfra-2.9.2 → pyinfra-3.0}/README.md +12 -10
  4. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/__init__.py +3 -0
  5. pyinfra-3.0/pyinfra/api/arguments.py +345 -0
  6. pyinfra-3.0/pyinfra/api/arguments_typed.py +80 -0
  7. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/command.py +68 -53
  8. pyinfra-3.0/pyinfra/api/config.py +231 -0
  9. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/connect.py +1 -1
  10. pyinfra-3.0/pyinfra/api/connectors.py +27 -0
  11. pyinfra-3.0/pyinfra/api/deploy.py +87 -0
  12. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/exceptions.py +33 -8
  13. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/facts.py +102 -137
  14. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/host.py +150 -82
  15. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/inventory.py +21 -25
  16. pyinfra-3.0/pyinfra/api/operation.py +438 -0
  17. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/operations.py +102 -148
  18. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/state.py +137 -79
  19. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/util.py +79 -86
  20. pyinfra-3.0/pyinfra/connectors/base.py +147 -0
  21. pyinfra-3.0/pyinfra/connectors/chroot.py +203 -0
  22. pyinfra-3.0/pyinfra/connectors/docker.py +288 -0
  23. pyinfra-3.0/pyinfra/connectors/dockerssh.py +291 -0
  24. pyinfra-3.0/pyinfra/connectors/local.py +232 -0
  25. pyinfra-3.0/pyinfra/connectors/ssh.py +628 -0
  26. pyinfra-3.0/pyinfra/connectors/ssh_util.py +114 -0
  27. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/sshuserclient/client.py +5 -3
  28. pyinfra-3.0/pyinfra/connectors/terraform.py +122 -0
  29. pyinfra-3.0/pyinfra/connectors/util.py +402 -0
  30. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/vagrant.py +60 -53
  31. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/context.py +4 -2
  32. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/apk.py +2 -0
  33. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/apt.py +2 -0
  34. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/brew.py +2 -0
  35. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/bsdinit.py +2 -0
  36. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/cargo.py +2 -0
  37. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/choco.py +2 -0
  38. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/deb.py +7 -2
  39. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/dnf.py +2 -0
  40. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/docker.py +19 -0
  41. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/files.py +47 -32
  42. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/gem.py +2 -0
  43. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/git.py +3 -1
  44. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/gpg.py +3 -1
  45. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/hardware.py +34 -24
  46. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/iptables.py +5 -3
  47. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/launchd.py +2 -0
  48. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/lxd.py +2 -0
  49. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/mysql.py +13 -6
  50. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/npm.py +1 -0
  51. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/openrc.py +2 -0
  52. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/pacman.py +6 -2
  53. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/pip.py +2 -0
  54. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/pkg.py +2 -0
  55. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/pkgin.py +2 -0
  56. pyinfra-2.9.2/pyinfra/facts/postgresql.py → pyinfra-3.0/pyinfra/facts/postgres.py +13 -10
  57. pyinfra-3.0/pyinfra/facts/postgresql.py +11 -0
  58. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/rpm.py +12 -9
  59. pyinfra-3.0/pyinfra/facts/runit.py +68 -0
  60. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/selinux.py +3 -1
  61. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/server.py +80 -36
  62. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/snap.py +2 -0
  63. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/systemd.py +31 -12
  64. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/sysvinit.py +10 -10
  65. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/upstart.py +2 -0
  66. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/util/packaging.py +7 -4
  67. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/vzctl.py +2 -0
  68. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/xbps.py +2 -0
  69. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/yum.py +2 -0
  70. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/zypper.py +2 -0
  71. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/local.py +4 -5
  72. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/apk.py +6 -4
  73. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/apt.py +46 -65
  74. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/brew.py +17 -22
  75. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/bsdinit.py +9 -7
  76. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/cargo.py +4 -2
  77. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/choco.py +4 -2
  78. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/dnf.py +19 -23
  79. pyinfra-3.0/pyinfra/operations/docker.py +339 -0
  80. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/files.py +188 -386
  81. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/gem.py +4 -2
  82. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/git.py +24 -53
  83. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/iptables.py +29 -35
  84. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/launchd.py +6 -7
  85. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/lxd.py +8 -13
  86. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/mysql.py +62 -81
  87. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/npm.py +9 -2
  88. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/openrc.py +6 -4
  89. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/pacman.py +7 -8
  90. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/pip.py +25 -24
  91. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/pkg.py +4 -2
  92. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/pkgin.py +6 -4
  93. pyinfra-2.9.2/pyinfra/operations/postgresql.py → pyinfra-3.0/pyinfra/operations/postgres.py +47 -89
  94. pyinfra-3.0/pyinfra/operations/postgresql.py +30 -0
  95. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/puppet.py +3 -1
  96. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/python.py +8 -19
  97. pyinfra-3.0/pyinfra/operations/runit.py +182 -0
  98. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/selinux.py +47 -44
  99. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/server.py +111 -127
  100. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/snap.py +4 -4
  101. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/ssh.py +20 -33
  102. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/systemd.py +19 -15
  103. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/sysvinit.py +9 -16
  104. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/upstart.py +9 -7
  105. pyinfra-3.0/pyinfra/operations/util/__init__.py +12 -0
  106. pyinfra-3.0/pyinfra/operations/util/docker.py +177 -0
  107. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/util/files.py +24 -16
  108. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/util/packaging.py +55 -57
  109. pyinfra-3.0/pyinfra/operations/util/service.py +46 -0
  110. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/vzctl.py +12 -10
  111. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/xbps.py +6 -4
  112. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/yum.py +18 -22
  113. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/zypper.py +12 -13
  114. pyinfra-3.0/pyinfra/version.py +9 -0
  115. {pyinfra-2.9.2 → pyinfra-3.0/pyinfra.egg-info}/PKG-INFO +72 -15
  116. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra.egg-info/SOURCES.txt +10 -16
  117. pyinfra-3.0/pyinfra.egg-info/entry_points.txt +11 -0
  118. pyinfra-3.0/pyinfra.egg-info/requires.txt +67 -0
  119. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/__main__.py +4 -3
  120. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/commands.py +7 -2
  121. pyinfra-3.0/pyinfra_cli/exceptions.py +163 -0
  122. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/inventory.py +40 -6
  123. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/log.py +17 -3
  124. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/main.py +133 -90
  125. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/prints.py +95 -127
  126. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/util.py +62 -29
  127. pyinfra-3.0/pyproject.toml +19 -0
  128. {pyinfra-2.9.2 → pyinfra-3.0}/setup.cfg +1 -1
  129. {pyinfra-2.9.2 → pyinfra-3.0}/setup.py +28 -29
  130. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api.py +2 -0
  131. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_arguments.py +13 -13
  132. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_deploys.py +28 -29
  133. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_facts.py +60 -98
  134. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_operations.py +101 -201
  135. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/test_cli.py +18 -49
  136. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/test_cli_deploy.py +11 -37
  137. pyinfra-3.0/tests/test_cli/test_cli_exceptions.py +86 -0
  138. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/util.py +1 -1
  139. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_chroot.py +6 -6
  140. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_docker.py +4 -4
  141. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_dockerssh.py +38 -50
  142. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_local.py +11 -12
  143. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_ssh.py +105 -93
  144. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_terraform.py +9 -15
  145. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_util.py +24 -46
  146. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_vagrant.py +7 -7
  147. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_global_arguments.py +2 -2
  148. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_operations.py +7 -51
  149. pyinfra-2.9.2/CHANGELOG.md +0 -322
  150. pyinfra-2.9.2/pyinfra/api/arguments.py +0 -333
  151. pyinfra-2.9.2/pyinfra/api/config.py +0 -124
  152. pyinfra-2.9.2/pyinfra/api/connectors.py +0 -46
  153. pyinfra-2.9.2/pyinfra/api/deploy.py +0 -118
  154. pyinfra-2.9.2/pyinfra/api/operation.py +0 -396
  155. pyinfra-2.9.2/pyinfra/api/operation.pyi +0 -117
  156. pyinfra-2.9.2/pyinfra/connectors/ansible.py +0 -171
  157. pyinfra-2.9.2/pyinfra/connectors/chroot.py +0 -212
  158. pyinfra-2.9.2/pyinfra/connectors/docker.py +0 -305
  159. pyinfra-2.9.2/pyinfra/connectors/dockerssh.py +0 -313
  160. pyinfra-2.9.2/pyinfra/connectors/local.py +0 -244
  161. pyinfra-2.9.2/pyinfra/connectors/mech.py +0 -186
  162. pyinfra-2.9.2/pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
  163. pyinfra-2.9.2/pyinfra/connectors/ssh.py +0 -711
  164. pyinfra-2.9.2/pyinfra/connectors/terraform.py +0 -101
  165. pyinfra-2.9.2/pyinfra/connectors/util.py +0 -328
  166. pyinfra-2.9.2/pyinfra/connectors/winrm.py +0 -320
  167. pyinfra-2.9.2/pyinfra/facts/windows.py +0 -366
  168. pyinfra-2.9.2/pyinfra/facts/windows_files.py +0 -90
  169. pyinfra-2.9.2/pyinfra/operations/util/service.py +0 -58
  170. pyinfra-2.9.2/pyinfra/operations/windows.py +0 -59
  171. pyinfra-2.9.2/pyinfra/operations/windows_files.py +0 -551
  172. pyinfra-2.9.2/pyinfra/version.py +0 -6
  173. pyinfra-2.9.2/pyinfra.egg-info/entry_points.txt +0 -14
  174. pyinfra-2.9.2/pyinfra.egg-info/requires.txt +0 -76
  175. pyinfra-2.9.2/pyinfra_cli/exceptions.py +0 -127
  176. pyinfra-2.9.2/pyproject.toml +0 -22
  177. pyinfra-2.9.2/tests/__init__.py +0 -12
  178. pyinfra-2.9.2/tests/paramiko_util.py +0 -103
  179. pyinfra-2.9.2/tests/test_cli/test_cli_exceptions.py +0 -55
  180. pyinfra-2.9.2/tests/test_connectors/__init__.py +0 -0
  181. pyinfra-2.9.2/tests/test_connectors/test_ansible.py +0 -64
  182. pyinfra-2.9.2/tests/test_connectors/test_mech.py +0 -126
  183. pyinfra-2.9.2/tests/test_connectors/test_winrm.py +0 -76
  184. pyinfra-2.9.2/tests/util.py +0 -430
  185. {pyinfra-2.9.2 → pyinfra-3.0}/LICENSE.md +0 -0
  186. {pyinfra-2.9.2 → pyinfra-3.0}/MANIFEST.in +0 -0
  187. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/__init__.py +0 -0
  188. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/__main__.py +0 -0
  189. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/__init__.py +0 -0
  190. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/sshuserclient/__init__.py +0 -0
  191. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/sshuserclient/config.py +0 -0
  192. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/__init__.py +0 -0
  193. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/util/__init__.py +0 -0
  194. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/util/databases.py +0 -0
  195. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/util/win_files.py +0 -0
  196. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/__init__.py +0 -0
  197. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/progress.py +0 -0
  198. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/py.typed +0 -0
  199. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra.egg-info/dependency_links.txt +0 -0
  200. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra.egg-info/top_level.txt +0 -0
  201. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/__init__.py +0 -0
  202. {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/virtualenv.py +0 -0
  203. {pyinfra-2.9.2/pyinfra/operations/util → pyinfra-3.0/tests/test_api}/__init__.py +0 -0
  204. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_command.py +0 -0
  205. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_config.py +0 -0
  206. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_host.py +0 -0
  207. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_inventory.py +0 -0
  208. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_util.py +0 -0
  209. {pyinfra-2.9.2/tests/test_api → pyinfra-3.0/tests/test_cli}/__init__.py +0 -0
  210. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/test_cli_util.py +0 -0
  211. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/test_context_objects.py +0 -0
  212. {pyinfra-2.9.2/tests/test_cli → pyinfra-3.0/tests/test_connectors}/__init__.py +0 -0
  213. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_sshuserclient.py +0 -0
  214. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_facts.py +0 -0
  215. {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_operations_utils.py +0 -0
@@ -0,0 +1,63 @@
1
+ # v3.0
2
+
3
+ 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:
4
+
5
+ ### Runtime operation execution
6
+
7
+ 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.
8
+
9
+ This represents a huge overhaul of pyinfra's internals and should be a huge improvement for users.
10
+
11
+ Care has been taken to reduce the overhead of this change which still supports the same diffs and change proposal mechanism.
12
+
13
+ ### CLI flow & prompts
14
+
15
+ 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).
16
+
17
+ ### Extendable connectors API, typing overhaul
18
+
19
+ 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.
20
+
21
+ ### Breaking changes
22
+
23
+ - Rename `_use_sudo_password` argument to `_sudo_password`
24
+ - Remove `winrm` connector and `windows*` operations/facts, moving to [`pyinfra-windows`](https://github.com/pyinfra-dev/pyinfra-windows)
25
+ - The deploy decorator must now be called, ie used as `@deploy()`, and is now typed
26
+ - Remove broken Ansible inventory connector
27
+
28
+ ### Operations & Facts
29
+
30
+ - Add `docker.container`, `docker.image`, `docker.volume`, `docker.network` & `docker.prune` operations (@apecnascimento)
31
+ - Add `runit.service` operation and `RunitStatus` fact (@lemmi)
32
+ - Add `TmpDir` fact
33
+ - Add `services` argument to systemd facts for filtering
34
+ - Add type hints for all the operations (@stone-w4tch3r)
35
+ - Lowercase pip packages properly (PEP-0426)
36
+ - Rename `postgresql` -> `postgres` operations & facts (old ones still work)
37
+ - Improve IP/MAC parsing in `NetworkDevices` fact (@sudoBash418)
38
+ - Enable getting `Home` fact for other users (@matthijskooijman)
39
+ - Use users correct home directory in `server.user_authorized_keys` operation (@matthijskooijman)
40
+ - Fix `destination`/`not_destination` arguments in `iptables.rule` operation
41
+ - Fix remote dirs when executing from Windows in `files.sync` operation (@Renerick)
42
+ - Fix quoting of systemd unit names (@martenlienen)
43
+
44
+ ### Other Changes
45
+
46
+ - Add new `_if` global argument to control operation execution at runtime
47
+ - Add `--debug-all` flag to set debug logging for all packages
48
+ - Retry SSH connections on failure (configurable, see [SSH connector](https://docs.pyinfra.com/en/3.x/connectors/ssh.html#available-data)) (@fwiesel)
49
+ - Documentation typo fixes (@szepeviktor, @sudoBash418)
50
+ - Fix handling of binary files in Docker connector (@matthijskooijman)
51
+ - Add `will_change` attribute and `did_change` context manager to `OperationMeta`
52
+ - Replace use of `pkg_resources` with `importlib.metadata` (@diazona)
53
+ - Fix identifying Python inventory files as modules (@martenlienen)
54
+ - Fix typed arguments order (@cdleonard)
55
+ - Check that fact commands don't take global arguments (@martenlienen)
56
+
57
+ # v2.x
58
+
59
+ [See this file in the `2.x` branch](https://github.com/Fizzadar/pyinfra/blob/2.x/CHANGELOG.md).
60
+
61
+ # v1.x
62
+
63
+ [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: 2.9.2
3
+ Version: 3.0
4
4
  Summary: pyinfra automates/provisions/manages/deploys infrastructure.
5
5
  Home-page: https://pyinfra.com
6
6
  Author: Nick / Fizzadar
@@ -16,20 +16,75 @@ Classifier: Intended Audience :: Information Technology
16
16
  Classifier: License :: OSI Approved :: MIT License
17
17
  Classifier: Operating System :: OS Independent
18
18
  Classifier: Programming Language :: Python :: 3
19
- Classifier: Programming Language :: Python :: 3.6
20
- Classifier: Programming Language :: Python :: 3.7
21
19
  Classifier: Programming Language :: Python :: 3.8
22
20
  Classifier: Programming Language :: Python :: 3.9
23
21
  Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
24
  Classifier: Topic :: System :: Systems Administration
25
25
  Classifier: Topic :: System :: Installation/Setup
26
26
  Classifier: Topic :: Utilities
27
+ Requires-Python: >=3.8
27
28
  Description-Content-Type: text/markdown
29
+ License-File: LICENSE.md
30
+ Requires-Dist: gevent>=1.5
31
+ Requires-Dist: paramiko<4,>=2.7
32
+ Requires-Dist: click>2
33
+ Requires-Dist: jinja2<4,>2
34
+ Requires-Dist: python-dateutil<3,>2
35
+ Requires-Dist: setuptools
36
+ Requires-Dist: configparser
37
+ Requires-Dist: pywinrm
38
+ Requires-Dist: typeguard
39
+ Requires-Dist: distro<2,>=1.6
40
+ Requires-Dist: packaging>=16.1
41
+ Requires-Dist: graphlib_backport; python_version < "3.9"
42
+ Requires-Dist: typing-extensions; python_version < "3.11"
43
+ Requires-Dist: importlib_metadata>=3.6; python_version < "3.10"
28
44
  Provides-Extra: test
45
+ Requires-Dist: pytest==8.2.1; extra == "test"
46
+ Requires-Dist: coverage==7.5.1; extra == "test"
47
+ Requires-Dist: pytest-cov==5.0.0; extra == "test"
48
+ Requires-Dist: black==24.4.2; extra == "test"
49
+ Requires-Dist: isort==5.13.2; extra == "test"
50
+ Requires-Dist: flake8==7.0.0; extra == "test"
51
+ Requires-Dist: flake8-black==0.3.6; extra == "test"
52
+ Requires-Dist: flake8-isort==6.1.1; extra == "test"
53
+ Requires-Dist: mypy; extra == "test"
54
+ Requires-Dist: types-cryptography; extra == "test"
55
+ Requires-Dist: types-paramiko; extra == "test"
56
+ Requires-Dist: types-python-dateutil; extra == "test"
57
+ Requires-Dist: types-PyYAML; extra == "test"
58
+ Requires-Dist: types-setuptools; extra == "test"
29
59
  Provides-Extra: docs
60
+ Requires-Dist: pyinfra-guzzle_sphinx_theme==0.16; extra == "docs"
61
+ Requires-Dist: myst-parser==2.0.0; extra == "docs"
62
+ Requires-Dist: sphinx==6.2.1; extra == "docs"
30
63
  Provides-Extra: dev
31
- Provides-Extra: ansible
32
- License-File: LICENSE.md
64
+ Requires-Dist: pytest==8.2.1; extra == "dev"
65
+ Requires-Dist: coverage==7.5.1; extra == "dev"
66
+ Requires-Dist: pytest-cov==5.0.0; extra == "dev"
67
+ Requires-Dist: black==24.4.2; extra == "dev"
68
+ Requires-Dist: isort==5.13.2; extra == "dev"
69
+ Requires-Dist: flake8==7.0.0; extra == "dev"
70
+ Requires-Dist: flake8-black==0.3.6; extra == "dev"
71
+ Requires-Dist: flake8-isort==6.1.1; extra == "dev"
72
+ Requires-Dist: mypy; extra == "dev"
73
+ Requires-Dist: types-cryptography; extra == "dev"
74
+ Requires-Dist: types-paramiko; extra == "dev"
75
+ Requires-Dist: types-python-dateutil; extra == "dev"
76
+ Requires-Dist: types-PyYAML; extra == "dev"
77
+ Requires-Dist: types-setuptools; extra == "dev"
78
+ Requires-Dist: pyinfra-guzzle_sphinx_theme==0.16; extra == "dev"
79
+ Requires-Dist: myst-parser==2.0.0; extra == "dev"
80
+ Requires-Dist: sphinx==6.2.1; extra == "dev"
81
+ Requires-Dist: wheel; extra == "dev"
82
+ Requires-Dist: twine; extra == "dev"
83
+ Requires-Dist: ipython; extra == "dev"
84
+ Requires-Dist: ipdb; extra == "dev"
85
+ Requires-Dist: ipdbplugin; extra == "dev"
86
+ Requires-Dist: flake8-spellcheck==0.12.1; extra == "dev"
87
+ Requires-Dist: redbaron; extra == "dev"
33
88
 
34
89
  <p align="center">
35
90
  <a href="https://pyinfra.com">
@@ -37,25 +92,27 @@ License-File: LICENSE.md
37
92
  </a>
38
93
  </p>
39
94
 
40
- <p align="center">
41
- <em>pyinfra automates infrastructure using Python. It’s fast and scales from one server to thousands. Great for ad-hoc command execution, service deployment, configuration management and more.</em>
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
+ <p>
100
+ 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.
42
101
  </p>
43
102
 
44
103
  ---
45
104
 
46
- <p align="center">
47
- <a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> &rArr;
105
+ <h3>
48
106
  <a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> &bull;
49
- <a href="https://docs.pyinfra.com/page/examples.html"><strong>Examples</strong></a> &bull;
107
+ <a href="https://github.com/pyinfra-dev/pyinfra-examples"><strong>Examples Repo</strong></a> &bull;
108
+ <a href="https://matrix.to/#/#pyinfra:matrix.org"><strong>Chat on Matrix</strong></a>
109
+ </h3>
110
+ <p>
111
+ <a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> &bull;
50
112
  <a href="https://docs.pyinfra.com/page/support.html"><strong>Help & Support</strong></a> &bull;
51
113
  <a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
52
114
  </p>
53
115
 
54
- <p align="center">
55
- Chat &rArr;
56
- <a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
57
- </p>
58
-
59
116
  ---
60
117
 
61
118
  Why pyinfra? Design features include:
@@ -4,25 +4,27 @@
4
4
  </a>
5
5
  </p>
6
6
 
7
- <p align="center">
8
- <em>pyinfra automates infrastructure using Python. It’s fast and scales from one server to thousands. Great for ad-hoc command execution, service deployment, configuration management and more.</em>
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
+ <p>
12
+ 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.
9
13
  </p>
10
14
 
11
15
  ---
12
16
 
13
- <p align="center">
14
- <a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> &rArr;
17
+ <h3>
15
18
  <a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> &bull;
16
- <a href="https://docs.pyinfra.com/page/examples.html"><strong>Examples</strong></a> &bull;
19
+ <a href="https://github.com/pyinfra-dev/pyinfra-examples"><strong>Examples Repo</strong></a> &bull;
20
+ <a href="https://matrix.to/#/#pyinfra:matrix.org"><strong>Chat on Matrix</strong></a>
21
+ </h3>
22
+ <p>
23
+ <a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> &bull;
17
24
  <a href="https://docs.pyinfra.com/page/support.html"><strong>Help & Support</strong></a> &bull;
18
25
  <a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
19
26
  </p>
20
27
 
21
- <p align="center">
22
- Chat &rArr;
23
- <a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
24
- </p>
25
-
26
28
  ---
27
29
 
28
30
  Why pyinfra? Design features include:
@@ -11,6 +11,9 @@ from .config import Config # noqa: F401 # pragma: no cover
11
11
  from .deploy import deploy # noqa: F401 # pragma: no cover
12
12
  from .exceptions import DeployError # noqa: F401 # pragma: no cover
13
13
  from .exceptions import ( # noqa: F401
14
+ FactError,
15
+ FactTypeError,
16
+ FactValueError,
14
17
  InventoryError,
15
18
  OperationError,
16
19
  OperationTypeError,
@@ -0,0 +1,345 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import (
4
+ TYPE_CHECKING,
5
+ Any,
6
+ Callable,
7
+ Generic,
8
+ Iterable,
9
+ List,
10
+ Mapping,
11
+ Optional,
12
+ Type,
13
+ TypeVar,
14
+ Union,
15
+ cast,
16
+ get_type_hints,
17
+ )
18
+
19
+ from typing_extensions import TypedDict
20
+
21
+ from pyinfra import context
22
+ from pyinfra.api.exceptions import ArgumentTypeError
23
+ from pyinfra.api.state import State
24
+ from pyinfra.api.util import raise_if_bad_type
25
+
26
+ if TYPE_CHECKING:
27
+ from pyinfra.api.config import Config
28
+ from pyinfra.api.host import Host
29
+
30
+ T = TypeVar("T")
31
+ default_sentinel = object()
32
+
33
+
34
+ class ArgumentMeta(Generic[T]):
35
+ description: str
36
+ default: Callable[["Config"], T]
37
+ handler: Optional[Callable[["Config", T], T]]
38
+
39
+ def __init__(self, description, default, handler=None) -> None:
40
+ self.description = description
41
+ self.default = default
42
+ self.handler = handler
43
+
44
+
45
+ # Connector arguments
46
+ # These are arguments passed to the various connectors that provide the underlying
47
+ # API to read/write external systems.
48
+
49
+
50
+ # Note: ConnectorArguments is specifically not total as it's used to type many
51
+ # functions via Unpack and we don't want to specify every kwarg.
52
+ class ConnectorArguments(TypedDict, total=False):
53
+ # Auth arguments
54
+ _sudo: bool
55
+ _sudo_user: str
56
+ _use_sudo_login: bool
57
+ _sudo_password: str
58
+ _preserve_sudo_env: bool
59
+ _su_user: str
60
+ _use_su_login: bool
61
+ _preserve_su_env: bool
62
+ _su_shell: str
63
+ _doas: bool
64
+ _doas_user: str
65
+
66
+ # Shell arguments
67
+ _shell_executable: str
68
+ _chdir: str
69
+ _env: Mapping[str, str]
70
+
71
+ # Connector control (outside of command generation)
72
+ _success_exit_codes: Iterable[int]
73
+ _timeout: int
74
+ _get_pty: bool
75
+ _stdin: Union[str, Iterable[str]]
76
+
77
+
78
+ def generate_env(config: "Config", value: dict) -> dict:
79
+ env = config.ENV.copy()
80
+ env.update(value)
81
+ return env
82
+
83
+
84
+ auth_argument_meta: dict[str, ArgumentMeta] = {
85
+ "_sudo": ArgumentMeta(
86
+ "Execute/apply any changes with sudo.",
87
+ default=lambda config: config.SUDO,
88
+ ),
89
+ "_sudo_user": ArgumentMeta(
90
+ "Execute/apply any changes with sudo as a non-root user.",
91
+ default=lambda config: config.SUDO_USER,
92
+ ),
93
+ "_use_sudo_login": ArgumentMeta(
94
+ "Execute sudo with a login shell.",
95
+ default=lambda config: config.USE_SUDO_LOGIN,
96
+ ),
97
+ "_sudo_password": ArgumentMeta(
98
+ "Password to sudo with. If needed and not specified pyinfra will prompt for it.",
99
+ default=lambda config: config.SUDO_PASSWORD,
100
+ ),
101
+ "_preserve_sudo_env": ArgumentMeta(
102
+ "Preserve the shell environment of the connecting user when using sudo.",
103
+ default=lambda config: config.PRESERVE_SUDO_ENV,
104
+ ),
105
+ "_su_user": ArgumentMeta(
106
+ "Execute/apply any changes with this user using su.",
107
+ default=lambda config: config.SU_USER,
108
+ ),
109
+ "_use_su_login": ArgumentMeta(
110
+ "Execute su with a login shell.",
111
+ default=lambda config: config.USE_SU_LOGIN,
112
+ ),
113
+ "_preserve_su_env": ArgumentMeta(
114
+ "Preserve the shell environment of the connecting user when using su.",
115
+ default=lambda config: config.PRESERVE_SU_ENV,
116
+ ),
117
+ "_su_shell": ArgumentMeta(
118
+ "Use this shell (instead of user login shell) when using ``_su``). "
119
+ + "Only available under Linux, for use when using `su` with a user that "
120
+ + "has nologin/similar as their login shell.",
121
+ default=lambda config: config.SU_SHELL,
122
+ ),
123
+ "_doas": ArgumentMeta(
124
+ "Execute/apply any changes with doas.",
125
+ default=lambda config: config.DOAS,
126
+ ),
127
+ "_doas_user": ArgumentMeta(
128
+ "Execute/apply any changes with doas as a non-root user.",
129
+ default=lambda config: config.DOAS_USER,
130
+ ),
131
+ }
132
+
133
+ shell_argument_meta: dict[str, ArgumentMeta] = {
134
+ "_shell_executable": ArgumentMeta(
135
+ "The shell executable to use for executing commands.",
136
+ default=lambda config: config.SHELL,
137
+ ),
138
+ "_chdir": ArgumentMeta(
139
+ "Directory to switch to before executing the command.",
140
+ default=lambda _: "",
141
+ ),
142
+ "_env": ArgumentMeta(
143
+ "Dictionary of environment variables to set.",
144
+ default=lambda _: {},
145
+ handler=generate_env,
146
+ ),
147
+ "_success_exit_codes": ArgumentMeta(
148
+ "List of exit codes to consider a success.",
149
+ default=lambda _: [0],
150
+ ),
151
+ "_timeout": ArgumentMeta(
152
+ "Timeout for *each* command executed during the operation.",
153
+ default=lambda _: None,
154
+ ),
155
+ "_get_pty": ArgumentMeta(
156
+ "Whether to get a pseudoTTY when executing any commands.",
157
+ default=lambda _: False,
158
+ ),
159
+ "_stdin": ArgumentMeta(
160
+ "String or buffer to send to the stdin of any commands.",
161
+ default=lambda _: None,
162
+ ),
163
+ }
164
+
165
+
166
+ # Meta arguments
167
+ # These provide/extend additional operation metadata
168
+
169
+
170
+ class MetaArguments(TypedDict):
171
+ name: str
172
+ _ignore_errors: bool
173
+ _continue_on_error: bool
174
+ _if: Union[List[Callable[[], bool]], Callable[[], bool], None]
175
+
176
+
177
+ meta_argument_meta: dict[str, ArgumentMeta] = {
178
+ # NOTE: name is the only non-_-prefixed argument
179
+ "name": ArgumentMeta(
180
+ "Name of the operation.",
181
+ default=lambda _: None,
182
+ ),
183
+ "_ignore_errors": ArgumentMeta(
184
+ "Ignore errors when executing the operation.",
185
+ default=lambda config: config.IGNORE_ERRORS,
186
+ ),
187
+ "_continue_on_error": ArgumentMeta(
188
+ (
189
+ "Continue executing operation commands after error. "
190
+ "Only applies when ``_ignore_errors`` is true."
191
+ ),
192
+ default=lambda _: False,
193
+ ),
194
+ "_if": ArgumentMeta(
195
+ "Only run this operation if these functions return True",
196
+ default=lambda _: [],
197
+ ),
198
+ }
199
+
200
+
201
+ # Execution arguments
202
+ # These alter how pyinfra is to execute an operation. Notably these must all have the same value
203
+ # over every target host for the same operation.
204
+
205
+
206
+ class ExecutionArguments(TypedDict):
207
+ _parallel: int
208
+ _run_once: bool
209
+ _serial: bool
210
+
211
+
212
+ execution_argument_meta: dict[str, ArgumentMeta] = {
213
+ "_parallel": ArgumentMeta(
214
+ "Run this operation in batches of hosts.",
215
+ default=lambda config: config.PARALLEL,
216
+ ),
217
+ "_run_once": ArgumentMeta(
218
+ "Only execute this operation once, on the first host to see it.",
219
+ default=lambda _: False,
220
+ ),
221
+ "_serial": ArgumentMeta(
222
+ "Run this operation host by host, rather than in parallel.",
223
+ default=lambda _: False,
224
+ ),
225
+ }
226
+
227
+
228
+ class AllArguments(ConnectorArguments, MetaArguments, ExecutionArguments):
229
+ pass
230
+
231
+
232
+ def all_global_arguments() -> List[tuple[str, Type]]:
233
+ """Return all global arguments and their types."""
234
+ return list(get_type_hints(AllArguments).items())
235
+
236
+
237
+ all_argument_meta: dict[str, ArgumentMeta] = {
238
+ **auth_argument_meta,
239
+ **shell_argument_meta,
240
+ **meta_argument_meta,
241
+ **execution_argument_meta,
242
+ }
243
+
244
+ EXECUTION_KWARG_KEYS = list(ExecutionArguments.__annotations__.keys())
245
+ CONNECTOR_ARGUMENT_KEYS = list(ConnectorArguments.__annotations__.keys())
246
+
247
+ __argument_docs__ = {
248
+ "Privilege & user escalation": (
249
+ auth_argument_meta,
250
+ """
251
+ .. code:: python
252
+
253
+ # Execute a command with sudo
254
+ server.user(
255
+ name="Create pyinfra user using sudo",
256
+ user="pyinfra",
257
+ _sudo=True,
258
+ )
259
+
260
+ # Execute a command with a specific sudo password
261
+ server.user(
262
+ name="Create pyinfra user using sudo",
263
+ user="pyinfra",
264
+ _sudo=True,
265
+ _sudo_password="my-secret-password",
266
+ )
267
+ """,
268
+ ),
269
+ "Shell control & features": (
270
+ shell_argument_meta,
271
+ """
272
+ .. code:: python
273
+
274
+ # Execute from a specific directory
275
+ server.shell(
276
+ name="Bootstrap nginx params",
277
+ commands=["openssl dhparam -out dhparam.pem 4096"],
278
+ _chdir="/etc/ssl/certs",
279
+ )
280
+ """,
281
+ ),
282
+ "Operation meta & callbacks": (meta_argument_meta, ""),
283
+ "Execution strategy": (execution_argument_meta, ""),
284
+ }
285
+
286
+
287
+ def pop_global_arguments(
288
+ kwargs: dict[str, Any],
289
+ state: Optional["State"] = None,
290
+ host: Optional["Host"] = None,
291
+ keys_to_check=None,
292
+ ) -> tuple[AllArguments, list[str]]:
293
+ """
294
+ Pop and return operation global keyword arguments, in preferred order:
295
+
296
+ + From the current context (a direct @operator or @deploy function being called)
297
+ + From any current @deploy context (deploy kwargs)
298
+ + From the host data variables
299
+ + From the config variables
300
+ """
301
+
302
+ state = state or context.state
303
+ host = host or context.host
304
+
305
+ config = state.config
306
+ if context.ctx_config.isset():
307
+ config = context.config
308
+
309
+ meta_kwargs: dict[str, Any] = host.current_deploy_kwargs or {} # type: ignore[assignment]
310
+
311
+ arguments: dict[str, Any] = {}
312
+ found_keys: list[str] = []
313
+
314
+ for key, type_ in all_global_arguments():
315
+ if keys_to_check and key not in keys_to_check:
316
+ continue
317
+
318
+ argument_meta = all_argument_meta[key]
319
+ handler = argument_meta.handler
320
+ default: Any = argument_meta.default(config)
321
+
322
+ host_default = getattr(host.data, key, default_sentinel)
323
+ if host_default is not default_sentinel:
324
+ default = host_default
325
+
326
+ if key in kwargs:
327
+ found_keys.append(key)
328
+ value = kwargs.pop(key)
329
+ else:
330
+ value = meta_kwargs.get(key, default)
331
+
332
+ if handler:
333
+ value = handler(config, value)
334
+
335
+ if value != default:
336
+ raise_if_bad_type(
337
+ value,
338
+ type_,
339
+ ArgumentTypeError,
340
+ f"Invalid argument `{key}`:",
341
+ )
342
+
343
+ # TODO: why is type failing here?
344
+ arguments[key] = value # type: ignore
345
+ return cast(AllArguments, arguments), found_keys
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import (
4
+ TYPE_CHECKING,
5
+ Callable,
6
+ Generator,
7
+ Generic,
8
+ Iterable,
9
+ List,
10
+ Mapping,
11
+ Optional,
12
+ Union,
13
+ )
14
+
15
+ from typing_extensions import ParamSpec, Protocol
16
+
17
+ if TYPE_CHECKING:
18
+ from pyinfra.api.operation import OperationMeta
19
+
20
+ P = ParamSpec("P")
21
+
22
+
23
+ # Unfortunately we have to re-type out all of the global arguments here because
24
+ # Python typing doesn't (yet) support merging kwargs. This acts as the operation
25
+ # decorator output function which merges actual operation args/kwargs in paramspec
26
+ # with the global arguments available in all operations.
27
+ # The nature of "global arguments" is somewhat opposed to static typing as it's
28
+ # indirect and somewhat magic, but we are where we are.
29
+ class PyinfraOperation(Generic[P], Protocol):
30
+ _inner: Callable[P, Generator]
31
+
32
+ def __call__(
33
+ self,
34
+ #
35
+ # op args
36
+ # needs to be first
37
+ #
38
+ *args: P.args,
39
+ #
40
+ # ConnectorArguments
41
+ #
42
+ # Auth
43
+ _sudo: bool = False,
44
+ _sudo_user: Optional[str] = None,
45
+ _use_sudo_login: bool = False,
46
+ _sudo_password: Optional[str] = None,
47
+ _preserve_sudo_env: bool = False,
48
+ _su_user: Optional[str] = None,
49
+ _use_su_login: bool = False,
50
+ _preserve_su_env: bool = False,
51
+ _su_shell: Optional[str] = None,
52
+ _doas: bool = False,
53
+ _doas_user: Optional[str] = None,
54
+ # Shell arguments
55
+ _shell_executable: Optional[str] = None,
56
+ _chdir: Optional[str] = None,
57
+ _env: Optional[Mapping[str, str]] = None,
58
+ # Connector control
59
+ _success_exit_codes: Iterable[int] = (0,),
60
+ _timeout: Optional[int] = None,
61
+ _get_pty: bool = False,
62
+ _stdin: Union[None, str, list[str], tuple[str, ...]] = None,
63
+ #
64
+ # MetaArguments
65
+ #
66
+ name: Optional[str] = None,
67
+ _ignore_errors: bool = False,
68
+ _continue_on_error: bool = False,
69
+ _if: Union[List[Callable[[], bool]], Callable[[], bool], None] = None,
70
+ #
71
+ # ExecutionArguments
72
+ #
73
+ _parallel: Optional[int] = None,
74
+ _run_once: bool = False,
75
+ _serial: bool = False,
76
+ #
77
+ # op kwargs
78
+ #
79
+ **kwargs: P.kwargs,
80
+ ) -> "OperationMeta": ...