pyinfra 2.9.2__tar.gz → 3.0b1__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 (207) hide show
  1. pyinfra-3.0b1/CHANGELOG.md +29 -0
  2. {pyinfra-2.9.2/pyinfra.egg-info → pyinfra-3.0b1}/PKG-INFO +9 -7
  3. {pyinfra-2.9.2 → pyinfra-3.0b1}/README.md +8 -4
  4. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/__init__.py +3 -0
  5. pyinfra-3.0b1/pyinfra/api/arguments.py +339 -0
  6. pyinfra-3.0b1/pyinfra/api/arguments_typed.py +77 -0
  7. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/command.py +66 -53
  8. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/config.py +27 -22
  9. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/connect.py +1 -1
  10. pyinfra-3.0b1/pyinfra/api/connectors.py +24 -0
  11. pyinfra-3.0b1/pyinfra/api/deploy.py +87 -0
  12. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/exceptions.py +33 -8
  13. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/facts.py +77 -113
  14. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/host.py +150 -82
  15. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/inventory.py +17 -25
  16. pyinfra-3.0b1/pyinfra/api/operation.py +430 -0
  17. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/operations.py +102 -148
  18. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/state.py +137 -79
  19. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/api/util.py +55 -70
  20. pyinfra-3.0b1/pyinfra/connectors/base.py +150 -0
  21. pyinfra-3.0b1/pyinfra/connectors/chroot.py +203 -0
  22. pyinfra-3.0b1/pyinfra/connectors/docker.py +295 -0
  23. pyinfra-3.0b1/pyinfra/connectors/dockerssh.py +291 -0
  24. pyinfra-3.0b1/pyinfra/connectors/local.py +232 -0
  25. pyinfra-3.0b1/pyinfra/connectors/ssh.py +624 -0
  26. pyinfra-3.0b1/pyinfra/connectors/ssh_util.py +114 -0
  27. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/connectors/sshuserclient/client.py +5 -3
  28. pyinfra-3.0b1/pyinfra/connectors/terraform.py +122 -0
  29. pyinfra-3.0b1/pyinfra/connectors/util.py +403 -0
  30. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/connectors/vagrant.py +55 -48
  31. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/context.py +3 -2
  32. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/docker.py +1 -0
  33. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/files.py +45 -32
  34. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/git.py +3 -1
  35. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/gpg.py +1 -1
  36. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/hardware.py +4 -2
  37. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/iptables.py +5 -3
  38. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/mysql.py +1 -0
  39. pyinfra-2.9.2/pyinfra/facts/postgresql.py → pyinfra-3.0b1/pyinfra/facts/postgres.py +7 -4
  40. pyinfra-3.0b1/pyinfra/facts/postgresql.py +9 -0
  41. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/selinux.py +3 -1
  42. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/server.py +77 -30
  43. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/systemd.py +29 -12
  44. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/sysvinit.py +10 -10
  45. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/util/packaging.py +4 -2
  46. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/local.py +4 -5
  47. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/apk.py +3 -3
  48. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/apt.py +25 -47
  49. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/brew.py +7 -14
  50. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/bsdinit.py +4 -4
  51. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/cargo.py +1 -1
  52. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/choco.py +1 -1
  53. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/dnf.py +4 -4
  54. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/files.py +108 -321
  55. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/gem.py +1 -1
  56. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/git.py +6 -37
  57. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/iptables.py +2 -10
  58. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/launchd.py +1 -1
  59. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/lxd.py +1 -9
  60. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/mysql.py +5 -28
  61. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/npm.py +1 -1
  62. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/openrc.py +1 -1
  63. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/pacman.py +3 -3
  64. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/pip.py +14 -15
  65. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/pkg.py +1 -1
  66. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/pkgin.py +3 -3
  67. pyinfra-2.9.2/pyinfra/operations/postgresql.py → pyinfra-3.0b1/pyinfra/operations/postgres.py +8 -52
  68. pyinfra-3.0b1/pyinfra/operations/postgresql.py +28 -0
  69. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/python.py +2 -17
  70. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/selinux.py +5 -28
  71. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/server.py +59 -84
  72. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/snap.py +1 -3
  73. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/ssh.py +8 -23
  74. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/systemd.py +7 -7
  75. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/sysvinit.py +3 -12
  76. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/upstart.py +4 -4
  77. pyinfra-3.0b1/pyinfra/operations/util/__init__.py +12 -0
  78. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/util/files.py +2 -2
  79. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/util/packaging.py +6 -24
  80. pyinfra-3.0b1/pyinfra/operations/util/service.py +39 -0
  81. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/vzctl.py +2 -2
  82. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/xbps.py +3 -3
  83. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/yum.py +4 -4
  84. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/zypper.py +4 -4
  85. {pyinfra-2.9.2 → pyinfra-3.0b1/pyinfra.egg-info}/PKG-INFO +9 -7
  86. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra.egg-info/SOURCES.txt +6 -13
  87. pyinfra-3.0b1/pyinfra.egg-info/entry_points.txt +11 -0
  88. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra.egg-info/requires.txt +12 -25
  89. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra_cli/__main__.py +2 -0
  90. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra_cli/commands.py +7 -2
  91. pyinfra-3.0b1/pyinfra_cli/exceptions.py +168 -0
  92. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra_cli/inventory.py +19 -4
  93. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra_cli/log.py +17 -3
  94. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra_cli/main.py +133 -90
  95. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra_cli/prints.py +93 -129
  96. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra_cli/util.py +60 -29
  97. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyproject.toml +3 -6
  98. {pyinfra-2.9.2 → pyinfra-3.0b1}/setup.py +16 -22
  99. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api.py +2 -0
  100. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api_arguments.py +13 -13
  101. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api_deploys.py +28 -29
  102. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api_facts.py +60 -98
  103. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api_operations.py +100 -200
  104. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_cli/test_cli.py +18 -49
  105. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_cli/test_cli_deploy.py +11 -37
  106. pyinfra-3.0b1/tests/test_cli/test_cli_exceptions.py +86 -0
  107. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_cli/util.py +1 -1
  108. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_connectors/test_chroot.py +6 -6
  109. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_connectors/test_docker.py +4 -4
  110. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_connectors/test_dockerssh.py +38 -50
  111. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_connectors/test_local.py +11 -12
  112. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_connectors/test_ssh.py +66 -107
  113. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_connectors/test_terraform.py +9 -15
  114. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_connectors/test_util.py +24 -46
  115. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_connectors/test_vagrant.py +4 -4
  116. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_global_arguments.py +2 -2
  117. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_operations.py +7 -51
  118. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/util.py +6 -29
  119. pyinfra-2.9.2/CHANGELOG.md +0 -322
  120. pyinfra-2.9.2/pyinfra/api/arguments.py +0 -333
  121. pyinfra-2.9.2/pyinfra/api/connectors.py +0 -46
  122. pyinfra-2.9.2/pyinfra/api/deploy.py +0 -118
  123. pyinfra-2.9.2/pyinfra/api/operation.py +0 -396
  124. pyinfra-2.9.2/pyinfra/api/operation.pyi +0 -117
  125. pyinfra-2.9.2/pyinfra/connectors/ansible.py +0 -171
  126. pyinfra-2.9.2/pyinfra/connectors/chroot.py +0 -212
  127. pyinfra-2.9.2/pyinfra/connectors/docker.py +0 -305
  128. pyinfra-2.9.2/pyinfra/connectors/dockerssh.py +0 -313
  129. pyinfra-2.9.2/pyinfra/connectors/local.py +0 -244
  130. pyinfra-2.9.2/pyinfra/connectors/mech.py +0 -186
  131. pyinfra-2.9.2/pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
  132. pyinfra-2.9.2/pyinfra/connectors/ssh.py +0 -711
  133. pyinfra-2.9.2/pyinfra/connectors/terraform.py +0 -101
  134. pyinfra-2.9.2/pyinfra/connectors/util.py +0 -328
  135. pyinfra-2.9.2/pyinfra/connectors/winrm.py +0 -320
  136. pyinfra-2.9.2/pyinfra/facts/windows.py +0 -366
  137. pyinfra-2.9.2/pyinfra/facts/windows_files.py +0 -90
  138. pyinfra-2.9.2/pyinfra/operations/util/service.py +0 -58
  139. pyinfra-2.9.2/pyinfra/operations/windows.py +0 -59
  140. pyinfra-2.9.2/pyinfra/operations/windows_files.py +0 -551
  141. pyinfra-2.9.2/pyinfra.egg-info/entry_points.txt +0 -14
  142. pyinfra-2.9.2/pyinfra_cli/exceptions.py +0 -127
  143. pyinfra-2.9.2/tests/test_cli/test_cli_exceptions.py +0 -55
  144. pyinfra-2.9.2/tests/test_connectors/__init__.py +0 -0
  145. pyinfra-2.9.2/tests/test_connectors/test_ansible.py +0 -64
  146. pyinfra-2.9.2/tests/test_connectors/test_mech.py +0 -126
  147. pyinfra-2.9.2/tests/test_connectors/test_winrm.py +0 -76
  148. {pyinfra-2.9.2 → pyinfra-3.0b1}/LICENSE.md +0 -0
  149. {pyinfra-2.9.2 → pyinfra-3.0b1}/MANIFEST.in +0 -0
  150. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/__init__.py +0 -0
  151. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/__main__.py +0 -0
  152. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/connectors/__init__.py +0 -0
  153. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/connectors/sshuserclient/__init__.py +0 -0
  154. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/connectors/sshuserclient/config.py +0 -0
  155. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/__init__.py +0 -0
  156. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/apk.py +0 -0
  157. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/apt.py +0 -0
  158. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/brew.py +0 -0
  159. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/bsdinit.py +0 -0
  160. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/cargo.py +0 -0
  161. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/choco.py +0 -0
  162. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/deb.py +0 -0
  163. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/dnf.py +0 -0
  164. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/gem.py +0 -0
  165. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/launchd.py +0 -0
  166. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/lxd.py +0 -0
  167. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/npm.py +0 -0
  168. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/openrc.py +0 -0
  169. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/pacman.py +0 -0
  170. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/pip.py +0 -0
  171. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/pkg.py +0 -0
  172. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/pkgin.py +0 -0
  173. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/rpm.py +0 -0
  174. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/snap.py +0 -0
  175. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/upstart.py +0 -0
  176. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/util/__init__.py +0 -0
  177. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/util/databases.py +0 -0
  178. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/util/win_files.py +0 -0
  179. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/vzctl.py +0 -0
  180. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/xbps.py +0 -0
  181. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/yum.py +0 -0
  182. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/facts/zypper.py +0 -0
  183. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/__init__.py +0 -0
  184. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/operations/puppet.py +0 -0
  185. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/progress.py +0 -0
  186. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/py.typed +0 -0
  187. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra/version.py +0 -0
  188. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra.egg-info/dependency_links.txt +0 -0
  189. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra.egg-info/top_level.txt +0 -0
  190. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra_cli/__init__.py +0 -0
  191. {pyinfra-2.9.2 → pyinfra-3.0b1}/pyinfra_cli/virtualenv.py +0 -0
  192. {pyinfra-2.9.2 → pyinfra-3.0b1}/setup.cfg +0 -0
  193. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/__init__.py +0 -0
  194. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/paramiko_util.py +0 -0
  195. {pyinfra-2.9.2/pyinfra/operations/util → pyinfra-3.0b1/tests/test_api}/__init__.py +0 -0
  196. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api_command.py +0 -0
  197. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api_config.py +0 -0
  198. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api_host.py +0 -0
  199. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api_inventory.py +0 -0
  200. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_api/test_api_util.py +0 -0
  201. {pyinfra-2.9.2/tests/test_api → pyinfra-3.0b1/tests/test_cli}/__init__.py +0 -0
  202. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_cli/test_cli_util.py +0 -0
  203. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_cli/test_context_objects.py +0 -0
  204. {pyinfra-2.9.2/tests/test_cli → pyinfra-3.0b1/tests/test_connectors}/__init__.py +0 -0
  205. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_connectors/test_sshuserclient.py +0 -0
  206. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_facts.py +0 -0
  207. {pyinfra-2.9.2 → pyinfra-3.0b1}/tests/test_operations_utils.py +0 -0
@@ -0,0 +1,29 @@
1
+ # v3.0.beta1
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 (skip with `-y`).
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
+ More TBC...
22
+
23
+ # v2.x
24
+
25
+ [See this file in the `2.x` branch](https://github.com/Fizzadar/pyinfra/blob/2.x/CHANGELOG.md).
26
+
27
+ # v1.x
28
+
29
+ [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.0b1
4
4
  Summary: pyinfra automates/provisions/manages/deploys infrastructure.
5
5
  Home-page: https://pyinfra.com
6
6
  Author: Nick / Fizzadar
@@ -16,7 +16,6 @@ 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
19
  Classifier: Programming Language :: Python :: 3.7
21
20
  Classifier: Programming Language :: Python :: 3.8
22
21
  Classifier: Programming Language :: Python :: 3.9
@@ -28,7 +27,6 @@ Description-Content-Type: text/markdown
28
27
  Provides-Extra: test
29
28
  Provides-Extra: docs
30
29
  Provides-Extra: dev
31
- Provides-Extra: ansible
32
30
  License-File: LICENSE.md
33
31
 
34
32
  <p align="center">
@@ -37,13 +35,17 @@ License-File: LICENSE.md
37
35
  </a>
38
36
  </p>
39
37
 
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>
38
+ <p>
39
+ <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>
40
+ </p>
41
+
42
+ <p>
43
+ 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
44
  </p>
43
45
 
44
46
  ---
45
47
 
46
- <p align="center">
48
+ <p>
47
49
  <a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> &rArr;
48
50
  <a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> &bull;
49
51
  <a href="https://docs.pyinfra.com/page/examples.html"><strong>Examples</strong></a> &bull;
@@ -51,7 +53,7 @@ License-File: LICENSE.md
51
53
  <a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
52
54
  </p>
53
55
 
54
- <p align="center">
56
+ <p>
55
57
  Chat &rArr;
56
58
  <a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
57
59
  </p>
@@ -4,13 +4,17 @@
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">
17
+ <p>
14
18
  <a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> &rArr;
15
19
  <a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> &bull;
16
20
  <a href="https://docs.pyinfra.com/page/examples.html"><strong>Examples</strong></a> &bull;
@@ -18,7 +22,7 @@
18
22
  <a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
19
23
  </p>
20
24
 
21
- <p align="center">
25
+ <p>
22
26
  Chat &rArr;
23
27
  <a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
24
28
  </p>
@@ -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,339 @@
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
+ TypeVar,
13
+ Union,
14
+ cast,
15
+ get_type_hints,
16
+ )
17
+
18
+ from typing_extensions import TypedDict
19
+
20
+ from pyinfra import context
21
+ from pyinfra.api.exceptions import ArgumentTypeError
22
+ from pyinfra.api.state import State
23
+ from pyinfra.api.util import raise_if_bad_type
24
+
25
+ if TYPE_CHECKING:
26
+ from pyinfra.api.config import Config
27
+ from pyinfra.api.host import Host
28
+
29
+ T = TypeVar("T")
30
+ default_sentinel = object()
31
+
32
+
33
+ class ArgumentMeta(Generic[T]):
34
+ description: str
35
+ default: Callable[["Config"], T]
36
+ handler: Optional[Callable[["Config", T], T]]
37
+
38
+ def __init__(self, description, default, handler=None) -> None:
39
+ self.description = description
40
+ self.default = default
41
+ self.handler = handler
42
+
43
+
44
+ # Connector arguments
45
+ # These are arguments passed to the various connectors that provide the underlying
46
+ # API to read/write external systems.
47
+
48
+
49
+ # Note: ConnectorArguments is specifically not total as it's used to type many
50
+ # functions via Unpack and we don't want to specify every kwarg.
51
+ class ConnectorArguments(TypedDict, total=False):
52
+ # Auth arguments
53
+ _sudo: bool
54
+ _sudo_user: str
55
+ _use_sudo_login: bool
56
+ _sudo_password: str
57
+ _preserve_sudo_env: bool
58
+ _su_user: str
59
+ _use_su_login: bool
60
+ _preserve_su_env: bool
61
+ _su_shell: str
62
+ _doas: bool
63
+ _doas_user: str
64
+
65
+ # Shell arguments
66
+ _shell_executable: str
67
+ _chdir: str
68
+ _env: Mapping[str, str]
69
+
70
+ # Connector control (outside of command generation)
71
+ _success_exit_codes: Iterable[int]
72
+ _timeout: int
73
+ _get_pty: bool
74
+ _stdin: Union[str, Iterable[str]]
75
+
76
+
77
+ def generate_env(config: "Config", value: dict) -> dict:
78
+ env = config.ENV.copy()
79
+ env.update(value)
80
+ return env
81
+
82
+
83
+ auth_argument_meta: dict[str, ArgumentMeta] = {
84
+ "_sudo": ArgumentMeta(
85
+ "Execute/apply any changes with sudo.",
86
+ default=lambda config: config.SUDO,
87
+ ),
88
+ "_sudo_user": ArgumentMeta(
89
+ "Execute/apply any changes with sudo as a non-root user.",
90
+ default=lambda config: config.SUDO_USER,
91
+ ),
92
+ "_use_sudo_login": ArgumentMeta(
93
+ "Execute sudo with a login shell.",
94
+ default=lambda config: config.USE_SUDO_LOGIN,
95
+ ),
96
+ "_sudo_password": ArgumentMeta(
97
+ "Password to sudo with. If needed and not specified pyinfra will prompt for it.",
98
+ default=lambda config: config.SUDO_PASSWORD,
99
+ ),
100
+ "_preserve_sudo_env": ArgumentMeta(
101
+ "Preserve the shell environment of the connecting user when using sudo.",
102
+ default=lambda config: config.PRESERVE_SUDO_ENV,
103
+ ),
104
+ "_su_user": ArgumentMeta(
105
+ "Execute/apply any changes with this user using su.",
106
+ default=lambda config: config.SU_USER,
107
+ ),
108
+ "_use_su_login": ArgumentMeta(
109
+ "Execute su with a login shell.",
110
+ default=lambda config: config.USE_SU_LOGIN,
111
+ ),
112
+ "_preserve_su_env": ArgumentMeta(
113
+ "Preserve the shell environment of the connecting user when using su.",
114
+ default=lambda config: config.PRESERVE_SU_ENV,
115
+ ),
116
+ "_su_shell": ArgumentMeta(
117
+ "Use this shell (instead of user login shell) when using ``_su``). "
118
+ + "Only available under Linux, for use when using `su` with a user that "
119
+ + "has nologin/similar as their login shell.",
120
+ default=lambda config: config.SU_SHELL,
121
+ ),
122
+ "_doas": ArgumentMeta(
123
+ "Execute/apply any changes with doas.",
124
+ default=lambda config: config.DOAS,
125
+ ),
126
+ "_doas_user": ArgumentMeta(
127
+ "Execute/apply any changes with doas as a non-root user.",
128
+ default=lambda config: config.DOAS_USER,
129
+ ),
130
+ }
131
+
132
+ shell_argument_meta: dict[str, ArgumentMeta] = {
133
+ "_shell_executable": ArgumentMeta(
134
+ "The shell executable to use for executing commands.",
135
+ default=lambda config: config.SHELL,
136
+ ),
137
+ "_chdir": ArgumentMeta(
138
+ "Directory to switch to before executing the command.",
139
+ default=lambda _: "",
140
+ ),
141
+ "_env": ArgumentMeta(
142
+ "Dictionary of environment variables to set.",
143
+ default=lambda _: {},
144
+ handler=generate_env,
145
+ ),
146
+ "_success_exit_codes": ArgumentMeta(
147
+ "List of exit codes to consider a success.",
148
+ default=lambda _: [0],
149
+ ),
150
+ "_timeout": ArgumentMeta(
151
+ "Timeout for *each* command executed during the operation.",
152
+ default=lambda _: None,
153
+ ),
154
+ "_get_pty": ArgumentMeta(
155
+ "Whether to get a pseudoTTY when executing any commands.",
156
+ default=lambda _: False,
157
+ ),
158
+ "_stdin": ArgumentMeta(
159
+ "String or buffer to send to the stdin of any commands.",
160
+ default=lambda _: None,
161
+ ),
162
+ }
163
+
164
+
165
+ # Meta arguments
166
+ # These provide/extend additional operation metadata
167
+
168
+
169
+ class MetaArguments(TypedDict):
170
+ name: str
171
+ _ignore_errors: bool
172
+ _continue_on_error: bool
173
+ _if: List[Callable[[], bool]]
174
+
175
+
176
+ meta_argument_meta: dict[str, ArgumentMeta] = {
177
+ # NOTE: name is the only non-_-prefixed argument
178
+ "name": ArgumentMeta(
179
+ "Name of the operation.",
180
+ default=lambda _: None,
181
+ ),
182
+ "_ignore_errors": ArgumentMeta(
183
+ "Ignore errors when executing the operation.",
184
+ default=lambda config: config.IGNORE_ERRORS,
185
+ ),
186
+ "_continue_on_error": ArgumentMeta(
187
+ (
188
+ "Continue executing operation commands after error. "
189
+ "Only applies when ``_ignore_errors`` is true."
190
+ ),
191
+ default=lambda _: False,
192
+ ),
193
+ "_if": ArgumentMeta(
194
+ "Only run this operation if these functions returns True",
195
+ default=lambda _: [],
196
+ ),
197
+ }
198
+
199
+
200
+ # Execution arguments
201
+ # These alter how pyinfra is to execute an operation. Notably these must all have the same value
202
+ # over every target host for the same operation.
203
+
204
+
205
+ class ExecutionArguments(TypedDict):
206
+ _parallel: int
207
+ _run_once: bool
208
+ _serial: bool
209
+
210
+
211
+ execution_argument_meta: dict[str, ArgumentMeta] = {
212
+ "_parallel": ArgumentMeta(
213
+ "Run this operation in batches of hosts.",
214
+ default=lambda config: config.PARALLEL,
215
+ ),
216
+ "_run_once": ArgumentMeta(
217
+ "Only execute this operation once, on the first host to see it.",
218
+ default=lambda _: False,
219
+ ),
220
+ "_serial": ArgumentMeta(
221
+ "Run this operation host by host, rather than in parallel.",
222
+ default=lambda _: False,
223
+ ),
224
+ }
225
+
226
+
227
+ class AllArguments(ConnectorArguments, MetaArguments, ExecutionArguments):
228
+ pass
229
+
230
+
231
+ all_argument_meta: dict[str, ArgumentMeta] = {
232
+ **auth_argument_meta,
233
+ **shell_argument_meta,
234
+ **meta_argument_meta,
235
+ **execution_argument_meta,
236
+ }
237
+
238
+ EXECUTION_KWARG_KEYS = list(ExecutionArguments.__annotations__.keys())
239
+ CONNECTOR_ARGUMENT_KEYS = list(ConnectorArguments.__annotations__.keys())
240
+
241
+ __argument_docs__ = {
242
+ "Privilege & user escalation": (
243
+ auth_argument_meta,
244
+ """
245
+ .. code:: python
246
+
247
+ # Execute a command with sudo
248
+ server.user(
249
+ name="Create pyinfra user using sudo",
250
+ user="pyinfra",
251
+ _sudo=True,
252
+ )
253
+
254
+ # Execute a command with a specific sudo password
255
+ server.user(
256
+ name="Create pyinfra user using sudo",
257
+ user="pyinfra",
258
+ _sudo=True,
259
+ _sudo_password="my-secret-password",
260
+ )
261
+ """,
262
+ ),
263
+ "Shell control & features": (
264
+ shell_argument_meta,
265
+ """
266
+ .. code:: python
267
+
268
+ # Execute from a specific directory
269
+ server.shell(
270
+ name="Bootstrap nginx params",
271
+ commands=["openssl dhparam -out dhparam.pem 4096"],
272
+ _chdir="/etc/ssl/certs",
273
+ )
274
+ """,
275
+ ),
276
+ "Operation meta & callbacks": (meta_argument_meta, ""),
277
+ "Execution strategy": (execution_argument_meta, ""),
278
+ }
279
+
280
+
281
+ def pop_global_arguments(
282
+ kwargs: dict[str, Any],
283
+ state: Optional["State"] = None,
284
+ host: Optional["Host"] = None,
285
+ keys_to_check=None,
286
+ ) -> tuple[AllArguments, list[str]]:
287
+ """
288
+ Pop and return operation global keyword arguments, in preferred order:
289
+
290
+ + From the current context (a direct @operator or @deploy function being called)
291
+ + From any current @deploy context (deploy kwargs)
292
+ + From the host data variables
293
+ + From the config variables
294
+ """
295
+
296
+ state = state or context.state
297
+ host = host or context.host
298
+
299
+ config = state.config
300
+ if context.ctx_config.isset():
301
+ config = context.config
302
+
303
+ meta_kwargs: dict[str, Any] = host.current_deploy_kwargs or {} # type: ignore[assignment]
304
+
305
+ arguments: dict[str, Any] = {}
306
+ found_keys: list[str] = []
307
+
308
+ for key, type_ in get_type_hints(AllArguments).items():
309
+ if keys_to_check and key not in keys_to_check:
310
+ continue
311
+
312
+ argument_meta = all_argument_meta[key]
313
+ handler = argument_meta.handler
314
+ default: Any = argument_meta.default(config)
315
+
316
+ host_default = getattr(host.data, key, default_sentinel)
317
+ if host_default is not default_sentinel:
318
+ default = host_default
319
+
320
+ if key in kwargs:
321
+ found_keys.append(key)
322
+ value = kwargs.pop(key)
323
+ else:
324
+ value = meta_kwargs.get(key, default)
325
+
326
+ if handler:
327
+ value = handler(config, value)
328
+
329
+ if value != default:
330
+ raise_if_bad_type(
331
+ value,
332
+ type_,
333
+ ArgumentTypeError,
334
+ f"Invalid argument `{key}`:",
335
+ )
336
+
337
+ # TODO: why is type failing here?
338
+ arguments[key] = value # type: ignore
339
+ return cast(AllArguments, arguments), found_keys
@@ -0,0 +1,77 @@
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
+ # ConnectorArguments
36
+ #
37
+ # Auth
38
+ _sudo: bool = False,
39
+ _sudo_user: Optional[str] = None,
40
+ _use_sudo_login: bool = False,
41
+ _sudo_password: Optional[str] = None,
42
+ _preserve_sudo_env: bool = False,
43
+ _su_user: Optional[str] = None,
44
+ _use_su_login: bool = False,
45
+ _preserve_su_env: bool = False,
46
+ _su_shell: Optional[str] = None,
47
+ _doas: bool = False,
48
+ _doas_user: Optional[str] = None,
49
+ # Shell arguments
50
+ _shell_executable: Optional[str] = None,
51
+ _chdir: Optional[str] = None,
52
+ _env: Optional[Mapping[str, str]] = None,
53
+ # Connector control
54
+ _success_exit_codes: Iterable[int] = (0,),
55
+ _timeout: Optional[int] = None,
56
+ _get_pty: bool = False,
57
+ _stdin: Union[None, str, list[str], tuple[str, ...]] = None,
58
+ #
59
+ # MetaArguments
60
+ #
61
+ name: Optional[str] = None,
62
+ _ignore_errors: bool = False,
63
+ _continue_on_error: bool = False,
64
+ _if: Optional[List[Callable[[], bool]]] = None,
65
+ #
66
+ # ExecutionArguments
67
+ #
68
+ _parallel: Optional[int] = None,
69
+ _run_once: bool = False,
70
+ _serial: bool = False,
71
+ #
72
+ # The op itself
73
+ #
74
+ *args: P.args,
75
+ **kwargs: P.kwargs,
76
+ ) -> "OperationMeta":
77
+ ...