duplicity 3.2.1.dev2__tar.gz → 3.2.2__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.2}/CHANGELOG.md +135 -20
  2. {duplicity-3.2.1.dev2/duplicity.egg-info → duplicity-3.2.2}/PKG-INFO +3 -4
  3. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/README-INSTALL.md +1 -2
  4. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/README-TESTING.md +2 -1
  5. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/__init__.py +2 -2
  6. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/__main__.py +2 -2
  7. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backend.py +37 -2
  8. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backend_pool.py +5 -7
  9. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/_cf_cloudfiles.py +8 -1
  10. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/_cf_pyrax.py +6 -0
  11. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/b2backend.py +38 -12
  12. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/boxbackend.py +38 -3
  13. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/hubicbackend.py +5 -0
  14. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/idrivedbackend.py +1 -2
  15. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/imapbackend.py +2 -1
  16. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/jottacloudbackend.py +3 -0
  17. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/mediafirebackend.py +1 -0
  18. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/onedrivebackend.py +39 -16
  19. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/par2backend.py +21 -4
  20. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/pyrax_identity/hubic.py +2 -0
  21. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/rsyncbackend.py +25 -1
  22. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/ssh_pexpect_backend.py +2 -2
  23. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/webdavbackend.py +20 -0
  24. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/xorrisobackend.py +1 -1
  25. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/cli_data.py +221 -36
  26. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/cli_main.py +95 -15
  27. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/cli_util.py +116 -1
  28. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/config.py +5 -1
  29. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/diffdir.py +4 -2
  30. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/dup_collections.py +18 -13
  31. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/dup_main.py +69 -62
  32. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/dup_temp.py +1 -1
  33. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/file_naming.py +15 -1
  34. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/gpg.py +218 -246
  35. duplicity-3.2.2/duplicity/gpginterface.py +706 -0
  36. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/log.py +1 -1
  37. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/manifest.py +17 -4
  38. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/patchdir.py +1 -1
  39. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/path.py +1 -1
  40. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/selection.py +44 -132
  41. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/tempdir.py +6 -5
  42. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/util.py +8 -21
  43. {duplicity-3.2.1.dev2 → duplicity-3.2.2/duplicity.egg-info}/PKG-INFO +3 -4
  44. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity.egg-info/SOURCES.txt +1 -0
  45. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity.egg-info/requires.txt +0 -2
  46. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/man/duplicity.1 +34 -1
  47. {duplicity-3.2.1.dev2/po → duplicity-3.2.2/po/af_ZA}/af_ZA.po +392 -386
  48. {duplicity-3.2.1.dev2/po/af_ZA → duplicity-3.2.2/po}/af_ZA.po +392 -386
  49. {duplicity-3.2.1.dev2/po → duplicity-3.2.2/po/ar_SA}/ar_SA.po +398 -397
  50. {duplicity-3.2.1.dev2/po/ar_SA → duplicity-3.2.2/po}/ar_SA.po +398 -397
  51. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ca_ES/ca_ES.po +392 -386
  52. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ca_ES.po +392 -386
  53. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/cs_CZ/cs_CZ.po +398 -397
  54. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/cs_CZ.po +398 -397
  55. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/da_DK/da_DK.po +398 -397
  56. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/da_DK.po +398 -397
  57. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/de_AT/de_AT.po +398 -397
  58. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/de_AT.po +398 -397
  59. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/de_DE/de_DE.po +398 -397
  60. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/de_DE.po +398 -397
  61. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/duplicity.pot +397 -390
  62. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/el_GR/el_GR.po +398 -392
  63. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/el_GR.po +398 -392
  64. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/en_AU/en_AU.po +392 -386
  65. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/en_AU.po +392 -386
  66. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/en_GB/en_GB.po +392 -386
  67. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/en_GB.po +392 -386
  68. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/en_PR/en_PR.po +392 -386
  69. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/en_PR.po +392 -386
  70. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/en_US/en_US.po +392 -386
  71. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/en_US.po +392 -386
  72. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_EM/es_EM.po +398 -397
  73. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_EM.po +398 -397
  74. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_ES/es_ES.po +398 -397
  75. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_ES.po +398 -397
  76. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_MX/es_MX.po +398 -397
  77. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_MX.po +398 -397
  78. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_PR/es_PR.po +398 -397
  79. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_PR.po +398 -397
  80. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_US/es_US.po +398 -397
  81. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/es_US.po +398 -397
  82. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/fi_FI/fi_FI.po +398 -397
  83. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/fi_FI.po +398 -397
  84. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/fr_FR/fr_FR.po +398 -394
  85. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/fr_FR.po +398 -394
  86. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/he_IL/he_IL.po +393 -389
  87. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/he_IL.po +393 -389
  88. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/hu_HU/hu_HU.po +393 -387
  89. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/hu_HU.po +393 -387
  90. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/it_IT/it_IT.po +398 -397
  91. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/it_IT.po +398 -397
  92. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ja_JP/ja_JP.po +398 -392
  93. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ja_JP.po +398 -392
  94. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ka_GE/ka_GE.po +392 -386
  95. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ka_GE.po +392 -386
  96. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ko_KR/ko_KR.po +392 -386
  97. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ko_KR.po +392 -386
  98. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/nl_BE/nl_BE.po +398 -397
  99. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/nl_BE.po +398 -397
  100. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/nl_NL/nl_NL.po +398 -397
  101. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/nl_NL.po +398 -397
  102. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/nl_SR/nl_SR.po +398 -397
  103. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/nl_SR.po +398 -397
  104. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/no_NO/no_NO.po +398 -397
  105. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/no_NO.po +398 -397
  106. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/pl_PL/pl_PL.po +398 -397
  107. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/pl_PL.po +398 -397
  108. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/pt_BR/pt_BR.po +398 -397
  109. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/pt_BR.po +398 -397
  110. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/pt_PT/pt_PT.po +398 -397
  111. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/pt_PT.po +398 -397
  112. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ro_RO/ro_RO.po +398 -397
  113. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ro_RO.po +398 -397
  114. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ru_BY/ru_BY.po +398 -397
  115. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ru_BY.po +398 -397
  116. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ru_MD/ru_MD.po +398 -397
  117. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ru_MD.po +398 -397
  118. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ru_RU/ru_RU.po +398 -397
  119. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ru_RU.po +398 -397
  120. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/sr_SP/sr_SP.po +392 -386
  121. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/sr_SP.po +392 -386
  122. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/sv_SE/sv_SE.po +398 -397
  123. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/sv_SE.po +398 -397
  124. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/tr_TR/tr_TR.po +392 -386
  125. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/tr_TR.po +392 -386
  126. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/uk_UA/uk_UA.po +393 -387
  127. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/uk_UA.po +393 -387
  128. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/vi_VN/vi_VN.po +392 -386
  129. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/vi_VN.po +392 -386
  130. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_CN/zh_CN.po +398 -397
  131. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_CN.po +398 -397
  132. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_HK/zh_HK.po +392 -386
  133. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_HK.po +392 -386
  134. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_MO/zh_MO.po +392 -386
  135. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_MO.po +392 -386
  136. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_SG/zh_SG.po +398 -397
  137. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_SG.po +398 -397
  138. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_TW/zh_TW.po +392 -386
  139. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/zh_TW.po +392 -386
  140. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/pyproject.toml +27 -42
  141. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/requirements.txt +0 -2
  142. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/setup.py +2 -1
  143. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/AUTHORS.md +0 -0
  144. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/COPYING +0 -0
  145. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/README-ARCH.md +0 -0
  146. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/README-LOG.md +0 -0
  147. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/README-RELEASE.md +0 -0
  148. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/README-REPO.md +0 -0
  149. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/README-SNAP.md +0 -0
  150. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/README.md +0 -0
  151. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/_librsync_ctypes.py +0 -0
  152. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/_librsyncmodule.c +0 -0
  153. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/argparse311.py +0 -0
  154. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/__init__.py +0 -0
  155. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/_testbackend.py +0 -0
  156. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/adbackend.py +0 -0
  157. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/azurebackend.py +0 -0
  158. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/cfbackend.py +0 -0
  159. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/dpbxbackend.py +0 -0
  160. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/gdocsbackend.py +0 -0
  161. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/gdrivebackend.py +0 -0
  162. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/giobackend.py +0 -0
  163. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/hsibackend.py +0 -0
  164. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/lftpbackend.py +0 -0
  165. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/localbackend.py +0 -0
  166. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/megabackend.py +0 -0
  167. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/megav2backend.py +0 -0
  168. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/megav3backend.py +0 -0
  169. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/multibackend.py +0 -0
  170. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/ncftpbackend.py +0 -0
  171. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/pcabackend.py +0 -0
  172. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/pydrivebackend.py +0 -0
  173. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/pyrax_identity/__init__.py +0 -0
  174. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/rclonebackend.py +0 -0
  175. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/s3_boto3_backend.py +0 -0
  176. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/slatebackend.py +0 -0
  177. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/ssh_paramiko_backend.py +0 -0
  178. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/swiftbackend.py +0 -0
  179. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/sxbackend.py +0 -0
  180. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/backends/tahoebackend.py +0 -0
  181. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/cached_ops.py +0 -0
  182. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/dup_tarfile.py +0 -0
  183. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/dup_time.py +0 -0
  184. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/errors.py +0 -0
  185. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/globmatch.py +0 -0
  186. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/lazy.py +0 -0
  187. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/librsync.py +0 -0
  188. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/progress.py +0 -0
  189. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/robust.py +0 -0
  190. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity/statistics.py +0 -0
  191. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity.egg-info/dependency_links.txt +0 -0
  192. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity.egg-info/entry_points.txt +0 -0
  193. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/duplicity.egg-info/top_level.txt +0 -0
  194. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ru_UA/ru_UA.po +0 -0
  195. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/po/ru_UA.po +0 -0
  196. {duplicity-3.2.1.dev2 → duplicity-3.2.2}/setup.cfg +0 -0
@@ -1,15 +1,40 @@
1
1
 
2
- (Unreleased) / 2026-08-20
2
+ (Unreleased) / 2026-10-14
3
3
  =========================
4
4
 
5
5
 
6
6
 
7
- rel.3.2.1.dev2 / 2026-08-20
8
- ===========================
7
+ rel.3.2.2 / 2026-10-14
8
+ ======================
9
+
10
+ * [`83fafd83`](https://gitlab.com/duplicity/duplicity/-/commit/83fafd83):chg: Improve core functionality with security and error handling enhancements
11
+ * [`33785064`](https://gitlab.com/duplicity/duplicity/-/commit/33785064):chg: Adjust pylint and core code for consistency and maintainability
12
+ * [`87610b0d`](https://gitlab.com/duplicity/duplicity/-/commit/87610b0d):chg: Replace `log.Notice` with `log.Debug` in `dup_temp.py`
13
+ * [`2c0e7749`](https://gitlab.com/duplicity/duplicity/-/commit/2c0e7749):chg: Update Python 3.15 CI job to use specific slim image (3.15.0rc2)
14
+ * [`4ca0c380`](https://gitlab.com/duplicity/duplicity/-/commit/4ca0c380):chg: Add Python 3.15 support across CI, testing, and dependency specifications
15
+ * [`34df9948`](https://gitlab.com/duplicity/duplicity/-/commit/34df9948):fix: Correct variable naming, import handling, and error messaging across multiple backends and core modules.
16
+
17
+ rel.3.2.1 / 2026-09-28
18
+ ======================
9
19
 
20
+ * [`d7da150b`](https://gitlab.com/duplicity/duplicity/-/commit/d7da150b):new: Create subpath in rsyncd.
10
21
  * [`77c5107e`](https://gitlab.com/duplicity/duplicity/-/commit/77c5107e):new: Add get_version() to librsync to retrieve underlying library version
11
22
  * [`b839f2c8`](https://gitlab.com/duplicity/duplicity/-/commit/b839f2c8):new: Add pure Python librsync implementation using ctypes as fallback
12
23
  * [`ba7957c3`](https://gitlab.com/duplicity/duplicity/-/commit/ba7957c3):new: Add coverage configuration and Makefile targets for testing.
24
+ * [`846e90ae`](https://gitlab.com/duplicity/duplicity/-/commit/846e90ae):chg: Adapt `makechangelog` for enhanced usability and stricter repo cleanliness checks
25
+ * [`35191e13`](https://gitlab.com/duplicity/duplicity/-/commit/35191e13):chg: Remove unused pytest options and manual testing directory from `pyproject.toml`
26
+ * [`eaa264be`](https://gitlab.com/duplicity/duplicity/-/commit/eaa264be):chg: Improve error handling for Box, OneDrive, and WebDAV backends; add unit tests for comprehensive validation
27
+ * [`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
28
+ * [`58a54680`](https://gitlab.com/duplicity/duplicity/-/commit/58a54680):chg: Add regex cache invalidation for file prefix changes; update tests
29
+ * [`fcd6920a`](https://gitlab.com/duplicity/duplicity/-/commit/fcd6920a):chg: Add deprecation warnings for CloudFiles, Pyrax, and Hubic backends
30
+ * [`1842e4de`](https://gitlab.com/duplicity/duplicity/-/commit/1842e4de):chg: Remove `python3-gnupg` and restore `gpginterface` module and unit tests.
31
+ * [`aae16c61`](https://gitlab.com/duplicity/duplicity/-/commit/aae16c61):chg: Remove `python3-gnupg` and restore `gpginterface` module and unit tests.
32
+ * [`a201453e`](https://gitlab.com/duplicity/duplicity/-/commit/a201453e):chg: Plan to remove obsolete Pyrax, CloudFiles, and Hubic backends; standardize on python-swiftclient
33
+ * [`abdf9a0e`](https://gitlab.com/duplicity/duplicity/-/commit/abdf9a0e):chg: Remove unused gnupg import from gpg.py for cleanup.
34
+ * [`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
35
+ * [`993cc651`](https://gitlab.com/duplicity/duplicity/-/commit/993cc651):chg: Decouple selection parsing from core engine and refactor tests
36
+ * [`1af57ea4`](https://gitlab.com/duplicity/duplicity/-/commit/1af57ea4):chg: Add support and tests for new CLI options
37
+ * [`df643666`](https://gitlab.com/duplicity/duplicity/-/commit/df643666):chg: Update Python3 version and dependencies in `debian/control`
13
38
  * [`855c6f1c`](https://gitlab.com/duplicity/duplicity/-/commit/855c6f1c):chg: Remove outdated comment for `python3-gnupg` in `debian/control`
14
39
  * [`22fae925`](https://gitlab.com/duplicity/duplicity/-/commit/22fae925):chg: Sync README files in `setup.py` and clean up verbosity flags
15
40
  * [`978355b4`](https://gitlab.com/duplicity/duplicity/-/commit/978355b4):chg: Enable verbose mode in debian/rules
@@ -34,6 +59,10 @@ rel.3.2.1.dev2 / 2026-08-20
34
59
  * [`1dee9e31`](https://gitlab.com/duplicity/duplicity/-/commit/1dee9e31):chg: b2backend prefer b2sdk.v3
35
60
  * [`4f4e052e`](https://gitlab.com/duplicity/duplicity/-/commit/4f4e052e):chg: Cleanup some minor issues
36
61
  * [`1e0a97dc`](https://gitlab.com/duplicity/duplicity/-/commit/1e0a97dc):chg: Format with Black/PEP8 and ensure file flush before rename
62
+ * [`7514a7e2`](https://gitlab.com/duplicity/duplicity/-/commit/7514a7e2):fix: Correct string formatting in help output and improve test stability
63
+ * [`c179caf1`](https://gitlab.com/duplicity/duplicity/-/commit/c179caf1):fix: Fix GPG sleep processes on verify, modernize tests, and update guidelines
64
+ * [`90f9137e`](https://gitlab.com/duplicity/duplicity/-/commit/90f9137e):fix: Fix subpath creation for rsync #943
65
+ * [`ed58fae5`](https://gitlab.com/duplicity/duplicity/-/commit/ed58fae5):fix: Restore Python versions, dependencies, and revert migration to 'python-gnupg'.
37
66
  * [`22da1a0d`](https://gitlab.com/duplicity/duplicity/-/commit/22da1a0d):fix: Resolve PEP8 style issues and whitespace in backend and main modules
38
67
  * [`06858c9a`](https://gitlab.com/duplicity/duplicity/-/commit/06858c9a):fix: Replace `os.system` calls with safer Python alternatives.
39
68
  * [`da745307`](https://gitlab.com/duplicity/duplicity/-/commit/da745307):fix: Add --ignore-installed flag for pip in Dockerfiles
@@ -50,6 +79,11 @@ rel.3.2.1.dev2 / 2026-08-20
50
79
  * [`9819e4d4`](https://gitlab.com/duplicity/duplicity/-/commit/9819e4d4):fix: Add get_last_continuous_volume for reliable backup resumption
51
80
  * [`5d737d07`](https://gitlab.com/duplicity/duplicity/-/commit/5d737d07):fix: Postpone metadata promotion to prevent orphaned cache files
52
81
 
82
+ rel.3.2.0.2 / 2026-08-22
83
+ ========================
84
+
85
+ * [`f7ccc81b`](https://gitlab.com/duplicity/duplicity/-/commit/f7ccc81b):chg: Update Python3 version and dependencies in `debian/control`
86
+
53
87
  rel.3.2.0.1 / 2026-08-15
54
88
  ========================
55
89
 
@@ -61,24 +95,12 @@ rel.3.2.0.1 / 2026-08-15
61
95
  * [`f0fb534c`](https://gitlab.com/duplicity/duplicity/-/commit/f0fb534c):chg: Update dependencies, streamline configs, and refine CI
62
96
  * [`6d719e1c`](https://gitlab.com/duplicity/duplicity/-/commit/6d719e1c):fix: Resolve PEP8 style issues and whitespace in backend and main modules
63
97
 
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
98
  rel.3.2.0 / 2026-08-10
76
99
  ======================
77
100
 
78
101
  * [`8612b567`](https://gitlab.com/duplicity/duplicity/-/commit/8612b567):new: Add get_version() to librsync to retrieve underlying library version
79
102
  * [`9dddcfc4`](https://gitlab.com/duplicity/duplicity/-/commit/9dddcfc4):new: Add pure Python librsync implementation using ctypes as fallback
80
103
  * [`acaedcfe`](https://gitlab.com/duplicity/duplicity/-/commit/acaedcfe):new: Add coverage configuration and Makefile targets for testing.
81
- * [`6feeafb1`](https://gitlab.com/duplicity/duplicity/-/commit/6feeafb1):new: Add PyCharm devcontainer configuration and base Dockerfile.
82
104
  * [`b3c4b349`](https://gitlab.com/duplicity/duplicity/-/commit/b3c4b349):chg: Update release-prep script to use `check_tags`
83
105
  * [`8befb2cf`](https://gitlab.com/duplicity/duplicity/-/commit/8befb2cf):chg: Update release-prep script to fix tag removal and file refs
84
106
  * [`33544f8c`](https://gitlab.com/duplicity/duplicity/-/commit/33544f8c):chg: Update pipeline triggers for push, web, and merge request events
@@ -89,11 +111,6 @@ rel.3.2.0 / 2026-08-10
89
111
  * [`59ed8f9e`](https://gitlab.com/duplicity/duplicity/-/commit/59ed8f9e):chg: Rewrite `makechangelog` script in Python
90
112
  * [`ffc31818`](https://gitlab.com/duplicity/duplicity/-/commit/ffc31818):chg: b2backend prefer b2sdk.v3
91
113
  * [`78da5b67`](https://gitlab.com/duplicity/duplicity/-/commit/78da5b67):chg: Cleanup some minor issues
92
- * [`64264da1`](https://gitlab.com/duplicity/duplicity/-/commit/64264da1):chg: Remove unused Tahoe-LAFS installation steps in Snapcraft
93
- * [`f4123b7e`](https://gitlab.com/duplicity/duplicity/-/commit/f4123b7e):chg: Add support for additional architectures in Snapcraft
94
- * [`6f015221`](https://gitlab.com/duplicity/duplicity/-/commit/6f015221):chg: Update Snapcraft to core26 and Python 3.14
95
- * [`938764f7`](https://gitlab.com/duplicity/duplicity/-/commit/938764f7):chg: Add setuptools dependency to requirements.dev for Python 3.12+
96
- * [`b17da54e`](https://gitlab.com/duplicity/duplicity/-/commit/b17da54e):chg: Update dependencies in requirements.txt for compatibility.
97
114
  * [`47c21150`](https://gitlab.com/duplicity/duplicity/-/commit/47c21150):fix: Replace `os.system` calls with safer Python alternatives.
98
115
  * [`12c98f2a`](https://gitlab.com/duplicity/duplicity/-/commit/12c98f2a):fix: Add --ignore-installed flag for pip in Dockerfiles
99
116
  * [`b1508a6d`](https://gitlab.com/duplicity/duplicity/-/commit/b1508a6d):fix: restore issue: AssertionError: (b'keys', [...]) not empty
@@ -105,6 +122,104 @@ rel.3.2.0 / 2026-08-10
105
122
  * [`c823ed36`](https://gitlab.com/duplicity/duplicity/-/commit/c823ed36):fix: Could not release lockfile
106
123
  * [`3d9eab94`](https://gitlab.com/duplicity/duplicity/-/commit/3d9eab94):fix: Comprehensive fix for backup, restart, and cleanup logic.
107
124
 
125
+ rel.4.0.0.dev0 / 2026-09-23
126
+ ===========================
127
+
128
+ * [`8427bb00`](https://gitlab.com/duplicity/duplicity/-/commit/8427bb00):chg: Add support for split signature and manifest volumes with atomic completion records
129
+ * [`2b0c76e7`](https://gitlab.com/duplicity/duplicity/-/commit/2b0c76e7):chg: Move remaining plans to 'plans_done' and resolve outdated references
130
+ * [`1d07db2f`](https://gitlab.com/duplicity/duplicity/-/commit/1d07db2f):chg: Remove legacy Pyrax and CloudFiles backends
131
+ * [`b04ca97b`](https://gitlab.com/duplicity/duplicity/-/commit/b04ca97b):chg: Restored "NOTICE" log level and updated verbosity handling
132
+ * [`f9b6ed8d`](https://gitlab.com/duplicity/duplicity/-/commit/f9b6ed8d):chg: Improve string formatting and update pylint job configuration
133
+ * [`5437ccf2`](https://gitlab.com/duplicity/duplicity/-/commit/5437ccf2):chg: Add `swig` to CI dependencies in `.gitlab-ci.yml`
134
+ * [`50e0e15f`](https://gitlab.com/duplicity/duplicity/-/commit/50e0e15f):chg: Remove legacy `gpginterface.py` and associated tests
135
+ * [`c5e53820`](https://gitlab.com/duplicity/duplicity/-/commit/c5e53820):chg: Remove redundant parentheses from class declarations
136
+ * [`f2fa175e`](https://gitlab.com/duplicity/duplicity/-/commit/f2fa175e):chg: Remove redundant `object` inheritance across classes for Python 3
137
+ * [`74f7d3a9`](https://gitlab.com/duplicity/duplicity/-/commit/74f7d3a9):chg: Standardize logging levels and refactor verbosity handling
138
+ * [`d090ab43`](https://gitlab.com/duplicity/duplicity/-/commit/d090ab43):chg: Replace `duplicity` references with `src` across codebase
139
+
140
+ rel.3.2.1.dev3 / 2026-09-23
141
+ ===========================
142
+
143
+ * [`d7da150b`](https://gitlab.com/duplicity/duplicity/-/commit/d7da150b):new: Create subpath in rsyncd.
144
+ * [`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
145
+ * [`58a54680`](https://gitlab.com/duplicity/duplicity/-/commit/58a54680):chg: Add regex cache invalidation for file prefix changes; update tests
146
+ * [`fcd6920a`](https://gitlab.com/duplicity/duplicity/-/commit/fcd6920a):chg: Add deprecation warnings for CloudFiles, Pyrax, and Hubic backends
147
+ * [`1842e4de`](https://gitlab.com/duplicity/duplicity/-/commit/1842e4de):chg: Remove `python3-gnupg` and restore `gpginterface` module and unit tests.
148
+ * [`a201453e`](https://gitlab.com/duplicity/duplicity/-/commit/a201453e):chg: Plan to remove obsolete Pyrax, CloudFiles, and Hubic backends; standardize on python-swiftclient
149
+ * [`abdf9a0e`](https://gitlab.com/duplicity/duplicity/-/commit/abdf9a0e):chg: Remove unused gnupg import from gpg.py for cleanup.
150
+ * [`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
151
+ * [`993cc651`](https://gitlab.com/duplicity/duplicity/-/commit/993cc651):chg: Decouple selection parsing from core engine and refactor tests
152
+ * [`1af57ea4`](https://gitlab.com/duplicity/duplicity/-/commit/1af57ea4):chg: Add support and tests for new CLI options
153
+ * [`df643666`](https://gitlab.com/duplicity/duplicity/-/commit/df643666):chg: Update Python3 version and dependencies in `debian/control`
154
+ * [`7514a7e2`](https://gitlab.com/duplicity/duplicity/-/commit/7514a7e2):fix: Correct string formatting in help output and improve test stability
155
+ * [`c179caf1`](https://gitlab.com/duplicity/duplicity/-/commit/c179caf1):fix: Fix GPG sleep processes on verify, modernize tests, and update guidelines
156
+ * [`90f9137e`](https://gitlab.com/duplicity/duplicity/-/commit/90f9137e):fix: Fix subpath creation for rsync #943
157
+ * [`ed58fae5`](https://gitlab.com/duplicity/duplicity/-/commit/ed58fae5):fix: Restore Python versions, dependencies, and revert migration to 'python-gnupg'.
158
+
159
+ rel.3.2.1.dev2 / 2026-08-20
160
+ ===========================
161
+
162
+ * [`855c6f1c`](https://gitlab.com/duplicity/duplicity/-/commit/855c6f1c):chg: Remove outdated comment for `python3-gnupg` in `debian/control`
163
+ * [`22fae925`](https://gitlab.com/duplicity/duplicity/-/commit/22fae925):chg: Sync README files in `setup.py` and clean up verbosity flags
164
+ * [`978355b4`](https://gitlab.com/duplicity/duplicity/-/commit/978355b4):chg: Enable verbose mode in debian/rules
165
+ * [`626cdccb`](https://gitlab.com/duplicity/duplicity/-/commit/626cdccb):chg: Remove redundant `apt` commands in `debian/rules`
166
+ * [`ba71d094`](https://gitlab.com/duplicity/duplicity/-/commit/ba71d094):chg: Update setuptools to >=61.0.0 in dev dependencies and `debian/rules`
167
+ * [`2b55864a`](https://gitlab.com/duplicity/duplicity/-/commit/2b55864a):chg: Simplify `gnupg` import logic in `gpg.py`
168
+ * [`80abbd02`](https://gitlab.com/duplicity/duplicity/-/commit/80abbd02):chg: Adjust dependencies in `requirements.txt` and `debian/control`
169
+
170
+ rel.3.2.1.dev1 / 2026-08-15
171
+ ===========================
172
+
173
+ * [`df52d45b`](https://gitlab.com/duplicity/duplicity/-/commit/df52d45b):chg: Add `python3-gnupg` as a build dependency in `debian/control`
174
+ * [`057c7d0a`](https://gitlab.com/duplicity/duplicity/-/commit/057c7d0a):chg: Update doc cleanup pattern in `debian/rules`
175
+ * [`4eaee861`](https://gitlab.com/duplicity/duplicity/-/commit/4eaee861):chg: Update doc cleanup to remove `duplicity-*` files in `debian/rules`
176
+ * [`7cd8ddb6`](https://gitlab.com/duplicity/duplicity/-/commit/7cd8ddb6):chg: Add `get_data_files` for dynamic data file handling in `setup.py`
177
+ * [`e9bf8843`](https://gitlab.com/duplicity/duplicity/-/commit/e9bf8843):chg: Simplify doc handling by removing outdated duplicity docs
178
+ * [`22da1a0d`](https://gitlab.com/duplicity/duplicity/-/commit/22da1a0d):fix: Resolve PEP8 style issues and whitespace in backend and main modules
179
+
180
+ rel.3.2.1.dev0 / 2026-08-11
181
+ ===========================
182
+
183
+ * [`77c5107e`](https://gitlab.com/duplicity/duplicity/-/commit/77c5107e):new: Add get_version() to librsync to retrieve underlying library version
184
+ * [`b839f2c8`](https://gitlab.com/duplicity/duplicity/-/commit/b839f2c8):new: Add pure Python librsync implementation using ctypes as fallback
185
+ * [`ba7957c3`](https://gitlab.com/duplicity/duplicity/-/commit/ba7957c3):new: Add coverage configuration and Makefile targets for testing.
186
+ * [`6feeafb1`](https://gitlab.com/duplicity/duplicity/-/commit/6feeafb1):new: Add PyCharm devcontainer configuration and base Dockerfile.
187
+ * [`4bc93712`](https://gitlab.com/duplicity/duplicity/-/commit/4bc93712):chg: Update dependencies, streamline configs, and refine CI
188
+ * [`ca78d6c5`](https://gitlab.com/duplicity/duplicity/-/commit/ca78d6c5):chg: Update release-prep script to use `check_tags`
189
+ * [`60ae51f3`](https://gitlab.com/duplicity/duplicity/-/commit/60ae51f3):chg: Update release-prep script to fix tag removal and file refs
190
+ * [`45495e09`](https://gitlab.com/duplicity/duplicity/-/commit/45495e09):chg: Update pipeline triggers for push, web, and merge request events
191
+ * [`f8fc71e3`](https://gitlab.com/duplicity/duplicity/-/commit/f8fc71e3):chg: Improve process in `setup.py` and release prep script
192
+ * [`f36c9922`](https://gitlab.com/duplicity/duplicity/-/commit/f36c9922):chg: Refactor versioning and metadata handling
193
+ * [`84afa6f2`](https://gitlab.com/duplicity/duplicity/-/commit/84afa6f2):chg: Refactor string concatenations to f-strings across codebase
194
+ * [`480cbc23`](https://gitlab.com/duplicity/duplicity/-/commit/480cbc23):chg: Clean up and refactor `pyproject.toml` and `Makefile`
195
+ * [`42d4838d`](https://gitlab.com/duplicity/duplicity/-/commit/42d4838d):chg: Rewrite `makechangelog` script in Python
196
+ * [`1dee9e31`](https://gitlab.com/duplicity/duplicity/-/commit/1dee9e31):chg: b2backend prefer b2sdk.v3
197
+ * [`4f4e052e`](https://gitlab.com/duplicity/duplicity/-/commit/4f4e052e):chg: Cleanup some minor issues
198
+ * [`1e0a97dc`](https://gitlab.com/duplicity/duplicity/-/commit/1e0a97dc):chg: Format with Black/PEP8 and ensure file flush before rename
199
+ * [`64264da1`](https://gitlab.com/duplicity/duplicity/-/commit/64264da1):chg: Remove unused Tahoe-LAFS installation steps in Snapcraft
200
+ * [`f4123b7e`](https://gitlab.com/duplicity/duplicity/-/commit/f4123b7e):chg: Add support for additional architectures in Snapcraft
201
+ * [`6f015221`](https://gitlab.com/duplicity/duplicity/-/commit/6f015221):chg: Update Snapcraft to core26 and Python 3.14
202
+ * [`938764f7`](https://gitlab.com/duplicity/duplicity/-/commit/938764f7):chg: Add setuptools dependency to requirements.dev for Python 3.12+
203
+ * [`b17da54e`](https://gitlab.com/duplicity/duplicity/-/commit/b17da54e):chg: Update dependencies in requirements.txt for compatibility.
204
+ * [`06858c9a`](https://gitlab.com/duplicity/duplicity/-/commit/06858c9a):fix: Replace `os.system` calls with safer Python alternatives.
205
+ * [`da745307`](https://gitlab.com/duplicity/duplicity/-/commit/da745307):fix: Add --ignore-installed flag for pip in Dockerfiles
206
+ * [`883cca1e`](https://gitlab.com/duplicity/duplicity/-/commit/883cca1e):fix: restore issue: AssertionError: (b'keys', [...]) not empty
207
+ * [`aa0b23e7`](https://gitlab.com/duplicity/duplicity/-/commit/aa0b23e7):fix: Replace `log.FatalError` with `raise errors.FatalError`.
208
+ * [`c3a45713`](https://gitlab.com/duplicity/duplicity/-/commit/c3a45713):fix: Add support for "sync" action and handle passphrase checks.
209
+ * [`db99858e`](https://gitlab.com/duplicity/duplicity/-/commit/db99858e):fix: Enhance error handling and debug logging in Python modules
210
+ * [`dbb899ad`](https://gitlab.com/duplicity/duplicity/-/commit/dbb899ad):fix: Use 'python-gnupg' instead of our 'gpginterface.py'.
211
+ * [`4d6e9f8c`](https://gitlab.com/duplicity/duplicity/-/commit/4d6e9f8c):fix: PCABackend GET URL needs prefix if one is defined
212
+ * [`d7cd05d8`](https://gitlab.com/duplicity/duplicity/-/commit/d7cd05d8):fix: Could not release lockfile
213
+ * [`fcbe3a7a`](https://gitlab.com/duplicity/duplicity/-/commit/fcbe3a7a):fix: Enforce --force requirement for destructive operations
214
+ * [`c6c8b26a`](https://gitlab.com/duplicity/duplicity/-/commit/c6c8b26a):fix: Enhance BackupSet.delete signature cleanup and fix lock release
215
+ * [`3f0ab55b`](https://gitlab.com/duplicity/duplicity/-/commit/3f0ab55b):fix: Prevent premature deletion of full backups during incremental starts
216
+ * [`9819e4d4`](https://gitlab.com/duplicity/duplicity/-/commit/9819e4d4):fix: Add get_last_continuous_volume for reliable backup resumption
217
+ * [`5d737d07`](https://gitlab.com/duplicity/duplicity/-/commit/5d737d07):fix: Postpone metadata promotion to prevent orphaned cache files
218
+
219
+ rel.3.1.1.dev0 / 2026-06-16
220
+ ===========================
221
+
222
+
108
223
  rel.3.1.0 / 2026-06-16
109
224
  ======================
110
225
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: duplicity
3
- Version: 3.2.1.dev2
3
+ Version: 3.2.2
4
4
  Summary: Encrypted backup using rsync algorithm
5
5
  Author-email: Kenneth Loafman <kenneth@loafman.com>
6
6
  Maintainer: Edgar Soldin, Thomas Laubrock
@@ -22,16 +22,15 @@ Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.12
23
23
  Classifier: Programming Language :: Python :: 3.13
24
24
  Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Programming Language :: Python :: 3.15
25
26
  Classifier: Topic :: System :: Archiving :: Backup
26
- Requires-Python: <3.15,>=3.10
27
+ Requires-Python: <3.16,>=3.10
27
28
  Description-Content-Type: text/markdown
28
29
  License-File: COPYING
29
30
  License-File: AUTHORS.md
30
- Requires-Dist: cryptography==43.0.3
31
31
  Requires-Dist: fasteners>=0.19
32
32
  Requires-Dist: httplib2
33
33
  Requires-Dist: pysocks
34
- Requires-Dist: python-gnupg
35
34
  Requires-Dist: requests
36
35
  Requires-Dist: requests-oauthlib
37
36
  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.2"
33
+ __reldate__: str = "October 14, 2026"
34
34
 
35
35
  gettext.install("duplicity", names=["ngettext"])
@@ -68,8 +68,8 @@ def dup_run():
68
68
  pass
69
69
  elif os.environ.get("CIBUILDWHEEL") is not None:
70
70
  pass
71
- elif not ((3, 10) <= sys.version_info[:2] <= (3, 14)):
72
- print("Sorry, duplicity requires Python version 3.10 thru 3.14.", file=sys.stderr)
71
+ elif not ((3, 10) <= sys.version_info[:2] <= (3, 15)):
72
+ print("Sorry, duplicity requires Python version 3.10 thru 3.15.", file=sys.stderr)
73
73
  sys.exit(1)
74
74
 
75
75
  try:
@@ -366,10 +366,45 @@ class ParsedUrl(object):
366
366
 
367
367
  def strip_auth_from_url(parsed_url):
368
368
  """
369
- Return a URL from a urlparse object without a username or password.
369
+ Return a URL from a urlparse object or string without username, password, or sensitive query parameters.
370
370
  """
371
+ url_string = parsed_url.geturl() if hasattr(parsed_url, "geturl") else str(parsed_url)
372
+ clean_url = re.sub(r"^([^:/]+://)(.*@)?(.*)", r"\1\3", url_string)
373
+
374
+ if "?" in clean_url:
375
+ try:
376
+ parts = urllib.parse.urlsplit(clean_url)
377
+ if parts.query:
378
+ query_tuples = urllib.parse.parse_qsl(parts.query, keep_blank_values=True)
379
+ sanitized_query = []
380
+ sensitive_keys = {
381
+ "key",
382
+ "token",
383
+ "secret",
384
+ "password",
385
+ "pass",
386
+ "passwd",
387
+ "signature",
388
+ "api_key",
389
+ "apikey",
390
+ "auth",
391
+ "auth_token",
392
+ "access_token",
393
+ "secret_key",
394
+ }
395
+ for k, v in query_tuples:
396
+ k_lower = k.lower()
397
+ if k_lower in sensitive_keys or any(
398
+ s in k_lower for s in ("secret", "token", "password", "passwd", "sig")
399
+ ):
400
+ sanitized_query.append((k, "REDACTED"))
401
+ else:
402
+ sanitized_query.append((k, v))
403
+ new_query = urllib.parse.urlencode(sanitized_query)
404
+ clean_url = urllib.parse.urlunsplit((parts.scheme, parts.netloc, parts.path, new_query, parts.fragment))
405
+ except Exception:
406
+ pass
371
407
 
372
- clean_url = re.sub("^([^:/]+://)(.*@)?(.*)", r"\1\3", parsed_url.geturl())
373
408
  return clean_url
374
409
 
375
410
 
@@ -65,7 +65,7 @@ class TrackRecord:
65
65
  ) # trace backs can't be pickled, store as string, to get it over into main process
66
66
  result: object = None # must be picklable
67
67
  log_prefix: str = ""
68
- start_time: datetime = field(default=datetime.now())
68
+ start_time: datetime = field(default_factory=datetime.now)
69
69
  stop_time: datetime = field(default=datetime.min)
70
70
 
71
71
  def __post_init__(self):
@@ -277,7 +277,7 @@ class BackendPool:
277
277
  end = len(self.all_results)
278
278
  for result in self.all_results[self._last_results_reported : end]:
279
279
  yield result
280
- self._last_results_reported = end
280
+ self._last_results_reported += 1
281
281
 
282
282
  def get_stats(self, last_index=None):
283
283
  """
@@ -323,16 +323,14 @@ class BackendPool:
323
323
  :param bool cancel_futures: Whether to cancel any pending futures.
324
324
  """
325
325
  log.Debug("Process Pool: Start shutdown.")
326
- if sys.version_info >= (3, 9):
327
- self.ppe.shutdown(wait=wait, cancel_futures=cancel_futures)
328
- else:
329
- self.ppe.shutdown(wait=wait)
326
+ self.ppe.shutdown(wait=wait, cancel_futures=cancel_futures)
330
327
  log.Debug("Process Pool: Shutdown done.")
331
328
 
332
329
 
333
330
  # code to run/test the pool independent, not relevant for duplicity
334
331
  if __name__ == "__main__":
335
- from duplicity import config, log
332
+ from duplicity import config
333
+ from duplicity import log
336
334
 
337
335
  log.setup()
338
336
  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
@@ -53,6 +59,7 @@ class CloudFilesBackend(duplicity.backend.Backend):
53
59
  Exception: {str(e)}""")
54
60
 
55
61
  self.resp_exc = ResponseError
62
+ self.nso_exc = NoSuchObject
56
63
  conn_kwargs = {}
57
64
 
58
65
  if "CLOUDFILES_USERNAME" not in os.environ:
@@ -81,7 +88,7 @@ Exception: {str(e)}""")
81
88
  self.container = conn.create_container(container)
82
89
 
83
90
  def _error_code(self, operation, e): # pylint: disable=unused-argument
84
- if isinstance(e, NoSuchObject):
91
+ if isinstance(e, self.nso_exc):
85
92
  return log.ErrorCode.backend_not_found
86
93
  elif isinstance(e, self.resp_exc):
87
94
  if e.status == 404:
@@ -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:
@@ -37,7 +37,8 @@ from duplicity import progress
37
37
  from duplicity.errors import BackendException
38
38
  from duplicity.errors import FatalBackendException
39
39
 
40
- global DownloadDestLocalFile, FileVersionInfoFactory
40
+ DownloadDestLocalFile = None
41
+ FileVersionInfoFactory = None
41
42
 
42
43
 
43
44
  class B2ProgressListener(object):
@@ -217,10 +218,24 @@ class B2Backend(duplicity.backend.Backend):
217
218
  log.Log(f"Delete: {full_filename}", log.INFO)
218
219
 
219
220
  if config.b2_hide_files:
220
- self.bucket.hide_file(full_filename)
221
+ try:
222
+ self.bucket.hide_file(full_filename)
223
+ except Exception as e:
224
+ code = self._error_code("delete", e)
225
+ if code == log.ErrorCode.backend_not_found:
226
+ log.Debug(f"B2Backend._delete: file {full_filename} not found, already deleted")
227
+ return
228
+ raise
221
229
  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)
230
+ try:
231
+ file_version_info = self.file_info(quote_plus(full_filename, "/"))
232
+ self.bucket.delete_file_version(file_version_info.id_, file_version_info.file_name)
233
+ except Exception as e:
234
+ code = self._error_code("delete", e)
235
+ if code == log.ErrorCode.backend_not_found:
236
+ log.Debug(f"B2Backend._delete: file {full_filename} not found, already deleted")
237
+ return
238
+ raise
224
239
 
225
240
  def _query(self, filename):
226
241
  """
@@ -231,14 +246,25 @@ class B2Backend(duplicity.backend.Backend):
231
246
  :rtype: dict
232
247
  """
233
248
  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
- }
249
+ try:
250
+ file_version_info = self.file_info(quote_plus(self.path + os.fsdecode(filename), "/"))
251
+ return {
252
+ "size": (
253
+ int(file_version_info.size)
254
+ if file_version_info is not None and file_version_info.size is not None
255
+ else -1
256
+ )
257
+ }
258
+ except Exception as e:
259
+ code = self._error_code("query", e)
260
+ if code == log.ErrorCode.backend_not_found:
261
+ return {"size": -1}
262
+ raise
263
+
264
+ def _error_code(self, operation, e):
265
+ if e.__class__.__name__ in ("FileNotPresent", "NonExistentBucket") or str(e) == "File not found":
266
+ return log.ErrorCode.backend_not_found
267
+ return log.ErrorCode.backend_error
242
268
 
243
269
  def file_info(self, filename):
244
270
  if self.v_num >= [1, 9, 0]:
@@ -25,6 +25,7 @@ Box backend.
25
25
  import os
26
26
 
27
27
  import duplicity.backend
28
+ from duplicity import log
28
29
  from duplicity.errors import BackendException
29
30
 
30
31
 
@@ -97,8 +98,14 @@ class BoxBackend(duplicity.backend.Backend):
97
98
  """
98
99
  Deletes file from the specified remote path
99
100
  """
100
-
101
- self.delete(remote_file=filename.decode())
101
+ try:
102
+ self.delete(remote_file=filename.decode())
103
+ except Exception as e:
104
+ code = self._error_code("delete", e)
105
+ if code == log.ErrorCode.backend_not_found:
106
+ log.Debug(f"BoxBackend._delete: file {filename.decode()} not found, already deleted")
107
+ return
108
+ raise
102
109
 
103
110
  def _query_list(self, filename_list):
104
111
  """
@@ -106,6 +113,17 @@ class BoxBackend(duplicity.backend.Backend):
106
113
  """
107
114
  return {filename: self._file_to_metadata_map.get(filename.decode(), {"size": -1}) for filename in filename_list}
108
115
 
116
+ def _error_code(self, operation, e):
117
+ if getattr(e, "code", None) == log.ErrorCode.backend_not_found:
118
+ return log.ErrorCode.backend_not_found
119
+ if getattr(e, "status", None) == 404:
120
+ return log.ErrorCode.backend_not_found
121
+ if getattr(e, "code", None) in (404, "not_found"):
122
+ return log.ErrorCode.backend_not_found
123
+ if "not found" in str(e).lower() or "does not exist" in str(e).lower():
124
+ return log.ErrorCode.backend_not_found
125
+ return log.ErrorCode.backend_error
126
+
109
127
  def get_id_from_path(self, remote_path, parent_id="0"):
110
128
  """
111
129
  Get the folder or file id from its path
@@ -142,6 +160,8 @@ class BoxBackend(duplicity.backend.Backend):
142
160
  return file["id"]
143
161
 
144
162
  file_id = self.get_id_from_path(remote_filename, parent_id=self._folder_id)
163
+ if file_id is None:
164
+ return None
145
165
  file = self._client.file(file_id).get()
146
166
  self._file_to_metadata_map[file.name] = {
147
167
  "id": file.id,
@@ -210,6 +230,8 @@ class BoxBackend(duplicity.backend.Backend):
210
230
  Download file in box folder
211
231
  """
212
232
  file_id = self.get_file_id_from_filename(remote_file)
233
+ if file_id is None:
234
+ raise BackendException(f"File {remote_file} not found.", code=log.ErrorCode.backend_not_found)
213
235
  with open(local_file, "wb") as fp:
214
236
  self._client.file(file_id).download_to(fp)
215
237
 
@@ -218,7 +240,20 @@ class BoxBackend(duplicity.backend.Backend):
218
240
  Delete file in box folder
219
241
  """
220
242
  file_id = self.get_file_id_from_filename(remote_file)
221
- self._client.file(file_id).delete()
243
+ if file_id is None:
244
+ self._file_to_metadata_map.pop(remote_file, None)
245
+ log.Debug(f"BoxBackend.delete: file {remote_file} not found, already deleted")
246
+ return
247
+ try:
248
+ self._client.file(file_id).delete()
249
+ except Exception as e:
250
+ code = self._error_code("delete", e)
251
+ if code == log.ErrorCode.backend_not_found:
252
+ log.Debug(f"BoxBackend.delete: file {remote_file} not found, already deleted")
253
+ return
254
+ raise
255
+ finally:
256
+ self._file_to_metadata_map.pop(remote_file, None)
222
257
 
223
258
 
224
259
  duplicity.backend.register_backend("box", BoxBackend)
@@ -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:
@@ -493,8 +493,7 @@ class IDriveBackend(duplicity.backend.Backend):
493
493
  # For each filename in list: take-out size (index 1) for requested filename (index -1)
494
494
  info = {}
495
495
  for filename in filename_list:
496
- if filtered:
497
- result = [x[1] for x in filtered if x[-1] == filename.decode("utf-8")]
496
+ result = [x[1] for x in filtered if x[-1] == filename.decode("utf-8")] if filtered else []
498
497
  if result:
499
498
  info[filename] = {"size": int(result[0])}
500
499
  else:
@@ -47,7 +47,8 @@ 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 import log
51
+ from duplicity.errors import BackendException
51
52
  import duplicity.backend
52
53
 
53
54