pyinfra 3.0b0__py2.py3-none-any.whl → 3.0b2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. pyinfra/api/__init__.py +3 -0
  2. pyinfra/api/arguments.py +12 -5
  3. pyinfra/api/arguments_typed.py +19 -6
  4. pyinfra/api/command.py +5 -3
  5. pyinfra/api/config.py +115 -13
  6. pyinfra/api/connectors.py +5 -2
  7. pyinfra/api/exceptions.py +19 -0
  8. pyinfra/api/facts.py +34 -33
  9. pyinfra/api/host.py +51 -12
  10. pyinfra/api/inventory.py +4 -0
  11. pyinfra/api/operation.py +88 -42
  12. pyinfra/api/operations.py +10 -11
  13. pyinfra/api/state.py +11 -2
  14. pyinfra/api/util.py +24 -16
  15. pyinfra/connectors/base.py +4 -7
  16. pyinfra/connectors/chroot.py +5 -6
  17. pyinfra/connectors/docker.py +13 -19
  18. pyinfra/connectors/dockerssh.py +5 -4
  19. pyinfra/connectors/local.py +7 -7
  20. pyinfra/connectors/ssh.py +46 -25
  21. pyinfra/connectors/terraform.py +9 -6
  22. pyinfra/connectors/util.py +7 -8
  23. pyinfra/connectors/vagrant.py +11 -10
  24. pyinfra/context.py +1 -0
  25. pyinfra/facts/apk.py +2 -0
  26. pyinfra/facts/apt.py +2 -0
  27. pyinfra/facts/brew.py +2 -0
  28. pyinfra/facts/bsdinit.py +2 -0
  29. pyinfra/facts/cargo.py +2 -0
  30. pyinfra/facts/choco.py +3 -1
  31. pyinfra/facts/deb.py +9 -4
  32. pyinfra/facts/dnf.py +2 -0
  33. pyinfra/facts/docker.py +2 -0
  34. pyinfra/facts/files.py +2 -0
  35. pyinfra/facts/gem.py +2 -0
  36. pyinfra/facts/gpg.py +2 -0
  37. pyinfra/facts/hardware.py +30 -22
  38. pyinfra/facts/launchd.py +2 -0
  39. pyinfra/facts/lxd.py +2 -0
  40. pyinfra/facts/mysql.py +12 -6
  41. pyinfra/facts/npm.py +1 -0
  42. pyinfra/facts/openrc.py +2 -0
  43. pyinfra/facts/pacman.py +6 -2
  44. pyinfra/facts/pip.py +2 -0
  45. pyinfra/facts/pkg.py +2 -0
  46. pyinfra/facts/pkgin.py +2 -0
  47. pyinfra/facts/postgres.py +168 -0
  48. pyinfra/facts/postgresql.py +5 -162
  49. pyinfra/facts/rpm.py +12 -9
  50. pyinfra/facts/server.py +10 -13
  51. pyinfra/facts/snap.py +2 -0
  52. pyinfra/facts/systemd.py +28 -10
  53. pyinfra/facts/upstart.py +2 -0
  54. pyinfra/facts/util/packaging.py +3 -2
  55. pyinfra/facts/vzctl.py +2 -0
  56. pyinfra/facts/xbps.py +2 -0
  57. pyinfra/facts/yum.py +2 -0
  58. pyinfra/facts/zypper.py +2 -0
  59. pyinfra/operations/apk.py +3 -1
  60. pyinfra/operations/apt.py +16 -18
  61. pyinfra/operations/brew.py +10 -8
  62. pyinfra/operations/bsdinit.py +5 -3
  63. pyinfra/operations/cargo.py +3 -1
  64. pyinfra/operations/choco.py +3 -1
  65. pyinfra/operations/dnf.py +15 -19
  66. pyinfra/operations/files.py +86 -69
  67. pyinfra/operations/gem.py +3 -1
  68. pyinfra/operations/git.py +18 -16
  69. pyinfra/operations/iptables.py +33 -25
  70. pyinfra/operations/launchd.py +5 -6
  71. pyinfra/operations/lxd.py +7 -4
  72. pyinfra/operations/mysql.py +57 -53
  73. pyinfra/operations/npm.py +8 -1
  74. pyinfra/operations/openrc.py +5 -3
  75. pyinfra/operations/pacman.py +4 -5
  76. pyinfra/operations/pip.py +16 -9
  77. pyinfra/operations/pkg.py +3 -1
  78. pyinfra/operations/pkgin.py +3 -1
  79. pyinfra/operations/postgres.py +349 -0
  80. pyinfra/operations/postgresql.py +18 -335
  81. pyinfra/operations/puppet.py +3 -1
  82. pyinfra/operations/python.py +7 -3
  83. pyinfra/operations/selinux.py +42 -16
  84. pyinfra/operations/server.py +48 -43
  85. pyinfra/operations/snap.py +3 -1
  86. pyinfra/operations/ssh.py +12 -10
  87. pyinfra/operations/systemd.py +13 -9
  88. pyinfra/operations/sysvinit.py +6 -4
  89. pyinfra/operations/upstart.py +5 -3
  90. pyinfra/operations/util/files.py +24 -16
  91. pyinfra/operations/util/packaging.py +53 -37
  92. pyinfra/operations/util/service.py +18 -13
  93. pyinfra/operations/vzctl.py +12 -10
  94. pyinfra/operations/xbps.py +3 -1
  95. pyinfra/operations/yum.py +14 -18
  96. pyinfra/operations/zypper.py +8 -9
  97. pyinfra/version.py +5 -2
  98. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/METADATA +31 -29
  99. pyinfra-3.0b2.dist-info/RECORD +163 -0
  100. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/WHEEL +1 -1
  101. pyinfra_cli/commands.py +3 -2
  102. pyinfra_cli/inventory.py +38 -19
  103. pyinfra_cli/main.py +2 -0
  104. pyinfra_cli/prints.py +27 -105
  105. pyinfra_cli/util.py +3 -1
  106. tests/test_api/test_api_deploys.py +5 -5
  107. tests/test_api/test_api_operations.py +5 -5
  108. tests/test_connectors/test_ssh.py +105 -0
  109. tests/test_connectors/test_terraform.py +11 -8
  110. tests/test_connectors/test_vagrant.py +6 -6
  111. pyinfra-3.0b0.dist-info/RECORD +0 -162
  112. pyinfra_cli/inventory_dsl.py +0 -23
  113. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/LICENSE.md +0 -0
  114. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/entry_points.txt +0 -0
  115. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,163 @@
1
+ pyinfra/__init__.py,sha256=7ZcKHGWk7_nYxsYrbFBB_vJr-J-Ddbc56ZS4sk5ArVw,535
2
+ pyinfra/__main__.py,sha256=aVd00glLz5CMJGXgt1XxbOvC2HluqaowoTOjxgIpBaA,47
3
+ pyinfra/context.py,sha256=S6DvGjjTEjM4u2m9oIAmAaV7kXIJzVwYf725P1muIuY,3395
4
+ pyinfra/local.py,sha256=0bpIRCyDKM6i_jA1i8Ej2qr_iWIF9cUYWutXNdLj8po,2751
5
+ pyinfra/progress.py,sha256=X3hXZ4Flh_L9FE4ZEWxWoG0R4dA5UPd1FCO-Exd5Xtc,4193
6
+ pyinfra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ pyinfra/version.py,sha256=LZf50PHDzEZv65w0G-iMICoQ9US0U5LWHAOEmNtkF3I,216
8
+ pyinfra/api/__init__.py,sha256=suGbKKM-qCduuXFYBEcyswlTqozewtYpdLRhK63PVn0,942
9
+ pyinfra/api/arguments.py,sha256=8BhuJiljFJzaCi9lM8HoEBB9mcnCBilv4Zwdx_349g8,9941
10
+ pyinfra/api/arguments_typed.py,sha256=WQKr0wDtlgJGq-Vkv_oPAz7f-LxjqQv3wJCdvVrePWk,2331
11
+ pyinfra/api/command.py,sha256=SyUlxvhYlXpgFpg0jua8bzQ2KPtVYQXHcvD6AUL2SCI,7226
12
+ pyinfra/api/config.py,sha256=wS6Pi4T4DxNkzO4llNY-ghLxyI5VBJ26uGvgMPZxIKY,9043
13
+ pyinfra/api/connect.py,sha256=Z9wusMLR_jBkKKk5D4AUOj8LHl3H5MsNO5FxAeR4jac,1416
14
+ pyinfra/api/connectors.py,sha256=nie7JuLxMSC6gqPjmjuCisQ11R-eAQDtMMWF6YbSQ48,659
15
+ pyinfra/api/deploy.py,sha256=xo4F7URUf3xzIChRHZn4zwqs_WTjLjZNC9i9eQjAFk8,2756
16
+ pyinfra/api/exceptions.py,sha256=cCbUp1qN1QO0d9aAvOAbRgYpLi0vUI5j7ZqSjcD1_P8,1861
17
+ pyinfra/api/facts.py,sha256=L_Wsrdq-u0zR69klnXWZ_2j9H7m3Oto53X0bQf670X8,10574
18
+ pyinfra/api/host.py,sha256=3lRhlZDRKvCNvpziaTglExy2Ep1wd4YdmGDNY4emAdA,13466
19
+ pyinfra/api/inventory.py,sha256=nPITdNEJ7q71adIqS_OKHsMjD7amUuHEuTl6xzgh1Gk,7734
20
+ pyinfra/api/operation.py,sha256=pB0LpjUqbMLGtoDnsckNw0FRoeo1BopL0fnXVDM1JyU,15112
21
+ pyinfra/api/operations.py,sha256=jvz9ISfwmQnAQVUKLnbrRdD9QHIAAfypo9l5b3fYG1w,10894
22
+ pyinfra/api/state.py,sha256=3dXRjeZJXnzLcbP9E4aogkRPwIg3_kK1h4Tf4FVZock,12622
23
+ pyinfra/api/util.py,sha256=vesFOxExETb-B-oAhWpJJrmALTubg3fkFqi0gYd0pJs,12265
24
+ pyinfra/connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ pyinfra/connectors/base.py,sha256=2fASiV-MvpXgcZAFLM_PUwYx5ax6EHai44ri_oEKeSE,3732
26
+ pyinfra/connectors/chroot.py,sha256=Xd72I8T58KIwKOoc0LXCw91AoEIaiHfRLDcDVTHGJ0o,5931
27
+ pyinfra/connectors/docker.py,sha256=2UNHhXS4hpLo7I19ixDeSd7JR8SNo43VgqsaUIZQZJ4,8741
28
+ pyinfra/connectors/dockerssh.py,sha256=VWHY--jqs3yf-RuPUZXav4vLeON9SzoVC9CUyOJo1rg,8919
29
+ pyinfra/connectors/local.py,sha256=vYOBQS_5rf-dVaPeG4dJlLwBHqkxAzLjj3aDEgbAsx8,6900
30
+ pyinfra/connectors/ssh.py,sha256=ESCZwehJ0Ve6gkjbqGTJrNEGZlu3ItjKLMkmCWq-Z3Y,20989
31
+ pyinfra/connectors/ssh_util.py,sha256=CN_5AdTA3RpiWCnXTrRBjez1NsN59hITDzQmXIkZvoE,3683
32
+ pyinfra/connectors/terraform.py,sha256=G7lK168Fz0jNFetc_7_bPT-RnoaRDksJat0R26fqkUk,3617
33
+ pyinfra/connectors/util.py,sha256=0bvoMsGMD-Tbfaer8NUhWJjBnaNKdmE83PDg48BYjcU,11374
34
+ pyinfra/connectors/vagrant.py,sha256=oEeRglzRmemRXW3vilsp_Xg9qnZMRprRJO9fd_C-f5M,4759
35
+ pyinfra/connectors/sshuserclient/__init__.py,sha256=Qc4RO2wknSWIiNTwOeQ0y2TeiuKHmyWDW2Dz4MOo9CE,44
36
+ pyinfra/connectors/sshuserclient/client.py,sha256=7YSd3QckZuPDRnKzy2FfG3J8zp7CY-jny8tbWwxvKro,9720
37
+ pyinfra/connectors/sshuserclient/config.py,sha256=UMwkvTgAIS7__re6Wz_pwH6EU4kO1-uMQ5zuFakH0v4,2721
38
+ pyinfra/facts/__init__.py,sha256=myTXSOZmAqmU88Fyifn035h9Lr6Gj2mlka_jDcXyKGw,347
39
+ pyinfra/facts/apk.py,sha256=zihlHc6BbBUNQRL3v6wVFUHypfIL7wC6CPLrp4yynHo,518
40
+ pyinfra/facts/apt.py,sha256=8BJX79dBM9t3ceOhP_B5-I008HEJAUj_ijKDVvSxbFo,2035
41
+ pyinfra/facts/brew.py,sha256=aG77URXfNYT50ZpeHyyByiiX08GR6Oz6L0M3UMf9ztI,2302
42
+ pyinfra/facts/bsdinit.py,sha256=KyX4gc8cXKNn3O_NAlKWvEDKvMCnkTWJQg61oTV9ZN0,526
43
+ pyinfra/facts/cargo.py,sha256=mHtT2Yxoqx_g0akDq6jkHFN5VWNHQu70vKvNLZ10-b8,567
44
+ pyinfra/facts/choco.py,sha256=Tf7_DuQY0eZ4SIxV0rlyulrBCg7A0qyPbtTcHgkVP_0,739
45
+ pyinfra/facts/deb.py,sha256=dy5PKdQqy1oLdCUd6iTxCa6yG8agsaxZrPVsjvlDi74,1756
46
+ pyinfra/facts/dnf.py,sha256=7YNicP8EbRvWJQKU0OcwcW3bnIxx9GJ1Fy4qdCFnI0Y,898
47
+ pyinfra/facts/docker.py,sha256=uaY2ui98t3p0a6F6DQq5FiA6y8pOCwsrkFK4JTRlj3Y,1714
48
+ pyinfra/facts/files.py,sha256=ki9-NQnYyt1VzuqKwEOYpX1nz5gJ_ph-ruq-4DS1VLg,11511
49
+ pyinfra/facts/gem.py,sha256=U1oF32LeiBo3ruaFm6hfF3XwNmgyhqamFUAeGn4cD3k,509
50
+ pyinfra/facts/git.py,sha256=rk4NS2SQJiosI6eY2eCy_p9kOP4O8UARRjFi16ObE2w,1294
51
+ pyinfra/facts/gpg.py,sha256=T5yVc_X9BLrDc77Yjk69x9SnP0qRWnKYEpi4JU__pKo,3765
52
+ pyinfra/facts/hardware.py,sha256=je1KjLfr4t-QZxTYei-V3Xqpll4TjbNeQxlHUvADg-c,11877
53
+ pyinfra/facts/iptables.py,sha256=sUkywfHZUXnMZF_KshAnyJufrJvZ9fBYnERSRbwOCRE,3374
54
+ pyinfra/facts/launchd.py,sha256=xjkszKmi9XNkovp7J33WTV19XfQbc5xGJkIBbFRTRhE,704
55
+ pyinfra/facts/lxd.py,sha256=ymBb_SdHbfAlx_tQyRPVa1ij_e68ZDODg1id1E0V8Rg,373
56
+ pyinfra/facts/mysql.py,sha256=0tpNks5be_mBWzIxuEqOyQ9MTYD9rRjeC3Oc_MQ2nns,6038
57
+ pyinfra/facts/npm.py,sha256=l_61BmbAWrO9RlYKUzLUcgicJ4RCMZHD70alrngC7-M,709
58
+ pyinfra/facts/openrc.py,sha256=NitG8BkwUCBrn-3SqM3FDiP4r6tAQTAWuHXTm1-3WGM,1386
59
+ pyinfra/facts/pacman.py,sha256=lU8IQYpQI3tzxRvKZHJD8giM_n17D5abzxIPasbII-A,1070
60
+ pyinfra/facts/pip.py,sha256=ORyrVxu_-8eIr0uSCkI6x4MH-sorDEavml4aozcdrOA,738
61
+ pyinfra/facts/pkg.py,sha256=2N-NlY_f3eQaW3dxCGKaKvu_ymC5_EF0-KASeul0EJc,488
62
+ pyinfra/facts/pkgin.py,sha256=Q1q7m4CCs_na92dDdQIjTuQnJ3axYv5qUdxnAy7e_XY,517
63
+ pyinfra/facts/postgres.py,sha256=M7ppmVvUXy8HSNPqrc8zLPyt8JamAyGs2IO2ocbzSZ8,4187
64
+ pyinfra/facts/postgresql.py,sha256=4nusMVvGhtku86KX4O4vjSxh_MamxZy_kmTQvvy0GhE,223
65
+ pyinfra/facts/rpm.py,sha256=v9OCfTlTSqs4UQWDwnt2tVJkqHOmHZvj7Cd1g4mZ3WI,2091
66
+ pyinfra/facts/selinux.py,sha256=N0zbJrAtBeRBtxZFUHbYTLQ2L4mRV7_Oj3Cj3OA1Npw,4272
67
+ pyinfra/facts/server.py,sha256=ocUPIIveHWfe4K4-7mt7Je7TswWbKmjdu1xAF2VxaD8,19798
68
+ pyinfra/facts/snap.py,sha256=MnZDllRZ1JKLw0SKRFQ1tI6Wi05gvipQPo7m4gpL4fI,1946
69
+ pyinfra/facts/systemd.py,sha256=7uYJyP9yryq9PZT0lRH597HHQFExxebz8og2OrRQUc8,3963
70
+ pyinfra/facts/sysvinit.py,sha256=PS7yMOrVxclywKjF3BIXmxTBgn2_vpSTQrDeOly_j8Q,1490
71
+ pyinfra/facts/upstart.py,sha256=4OSQ257KmYvWWboeXiqKGbhvOmLCMCwwOBgDXKCq1XE,579
72
+ pyinfra/facts/vzctl.py,sha256=LoWXJdFVg7bWcY-aGvSk-teFaAjUjKzQHnR-VuaomZ8,627
73
+ pyinfra/facts/xbps.py,sha256=k7G0L_IgOWIQUs-UswVgs3WzqdjokSCzq0TKT3Tvok0,517
74
+ pyinfra/facts/yum.py,sha256=5nhp7iXLFyEM7MSrBqierSQpTzqyBOwMB-e658Fe838,863
75
+ pyinfra/facts/zypper.py,sha256=hCgm37xwVqgrsG6h2FMNnzW17UH64y8qZbDOVrLglIY,802
76
+ pyinfra/facts/util/__init__.py,sha256=f7HKu8z9_yFC899ajJ3RFiyivioaZeGfOI6nf9GviCs,521
77
+ pyinfra/facts/util/databases.py,sha256=EphGQApzRBXI2nG1FL9h8bozY-o4SgdQgpv9YcnCkxs,730
78
+ pyinfra/facts/util/packaging.py,sha256=4RzjDYb3HrRWZuuPlEfYHgbftLH4r1FOccN5QyIGkrk,1181
79
+ pyinfra/facts/util/win_files.py,sha256=S_IQ5kJD6ZgkEcVHajgh7BIMolLV-1q1ghIcwAS-E1Q,2561
80
+ pyinfra/operations/__init__.py,sha256=SOcW337KXIzD_LH-iJJfq14BQcCs5JzwswJ0PIzDgF4,357
81
+ pyinfra/operations/apk.py,sha256=_0vOjbSiGx6EWv9rvTmQdGnRZQ_NA_Dyd3QW1cTzFgI,2111
82
+ pyinfra/operations/apt.py,sha256=TGNO-ovc24v0T5pBzweB68Z3Hd_130sauGsmNzcXyJI,13663
83
+ pyinfra/operations/brew.py,sha256=aghLE4qyuhhRbt6fgSPV6_5fyWgTohA77Dc0gol19UU,5155
84
+ pyinfra/operations/bsdinit.py,sha256=okQUQDr2H8Z-cAdfdbPJiuGujsHLuV5gpuMZ1UlICEM,1648
85
+ pyinfra/operations/cargo.py,sha256=mXWd6pb0IR6kzJMmPHwXZN-VJ-B_y8AdOFlrRzDQOZI,1104
86
+ pyinfra/operations/choco.py,sha256=8nG0wc1tZEA0L0HTIjgR00IDiONARokyzHyKj-R3xmo,1515
87
+ pyinfra/operations/dnf.py,sha256=3154Rer6dejVB1AK-CqyJhpMVn_djaSDJrVMs62GNcE,5599
88
+ pyinfra/operations/files.py,sha256=9O_HKgmVD_z74jtSivY4pKBPrCDKKHDSy0jAB9QERHU,53639
89
+ pyinfra/operations/gem.py,sha256=2C85sOwIRMHGvmPg4uAlUVf6MokhiA7LLPqzdJRHsBg,1132
90
+ pyinfra/operations/git.py,sha256=b26tQF_4hykTy0FtxiuCkqPk9i8JdZaz-RBhH4X96yw,11789
91
+ pyinfra/operations/iptables.py,sha256=brYa4kMhZKFTu24BNds_1b6sOaG94EfqWEoWrScx-Ck,9341
92
+ pyinfra/operations/launchd.py,sha256=6HWvqoQ74idV_NStOEmFXwu0dmTv7YDvFtsK8An2Lu4,1177
93
+ pyinfra/operations/lxd.py,sha256=bKm9gsgZaruKYSL7OYFMiou-wGP4BzwIMWzjW4AZYrk,1742
94
+ pyinfra/operations/mysql.py,sha256=QcYvEQDlPESzDDoJ-HFwJFzN7ftsbsP892LMRZrmaLQ,19873
95
+ pyinfra/operations/npm.py,sha256=bUmfQsClZ2YcHiihiC7k5widIXIi6lbfx_32iyaAKfo,1499
96
+ pyinfra/operations/openrc.py,sha256=GXFoCHEEKeyQyRvrZcNYx8og4fmgmtzTVAViBzt84TE,1580
97
+ pyinfra/operations/pacman.py,sha256=QMjmsBiiw362nhZY0rEDVQL5A32MG3u7GcmX4q4PzfI,1702
98
+ pyinfra/operations/pip.py,sha256=7PpQvZHnwBGZ60V5b0XKNR4tHLW0MXJo6_6UX7HBtGY,5856
99
+ pyinfra/operations/pkg.py,sha256=rORQBbKeb-6gS0LYu0a0VdiWcDZoovcUONCaf6KMdeQ,2298
100
+ pyinfra/operations/pkgin.py,sha256=zhUyGzKjnUfGoyHbMoYMbeeMzcsiOUpBz1zIzppigJ0,1992
101
+ pyinfra/operations/postgres.py,sha256=LRoedDevQqiM5eX5Lmzb5mr_E9Od0ROVC0j18ZqaR0w,9661
102
+ pyinfra/operations/postgresql.py,sha256=agZjL2W4yxigk9ThIC0V_3wvmcWVdX308aJO24WkN6g,833
103
+ pyinfra/operations/puppet.py,sha256=eDe8D9jQbHYQ4_r4-dmEZfMASKQvj36BR8z_h8aDfw8,861
104
+ pyinfra/operations/python.py,sha256=u569cdPrPesrmzU09nwIPA3bk6TZ-Qv2QP0lJLcO_bw,2021
105
+ pyinfra/operations/selinux.py,sha256=khqWJsr9MOTyZmxP9P4dQ_7KUNlAfo5fx3Nv7kWm49w,5961
106
+ pyinfra/operations/server.py,sha256=TUJ_E61ar1sOYUykX35mYUuwtJRqOpiDZ22HYDP6Vys,36315
107
+ pyinfra/operations/snap.py,sha256=a-QtNE4Dlsavqq425TUIwpEJu4oGw8UlLRkdTFyT1F8,3049
108
+ pyinfra/operations/ssh.py,sha256=wocoaYDlOhhItItAVQCEfnVowTtkg3AP0hQ3mnpUnl0,5634
109
+ pyinfra/operations/systemd.py,sha256=89bq9VMpQ-qnupTa6U8OsBFFoDWUNwWvrLP_LN8uaxE,3944
110
+ pyinfra/operations/sysvinit.py,sha256=WzzthkmWL46MNNY6LsBZ90e37yPj0w2QyUtEAlGBwqY,4078
111
+ pyinfra/operations/upstart.py,sha256=pHb9RGnVhT14A_y6OezfOH-lmniKpiyJqpeoOJl0beE,1978
112
+ pyinfra/operations/vzctl.py,sha256=2u2CDkuDjzHBRQ54HfyfLpLrsbT8U7_05EEjbbhKUiU,3110
113
+ pyinfra/operations/xbps.py,sha256=ru3_srMBUyUXGzAsPo7WwoomfM0AeDglFv8CDqB33B0,1508
114
+ pyinfra/operations/yum.py,sha256=Ig7AzQy1C7I8XM37lWbw0nI5lzFGMoX30P8FV8-V5uA,5600
115
+ pyinfra/operations/zypper.py,sha256=z1CWv2uwWBlCLIhHna7U5DojVoKZYoUYpezJ_FM_xK8,5555
116
+ pyinfra/operations/util/__init__.py,sha256=ZAHjeCXtLo0TIOSfZ9h0Sh5IXXRCspfHs3RR1l8tQCE,366
117
+ pyinfra/operations/util/files.py,sha256=Zcet3ydNVbdT9jss0BDm6RJFyR_s6XTr0isDR60Zubw,3622
118
+ pyinfra/operations/util/packaging.py,sha256=xFtOlEX46ms7g3gDvOOInRVR1RVfgsmhLzFzsJAL_eU,9381
119
+ pyinfra/operations/util/service.py,sha256=RQjnByy-x_KdOSjOLweS12x8pOXpLkTPLlaHsntpYQE,1230
120
+ pyinfra_cli/__init__.py,sha256=G0X7tNdqT45uWuK3aHIKxMdDeCgJ7zHo6vbxoG6zy_8,284
121
+ pyinfra_cli/__main__.py,sha256=8tjq8HUll8P8naFw7pGlygwSz7u9je_MQ-0pqcDlENY,881
122
+ pyinfra_cli/commands.py,sha256=J-mCJYvDebJ8M7o3HreB2zToa871-xO6_KjVhPLeHho,1832
123
+ pyinfra_cli/exceptions.py,sha256=iptx9Zj1od7VgSbOyXs7P8tD4zAZ_fwrQFKPlpPrfS0,4806
124
+ pyinfra_cli/inventory.py,sha256=lggXV9blVqNDT2lgVkq9FQWqYBPOakoLYLbuuVQ8upE,10179
125
+ pyinfra_cli/log.py,sha256=7WEGtmf3ncF1BtXL2icUjyxeRKy-7XrCcQ2Hg4GWX5Y,2201
126
+ pyinfra_cli/main.py,sha256=MsBn0RCD5ce4GY-dDBe6vLXT0LanDrrQZpJOTIYZPBs,19715
127
+ pyinfra_cli/prints.py,sha256=za6V-yjXf-LViBW73qWcyfsajCUnf0NCG-7K0ugOA0k,9170
128
+ pyinfra_cli/util.py,sha256=f3iGIPxlUiQJ5LmUGYbEz0QrySQAKmf9xov9WvHXbrk,6364
129
+ pyinfra_cli/virtualenv.py,sha256=6j9W54JkQLN02SrZZIVwszp0GxlaaDEUWFZjBDHIWNA,2466
130
+ tests/test_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
+ tests/test_api/test_api.py,sha256=Ig2ebkNACYbHcC4_zRkxS9vj5ZEogoPqGx30ErIKChg,2413
132
+ tests/test_api/test_api_arguments.py,sha256=5k7w0_x5cnABEFOk0LQBCt5gU9iTN9lo2XS6MlJTnhQ,1961
133
+ tests/test_api/test_api_command.py,sha256=OW0ESMyS5vo38u17DHeCrSIaIkW9gMU5PSkXL7mRrq0,3204
134
+ tests/test_api/test_api_config.py,sha256=bf0mDrUie3On6zGC_hJBpv-wvSf3LHBIBzUDvkopEt0,708
135
+ tests/test_api/test_api_deploys.py,sha256=h_zbI6CK4K8SdzEr3LEAMPxOf9hnQBdi_suqiNPqHHQ,4200
136
+ tests/test_api/test_api_facts.py,sha256=fUPadZbZ5xaKSF-kmLj7XGwsNiBmfj7Av0gl8fE01Qc,10687
137
+ tests/test_api/test_api_host.py,sha256=U_VW2vTl35vR8EdyIGMKr4y0ydsDLbvHSjZDa99CyNE,1119
138
+ tests/test_api/test_api_inventory.py,sha256=VLbV0MXdRLOPvTXJF156ne6rAx1cBlFfgq_1S79s4tw,2013
139
+ tests/test_api/test_api_operations.py,sha256=GUfnuHK2NoTAGdOT4AbytT9R8i3ZZIvGP7KBfoYcYUQ,20134
140
+ tests/test_api/test_api_util.py,sha256=uHv4oLpoy1_tzOoqFA1zpdvC74SvjitZbxQwp0dmjTs,1716
141
+ tests/test_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
+ tests/test_cli/test_cli.py,sha256=nZQH0zK1SOgIr5VxBuuHH68hyzG4lhwyw_Z7EhjPtf4,6045
143
+ tests/test_cli/test_cli_deploy.py,sha256=KBnnDsiD21h7t1S2JXpEDpiMxh0AFqwxaEl0z78IE9E,4858
144
+ tests/test_cli/test_cli_exceptions.py,sha256=02sjC6rMptuqchgcdjdsVNQbSQYW6HwGutSy6Q6sMs4,3088
145
+ tests/test_cli/test_cli_util.py,sha256=-Ehnj0cO-EkF-6KLxcPPcFeuAUMTz-fKITrxhuiYhV4,2562
146
+ tests/test_cli/test_context_objects.py,sha256=JiUTwQP7yvcqA47Kq9jtdsB_Z8nxGMZN46d9pR--FYA,2130
147
+ tests/test_cli/util.py,sha256=kp_-XsGnTyDgG6IHWorYzl5VD_WLe77dKOH007TDOUE,338
148
+ tests/test_connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
+ tests/test_connectors/test_chroot.py,sha256=QK7YgFPXzHh8y363-tmHvzZ0Ok5PVJWFTDAvwt91eac,5907
150
+ tests/test_connectors/test_docker.py,sha256=0EjkfhCHpLCfL4X-AIdMNw5ASaseY0tbRAn7T_TAkMQ,6566
151
+ tests/test_connectors/test_dockerssh.py,sha256=MaC9IK1OZDiqoIsuLOZBJnPDglsMoPDoL19LQtXsyCE,9303
152
+ tests/test_connectors/test_local.py,sha256=N_FkejDZKu7XLnKeApqfBARYMyxf-hRXCQJrXLHvwRg,7442
153
+ tests/test_connectors/test_ssh.py,sha256=zYL0FbRXzqkYJslhmVeUgSkcHtozhmvZfRcaqDrYKvI,40386
154
+ tests/test_connectors/test_sshuserclient.py,sha256=2PQNLPhNL6lBACc6tQuXmPoog-9L6AdDQNrA-rEw1_8,5734
155
+ tests/test_connectors/test_terraform.py,sha256=Z5MhgDeRDFumu-GlbjMD0ZRkecwBIPP8C8ZVg-mq7C8,3743
156
+ tests/test_connectors/test_util.py,sha256=hQir0WyjH0LEF6xvIyHNyqdI5pkJX6qUR9287MgO2bY,4647
157
+ tests/test_connectors/test_vagrant.py,sha256=27qRB7ftjEPaj4ejBNZ-rR4Ou1AD1VyVcf2XjwZPG3M,3640
158
+ pyinfra-3.0b2.dist-info/LICENSE.md,sha256=gwC95tUll0gwB32tHNkTAasN7Sb6vjWzXa305NwClbI,1076
159
+ pyinfra-3.0b2.dist-info/METADATA,sha256=lISn-ii_LETvqwvTJMl5HZ4oa1jNndtp6M-Q1Q8TSzk,8322
160
+ pyinfra-3.0b2.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
161
+ pyinfra-3.0b2.dist-info/entry_points.txt,sha256=BraEFyquy05M8ch33HZXOHoH_m2BTqejL3xX3NrpzOM,471
162
+ pyinfra-3.0b2.dist-info/top_level.txt,sha256=2K6D1mK35JTSEBgOfEPV-N-uA2SDErxGiE0J-HUMMVI,26
163
+ pyinfra-3.0b2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.3)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any
pyinfra_cli/commands.py CHANGED
@@ -36,7 +36,7 @@ def get_func_and_args(commands):
36
36
 
37
37
 
38
38
  def get_facts_and_args(commands):
39
- facts: list[FactBase] = []
39
+ facts: list[tuple[FactBase, tuple, dict]] = []
40
40
 
41
41
  current_fact = None
42
42
 
@@ -46,7 +46,7 @@ def get_facts_and_args(commands):
46
46
  raise CliError("Invalid fact commands: `{0}`".format(commands))
47
47
 
48
48
  key, value = command.split("=", 1)
49
- current_fact[2][key] = value
49
+ current_fact[2][key] = parse_cli_arg(value)
50
50
  continue
51
51
 
52
52
  if current_fact:
@@ -57,6 +57,7 @@ def get_facts_and_args(commands):
57
57
  raise CliError(f"Invalid fact: `{command}`, should be in the format `module.cls`")
58
58
 
59
59
  fact_cls = try_import_module_attribute(command, prefix="pyinfra.facts")
60
+ assert fact_cls is not None
60
61
  current_fact = (fact_cls, (), {})
61
62
 
62
63
  if current_fact:
pyinfra_cli/inventory.py CHANGED
@@ -1,4 +1,3 @@
1
- import re
2
1
  import socket
3
2
  from collections import defaultdict
4
3
  from os import listdir, path
@@ -81,32 +80,52 @@ def _get_any_tuple_first(item: Union[T, Tuple[T, Any]]) -> T:
81
80
  return item[0] if isinstance(item, tuple) else item
82
81
 
83
82
 
83
+ def _resolves_to_host(maybe_host: str) -> bool:
84
+ """Check if a string resolves to a valid IP address."""
85
+ try:
86
+ # Use getaddrinfo to support IPv6 hosts
87
+ socket.getaddrinfo(maybe_host, port=None)
88
+ return True
89
+ except socket.gaierror:
90
+ return False
91
+
92
+
84
93
  def make_inventory(
85
94
  inventory: str,
86
95
  override_data=None,
87
96
  cwd: Optional[str] = None,
88
97
  group_data_directories=None,
89
98
  ):
90
- inventory_func = None
91
-
92
- # (Un)fortunately the CLI is pretty flexible for inventory inputs; we support a single hostname,
93
- # a Python module.function import or a Python file path. All of these are kind of similar, and
94
- # we want error handling to be a good user experience.
95
- # Thus, we'll check for everything but also drop a warning to the console if the inventory looks
96
- # like either an import or hostname but neither works.
97
- if re.match("[a-zA-Z0-9\\._]+[\\.:][a-zA-Z0-9_]+", inventory):
98
- # First, try loading the inventory as if it's a Python import function
99
+ # (Un)fortunately the CLI is pretty flexible for inventory inputs; we support inventory files, a
100
+ # single hostname, list of hosts, connectors, and python module.function or module:function
101
+ # imports.
102
+ #
103
+ # We check first for an inventory file, a list of hosts or anything with a connector, because
104
+ # (1) an inventory file is a common use case and (2) no other option can have a comma or an @
105
+ # symbol in them.
106
+ is_path_or_host_list_or_connector = (
107
+ path.exists(inventory) or "," in inventory or "@" in inventory
108
+ )
109
+ if not is_path_or_host_list_or_connector:
110
+ # Next, try loading the inventory from a python function. This happens before checking for a
111
+ # single-host inventory, so that your command does not stop working because somebody
112
+ # registered the domain `my.module.name`.
99
113
  inventory_func = try_import_module_attribute(inventory, raise_for_none=False)
100
- if inventory_func is None:
101
- try:
102
- socket.gethostbyname(inventory)
103
- except socket.gaierror:
104
- logger.warning(f"{inventory} is neither a valid Python import or hostname.")
105
-
106
- if inventory_func is None:
107
- # If not an import, load as if from the filesystem *or* comma separated list, which also
108
- # loads any all.py group data files (imported functions do not load group data).
114
+
115
+ # If the inventory does not refer to a module, we finally check if it refers to a reachable
116
+ # host
117
+ if inventory_func is None and _resolves_to_host(inventory):
118
+ is_path_or_host_list_or_connector = True
119
+
120
+ if is_path_or_host_list_or_connector:
121
+ # The inventory is either an inventory file or a (list of) hosts
109
122
  return make_inventory_from_files(inventory, override_data, cwd, group_data_directories)
123
+ elif inventory_func is None:
124
+ logger.warn(
125
+ f"{inventory} is neither an inventory file, a (list of) hosts or connectors "
126
+ "nor refers to a python module"
127
+ )
128
+ return Inventory.empty()
110
129
  else:
111
130
  return make_inventory_from_func(inventory_func, override_data)
112
131
 
pyinfra_cli/main.py CHANGED
@@ -70,6 +70,8 @@ def _print_support(ctx, param, value):
70
70
  is_flag=True,
71
71
  default=False,
72
72
  help="Execute operations immediately on hosts without prompt or checking for changes.",
73
+ envvar="PYINFRA_YES",
74
+ show_envvar=True,
73
75
  )
74
76
  @click.option(
75
77
  "--limit",
pyinfra_cli/prints.py CHANGED
@@ -217,7 +217,7 @@ def pretty_op_name(op_meta):
217
217
 
218
218
  def print_meta(state: "State"):
219
219
  rows: List[Tuple[Callable, Union[List[str], str]]] = [
220
- (logger.info, ["Operation", "Hosts"]),
220
+ (logger.info, ["Operation", "Change", "Conditional Change"]),
221
221
  ]
222
222
 
223
223
  for op_hash in state.get_op_order():
@@ -237,14 +237,22 @@ def print_meta(state: "State"):
237
237
  logger.info,
238
238
  [
239
239
  pretty_op_name(state.op_meta[op_hash]),
240
- "{0}{1}/{2} ({3})".format(
241
- len(hosts_in_op),
242
- f"-{len(hosts_maybe_in_op)}" if hosts_maybe_in_op else "",
243
- len(state.inventory),
244
- truncate(", ".join(sorted(hosts_in_op + hosts_maybe_in_op)), 48),
245
- )
246
- if hosts_in_op or hosts_maybe_in_op
247
- else "No hosts with changes at this time",
240
+ (
241
+ "-"
242
+ if len(hosts_in_op) == 0
243
+ else "{0} ({1})".format(
244
+ len(hosts_in_op),
245
+ truncate(", ".join(sorted(hosts_in_op)), 48),
246
+ )
247
+ ),
248
+ (
249
+ "-"
250
+ if len(hosts_maybe_in_op) == 0
251
+ else "{0} ({1})".format(
252
+ len(hosts_maybe_in_op),
253
+ truncate(", ".join(sorted(hosts_maybe_in_op)), 48),
254
+ )
255
+ ),
248
256
  ],
249
257
  )
250
258
  )
@@ -261,23 +269,21 @@ def print_results(state: "State"):
261
269
  hosts_in_op = 0
262
270
  hosts_in_op_success: list[str] = []
263
271
  hosts_in_op_error: list[str] = []
264
- hosts_in_op_no_attempt: list[str] = []
272
+ hosts_in_op_no_change: list[str] = []
265
273
  for host in state.inventory.iter_activated_hosts():
266
274
  if op_hash not in state.ops[host]:
267
275
  continue
268
276
 
269
277
  hosts_in_op += 1
270
278
 
271
- result = state.ops[host][op_hash].operation_meta.did_succeed()
272
- if result is True:
273
- hosts_in_op_success.append(host.name)
274
- elif result is False:
275
- hosts_in_op_error.append(host.name)
279
+ op_meta = state.ops[host][op_hash].operation_meta
280
+ if op_meta.did_succeed(_raise_if_not_complete=False):
281
+ if op_meta._did_change():
282
+ hosts_in_op_success.append(host.name)
283
+ else:
284
+ hosts_in_op_no_change.append(host.name)
276
285
  else:
277
- hosts_in_op_no_attempt.append(host.name)
278
-
279
- # if not hosts_in_op:
280
- # continue
286
+ hosts_in_op_error.append(host.name)
281
287
 
282
288
  row = [
283
289
  pretty_op_name(state.op_meta[op_hash]),
@@ -292,95 +298,11 @@ def print_results(state: "State"):
292
298
  row.append(f"{len(hosts_in_op_error)}")
293
299
  else:
294
300
  row.append("-")
295
- if hosts_in_op_no_attempt:
296
- row.append(f"{len(hosts_in_op_no_attempt)}")
301
+ if hosts_in_op_no_change:
302
+ row.append(f"{len(hosts_in_op_no_change)}")
297
303
  else:
298
304
  row.append("-")
299
305
 
300
306
  rows.append((logger.info, row))
301
307
 
302
308
  print_rows(rows)
303
-
304
-
305
- def get_fucked(state: "State"):
306
- group_combinations = _get_group_combinations(state.inventory.iter_activated_hosts())
307
- rows: List[Tuple[Callable, Union[List[str], str]]] = []
308
-
309
- for i, (groups, hosts) in enumerate(group_combinations.items(), 1):
310
- if not hosts:
311
- continue
312
-
313
- if groups:
314
- rows.append(
315
- (
316
- logger.info,
317
- "Groups: {0}".format(
318
- click.style(" / ".join(groups), bold=True),
319
- ),
320
- ),
321
- )
322
- else:
323
- rows.append((logger.info, "Ungrouped:"))
324
-
325
- for host in hosts:
326
- # Didn't connect to this host?
327
- if host not in state.activated_hosts:
328
- rows.append(
329
- (
330
- logger.info,
331
- [
332
- host.style_print_prefix("red", bold=True),
333
- click.style("No connection", "red"),
334
- ],
335
- ),
336
- )
337
- continue
338
-
339
- results = state.results[host]
340
-
341
- meta = state.meta[host]
342
- success_ops = results.success_ops
343
- partial_ops = results.partial_ops
344
- # TODO: type meta object
345
- changed_ops = success_ops - meta.ops_no_change # type: ignore
346
- error_ops = results.error_ops
347
- ignored_error_ops = results.ignored_error_ops
348
-
349
- host_args = ("green",)
350
- host_kwargs = {}
351
-
352
- # If all ops got complete
353
- if results.ops == meta.ops:
354
- # We had some errors - but we ignored them - so "warning" color
355
- if error_ops != 0:
356
- host_args = ("yellow",)
357
-
358
- # Ops did not complete!
359
- else:
360
- host_args = ("red",)
361
- host_kwargs["bold"] = True
362
-
363
- changed_str = "Changed: {0}".format(click.style(f"{changed_ops}", bold=True))
364
- if partial_ops:
365
- changed_str = f"{changed_str} ({partial_ops} partial)"
366
-
367
- error_str = "Errors: {0}".format(click.style(f"{error_ops}", bold=True))
368
- if ignored_error_ops:
369
- error_str = f"{error_str} ({ignored_error_ops} ignored)"
370
-
371
- rows.append(
372
- (
373
- logger.info,
374
- [
375
- host.style_print_prefix(*host_args, **host_kwargs),
376
- changed_str,
377
- "No change: {0}".format(click.style(f"{meta.ops_no_change}", bold=True)),
378
- error_str,
379
- ],
380
- ),
381
- )
382
-
383
- if i != len(group_combinations):
384
- rows.append((lambda m: click.echo(m, err=True), []))
385
-
386
- print_rows(rows)
pyinfra_cli/util.py CHANGED
@@ -154,9 +154,11 @@ def try_import_module_attribute(path, prefix=None, raise_for_none=True):
154
154
  if ":" in path:
155
155
  # Allow a.module.name:function syntax
156
156
  mod_path, attr_name = path.rsplit(":", 1)
157
- else:
157
+ elif "." in path:
158
158
  # And also a.module.name.function
159
159
  mod_path, attr_name = path.rsplit(".", 1)
160
+ else:
161
+ return None
160
162
 
161
163
  possible_modules = [mod_path]
162
164
  if prefix:
@@ -40,7 +40,7 @@ class TestDeploysApi(PatchSSHTestCase):
40
40
  run_ops(state)
41
41
 
42
42
  first_op_hash = op_order[0]
43
- assert state.op_meta[first_op_hash].names == {"test_deploy | Server/Shell"}
43
+ assert state.op_meta[first_op_hash].names == {"test_deploy | server.shell"}
44
44
  assert state.ops[somehost][first_op_hash].operation_meta._commands == [
45
45
  StringCommand("echo first command"),
46
46
  ]
@@ -49,7 +49,7 @@ class TestDeploysApi(PatchSSHTestCase):
49
49
  ]
50
50
 
51
51
  second_op_hash = op_order[1]
52
- assert state.op_meta[second_op_hash].names == {"test_deploy | Server/Shell"}
52
+ assert state.op_meta[second_op_hash].names == {"test_deploy | server.shell"}
53
53
  assert state.ops[somehost][second_op_hash].operation_meta._commands == [
54
54
  StringCommand("echo second command"),
55
55
  ]
@@ -104,21 +104,21 @@ class TestDeploysApi(PatchSSHTestCase):
104
104
  run_ops(state)
105
105
 
106
106
  first_op_hash = op_order[0]
107
- assert state.op_meta[first_op_hash].names == {"test_deploy | Server/Shell"}
107
+ assert state.op_meta[first_op_hash].names == {"test_deploy | server.shell"}
108
108
  assert state.ops[somehost][first_op_hash].operation_meta._commands == [
109
109
  StringCommand("echo first command"),
110
110
  ]
111
111
 
112
112
  second_op_hash = op_order[1]
113
113
  assert state.op_meta[second_op_hash].names == {
114
- "test_deploy | test_nested_deploy | Server/Shell",
114
+ "test_deploy | test_nested_deploy | server.shell",
115
115
  }
116
116
  assert state.ops[somehost][second_op_hash].operation_meta._commands == [
117
117
  StringCommand("echo nested command"),
118
118
  ]
119
119
 
120
120
  third_op_hash = op_order[2]
121
- assert state.op_meta[third_op_hash].names == {"test_deploy | Server/Shell"}
121
+ assert state.op_meta[third_op_hash].names == {"test_deploy | server.shell"}
122
122
  assert state.ops[somehost][third_op_hash].operation_meta._commands == [
123
123
  StringCommand("echo second command"),
124
124
  ]
@@ -78,7 +78,7 @@ class TestOperationsApi(PatchSSHTestCase):
78
78
  first_op_hash = op_order[0]
79
79
 
80
80
  # Ensure the op name
81
- assert state.op_meta[first_op_hash].names == {"Files/File"}
81
+ assert state.op_meta[first_op_hash].names == {"files.file"}
82
82
 
83
83
  # Ensure the global kwargs (same for both hosts)
84
84
  somehost_global_arguments = state.ops[somehost][first_op_hash].global_arguments
@@ -390,7 +390,7 @@ class TestOperationsApi(PatchSSHTestCase):
390
390
  state = State(inventory, Config())
391
391
  connect_all(state)
392
392
 
393
- with patch("pyinfra.connectors.ssh.find_executable", lambda x: None):
393
+ with patch("pyinfra.connectors.ssh.which", lambda x: None):
394
394
  with self.assertRaises(OperationError) as context:
395
395
  add_op(state, files.rsync, "src", "dest")
396
396
 
@@ -433,11 +433,11 @@ class TestNestedOperationsApi(PatchSSHTestCase):
433
433
 
434
434
  try:
435
435
  outer_result = server.shell(commands="echo outer")
436
- assert outer_result._combined_output_lines is None
436
+ assert outer_result._combined_output is None
437
437
 
438
438
  def callback():
439
439
  inner_result = server.shell(commands="echo inner")
440
- assert inner_result._combined_output_lines is not None
440
+ assert inner_result._combined_output is not None
441
441
 
442
442
  python.call(function=callback)
443
443
 
@@ -447,7 +447,7 @@ class TestNestedOperationsApi(PatchSSHTestCase):
447
447
 
448
448
  assert len(state.get_op_order()) == 3
449
449
  assert state.results[somehost].success_ops == 3
450
- assert outer_result._combined_output_lines is not None
450
+ assert outer_result._combined_output is not None
451
451
 
452
452
  disconnect_all(state)
453
453
  finally: