devpi-server 6.17.0__tar.gz → 6.18.0__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 (145) hide show
  1. {devpi_server-6.17.0 → devpi_server-6.18.0}/.flake8 +0 -1
  2. {devpi_server-6.17.0 → devpi_server-6.18.0}/CHANGELOG +31 -0
  3. {devpi_server-6.17.0 → devpi_server-6.18.0}/CHANGELOG.short.rst +31 -30
  4. {devpi_server-6.17.0 → devpi_server-6.18.0}/PKG-INFO +33 -31
  5. devpi_server-6.18.0/devpi_server/__init__.py +1 -0
  6. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/__main__.py +1 -0
  7. devpi_server-6.18.0/devpi_server/compat.py +35 -0
  8. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/config.py +95 -36
  9. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/filestore.py +144 -59
  10. devpi_server-6.18.0/devpi_server/filestore_db.py +82 -0
  11. devpi_server-6.18.0/devpi_server/filestore_fs.py +178 -0
  12. devpi_server-6.18.0/devpi_server/filestore_fs_base.py +329 -0
  13. devpi_server-6.18.0/devpi_server/filestore_hash_hl.py +232 -0
  14. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/fileutil.py +30 -18
  15. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/fsck.py +9 -10
  16. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/genconfig.py +21 -18
  17. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/hookspecs.py +1 -0
  18. devpi_server-6.18.0/devpi_server/htmlpage.py +73 -0
  19. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/httpclient.py +35 -17
  20. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/importexport.py +147 -113
  21. devpi_server-6.18.0/devpi_server/interfaces.py +569 -0
  22. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/keyfs.py +201 -39
  23. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/keyfs_sqlite.py +43 -21
  24. devpi_server-6.18.0/devpi_server/keyfs_sqlite_fs.py +47 -0
  25. devpi_server-6.18.0/devpi_server/keyfs_types.py +302 -0
  26. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/main.py +37 -33
  27. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/mirror.py +265 -130
  28. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/model.py +313 -158
  29. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/mythread.py +1 -0
  30. devpi_server-6.18.0/devpi_server/normalized.py +29 -0
  31. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/readonly.py +35 -10
  32. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/replica.py +133 -61
  33. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/sizeof.py +13 -6
  34. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/view_auth.py +16 -10
  35. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/views.py +49 -38
  36. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/PKG-INFO +33 -31
  37. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/SOURCES.txt +7 -3
  38. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/entry_points.txt +0 -3
  39. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/requires.txt +3 -0
  40. {devpi_server-6.17.0 → devpi_server-6.18.0}/mypy.ini +59 -25
  41. {devpi_server-6.17.0 → devpi_server-6.18.0}/pyproject.toml +3 -136
  42. devpi_server-6.18.0/pytest_devpi_server/__init__.py +11 -0
  43. devpi_server-6.18.0/test_devpi_server/example.py +25 -0
  44. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/functional.py +63 -6
  45. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/plugin.py +182 -61
  46. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/simpypi.py +9 -1
  47. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_auth.py +7 -1
  48. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_config.py +14 -3
  49. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_conftest.py +1 -0
  50. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_filestore.py +121 -49
  51. devpi_server-6.18.0/test_devpi_server/test_filestore_fs.py +180 -0
  52. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_importexport.py +69 -37
  53. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_keyfs.py +123 -49
  54. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_log.py +6 -5
  55. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_main.py +9 -6
  56. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_mirror.py +140 -35
  57. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_mirror_no_project_list.py +4 -2
  58. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_model.py +156 -74
  59. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_mythread.py +0 -1
  60. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_permissions.py +6 -1
  61. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_replica.py +157 -38
  62. devpi_server-6.18.0/test_devpi_server/test_replica_functional.py +172 -0
  63. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_stage_customizer.py +21 -6
  64. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_view_auth.py +3 -0
  65. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_views.py +49 -26
  66. {devpi_server-6.17.0 → devpi_server-6.18.0}/tox.ini +16 -3
  67. devpi_server-6.17.0/devpi_server/__init__.py +0 -1
  68. devpi_server-6.17.0/devpi_server/filestore_fs.py +0 -136
  69. devpi_server-6.17.0/devpi_server/interfaces.py +0 -289
  70. devpi_server-6.17.0/devpi_server/keyfs_sqlite_fs.py +0 -227
  71. devpi_server-6.17.0/devpi_server/keyfs_types.py +0 -144
  72. devpi_server-6.17.0/devpi_server/vendor/_pip.py +0 -152
  73. devpi_server-6.17.0/pytest_devpi_server/__init__.py +0 -4
  74. devpi_server-6.17.0/test_devpi_server/__init__.py +0 -0
  75. devpi_server-6.17.0/test_devpi_server/example.py +0 -22
  76. devpi_server-6.17.0/test_devpi_server/test_keyfs_sqlite_fs.py +0 -71
  77. devpi_server-6.17.0/test_devpi_server/test_replica_functional.py +0 -98
  78. {devpi_server-6.17.0 → devpi_server-6.18.0}/LICENSE +0 -0
  79. {devpi_server-6.17.0 → devpi_server-6.18.0}/MANIFEST.in +0 -0
  80. {devpi_server-6.17.0 → devpi_server-6.18.0}/README.rst +0 -0
  81. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/auth.py +0 -0
  82. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/auth_basic.py +0 -0
  83. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/auth_devpi.py +0 -0
  84. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/__init__.py +0 -0
  85. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/crontab.template +0 -0
  86. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/devpi.service.template +0 -0
  87. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/launchd-macos.txt.template +0 -0
  88. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi-caching-http.conf.template +0 -0
  89. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi-caching-location.conf.template +0 -0
  90. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi-caching-proxy.conf.template +0 -0
  91. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi-caching-server.conf.template +0 -0
  92. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi.conf.template +0 -0
  93. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/supervisor-devpi.conf.template +0 -0
  94. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/supervisord.conf.template +0 -0
  95. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/windows-service.txt.template +0 -0
  96. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/exceptions.py +0 -0
  97. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/init.py +0 -0
  98. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/log.py +0 -0
  99. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/markers.py +0 -0
  100. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/middleware.py +0 -0
  101. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/passwd.py +0 -0
  102. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/py.typed +0 -0
  103. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/dependency_links.txt +0 -0
  104. {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/top_level.txt +0 -0
  105. {devpi_server-6.17.0 → devpi_server-6.18.0}/setup.cfg +0 -0
  106. {devpi_server-6.17.0/devpi_server/vendor → devpi_server-6.18.0/test_devpi_server}/__init__.py +0 -0
  107. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/conftest.py +0 -0
  108. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/badindexname/dataindex.json +0 -0
  109. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/badusername/dataindex.json +0 -0
  110. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/basescycle/dataindex.json +0 -0
  111. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/createdmodified/dataindex.json +0 -0
  112. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/deletedbase/dataindex.json +0 -0
  113. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/mirrordata/dataindex.json +0 -0
  114. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/mirrordata/root/pypi/dddttt/0.1.dev1/dddttt-0.1.dev1.tar.gz +0 -0
  115. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/modifiedpypi/dataindex.json +0 -0
  116. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/nocreatedmodified/dataindex.json +0 -0
  117. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/normalization/dataindex.json +0 -0
  118. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/normalization/root/dev/hello.pkg/hello.pkg-1.0.tar.gz +0 -0
  119. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/normalization_merge/dataindex.json +0 -0
  120. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/normalization_merge/root/dev/hello-pkg/hello.pkg-1.1.tar.gz +0 -0
  121. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/normalization_merge/root/dev/hello.pkg/hello.pkg-1.0.tar.gz +0 -0
  122. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/norootpypi/dataindex.json +0 -0
  123. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/nouser/dataindex.json +0 -0
  124. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/removedindexplugin/dataindex.json +0 -0
  125. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/removedindexplugin/user/dev/pkg/pkg-1.0.tar.gz +0 -0
  126. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/toxresult_naming_scheme/dataindex.json +0 -0
  127. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/toxresult_naming_scheme/root/dev/hello/0.9/hello-0.9.tar.gz +0 -0
  128. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/toxresult_naming_scheme/root/dev/hello/sha256=ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73/hello-0.9.tar.gz.toxresult0 +0 -0
  129. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/toxresult_upload_default/dataindex.json +0 -0
  130. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/py.typed +0 -0
  131. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/reqmock.py +0 -0
  132. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_authcheck.py +0 -0
  133. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_fileutil.py +1 -1
  134. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_fsck.py +0 -0
  135. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_genconfig.py +1 -1
  136. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_nginx.py +0 -0
  137. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_nginx_replica.py +3 -3
  138. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_readonly.py +0 -0
  139. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_streaming.py +0 -0
  140. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_streaming_nginx.py +1 -1
  141. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_streaming_replica.py +1 -1
  142. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_streaming_replica_nginx.py +1 -1
  143. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_views_patch.py +0 -0
  144. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_views_push_external.py +0 -0
  145. {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_views_status.py +0 -0
@@ -3,7 +3,6 @@
3
3
  ignore = E203,E501,E704,E741,W503
4
4
  per-file-ignores =
5
5
  plugin.py:E127,E128,E231
6
- importexport.py:E127
7
6
  model.py:E128,E231
8
7
  test_importexport.py:E121
9
8
  test*.py:E126,E127,E128,E225,E226,E231,E251
@@ -2,6 +2,37 @@
2
2
 
3
3
  .. towncrier release notes start
4
4
 
5
+ 6.18.0 (2026-01-27)
6
+ ===================
7
+
8
+ Features
9
+ --------
10
+
11
+ - Store all available hashes of files.
12
+
13
+ - Validate hashes of all files during devpi-import, not only releases.
14
+
15
+ Bug Fixes
16
+ ---------
17
+
18
+ - Apply argparse transformations on values read from config file or environment.
19
+
20
+ - Restore Python and platform info in user agent string after switch to httpx.
21
+
22
+ - Remove all database entries on project deletion instead of only emptying them.
23
+
24
+ - Fix error at end of replica streaming caused by changed behavior from switch to httpx.
25
+
26
+ - Fix #1102: The data stream was cut off after 64k when proxying from replica to primary after switching to httpx.
27
+
28
+ - Fix #1107: retry file downloads if there has been an error during download.
29
+
30
+ Other Changes
31
+ -------------
32
+
33
+ - The filenames of some exported doczip files change due to normalization of the project name caused by changing the internals during export to allow ``--hard-links`` to work.
34
+
35
+
5
36
  6.17.0 (2025-08-27)
6
37
  ===================
7
38
 
@@ -9,6 +9,37 @@ Changelog
9
9
 
10
10
  .. towncrier release notes start
11
11
 
12
+ 6.18.0 (2026-01-27)
13
+ ===================
14
+
15
+ Features
16
+ --------
17
+
18
+ - Store all available hashes of files.
19
+
20
+ - Validate hashes of all files during devpi-import, not only releases.
21
+
22
+ Bug Fixes
23
+ ---------
24
+
25
+ - Apply argparse transformations on values read from config file or environment.
26
+
27
+ - Restore Python and platform info in user agent string after switch to httpx.
28
+
29
+ - Remove all database entries on project deletion instead of only emptying them.
30
+
31
+ - Fix error at end of replica streaming caused by changed behavior from switch to httpx.
32
+
33
+ - Fix #1102: The data stream was cut off after 64k when proxying from replica to primary after switching to httpx.
34
+
35
+ - Fix #1107: retry file downloads if there has been an error during download.
36
+
37
+ Other Changes
38
+ -------------
39
+
40
+ - The filenames of some exported doczip files change due to normalization of the project name caused by changing the internals during export to allow ``--hard-links`` to work.
41
+
42
+
12
43
  6.17.0 (2025-08-27)
13
44
  ===================
14
45
 
@@ -104,33 +135,3 @@ Bug Fixes
104
135
 
105
136
  - No longer automatically "register" a project when pushing releases to PyPI. The reply changed from HTTP status 410 to 400 breaking the upload. With devpi-client 7.2.0 there is a ``--register-project`` option if it is still required for some other package registry.
106
137
 
107
-
108
- 6.13.0 (2024-09-19)
109
- ===================
110
-
111
- Deprecations and Removals
112
- -------------------------
113
-
114
- - Remove/Deprecate "master" related terminology in favor of "primary".
115
- Usage related changes are the switch to ``--primary-url`` instead of ``--master-url`` and ``--role=primary`` instead of ``--role=master``.
116
- Using the old terms will now output warnings.
117
- The ``+status`` API has additional fields and the ``role`` field content will change with 7.0.0.
118
-
119
- Features
120
- --------
121
-
122
- - Enable logging command line options for all commands.
123
-
124
- - Added support uv pip as an installer.
125
-
126
- Bug Fixes
127
- ---------
128
-
129
- - Don't report on lagging event processing while replicating.
130
-
131
- - Report primary serial correctly with streaming replication.
132
-
133
- - Don't store file data in memory when fetching a release while pushing from a mirror.
134
-
135
- - Only warn about replica not being in sync instead of fatal status while still replicating.
136
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devpi-server
3
- Version: 6.17.0
3
+ Version: 6.18.0
4
4
  Summary: devpi-server: reliable, private, and pypi.org caching server
5
5
  Maintainer-email: Florian Schulze <mail@pyfidelity.com>
6
6
  License-Expression: MIT
@@ -42,6 +42,7 @@ Requires-Dist: pluggy<2.0,>=0.6.0
42
42
  Requires-Dist: py>=1.4.23
43
43
  Requires-Dist: pyramid>=2
44
44
  Requires-Dist: repoze.lru>=0.6
45
+ Requires-Dist: strenum; python_version < "3.11"
45
46
  Requires-Dist: strictyaml
46
47
  Requires-Dist: waitress>=1.0.1
47
48
  Requires-Dist: ruamel.yaml
@@ -121,6 +122,37 @@ Changelog
121
122
 
122
123
  .. towncrier release notes start
123
124
 
125
+ 6.18.0 (2026-01-27)
126
+ ===================
127
+
128
+ Features
129
+ --------
130
+
131
+ - Store all available hashes of files.
132
+
133
+ - Validate hashes of all files during devpi-import, not only releases.
134
+
135
+ Bug Fixes
136
+ ---------
137
+
138
+ - Apply argparse transformations on values read from config file or environment.
139
+
140
+ - Restore Python and platform info in user agent string after switch to httpx.
141
+
142
+ - Remove all database entries on project deletion instead of only emptying them.
143
+
144
+ - Fix error at end of replica streaming caused by changed behavior from switch to httpx.
145
+
146
+ - Fix #1102: The data stream was cut off after 64k when proxying from replica to primary after switching to httpx.
147
+
148
+ - Fix #1107: retry file downloads if there has been an error during download.
149
+
150
+ Other Changes
151
+ -------------
152
+
153
+ - The filenames of some exported doczip files change due to normalization of the project name caused by changing the internals during export to allow ``--hard-links`` to work.
154
+
155
+
124
156
  6.17.0 (2025-08-27)
125
157
  ===================
126
158
 
@@ -216,33 +248,3 @@ Bug Fixes
216
248
 
217
249
  - No longer automatically "register" a project when pushing releases to PyPI. The reply changed from HTTP status 410 to 400 breaking the upload. With devpi-client 7.2.0 there is a ``--register-project`` option if it is still required for some other package registry.
218
250
 
219
-
220
- 6.13.0 (2024-09-19)
221
- ===================
222
-
223
- Deprecations and Removals
224
- -------------------------
225
-
226
- - Remove/Deprecate "master" related terminology in favor of "primary".
227
- Usage related changes are the switch to ``--primary-url`` instead of ``--master-url`` and ``--role=primary`` instead of ``--role=master``.
228
- Using the old terms will now output warnings.
229
- The ``+status`` API has additional fields and the ``role`` field content will change with 7.0.0.
230
-
231
- Features
232
- --------
233
-
234
- - Enable logging command line options for all commands.
235
-
236
- - Added support uv pip as an installer.
237
-
238
- Bug Fixes
239
- ---------
240
-
241
- - Don't report on lagging event processing while replicating.
242
-
243
- - Report primary serial correctly with streaming replication.
244
-
245
- - Don't store file data in memory when fetching a release while pushing from a mirror.
246
-
247
- - Only warn about replica not being in sync instead of fatal status while still replicating.
248
-
@@ -0,0 +1 @@
1
+ __version__ = "6.18.0"
@@ -1,4 +1,5 @@
1
1
  import devpi_server.main
2
2
 
3
+
3
4
  if __name__ == "__main__":
4
5
  devpi_server.main.main()
@@ -0,0 +1,35 @@
1
+ try:
2
+ from enum import StrEnum
3
+ except ImportError:
4
+ from strenum import StrEnum # noqa: F401
5
+ from tempfile import SpooledTemporaryFile
6
+
7
+
8
+ # before Python 3.11 some methods were missing
9
+ if not hasattr(SpooledTemporaryFile, "readable"):
10
+
11
+ def readable(self):
12
+ return self._file.readable()
13
+
14
+ SpooledTemporaryFile.readable = readable # type: ignore[method-assign]
15
+
16
+ if not hasattr(SpooledTemporaryFile, "readinto"):
17
+
18
+ def readinto(self, buffer):
19
+ return self._file.readinto(buffer)
20
+
21
+ SpooledTemporaryFile.readinto = readinto # type: ignore[attr-defined]
22
+
23
+ if not hasattr(SpooledTemporaryFile, "seekable"):
24
+
25
+ def seekable(self):
26
+ return self._file.seekable()
27
+
28
+ SpooledTemporaryFile.seekable = seekable # type: ignore[method-assign]
29
+
30
+ if not hasattr(SpooledTemporaryFile, "writable"):
31
+
32
+ def writable(self):
33
+ return self._file.writable()
34
+
35
+ SpooledTemporaryFile.writable = writable # type: ignore[method-assign]
@@ -1,26 +1,36 @@
1
+ from __future__ import annotations
2
+
3
+ from . import fileutil
4
+ from . import hookspecs
5
+ from .interfaces import IIOFileFactory
6
+ from .log import threadlog
7
+ from devpi_common.types import cached_property
8
+ from devpi_common.url import URL
9
+ from functools import partial
10
+ from operator import itemgetter
11
+ from pathlib import Path
12
+ from pluggy import HookimplMarker
13
+ from pluggy import PluginManager
14
+ from tempfile import NamedTemporaryFile
15
+ from typing import TYPE_CHECKING
1
16
  import argon2
17
+ import argparse
2
18
  import base64
19
+ import devpi_server
20
+ import json
3
21
  import os.path
4
- import argparse
22
+ import py
5
23
  import secrets
6
24
  import sys
7
25
  import uuid
8
- from operator import itemgetter
9
- from pathlib import Path
10
- from tempfile import NamedTemporaryFile
11
- from pluggy import HookimplMarker, PluginManager
12
- import py
13
- from devpi_common.types import cached_property
14
- from functools import partial
15
- from .log import threadlog
16
- from . import fileutil
17
- from . import hookspecs
18
- import json
19
- import devpi_server
20
- from devpi_common.url import URL
21
26
  import warnings
22
27
 
23
28
 
29
+ if TYPE_CHECKING:
30
+ from .interfaces import IStorageConnection4
31
+ from collections.abc import Callable
32
+
33
+
24
34
  log = threadlog
25
35
 
26
36
 
@@ -70,7 +80,7 @@ def traced_pluggy_call(hook, **caller_kwargs):
70
80
  if firstresult:
71
81
  break
72
82
  if firstresult:
73
- results = results[0] if results else None
83
+ return (results[0] if results else None, plugin_names)
74
84
  return (results, plugin_names)
75
85
 
76
86
 
@@ -458,9 +468,11 @@ def get_parser(pluginmanager):
458
468
 
459
469
  def find_config_file():
460
470
  import platformdirs
461
- config_dirs = platformdirs.site_config_dir(
462
- 'devpi-server', 'devpi', multipath=True)
463
- config_dirs = config_dirs.split(os.pathsep)
471
+
472
+ config_dirs_str: str = platformdirs.site_config_dir(
473
+ "devpi-server", "devpi", multipath=True
474
+ )
475
+ config_dirs: list[str] = config_dirs_str.split(os.pathsep)
464
476
  config_dirs.append(
465
477
  platformdirs.user_config_dir('devpi-server', 'devpi'))
466
478
  config_files = []
@@ -537,15 +549,18 @@ def parseoptions(pluginmanager, argv, parser=None):
537
549
  try:
538
550
  config_options = load_config_file(config_file)
539
551
  except InvalidConfigError as e:
540
- log.error("Error in config file '%s':\n %s" % ( # noqa: TRY400
541
- config_file, e))
552
+ log.error( # noqa: TRY400
553
+ "Error in config file '%s':\n %s", config_file, e
554
+ )
542
555
  sys.exit(4)
543
556
  defaultget = partial(
544
557
  default_getter,
545
558
  config_options=config_options,
546
559
  environ=os.environ)
547
560
  parser.post_process_actions(defaultget=defaultget)
548
- if args.help is True:
561
+ # the getattr is a workaround for a problem with 3.14t-dev
562
+ # weirdly enough it does not happen with 3.14-dev
563
+ if getattr(args, "help", False) is True:
549
564
  parser.print_help()
550
565
  parser.exit()
551
566
  args = parser.parse_args(argv[1:])
@@ -553,12 +568,11 @@ def parseoptions(pluginmanager, argv, parser=None):
553
568
  return config
554
569
 
555
570
 
556
- def get_action_long_name(action):
557
- """ extract long name of action
571
+ def get_action_long_option_string(action):
572
+ """extract long option string of action
558
573
 
559
- Looks for the first option string that is long enough and
560
- starts with two ``prefix_chars``.
561
- For example ``--no-events`` would return ``no-events``.
574
+ Looks for the first option string that is long enough and
575
+ starts with two ``prefix_chars``.
562
576
  """
563
577
  for option_string in action.option_strings:
564
578
  if not len(option_string) > 2:
@@ -567,7 +581,8 @@ def get_action_long_name(action):
567
581
  continue
568
582
  if option_string[1] not in action.container.prefix_chars:
569
583
  continue
570
- return option_string[2:]
584
+ return option_string
585
+ return None
571
586
 
572
587
 
573
588
  class MyArgumentParser(argparse.ArgumentParser):
@@ -584,25 +599,33 @@ class MyArgumentParser(argparse.ArgumentParser):
584
599
  get the current value if a global or user config file is loaded.
585
600
  """
586
601
  for action in self._actions:
587
- if defaultget is not None:
602
+ if isinstance(action, argparse._HelpAction):
603
+ continue
604
+ default = action.default
605
+ option_string = get_action_long_option_string(action)
606
+ if defaultget is not None and option_string is not None:
588
607
  try:
589
- action.default = defaultget(get_action_long_name(action))
608
+ default = defaultget(option_string[2:])
590
609
  except KeyError:
591
610
  pass
592
611
  else:
593
612
  if isinstance(action, argparse._StoreTrueAction):
594
- action.default = bool(strtobool(action.default))
613
+ default = bool(strtobool(default))
595
614
  elif isinstance(action, argparse._StoreFalseAction):
596
- action.default = not bool(strtobool(action.default))
597
- default = action.default
615
+ default = not bool(strtobool(default))
616
+ else:
617
+ temp_args = argparse.Namespace()
618
+ action(self, temp_args, default, option_string)
619
+ default = getattr(temp_args, action.dest)
620
+ action.default = default
598
621
  if isinstance(action, argparse._StoreFalseAction):
599
622
  default = not default
600
623
  if action.help and argparse.SUPPRESS not in (action.help, default):
601
624
  action.help += " [%s]" % default
602
625
 
603
626
  def addgroup(self, *args, **kwargs):
604
- grp = super(MyArgumentParser, self).add_argument_group(*args, **kwargs)
605
- grp.addoption = grp.add_argument
627
+ grp = super().add_argument_group(*args, **kwargs)
628
+ grp.addoption = grp.add_argument # type: ignore[attr-defined]
606
629
  return grp
607
630
 
608
631
  def add_all_options(self):
@@ -658,6 +681,36 @@ class ConfigurationError(Exception):
658
681
  """ incorrect configuration or environment settings. """
659
682
 
660
683
 
684
+ def get_io_file_factory(storage_info: dict) -> IIOFileFactory:
685
+ from .interfaces import IIOFile
686
+ from zope.interface import provider
687
+ from zope.interface.verify import verifyObject
688
+
689
+ _io_file_factory: Callable
690
+ db_filestore = storage_info.setdefault("db_filestore", True)
691
+ settings = storage_info.setdefault("settings", {})
692
+ if db_filestore:
693
+ from .filestore_db import DBIOFile
694
+
695
+ _io_file_factory = DBIOFile
696
+ else:
697
+ fsbackend = settings.setdefault("fsbackend", "fs")
698
+ _io_file_factory = __import__(
699
+ f"filestore_{fsbackend}", globals=globals(), level=1
700
+ ).fsiofile_factory
701
+
702
+ storage_info.setdefault("_test_markers", []).append("storage_with_filesystem")
703
+ verifyObject(IIOFileFactory, _io_file_factory)
704
+
705
+ @provider(IIOFileFactory)
706
+ def io_file_factory(conn: IStorageConnection4) -> IIOFile:
707
+ result = IIOFile(_io_file_factory(conn, settings))
708
+ verifyObject(IIOFile, result)
709
+ return result
710
+
711
+ return io_file_factory
712
+
713
+
661
714
  class Config:
662
715
  def __init__(self, args, pluginmanager):
663
716
  self.args = args
@@ -1004,7 +1057,11 @@ class Config:
1004
1057
  return self._storage_info_from_name(name, settings)
1005
1058
 
1006
1059
  @property
1007
- def storage(self):
1060
+ def io_file_factory(self) -> IIOFileFactory:
1061
+ return get_io_file_factory(self._storage_info())
1062
+
1063
+ @property
1064
+ def storage(self) -> type:
1008
1065
  return self._storage_info()["storage"]
1009
1066
 
1010
1067
  def _determine_storage(self):
@@ -1047,7 +1104,9 @@ class Config:
1047
1104
  return None
1048
1105
  log.warning(
1049
1106
  "Using deprecated existing secret file at '%s', use "
1050
- "--secretfile to explicitly provide the location." % secretfile)
1107
+ "--secretfile to explicitly provide the location.",
1108
+ secretfile,
1109
+ )
1051
1110
  return secretfile
1052
1111
  return Path(self.args.secretfile).expanduser()
1053
1112