duplicity 3.2.1.dev2__tar.gz → 3.2.1.dev3__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 (196) hide show
  1. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/CHANGELOG.md +45 -16
  2. {duplicity-3.2.1.dev2/duplicity.egg-info → duplicity-3.2.1.dev3}/PKG-INFO +1 -3
  3. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/README-INSTALL.md +1 -2
  4. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/README-TESTING.md +2 -1
  5. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/__init__.py +2 -2
  6. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backend_pool.py +2 -1
  7. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/_cf_cloudfiles.py +6 -0
  8. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/_cf_pyrax.py +6 -0
  9. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/b2backend.py +36 -11
  10. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/hubicbackend.py +5 -0
  11. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/imapbackend.py +1 -1
  12. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/par2backend.py +21 -4
  13. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/rsyncbackend.py +25 -1
  14. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/ssh_pexpect_backend.py +2 -2
  15. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/cli_data.py +215 -36
  16. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/cli_main.py +93 -14
  17. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/cli_util.py +116 -1
  18. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/config.py +2 -1
  19. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/dup_collections.py +10 -8
  20. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/dup_main.py +68 -61
  21. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/file_naming.py +15 -1
  22. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/gpg.py +217 -246
  23. duplicity-3.2.1.dev3/duplicity/gpginterface.py +702 -0
  24. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/selection.py +43 -119
  25. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/tempdir.py +6 -5
  26. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3/duplicity.egg-info}/PKG-INFO +1 -3
  27. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity.egg-info/SOURCES.txt +1 -0
  28. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity.egg-info/requires.txt +0 -2
  29. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/man/duplicity.1 +25 -1
  30. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/pyproject.toml +17 -9
  31. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/requirements.txt +0 -2
  32. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/setup.py +2 -1
  33. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/AUTHORS.md +0 -0
  34. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/COPYING +0 -0
  35. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/README-ARCH.md +0 -0
  36. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/README-LOG.md +0 -0
  37. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/README-RELEASE.md +0 -0
  38. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/README-REPO.md +0 -0
  39. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/README-SNAP.md +0 -0
  40. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/README.md +0 -0
  41. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/__main__.py +0 -0
  42. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/_librsync_ctypes.py +0 -0
  43. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/_librsyncmodule.c +0 -0
  44. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/argparse311.py +0 -0
  45. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backend.py +0 -0
  46. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/__init__.py +0 -0
  47. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/_testbackend.py +0 -0
  48. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/adbackend.py +0 -0
  49. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/azurebackend.py +0 -0
  50. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/boxbackend.py +0 -0
  51. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/cfbackend.py +0 -0
  52. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/dpbxbackend.py +0 -0
  53. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/gdocsbackend.py +0 -0
  54. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/gdrivebackend.py +0 -0
  55. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/giobackend.py +0 -0
  56. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/hsibackend.py +0 -0
  57. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/idrivedbackend.py +0 -0
  58. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/jottacloudbackend.py +0 -0
  59. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/lftpbackend.py +0 -0
  60. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/localbackend.py +0 -0
  61. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/mediafirebackend.py +0 -0
  62. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/megabackend.py +0 -0
  63. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/megav2backend.py +0 -0
  64. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/megav3backend.py +0 -0
  65. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/multibackend.py +0 -0
  66. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/ncftpbackend.py +0 -0
  67. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/onedrivebackend.py +0 -0
  68. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/pcabackend.py +0 -0
  69. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/pydrivebackend.py +0 -0
  70. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/pyrax_identity/__init__.py +0 -0
  71. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/pyrax_identity/hubic.py +0 -0
  72. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/rclonebackend.py +0 -0
  73. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/s3_boto3_backend.py +0 -0
  74. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/slatebackend.py +0 -0
  75. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/ssh_paramiko_backend.py +0 -0
  76. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/swiftbackend.py +0 -0
  77. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/sxbackend.py +0 -0
  78. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/tahoebackend.py +0 -0
  79. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/webdavbackend.py +0 -0
  80. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/backends/xorrisobackend.py +0 -0
  81. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/cached_ops.py +0 -0
  82. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/diffdir.py +0 -0
  83. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/dup_tarfile.py +0 -0
  84. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/dup_temp.py +0 -0
  85. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/dup_time.py +0 -0
  86. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/errors.py +0 -0
  87. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/globmatch.py +0 -0
  88. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/lazy.py +0 -0
  89. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/librsync.py +0 -0
  90. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/log.py +0 -0
  91. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/manifest.py +0 -0
  92. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/patchdir.py +0 -0
  93. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/path.py +0 -0
  94. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/progress.py +0 -0
  95. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/robust.py +0 -0
  96. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/statistics.py +0 -0
  97. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity/util.py +0 -0
  98. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity.egg-info/dependency_links.txt +0 -0
  99. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity.egg-info/entry_points.txt +0 -0
  100. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/duplicity.egg-info/top_level.txt +0 -0
  101. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/af_ZA/af_ZA.po +0 -0
  102. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/af_ZA.po +0 -0
  103. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ar_SA/ar_SA.po +0 -0
  104. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ar_SA.po +0 -0
  105. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ca_ES/ca_ES.po +0 -0
  106. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ca_ES.po +0 -0
  107. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/cs_CZ/cs_CZ.po +0 -0
  108. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/cs_CZ.po +0 -0
  109. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/da_DK/da_DK.po +0 -0
  110. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/da_DK.po +0 -0
  111. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/de_AT/de_AT.po +0 -0
  112. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/de_AT.po +0 -0
  113. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/de_DE/de_DE.po +0 -0
  114. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/de_DE.po +0 -0
  115. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/duplicity.pot +0 -0
  116. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/el_GR/el_GR.po +0 -0
  117. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/el_GR.po +0 -0
  118. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/en_AU/en_AU.po +0 -0
  119. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/en_AU.po +0 -0
  120. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/en_GB/en_GB.po +0 -0
  121. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/en_GB.po +0 -0
  122. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/en_PR/en_PR.po +0 -0
  123. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/en_PR.po +0 -0
  124. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/en_US/en_US.po +0 -0
  125. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/en_US.po +0 -0
  126. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_EM/es_EM.po +0 -0
  127. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_EM.po +0 -0
  128. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_ES/es_ES.po +0 -0
  129. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_ES.po +0 -0
  130. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_MX/es_MX.po +0 -0
  131. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_MX.po +0 -0
  132. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_PR/es_PR.po +0 -0
  133. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_PR.po +0 -0
  134. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_US/es_US.po +0 -0
  135. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/es_US.po +0 -0
  136. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/fi_FI/fi_FI.po +0 -0
  137. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/fi_FI.po +0 -0
  138. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/fr_FR/fr_FR.po +0 -0
  139. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/fr_FR.po +0 -0
  140. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/he_IL/he_IL.po +0 -0
  141. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/he_IL.po +0 -0
  142. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/hu_HU/hu_HU.po +0 -0
  143. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/hu_HU.po +0 -0
  144. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/it_IT/it_IT.po +0 -0
  145. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/it_IT.po +0 -0
  146. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ja_JP/ja_JP.po +0 -0
  147. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ja_JP.po +0 -0
  148. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ka_GE/ka_GE.po +0 -0
  149. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ka_GE.po +0 -0
  150. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ko_KR/ko_KR.po +0 -0
  151. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ko_KR.po +0 -0
  152. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/nl_BE/nl_BE.po +0 -0
  153. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/nl_BE.po +0 -0
  154. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/nl_NL/nl_NL.po +0 -0
  155. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/nl_NL.po +0 -0
  156. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/nl_SR/nl_SR.po +0 -0
  157. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/nl_SR.po +0 -0
  158. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/no_NO/no_NO.po +0 -0
  159. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/no_NO.po +0 -0
  160. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/pl_PL/pl_PL.po +0 -0
  161. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/pl_PL.po +0 -0
  162. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/pt_BR/pt_BR.po +0 -0
  163. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/pt_BR.po +0 -0
  164. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/pt_PT/pt_PT.po +0 -0
  165. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/pt_PT.po +0 -0
  166. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ro_RO/ro_RO.po +0 -0
  167. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ro_RO.po +0 -0
  168. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ru_BY/ru_BY.po +0 -0
  169. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ru_BY.po +0 -0
  170. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ru_MD/ru_MD.po +0 -0
  171. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ru_MD.po +0 -0
  172. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ru_RU/ru_RU.po +0 -0
  173. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ru_RU.po +0 -0
  174. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ru_UA/ru_UA.po +0 -0
  175. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/ru_UA.po +0 -0
  176. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/sr_SP/sr_SP.po +0 -0
  177. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/sr_SP.po +0 -0
  178. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/sv_SE/sv_SE.po +0 -0
  179. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/sv_SE.po +0 -0
  180. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/tr_TR/tr_TR.po +0 -0
  181. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/tr_TR.po +0 -0
  182. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/uk_UA/uk_UA.po +0 -0
  183. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/uk_UA.po +0 -0
  184. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/vi_VN/vi_VN.po +0 -0
  185. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/vi_VN.po +0 -0
  186. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_CN/zh_CN.po +0 -0
  187. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_CN.po +0 -0
  188. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_HK/zh_HK.po +0 -0
  189. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_HK.po +0 -0
  190. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_MO/zh_MO.po +0 -0
  191. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_MO.po +0 -0
  192. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_SG/zh_SG.po +0 -0
  193. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_SG.po +0 -0
  194. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_TW/zh_TW.po +0 -0
  195. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/po/zh_TW.po +0 -0
  196. {duplicity-3.2.1.dev2 → duplicity-3.2.1.dev3}/setup.cfg +0 -0
@@ -1,15 +1,35 @@
1
1
 
2
- (Unreleased) / 2026-08-20
2
+ (Unreleased) / 2026-09-23
3
3
  =========================
4
4
 
5
5
 
6
6
 
7
+ rel.3.2.1.dev3 / 2026-09-23
8
+ ===========================
9
+
10
+
11
+ rel.3.3.1.dev3 / 2026-09-22
12
+ ===========================
13
+
14
+ * [`d7da150b`](https://gitlab.com/duplicity/duplicity/-/commit/d7da150b):new: Create subpath in rsyncd.
15
+ * [`e181a9e9`](https://gitlab.com/duplicity/duplicity/-/commit/e181a9e9):chg: Improve error handling and signature file filtering logic; add unit tests for B2 and PAR2 backends
16
+ * [`58a54680`](https://gitlab.com/duplicity/duplicity/-/commit/58a54680):chg: Add regex cache invalidation for file prefix changes; update tests
17
+ * [`fcd6920a`](https://gitlab.com/duplicity/duplicity/-/commit/fcd6920a):chg: Add deprecation warnings for CloudFiles, Pyrax, and Hubic backends
18
+ * [`1842e4de`](https://gitlab.com/duplicity/duplicity/-/commit/1842e4de):chg: Remove `python3-gnupg` and restore `gpginterface` module and unit tests.
19
+ * [`a201453e`](https://gitlab.com/duplicity/duplicity/-/commit/a201453e):chg: Plan to remove obsolete Pyrax, CloudFiles, and Hubic backends; standardize on python-swiftclient
20
+ * [`abdf9a0e`](https://gitlab.com/duplicity/duplicity/-/commit/abdf9a0e):chg: Remove unused gnupg import from gpg.py for cleanup.
21
+ * [`bd649791`](https://gitlab.com/duplicity/duplicity/-/commit/bd649791):chg: Split wildcard and multiline imports into individual lines for improved clarity and compliance with coding standards
22
+ * [`993cc651`](https://gitlab.com/duplicity/duplicity/-/commit/993cc651):chg: Decouple selection parsing from core engine and refactor tests
23
+ * [`1af57ea4`](https://gitlab.com/duplicity/duplicity/-/commit/1af57ea4):chg: Add support and tests for new CLI options
24
+ * [`df643666`](https://gitlab.com/duplicity/duplicity/-/commit/df643666):chg: Update Python3 version and dependencies in `debian/control`
25
+ * [`7514a7e2`](https://gitlab.com/duplicity/duplicity/-/commit/7514a7e2):fix: Correct string formatting in help output and improve test stability
26
+ * [`c179caf1`](https://gitlab.com/duplicity/duplicity/-/commit/c179caf1):fix: Fix GPG sleep processes on verify, modernize tests, and update guidelines
27
+ * [`90f9137e`](https://gitlab.com/duplicity/duplicity/-/commit/90f9137e):fix: Fix subpath creation for rsync #943
28
+ * [`ed58fae5`](https://gitlab.com/duplicity/duplicity/-/commit/ed58fae5):fix: Restore Python versions, dependencies, and revert migration to 'python-gnupg'.
29
+
7
30
  rel.3.2.1.dev2 / 2026-08-20
8
31
  ===========================
9
32
 
10
- * [`77c5107e`](https://gitlab.com/duplicity/duplicity/-/commit/77c5107e):new: Add get_version() to librsync to retrieve underlying library version
11
- * [`b839f2c8`](https://gitlab.com/duplicity/duplicity/-/commit/b839f2c8):new: Add pure Python librsync implementation using ctypes as fallback
12
- * [`ba7957c3`](https://gitlab.com/duplicity/duplicity/-/commit/ba7957c3):new: Add coverage configuration and Makefile targets for testing.
13
33
  * [`855c6f1c`](https://gitlab.com/duplicity/duplicity/-/commit/855c6f1c):chg: Remove outdated comment for `python3-gnupg` in `debian/control`
14
34
  * [`22fae925`](https://gitlab.com/duplicity/duplicity/-/commit/22fae925):chg: Sync README files in `setup.py` and clean up verbosity flags
15
35
  * [`978355b4`](https://gitlab.com/duplicity/duplicity/-/commit/978355b4):chg: Enable verbose mode in debian/rules
@@ -17,11 +37,23 @@ rel.3.2.1.dev2 / 2026-08-20
17
37
  * [`ba71d094`](https://gitlab.com/duplicity/duplicity/-/commit/ba71d094):chg: Update setuptools to >=61.0.0 in dev dependencies and `debian/rules`
18
38
  * [`2b55864a`](https://gitlab.com/duplicity/duplicity/-/commit/2b55864a):chg: Simplify `gnupg` import logic in `gpg.py`
19
39
  * [`80abbd02`](https://gitlab.com/duplicity/duplicity/-/commit/80abbd02):chg: Adjust dependencies in `requirements.txt` and `debian/control`
40
+
41
+ rel.3.2.1.dev1 / 2026-08-15
42
+ ===========================
43
+
20
44
  * [`df52d45b`](https://gitlab.com/duplicity/duplicity/-/commit/df52d45b):chg: Add `python3-gnupg` as a build dependency in `debian/control`
21
45
  * [`057c7d0a`](https://gitlab.com/duplicity/duplicity/-/commit/057c7d0a):chg: Update doc cleanup pattern in `debian/rules`
22
46
  * [`4eaee861`](https://gitlab.com/duplicity/duplicity/-/commit/4eaee861):chg: Update doc cleanup to remove `duplicity-*` files in `debian/rules`
23
47
  * [`7cd8ddb6`](https://gitlab.com/duplicity/duplicity/-/commit/7cd8ddb6):chg: Add `get_data_files` for dynamic data file handling in `setup.py`
24
48
  * [`e9bf8843`](https://gitlab.com/duplicity/duplicity/-/commit/e9bf8843):chg: Simplify doc handling by removing outdated duplicity docs
49
+ * [`22da1a0d`](https://gitlab.com/duplicity/duplicity/-/commit/22da1a0d):fix: Resolve PEP8 style issues and whitespace in backend and main modules
50
+
51
+ rel.3.2.1.dev0 / 2026-08-11
52
+ ===========================
53
+
54
+ * [`77c5107e`](https://gitlab.com/duplicity/duplicity/-/commit/77c5107e):new: Add get_version() to librsync to retrieve underlying library version
55
+ * [`b839f2c8`](https://gitlab.com/duplicity/duplicity/-/commit/b839f2c8):new: Add pure Python librsync implementation using ctypes as fallback
56
+ * [`ba7957c3`](https://gitlab.com/duplicity/duplicity/-/commit/ba7957c3):new: Add coverage configuration and Makefile targets for testing.
25
57
  * [`4bc93712`](https://gitlab.com/duplicity/duplicity/-/commit/4bc93712):chg: Update dependencies, streamline configs, and refine CI
26
58
  * [`ca78d6c5`](https://gitlab.com/duplicity/duplicity/-/commit/ca78d6c5):chg: Update release-prep script to use `check_tags`
27
59
  * [`60ae51f3`](https://gitlab.com/duplicity/duplicity/-/commit/60ae51f3):chg: Update release-prep script to fix tag removal and file refs
@@ -34,7 +66,6 @@ rel.3.2.1.dev2 / 2026-08-20
34
66
  * [`1dee9e31`](https://gitlab.com/duplicity/duplicity/-/commit/1dee9e31):chg: b2backend prefer b2sdk.v3
35
67
  * [`4f4e052e`](https://gitlab.com/duplicity/duplicity/-/commit/4f4e052e):chg: Cleanup some minor issues
36
68
  * [`1e0a97dc`](https://gitlab.com/duplicity/duplicity/-/commit/1e0a97dc):chg: Format with Black/PEP8 and ensure file flush before rename
37
- * [`22da1a0d`](https://gitlab.com/duplicity/duplicity/-/commit/22da1a0d):fix: Resolve PEP8 style issues and whitespace in backend and main modules
38
69
  * [`06858c9a`](https://gitlab.com/duplicity/duplicity/-/commit/06858c9a):fix: Replace `os.system` calls with safer Python alternatives.
39
70
  * [`da745307`](https://gitlab.com/duplicity/duplicity/-/commit/da745307):fix: Add --ignore-installed flag for pip in Dockerfiles
40
71
  * [`883cca1e`](https://gitlab.com/duplicity/duplicity/-/commit/883cca1e):fix: restore issue: AssertionError: (b'keys', [...]) not empty
@@ -50,6 +81,11 @@ rel.3.2.1.dev2 / 2026-08-20
50
81
  * [`9819e4d4`](https://gitlab.com/duplicity/duplicity/-/commit/9819e4d4):fix: Add get_last_continuous_volume for reliable backup resumption
51
82
  * [`5d737d07`](https://gitlab.com/duplicity/duplicity/-/commit/5d737d07):fix: Postpone metadata promotion to prevent orphaned cache files
52
83
 
84
+ rel.3.2.0.2 / 2026-08-22
85
+ ========================
86
+
87
+ * [`f7ccc81b`](https://gitlab.com/duplicity/duplicity/-/commit/f7ccc81b):chg: Update Python3 version and dependencies in `debian/control`
88
+
53
89
  rel.3.2.0.1 / 2026-08-15
54
90
  ========================
55
91
 
@@ -61,17 +97,6 @@ rel.3.2.0.1 / 2026-08-15
61
97
  * [`f0fb534c`](https://gitlab.com/duplicity/duplicity/-/commit/f0fb534c):chg: Update dependencies, streamline configs, and refine CI
62
98
  * [`6d719e1c`](https://gitlab.com/duplicity/duplicity/-/commit/6d719e1c):fix: Resolve PEP8 style issues and whitespace in backend and main modules
63
99
 
64
- rel.3.2.1.dev1 / 2026-08-15
65
- ===========================
66
-
67
- * [`29b7ca68`](https://gitlab.com/duplicity/duplicity/-/commit/29b7ca68):chg: Add `python3-gnupg` as a build dependency in `debian/control`
68
- * [`d5ab54d3`](https://gitlab.com/duplicity/duplicity/-/commit/d5ab54d3):chg: Update doc cleanup pattern in `debian/rules`
69
- * [`6fbffc54`](https://gitlab.com/duplicity/duplicity/-/commit/6fbffc54):chg: Update doc cleanup to remove `duplicity-*` files in `debian/rules`
70
- * [`bf4b9c5d`](https://gitlab.com/duplicity/duplicity/-/commit/bf4b9c5d):chg: Add `get_data_files` for dynamic data file handling in `setup.py`
71
- * [`c88e9239`](https://gitlab.com/duplicity/duplicity/-/commit/c88e9239):chg: Simplify doc handling by removing outdated duplicity docs
72
- * [`e05cf2f2`](https://gitlab.com/duplicity/duplicity/-/commit/e05cf2f2):chg: Update dependencies, streamline configs, and refine CI
73
- * [`3bced29a`](https://gitlab.com/duplicity/duplicity/-/commit/3bced29a):fix: Resolve PEP8 style issues and whitespace in backend and main modules
74
-
75
100
  rel.3.2.0 / 2026-08-10
76
101
  ======================
77
102
 
@@ -105,6 +130,10 @@ rel.3.2.0 / 2026-08-10
105
130
  * [`c823ed36`](https://gitlab.com/duplicity/duplicity/-/commit/c823ed36):fix: Could not release lockfile
106
131
  * [`3d9eab94`](https://gitlab.com/duplicity/duplicity/-/commit/3d9eab94):fix: Comprehensive fix for backup, restart, and cleanup logic.
107
132
 
133
+ rel.3.1.1.dev0 / 2026-06-16
134
+ ===========================
135
+
136
+
108
137
  rel.3.1.0 / 2026-06-16
109
138
  ======================
110
139
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: duplicity
3
- Version: 3.2.1.dev2
3
+ Version: 3.2.1.dev3
4
4
  Summary: Encrypted backup using rsync algorithm
5
5
  Author-email: Kenneth Loafman <kenneth@loafman.com>
6
6
  Maintainer: Edgar Soldin, Thomas Laubrock
@@ -27,11 +27,9 @@ Requires-Python: <3.15,>=3.10
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: COPYING
29
29
  License-File: AUTHORS.md
30
- Requires-Dist: cryptography==43.0.3
31
30
  Requires-Dist: fasteners>=0.19
32
31
  Requires-Dist: httplib2
33
32
  Requires-Dist: pysocks
34
- Requires-Dist: python-gnupg
35
33
  Requires-Dist: requests
36
34
  Requires-Dist: requests-oauthlib
37
35
  Requires-Dist: azure-storage-blob
@@ -22,6 +22,7 @@ sudo apt-get install -y \
22
22
  par2 \
23
23
  python3-dev \
24
24
  python3-lxml \
25
+ python3-cryptography \
25
26
  python3-pip \
26
27
  python3-venv \
27
28
  python3 \
@@ -85,7 +86,6 @@ sudo apt-get install -y \
85
86
  python3-fasteners \
86
87
  python3-httplib2 \
87
88
  python3-socks \
88
- python3-gnupg \
89
89
  python3-requests \
90
90
  python3-requests-oauthlib \
91
91
  python3-azure-storage-blob \
@@ -130,7 +130,6 @@ sudo apt-get install -y \
130
130
  python3-fasteners \
131
131
  python3-httplib2 \
132
132
  python3-socks \
133
- python3-gnupg \
134
133
  python3-requests \
135
134
  python3-requests-oauthlib \
136
135
  python3-azure-storage-blob \
@@ -16,7 +16,7 @@ environment. You can run tests on your branch as follows:
16
16
 
17
17
  Please test your branch using this method and ensure all tests pass before submitting a merge request.
18
18
 
19
- The decorator `@unittest.expectedFailure` can be used to commit a known-failing test case without breaking the test
19
+ The decorator `@pytest.mark.xfail` can be used to commit a known-failing test case without breaking the test
20
20
  suite, for example to exhibit the behaviour in a bug report before it has been fixed.
21
21
 
22
22
  ## Manual testing and running individual tests
@@ -34,3 +34,4 @@ See _Dependencies for testing_ to setup your environment.
34
34
  ## Dependencies for testing
35
35
  If you should prefer to execute the tests locally without using Docker, see [README-INSTALL.md](README-INSTALL.md) for
36
36
  comprehensive `apt` commands to set up your environment (see "APT Only Installation (Development)").
37
+ Duplicity rely on some python packages provided by the system/distribution, to avoid compilations issues if installed via pip.
@@ -29,7 +29,7 @@ orchestration.
29
29
 
30
30
  import gettext
31
31
 
32
- __version__: str = "3.2.1.dev2"
33
- __reldate__: str = "August 20, 2026"
32
+ __version__: str = "3.2.1.dev3"
33
+ __reldate__: str = "September 23, 2026"
34
34
 
35
35
  gettext.install("duplicity", names=["ngettext"])
@@ -332,7 +332,8 @@ class BackendPool:
332
332
 
333
333
  # code to run/test the pool independent, not relevant for duplicity
334
334
  if __name__ == "__main__":
335
- from duplicity import config, log
335
+ from duplicity import config
336
+ from duplicity import log
336
337
 
337
338
  log.setup()
338
339
  log.add_file("/tmp/tmp.log")
@@ -42,6 +42,12 @@ class CloudFilesBackend(duplicity.backend.Backend):
42
42
 
43
43
  :param ParsedUrl parsed_url: The parsed URL.
44
44
  """
45
+ log.Warn(
46
+ "DEPRECATION NOTICE: The cloudfiles backend will be removed with the next major version release. "
47
+ "It is based on the outdated pyrax library that is no longer being developed or supported. "
48
+ "As instant replacement consider using either `swift://` or `rclone://` backend."
49
+ )
50
+
45
51
  super().__init__(parsed_url)
46
52
  try:
47
53
  from cloudfiles import Connection
@@ -44,6 +44,12 @@ class PyraxBackend(duplicity.backend.Backend):
44
44
  """
45
45
  duplicity.backend.Backend.__init__(self, parsed_url)
46
46
 
47
+ log.Warn(
48
+ "DEPRECATION NOTICE: The cloudfiles pyrax backend will be removed with the next major version release. "
49
+ "It is based on the outdated python-cloudfiles library that is no longer being developed or supported. "
50
+ "As instant replacement consider using either `swift://` or `rclone://` backend."
51
+ )
52
+
47
53
  try:
48
54
  import pyrax
49
55
  except ImportError as e:
@@ -217,10 +217,24 @@ class B2Backend(duplicity.backend.Backend):
217
217
  log.Log(f"Delete: {full_filename}", log.INFO)
218
218
 
219
219
  if config.b2_hide_files:
220
- self.bucket.hide_file(full_filename)
220
+ try:
221
+ self.bucket.hide_file(full_filename)
222
+ except Exception as e:
223
+ code = self._error_code("delete", e)
224
+ if code == log.ErrorCode.backend_not_found:
225
+ log.Debug(f"B2Backend._delete: file {full_filename} not found, already deleted")
226
+ return
227
+ raise
221
228
  else:
222
- file_version_info = self.file_info(quote_plus(full_filename, "/"))
223
- self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)
229
+ try:
230
+ file_version_info = self.file_info(quote_plus(full_filename, "/"))
231
+ self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)
232
+ except Exception as e:
233
+ code = self._error_code("delete", e)
234
+ if code == log.ErrorCode.backend_not_found:
235
+ log.Debug(f"B2Backend._delete: file {full_filename} not found, already deleted")
236
+ return
237
+ raise
224
238
 
225
239
  def _query(self, filename):
226
240
  """
@@ -231,14 +245,25 @@ class B2Backend(duplicity.backend.Backend):
231
245
  :rtype: dict
232
246
  """
233
247
  log.Log(f"Query: {self.path}{os.fsdecode(filename)}", log.INFO)
234
- file_version_info = self.file_info(quote_plus(self.path + os.fsdecode(filename), "/"))
235
- return {
236
- "size": (
237
- int(file_version_info.size)
238
- if file_version_info is not None and file_version_info.size is not None
239
- else -1
240
- )
241
- }
248
+ try:
249
+ file_version_info = self.file_info(quote_plus(self.path + os.fsdecode(filename), "/"))
250
+ return {
251
+ "size": (
252
+ int(file_version_info.size)
253
+ if file_version_info is not None and file_version_info.size is not None
254
+ else -1
255
+ )
256
+ }
257
+ except Exception as e:
258
+ code = self._error_code("query", e)
259
+ if code == log.ErrorCode.backend_not_found:
260
+ return {"size": -1}
261
+ raise
262
+
263
+ def _error_code(self, operation, e):
264
+ if e.__class__.__name__ in ("FileNotPresent", "NonExistentBucket") or str(e) == "File not found":
265
+ return log.ErrorCode.backend_not_found
266
+ return log.ErrorCode.backend_error
242
267
 
243
268
  def file_info(self, filename):
244
269
  if self.v_num >= [1, 9, 0]:
@@ -46,6 +46,11 @@ class HubicBackend(PyraxBackend):
46
46
  """
47
47
  duplicity.backend.Backend.__init__(self, parsed_url)
48
48
 
49
+ log.Warn(
50
+ "DEPRECATION NOTICE: The hubic backend will be removed with the next major version release. "
51
+ "the hubiC service was shut down in 2022. the pyrax access library is outdated."
52
+ )
53
+
49
54
  try:
50
55
  import pyrax
51
56
  except ImportError as e:
@@ -47,7 +47,7 @@ import ssl
47
47
  socket.sslerror = ssl.SSLError
48
48
 
49
49
  from duplicity import config
50
- from duplicity.errors import * # pylint: disable=unused-wildcard-import
50
+ from duplicity.errors import BackendException
51
51
  import duplicity.backend
52
52
 
53
53
 
@@ -202,14 +202,24 @@ class Par2Backend(backend.Backend):
202
202
  """
203
203
  delete given filename and its .par2 files
204
204
  """
205
- self.wrapped_backend._delete(filename)
205
+ try:
206
+ self.wrapped_backend._delete(filename)
207
+ except Exception as e:
208
+ code = backend._get_code_from_exception(self.wrapped_backend, "delete", e)
209
+ if code != log.ErrorCode.backend_not_found:
210
+ raise
206
211
 
207
212
  remote_list = self.unfiltered_list()
208
213
 
209
214
  c = re.compile(f"{os.fsdecode(filename)}(?:\\.vol[\\d+]*)?\\.par2")
210
215
  for remote_filename in remote_list:
211
216
  if c.match(os.fsdecode(remote_filename)):
212
- self.wrapped_backend._delete(os.fsencode(remote_filename))
217
+ try:
218
+ self.wrapped_backend._delete(os.fsencode(remote_filename))
219
+ except Exception as e:
220
+ code = backend._get_code_from_exception(self.wrapped_backend, "delete", e)
221
+ if code != log.ErrorCode.backend_not_found:
222
+ raise
213
223
 
214
224
  def delete_list(self, filename_list):
215
225
  """
@@ -228,7 +238,12 @@ class Par2Backend(backend.Backend):
228
238
  return self.wrapped_backend._delete_list(filename_list)
229
239
  else:
230
240
  for filename in filename_list:
231
- self.wrapped_backend._delete(filename)
241
+ try:
242
+ self.wrapped_backend._delete(filename)
243
+ except Exception as e:
244
+ code = backend._get_code_from_exception(self.wrapped_backend, "delete", e)
245
+ if code != log.ErrorCode.backend_not_found:
246
+ raise
232
247
 
233
248
  def list(self):
234
249
  """
@@ -255,7 +270,9 @@ class Par2Backend(backend.Backend):
255
270
  self.wrapped_backend._retry_cleanup()
256
271
 
257
272
  def error_code(self, operation, e):
258
- return self.wrapped_backend._error_code(operation, e)
273
+ if hasattr(self.wrapped_backend, "_error_code"):
274
+ return self.wrapped_backend._error_code(operation, e)
275
+ return log.ErrorCode.backend_error
259
276
 
260
277
  def query(self, filename):
261
278
  return self.wrapped_backend._query(filename)
@@ -29,6 +29,7 @@ import tempfile
29
29
 
30
30
  import duplicity.backend
31
31
  from duplicity import config
32
+ from duplicity import log
32
33
  from duplicity import tempdir
33
34
  from duplicity import util
34
35
  from duplicity.errors import InvalidBackendURL
@@ -65,9 +66,14 @@ class RsyncBackend(duplicity.backend.Backend):
65
66
  if "RSYNC_RSH" in os.environ:
66
67
  del os.environ["RSYNC_RSH"]
67
68
  if self.over_rsyncd():
68
- # its a module path
69
+ # Split the daemon URL into its module root and the subpath used
70
+ # by duplicity, because rsyncd cannot create a missing subpath as
71
+ # the direct destination.
69
72
  path, port = self.get_rsync_path()
70
73
  self.url_string = f"{host}::{path.lstrip('/:')}"
74
+ module, separator, subpath = path.lstrip("/").partition("/")
75
+ self.rsyncd_module_url = f"{host}::{module}/"
76
+ self.rsyncd_subpath = subpath if separator else ""
71
77
  if port:
72
78
  port = f" --port={port}"
73
79
  else:
@@ -101,6 +107,10 @@ class RsyncBackend(duplicity.backend.Backend):
101
107
  rsyncOptions = config.rsync_options
102
108
  # build cmd
103
109
  self.cmd = f"rsync {portOption} {rsyncOptions}"
110
+ if self.over_rsyncd():
111
+ # Track whether the subpath has been created from the module root.
112
+ self.remote_path_created = False
113
+ self.ensure_remote_path()
104
114
 
105
115
  def over_rsyncd(self):
106
116
  url = self.parsed_url.url_string
@@ -116,6 +126,20 @@ class RsyncBackend(duplicity.backend.Backend):
116
126
  return m.group(2), m.group(1).lstrip(":")
117
127
  raise InvalidBackendURL(f"Could not determine rsync path: {self.munge_password(url)}")
118
128
 
129
+ def ensure_remote_path(self):
130
+ """Create the rsync daemon subpath before accessing stored files."""
131
+ if not self.over_rsyncd() or self.remote_path_created or not self.rsyncd_subpath:
132
+ return
133
+ with tempfile.TemporaryDirectory() as local_path:
134
+ local_subpath = os.path.join(local_path, self.rsyncd_subpath)
135
+ # Mirror the requested subpath locally so rsync creates each
136
+ # missing directory below the daemon module.
137
+ os.makedirs(local_subpath)
138
+ commandline = f"{self.cmd} --recursive {local_path}/ {self.rsyncd_module_url}"
139
+ self.subprocess_popen(commandline)
140
+ log.Debug(f"Created rsync daemon subpath '{self.rsyncd_subpath}'.")
141
+ self.remote_path_created = True
142
+
119
143
  def _put(self, source_path, remote_filename):
120
144
  remote_filename = os.fsdecode(remote_filename)
121
145
  remote_path = os.path.join(self.url_string, remote_filename)
@@ -318,9 +318,9 @@ class SSHPExpectBackend(duplicity.backend.Backend):
318
318
  commands = mkdir_commands + ["ls -1"]
319
319
  commandline = f"{self.sftp_command} {config.ssh_options} {self.host_string}"
320
320
 
321
- l = self.run_sftp_command(commandline, commands).split("\n")[1:]
321
+ lines = self.run_sftp_command(commandline, commands).split("\n")[1:]
322
322
 
323
- return [x for x in map(str.strip, l) if x]
323
+ return [os.fsencode(x) for x in map(str.strip, lines) if x]
324
324
 
325
325
  def _delete(self, filename):
326
326
  commands = [f'cd "{self.remote_dir}"']