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.
- {devpi_server-6.17.0 → devpi_server-6.18.0}/.flake8 +0 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/CHANGELOG +31 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/CHANGELOG.short.rst +31 -30
- {devpi_server-6.17.0 → devpi_server-6.18.0}/PKG-INFO +33 -31
- devpi_server-6.18.0/devpi_server/__init__.py +1 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/__main__.py +1 -0
- devpi_server-6.18.0/devpi_server/compat.py +35 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/config.py +95 -36
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/filestore.py +144 -59
- devpi_server-6.18.0/devpi_server/filestore_db.py +82 -0
- devpi_server-6.18.0/devpi_server/filestore_fs.py +178 -0
- devpi_server-6.18.0/devpi_server/filestore_fs_base.py +329 -0
- devpi_server-6.18.0/devpi_server/filestore_hash_hl.py +232 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/fileutil.py +30 -18
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/fsck.py +9 -10
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/genconfig.py +21 -18
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/hookspecs.py +1 -0
- devpi_server-6.18.0/devpi_server/htmlpage.py +73 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/httpclient.py +35 -17
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/importexport.py +147 -113
- devpi_server-6.18.0/devpi_server/interfaces.py +569 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/keyfs.py +201 -39
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/keyfs_sqlite.py +43 -21
- devpi_server-6.18.0/devpi_server/keyfs_sqlite_fs.py +47 -0
- devpi_server-6.18.0/devpi_server/keyfs_types.py +302 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/main.py +37 -33
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/mirror.py +265 -130
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/model.py +313 -158
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/mythread.py +1 -0
- devpi_server-6.18.0/devpi_server/normalized.py +29 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/readonly.py +35 -10
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/replica.py +133 -61
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/sizeof.py +13 -6
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/view_auth.py +16 -10
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/views.py +49 -38
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/PKG-INFO +33 -31
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/SOURCES.txt +7 -3
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/entry_points.txt +0 -3
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/requires.txt +3 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/mypy.ini +59 -25
- {devpi_server-6.17.0 → devpi_server-6.18.0}/pyproject.toml +3 -136
- devpi_server-6.18.0/pytest_devpi_server/__init__.py +11 -0
- devpi_server-6.18.0/test_devpi_server/example.py +25 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/functional.py +63 -6
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/plugin.py +182 -61
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/simpypi.py +9 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_auth.py +7 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_config.py +14 -3
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_conftest.py +1 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_filestore.py +121 -49
- devpi_server-6.18.0/test_devpi_server/test_filestore_fs.py +180 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_importexport.py +69 -37
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_keyfs.py +123 -49
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_log.py +6 -5
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_main.py +9 -6
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_mirror.py +140 -35
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_mirror_no_project_list.py +4 -2
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_model.py +156 -74
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_mythread.py +0 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_permissions.py +6 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_replica.py +157 -38
- devpi_server-6.18.0/test_devpi_server/test_replica_functional.py +172 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_stage_customizer.py +21 -6
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_view_auth.py +3 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_views.py +49 -26
- {devpi_server-6.17.0 → devpi_server-6.18.0}/tox.ini +16 -3
- devpi_server-6.17.0/devpi_server/__init__.py +0 -1
- devpi_server-6.17.0/devpi_server/filestore_fs.py +0 -136
- devpi_server-6.17.0/devpi_server/interfaces.py +0 -289
- devpi_server-6.17.0/devpi_server/keyfs_sqlite_fs.py +0 -227
- devpi_server-6.17.0/devpi_server/keyfs_types.py +0 -144
- devpi_server-6.17.0/devpi_server/vendor/_pip.py +0 -152
- devpi_server-6.17.0/pytest_devpi_server/__init__.py +0 -4
- devpi_server-6.17.0/test_devpi_server/__init__.py +0 -0
- devpi_server-6.17.0/test_devpi_server/example.py +0 -22
- devpi_server-6.17.0/test_devpi_server/test_keyfs_sqlite_fs.py +0 -71
- devpi_server-6.17.0/test_devpi_server/test_replica_functional.py +0 -98
- {devpi_server-6.17.0 → devpi_server-6.18.0}/LICENSE +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/MANIFEST.in +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/README.rst +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/auth.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/auth_basic.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/auth_devpi.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/__init__.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/crontab.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/devpi.service.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/launchd-macos.txt.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi-caching-http.conf.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi-caching-location.conf.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi-caching-proxy.conf.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi-caching-server.conf.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/nginx-devpi.conf.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/supervisor-devpi.conf.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/supervisord.conf.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/cfg/windows-service.txt.template +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/exceptions.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/init.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/log.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/markers.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/middleware.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/passwd.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server/py.typed +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/dependency_links.txt +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/devpi_server.egg-info/top_level.txt +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/setup.cfg +0 -0
- {devpi_server-6.17.0/devpi_server/vendor → devpi_server-6.18.0/test_devpi_server}/__init__.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/conftest.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/badindexname/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/badusername/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/basescycle/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/createdmodified/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/deletedbase/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/mirrordata/dataindex.json +0 -0
- {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
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/modifiedpypi/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/nocreatedmodified/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/normalization/dataindex.json +0 -0
- {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
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/normalization_merge/dataindex.json +0 -0
- {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
- {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
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/norootpypi/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/nouser/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/removedindexplugin/dataindex.json +0 -0
- {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
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/toxresult_naming_scheme/dataindex.json +0 -0
- {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
- {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
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/importexportdata/toxresult_upload_default/dataindex.json +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/py.typed +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/reqmock.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_authcheck.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_fileutil.py +1 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_fsck.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_genconfig.py +1 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_nginx.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_nginx_replica.py +3 -3
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_readonly.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_streaming.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_streaming_nginx.py +1 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_streaming_replica.py +1 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_streaming_replica_nginx.py +1 -1
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_views_patch.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_views_push_external.py +0 -0
- {devpi_server-6.17.0 → devpi_server-6.18.0}/test_devpi_server/test_views_status.py +0 -0
|
@@ -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.
|
|
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"
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
462
|
-
|
|
463
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
557
|
-
"""
|
|
571
|
+
def get_action_long_option_string(action):
|
|
572
|
+
"""extract long option string of action
|
|
558
573
|
|
|
559
|
-
|
|
560
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
608
|
+
default = defaultget(option_string[2:])
|
|
590
609
|
except KeyError:
|
|
591
610
|
pass
|
|
592
611
|
else:
|
|
593
612
|
if isinstance(action, argparse._StoreTrueAction):
|
|
594
|
-
|
|
613
|
+
default = bool(strtobool(default))
|
|
595
614
|
elif isinstance(action, argparse._StoreFalseAction):
|
|
596
|
-
|
|
597
|
-
|
|
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(
|
|
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
|
|
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."
|
|
1107
|
+
"--secretfile to explicitly provide the location.",
|
|
1108
|
+
secretfile,
|
|
1109
|
+
)
|
|
1051
1110
|
return secretfile
|
|
1052
1111
|
return Path(self.args.secretfile).expanduser()
|
|
1053
1112
|
|