pyinfra 3.0b0__tar.gz → 3.0b2__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.0b0 → pyinfra-3.0b2}/CHANGELOG.md +1 -1
  2. {pyinfra-3.0b0/pyinfra.egg-info → pyinfra-3.0b2}/PKG-INFO +69 -14
  3. {pyinfra-3.0b0 → pyinfra-3.0b2}/README.md +9 -11
  4. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/__init__.py +3 -0
  5. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/arguments.py +12 -5
  6. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/arguments_typed.py +19 -6
  7. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/command.py +5 -3
  8. pyinfra-3.0b2/pyinfra/api/config.py +231 -0
  9. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/connectors.py +5 -2
  10. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/exceptions.py +19 -0
  11. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/facts.py +34 -33
  12. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/host.py +51 -12
  13. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/inventory.py +4 -0
  14. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/operation.py +88 -42
  15. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/operations.py +10 -11
  16. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/state.py +11 -2
  17. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/util.py +24 -16
  18. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/base.py +4 -7
  19. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/chroot.py +5 -6
  20. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/docker.py +13 -19
  21. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/dockerssh.py +5 -4
  22. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/local.py +7 -7
  23. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/ssh.py +46 -25
  24. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/terraform.py +9 -6
  25. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/util.py +7 -8
  26. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/vagrant.py +11 -10
  27. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/context.py +1 -0
  28. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/apk.py +2 -0
  29. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/apt.py +2 -0
  30. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/brew.py +2 -0
  31. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/bsdinit.py +2 -0
  32. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/cargo.py +2 -0
  33. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/choco.py +3 -1
  34. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/deb.py +9 -4
  35. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/dnf.py +2 -0
  36. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/docker.py +2 -0
  37. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/files.py +2 -0
  38. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/gem.py +2 -0
  39. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/gpg.py +2 -0
  40. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/hardware.py +30 -22
  41. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/launchd.py +2 -0
  42. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/lxd.py +2 -0
  43. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/mysql.py +12 -6
  44. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/npm.py +1 -0
  45. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/openrc.py +2 -0
  46. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/pacman.py +6 -2
  47. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/pip.py +2 -0
  48. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/pkg.py +2 -0
  49. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/pkgin.py +2 -0
  50. pyinfra-3.0b0/pyinfra/facts/postgresql.py → pyinfra-3.0b2/pyinfra/facts/postgres.py +9 -9
  51. pyinfra-3.0b2/pyinfra/facts/postgresql.py +11 -0
  52. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/rpm.py +12 -9
  53. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/server.py +10 -13
  54. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/snap.py +2 -0
  55. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/systemd.py +28 -10
  56. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/upstart.py +2 -0
  57. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/util/packaging.py +3 -2
  58. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/vzctl.py +2 -0
  59. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/xbps.py +2 -0
  60. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/yum.py +2 -0
  61. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/zypper.py +2 -0
  62. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/apk.py +3 -1
  63. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/apt.py +16 -18
  64. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/brew.py +10 -8
  65. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/bsdinit.py +5 -3
  66. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/cargo.py +3 -1
  67. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/choco.py +3 -1
  68. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/dnf.py +15 -19
  69. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/files.py +86 -69
  70. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/gem.py +3 -1
  71. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/git.py +18 -16
  72. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/iptables.py +33 -25
  73. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/launchd.py +5 -6
  74. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/lxd.py +7 -4
  75. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/mysql.py +57 -53
  76. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/npm.py +8 -1
  77. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/openrc.py +5 -3
  78. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/pacman.py +4 -5
  79. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/pip.py +16 -9
  80. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/pkg.py +3 -1
  81. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/pkgin.py +3 -1
  82. pyinfra-3.0b0/pyinfra/operations/postgresql.py → pyinfra-3.0b2/pyinfra/operations/postgres.py +44 -42
  83. pyinfra-3.0b2/pyinfra/operations/postgresql.py +30 -0
  84. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/puppet.py +3 -1
  85. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/python.py +7 -3
  86. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/selinux.py +42 -16
  87. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/server.py +48 -43
  88. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/snap.py +3 -1
  89. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/ssh.py +12 -10
  90. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/systemd.py +13 -9
  91. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/sysvinit.py +6 -4
  92. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/upstart.py +5 -3
  93. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/util/files.py +24 -16
  94. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/util/packaging.py +53 -37
  95. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/util/service.py +18 -13
  96. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/vzctl.py +12 -10
  97. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/xbps.py +3 -1
  98. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/yum.py +14 -18
  99. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/zypper.py +8 -9
  100. pyinfra-3.0b2/pyinfra/version.py +9 -0
  101. {pyinfra-3.0b0 → pyinfra-3.0b2/pyinfra.egg-info}/PKG-INFO +69 -14
  102. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra.egg-info/SOURCES.txt +2 -4
  103. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra.egg-info/requires.txt +20 -16
  104. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/commands.py +3 -2
  105. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/inventory.py +38 -19
  106. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/main.py +2 -0
  107. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/prints.py +27 -105
  108. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/util.py +3 -1
  109. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyproject.toml +1 -1
  110. {pyinfra-3.0b0 → pyinfra-3.0b2}/setup.cfg +1 -1
  111. {pyinfra-3.0b0 → pyinfra-3.0b2}/setup.py +14 -9
  112. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api_deploys.py +5 -5
  113. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api_operations.py +5 -5
  114. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/test_ssh.py +105 -0
  115. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/test_terraform.py +11 -8
  116. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/test_vagrant.py +6 -6
  117. pyinfra-3.0b0/pyinfra/api/config.py +0 -129
  118. pyinfra-3.0b0/pyinfra/version.py +0 -6
  119. pyinfra-3.0b0/pyinfra_cli/inventory_dsl.py +0 -23
  120. pyinfra-3.0b0/tests/__init__.py +0 -12
  121. pyinfra-3.0b0/tests/paramiko_util.py +0 -103
  122. pyinfra-3.0b0/tests/util.py +0 -407
  123. {pyinfra-3.0b0 → pyinfra-3.0b2}/LICENSE.md +0 -0
  124. {pyinfra-3.0b0 → pyinfra-3.0b2}/MANIFEST.in +0 -0
  125. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/__init__.py +0 -0
  126. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/__main__.py +0 -0
  127. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/connect.py +0 -0
  128. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/api/deploy.py +0 -0
  129. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/__init__.py +0 -0
  130. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/ssh_util.py +0 -0
  131. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/sshuserclient/__init__.py +0 -0
  132. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/sshuserclient/client.py +0 -0
  133. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/connectors/sshuserclient/config.py +0 -0
  134. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/__init__.py +0 -0
  135. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/git.py +0 -0
  136. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/iptables.py +0 -0
  137. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/selinux.py +0 -0
  138. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/sysvinit.py +0 -0
  139. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/util/__init__.py +0 -0
  140. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/util/databases.py +0 -0
  141. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/facts/util/win_files.py +0 -0
  142. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/local.py +0 -0
  143. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/__init__.py +0 -0
  144. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/operations/util/__init__.py +0 -0
  145. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/progress.py +0 -0
  146. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra/py.typed +0 -0
  147. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra.egg-info/dependency_links.txt +0 -0
  148. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra.egg-info/entry_points.txt +0 -0
  149. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra.egg-info/top_level.txt +0 -0
  150. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/__init__.py +0 -0
  151. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/__main__.py +0 -0
  152. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/exceptions.py +0 -0
  153. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/log.py +0 -0
  154. {pyinfra-3.0b0 → pyinfra-3.0b2}/pyinfra_cli/virtualenv.py +0 -0
  155. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/__init__.py +0 -0
  156. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api.py +0 -0
  157. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api_arguments.py +0 -0
  158. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api_command.py +0 -0
  159. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api_config.py +0 -0
  160. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api_facts.py +0 -0
  161. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api_host.py +0 -0
  162. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api_inventory.py +0 -0
  163. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_api/test_api_util.py +0 -0
  164. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_cli/__init__.py +0 -0
  165. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_cli/test_cli.py +0 -0
  166. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_cli/test_cli_deploy.py +0 -0
  167. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_cli/test_cli_exceptions.py +0 -0
  168. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_cli/test_cli_util.py +0 -0
  169. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_cli/test_context_objects.py +0 -0
  170. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_cli/util.py +0 -0
  171. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/__init__.py +0 -0
  172. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/test_chroot.py +0 -0
  173. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/test_docker.py +0 -0
  174. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/test_dockerssh.py +0 -0
  175. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/test_local.py +0 -0
  176. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/test_sshuserclient.py +0 -0
  177. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_connectors/test_util.py +0 -0
  178. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_facts.py +0 -0
  179. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_global_arguments.py +0 -0
  180. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_operations.py +0 -0
  181. {pyinfra-3.0b0 → pyinfra-3.0b2}/tests/test_operations_utils.py +0 -0
@@ -1,4 +1,4 @@
1
- # v3.0.beta0
1
+ # v3.0.beta2
2
2
 
3
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
4
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyinfra
3
- Version: 3.0b0
3
+ Version: 3.0b2
4
4
  Summary: pyinfra automates/provisions/manages/deploys infrastructure.
5
5
  Home-page: https://pyinfra.com
6
6
  Author: Nick / Fizzadar
@@ -16,18 +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.7
20
19
  Classifier: Programming Language :: Python :: 3.8
21
20
  Classifier: Programming Language :: Python :: 3.9
22
21
  Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
23
24
  Classifier: Topic :: System :: Systems Administration
24
25
  Classifier: Topic :: System :: Installation/Setup
25
26
  Classifier: Topic :: Utilities
27
+ Requires-Python: >=3.8
26
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"
27
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"
28
59
  Provides-Extra: docs
60
+ Requires-Dist: pyinfra-guzzle_sphinx_theme==0.15; extra == "docs"
61
+ Requires-Dist: myst-parser==2.0.0; extra == "docs"
62
+ Requires-Dist: sphinx==6.2.1; extra == "docs"
29
63
  Provides-Extra: dev
30
- 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.15; 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"
31
88
 
32
89
  <p align="center">
33
90
  <a href="https://pyinfra.com">
@@ -35,29 +92,27 @@ License-File: LICENSE.md
35
92
  </a>
36
93
  </p>
37
94
 
38
- <p align="center">
95
+ <p>
39
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>
40
97
  </p>
41
98
 
42
- <p align="center">
43
- <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>
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.
44
101
  </p>
45
102
 
46
103
  ---
47
104
 
48
- <p align="center">
49
- <a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> &rArr;
105
+ <h3>
50
106
  <a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> &bull;
51
- <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;
52
112
  <a href="https://docs.pyinfra.com/page/support.html"><strong>Help & Support</strong></a> &bull;
53
113
  <a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
54
114
  </p>
55
115
 
56
- <p align="center">
57
- Chat &rArr;
58
- <a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
59
- </p>
60
-
61
116
  ---
62
117
 
63
118
  Why pyinfra? Design features include:
@@ -4,29 +4,27 @@
4
4
  </a>
5
5
  </p>
6
6
 
7
- <p align="center">
7
+ <p>
8
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
9
  </p>
10
10
 
11
- <p align="center">
12
- <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>
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.
13
13
  </p>
14
14
 
15
15
  ---
16
16
 
17
- <p align="center">
18
- <a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> &rArr;
17
+ <h3>
19
18
  <a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> &bull;
20
- <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;
21
24
  <a href="https://docs.pyinfra.com/page/support.html"><strong>Help & Support</strong></a> &bull;
22
25
  <a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
23
26
  </p>
24
27
 
25
- <p align="center">
26
- Chat &rArr;
27
- <a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
28
- </p>
29
-
30
28
  ---
31
29
 
32
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,
@@ -6,8 +6,10 @@ from typing import (
6
6
  Callable,
7
7
  Generic,
8
8
  Iterable,
9
+ List,
9
10
  Mapping,
10
11
  Optional,
12
+ Type,
11
13
  TypeVar,
12
14
  Union,
13
15
  cast,
@@ -169,7 +171,7 @@ class MetaArguments(TypedDict):
169
171
  name: str
170
172
  _ignore_errors: bool
171
173
  _continue_on_error: bool
172
- _if: Callable[[], bool]
174
+ _if: Union[List[Callable[[], bool]], Callable[[], bool], None]
173
175
 
174
176
 
175
177
  meta_argument_meta: dict[str, ArgumentMeta] = {
@@ -190,8 +192,8 @@ meta_argument_meta: dict[str, ArgumentMeta] = {
190
192
  default=lambda _: False,
191
193
  ),
192
194
  "_if": ArgumentMeta(
193
- "Only run this operation if this function returns True",
194
- default=lambda _: None,
195
+ "Only run this operation if these functions return True",
196
+ default=lambda _: [],
195
197
  ),
196
198
  }
197
199
 
@@ -227,6 +229,11 @@ class AllArguments(ConnectorArguments, MetaArguments, ExecutionArguments):
227
229
  pass
228
230
 
229
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
+
230
237
  all_argument_meta: dict[str, ArgumentMeta] = {
231
238
  **auth_argument_meta,
232
239
  **shell_argument_meta,
@@ -299,12 +306,12 @@ def pop_global_arguments(
299
306
  if context.ctx_config.isset():
300
307
  config = context.config
301
308
 
302
- meta_kwargs = host.current_deploy_kwargs or {}
309
+ meta_kwargs: dict[str, Any] = host.current_deploy_kwargs or {} # type: ignore[assignment]
303
310
 
304
311
  arguments: dict[str, Any] = {}
305
312
  found_keys: list[str] = []
306
313
 
307
- for key, type_ in get_type_hints(AllArguments).items():
314
+ for key, type_ in all_global_arguments():
308
315
  if keys_to_check and key not in keys_to_check:
309
316
  continue
310
317
 
@@ -1,6 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Callable, Generator, Generic, Iterable, Mapping, Optional, Union
3
+ from typing import (
4
+ TYPE_CHECKING,
5
+ Callable,
6
+ Generator,
7
+ Generic,
8
+ Iterable,
9
+ List,
10
+ Mapping,
11
+ Optional,
12
+ Union,
13
+ )
4
14
 
5
15
  from typing_extensions import ParamSpec, Protocol
6
16
 
@@ -22,6 +32,11 @@ class PyinfraOperation(Generic[P], Protocol):
22
32
  def __call__(
23
33
  self,
24
34
  #
35
+ # op args
36
+ # needs to be first
37
+ #
38
+ *args: P.args,
39
+ #
25
40
  # ConnectorArguments
26
41
  #
27
42
  # Auth
@@ -51,7 +66,7 @@ class PyinfraOperation(Generic[P], Protocol):
51
66
  name: Optional[str] = None,
52
67
  _ignore_errors: bool = False,
53
68
  _continue_on_error: bool = False,
54
- _if: Optional[Callable[[], bool]] = None,
69
+ _if: Union[List[Callable[[], bool]], Callable[[], bool], None] = None,
55
70
  #
56
71
  # ExecutionArguments
57
72
  #
@@ -59,9 +74,7 @@ class PyinfraOperation(Generic[P], Protocol):
59
74
  _run_once: bool = False,
60
75
  _serial: bool = False,
61
76
  #
62
- # The op itself
77
+ # op kwargs
63
78
  #
64
- *args: P.args,
65
79
  **kwargs: P.kwargs,
66
- ) -> "OperationMeta":
67
- ...
80
+ ) -> "OperationMeta": ...
@@ -1,7 +1,9 @@
1
+ from __future__ import annotations
2
+
1
3
  import shlex
2
4
  from inspect import getfullargspec
3
5
  from string import Formatter
4
- from typing import TYPE_CHECKING, Callable, Union
6
+ from typing import IO, TYPE_CHECKING, Callable, Union
5
7
 
6
8
  import gevent
7
9
  from typing_extensions import Unpack
@@ -143,7 +145,7 @@ class StringCommand(PyinfraCommand):
143
145
  class FileUploadCommand(PyinfraCommand):
144
146
  def __init__(
145
147
  self,
146
- src: str,
148
+ src: str | IO,
147
149
  dest: str,
148
150
  remote_temp_filename=None,
149
151
  **kwargs: Unpack[ConnectorArguments],
@@ -173,7 +175,7 @@ class FileDownloadCommand(PyinfraCommand):
173
175
  def __init__(
174
176
  self,
175
177
  src: str,
176
- dest: str,
178
+ dest: str | IO,
177
179
  remote_temp_filename=None,
178
180
  **kwargs: Unpack[ConnectorArguments],
179
181
  ):
@@ -0,0 +1,231 @@
1
+ try:
2
+ import importlib_metadata
3
+ except ImportError:
4
+ import importlib.metadata as importlib_metadata # type: ignore[no-redef]
5
+ from os import path
6
+ from typing import Iterable, Optional, Set
7
+
8
+ from packaging.markers import Marker
9
+ from packaging.requirements import Requirement
10
+ from packaging.specifiers import SpecifierSet
11
+ from packaging.version import Version
12
+
13
+ from pyinfra import __version__, state
14
+
15
+ from .exceptions import PyinfraError
16
+
17
+
18
+ class ConfigDefaults:
19
+ # % of hosts which have to fail for all operations to stop
20
+ FAIL_PERCENT: Optional[int] = None
21
+ # Seconds to timeout SSH connections
22
+ CONNECT_TIMEOUT: int = 10
23
+ # Temporary directory (on the remote side) to use for caching any files/downloads, the default
24
+ # None value first tries to load the hosts' temporary directory configured via "TMPDIR" env
25
+ # variable, falling back to DEFAULT_TEMP_DIR if not set.
26
+ TEMP_DIR: Optional[str] = None
27
+ DEFAULT_TEMP_DIR: str = "/tmp"
28
+ # Gevent pool size (defaults to #of target hosts)
29
+ PARALLEL: int = 0
30
+ # Specify the required pyinfra version (using PEP 440 setuptools specifier)
31
+ REQUIRE_PYINFRA_VERSION: Optional[str] = None
32
+ # Specify any required packages (either using PEP 440 or a requirements file)
33
+ # Note: this can also include pyinfra potentially replacing REQUIRE_PYINFRA_VERSION
34
+ REQUIRE_PACKAGES: Optional[str] = None
35
+ # All these can be overridden inside individual operation calls:
36
+ # Switch to this user (from ssh_user) using su before executing operations
37
+ SU_USER: Optional[str] = None
38
+ USE_SU_LOGIN: bool = False
39
+ SU_SHELL: bool = False
40
+ PRESERVE_SU_ENV: bool = False
41
+ # Use sudo and optional user
42
+ SUDO: bool = False
43
+ SUDO_USER: Optional[str] = None
44
+ PRESERVE_SUDO_ENV: bool = False
45
+ USE_SUDO_LOGIN: bool = False
46
+ SUDO_PASSWORD: Optional[str] = None
47
+ # Use doas and optional user
48
+ DOAS: bool = False
49
+ DOAS_USER: Optional[str] = None
50
+ # Only show errors but don't count as failure
51
+ IGNORE_ERRORS: bool = False
52
+ # Shell to use to execute commands
53
+ SHELL: str = "sh"
54
+
55
+
56
+ config_defaults = {key: value for key, value in ConfigDefaults.__dict__.items() if key.isupper()}
57
+
58
+
59
+ def check_pyinfra_version(version: str):
60
+ if not version:
61
+ return
62
+ running_version = Version(__version__)
63
+ required_versions = SpecifierSet(version)
64
+
65
+ if running_version not in required_versions:
66
+ raise PyinfraError(
67
+ f"pyinfra version requirement not met (requires {version}, running {__version__})"
68
+ )
69
+
70
+
71
+ def _check_requirements(requirements: Iterable[str]) -> Set[Requirement]:
72
+ """
73
+ Check whether each of the given requirements and all their dependencies are
74
+ installed.
75
+
76
+ Or more precisely, this checks that each of the given *requirements* is
77
+ satisfied by some installed *distribution package*, and so on recursively
78
+ for each of the dependencies of those distribution packages. The terminology
79
+ here is as follows:
80
+
81
+ * A *distribution package* is essentially a thing that can be installed with
82
+ ``pip``, from an sdist or wheel or Git repo or so on.
83
+ * A *requirement* is the expectation that a distribution package satisfying
84
+ some constraint is installed.
85
+ * A *dependency* is a requirement specified by a distribution package (as
86
+ opposed to the requirements passed in to this function).
87
+
88
+ So what this function does is start from the given requirements, for each
89
+ one check that it is satisfied by some installed distribution package, and
90
+ if so recursively perform the same check on all the dependencies of that
91
+ distribution package. In short, it's traversing the graph of package
92
+ requirements. It stops whenever it finds a requirement that is not satisfied
93
+ (i.e. a required package that is not installed), or when it runs out of
94
+ requirements to check.
95
+
96
+ .. note::
97
+ This is basically equivalent to ``pkg_resources.require()`` except that
98
+ when ``require()`` succeeds, it will return the list of distribution
99
+ packages that satisfy the given requirements and their dependencies, and
100
+ when it fails, it will raise an exception. This function just returns
101
+ the requirements which were not satisfied instead.
102
+
103
+ :param requirements: The requirements to check for in the set of installed
104
+ packages (along with their dependencies).
105
+ :return: The set of requirements that were not satisfied, which will be
106
+ an empty set if all requirements (recursively) were satisfied.
107
+ """
108
+
109
+ # Based on pkg_resources.require() from setuptools. The implementation of
110
+ # hbutils.system.check_reqs() from the hbutils package was also helpful in
111
+ # clarifying what this is supposed to do.
112
+
113
+ reqs_to_check: Set[Requirement] = set(Requirement(r) for r in requirements)
114
+ reqs_satisfied: Set[Requirement] = set()
115
+ reqs_not_satisfied: Set[Requirement] = set()
116
+
117
+ while reqs_to_check:
118
+ req = reqs_to_check.pop()
119
+ assert req not in reqs_satisfied and req not in reqs_not_satisfied
120
+
121
+ # Check for an installed distribution package with the right name and version
122
+ try:
123
+ dist = importlib_metadata.distribution(req.name)
124
+ except importlib_metadata.PackageNotFoundError:
125
+ # No installed package with the right name
126
+ # This would raise a DistributionNotFound error from pkg_resources.require()
127
+ reqs_not_satisfied.add(req)
128
+ continue
129
+
130
+ if dist.version not in req.specifier:
131
+ # There is a distribution with the right name but wrong version
132
+ # This would raise a VersionConflict error from pkg_resources.require()
133
+ reqs_not_satisfied.add(req)
134
+ continue
135
+
136
+ reqs_satisfied.add(req)
137
+
138
+ # If the distribution package has dependencies of its own, go through
139
+ # those dependencies and for each one add it to the set to be checked if
140
+ # - it's unconditional (no marker)
141
+ # - or it's conditional and the condition is satisfied (the marker
142
+ # evaluates to true) in the current environment
143
+ # Markers can check things like the Python version and system version
144
+ # etc., and/or they can check which extras of the distribution package
145
+ # were required. To facilitate checking extras we have to pass the extra
146
+ # in the environment when calling Marker.evaluate().
147
+ if dist.requires:
148
+ if req.extras:
149
+ extras_envs = [{"extra": extra} for extra in req.extras]
150
+
151
+ def evaluate_marker(marker: Marker) -> bool:
152
+ return any(map(marker.evaluate, extras_envs))
153
+
154
+ else:
155
+
156
+ def evaluate_marker(marker: Marker) -> bool:
157
+ return marker.evaluate()
158
+
159
+ for dist_req_str in dist.requires:
160
+ dist_req = Requirement(dist_req_str)
161
+ if dist_req in reqs_satisfied or dist_req in reqs_not_satisfied:
162
+ continue
163
+ if (not dist_req.marker) or evaluate_marker(dist_req.marker):
164
+ reqs_to_check.add(dist_req)
165
+
166
+ return reqs_not_satisfied
167
+
168
+
169
+ def check_require_packages(requirements_config):
170
+ if not requirements_config:
171
+ return
172
+
173
+ if isinstance(requirements_config, (list, tuple)):
174
+ requirements = requirements_config
175
+ else:
176
+ with open(path.join(state.cwd or "", requirements_config), encoding="utf-8") as f:
177
+ requirements = [line.split("#egg=")[-1] for line in f.read().splitlines()]
178
+
179
+ requirements_not_met = _check_requirements(requirements)
180
+ if requirements_not_met:
181
+ raise PyinfraError(
182
+ "Deploy requirements ({0}) not met: missing {1}".format(
183
+ requirements_config, ", ".join(str(r) for r in requirements_not_met)
184
+ )
185
+ )
186
+
187
+
188
+ config_checkers = {
189
+ "REQUIRE_PYINFRA_VERSION": check_pyinfra_version,
190
+ "REQUIRE_PACKAGES": check_require_packages,
191
+ }
192
+
193
+
194
+ class Config(ConfigDefaults):
195
+ """
196
+ The default/base configuration options for a pyinfra deploy.
197
+ """
198
+
199
+ def __init__(self, **kwargs):
200
+ # Always apply some env
201
+ env = kwargs.pop("ENV", {})
202
+ self.ENV = env
203
+
204
+ config = config_defaults.copy()
205
+ config.update(kwargs)
206
+
207
+ for key, value in config.items():
208
+ setattr(self, key, value)
209
+
210
+ def __setattr__(self, key, value):
211
+ super().__setattr__(key, value)
212
+
213
+ checker = config_checkers.get(key)
214
+ if checker:
215
+ checker(value)
216
+
217
+ def get_current_state(self):
218
+ return [(key, getattr(self, key)) for key in config_defaults.keys()]
219
+
220
+ def set_current_state(self, config_state):
221
+ for key, value in config_state:
222
+ setattr(self, key, value)
223
+
224
+ def lock_current_state(self):
225
+ self._locked_config = self.get_current_state()
226
+
227
+ def reset_locked_state(self):
228
+ self.set_current_state(self._locked_config)
229
+
230
+ def copy(self) -> "Config":
231
+ return Config(**dict(self.get_current_state()))
@@ -1,4 +1,7 @@
1
- import pkg_resources
1
+ try:
2
+ from importlib_metadata import entry_points
3
+ except ImportError:
4
+ from importlib.metadata import entry_points # type: ignore[assignment]
2
5
 
3
6
 
4
7
  def _load_connector(entrypoint):
@@ -8,7 +11,7 @@ def _load_connector(entrypoint):
8
11
  def get_all_connectors():
9
12
  return {
10
13
  entrypoint.name: _load_connector(entrypoint)
11
- for entrypoint in pkg_resources.iter_entry_points("pyinfra.connectors")
14
+ for entrypoint in entry_points(group="pyinfra.connectors")
12
15
  }
13
16
 
14
17
 
@@ -10,6 +10,25 @@ class ConnectError(PyinfraError):
10
10
  """
11
11
 
12
12
 
13
+ class FactError(PyinfraError):
14
+ """
15
+ Exception raised during fact gathering staging if a fact is unable to
16
+ generate output/change state.
17
+ """
18
+
19
+
20
+ class FactTypeError(FactError, TypeError):
21
+ """
22
+ Exception raised when a fact is passed invalid argument types.
23
+ """
24
+
25
+
26
+ class FactValueError(FactError, ValueError):
27
+ """
28
+ Exception raised when a fact is passed invalid argument values.
29
+ """
30
+
31
+
13
32
  class OperationError(PyinfraError):
14
33
  """
15
34
  Exception raised during fact gathering staging if an operation is unable to