devpi-web 5.0.0__tar.gz → 5.0.1__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 (77) hide show
  1. {devpi_web-5.0.0 → devpi_web-5.0.1}/CHANGELOG +10 -0
  2. {devpi_web-5.0.0 → devpi_web-5.0.1}/CHANGELOG.short.rst +10 -11
  3. {devpi_web-5.0.0 → devpi_web-5.0.1}/PKG-INFO +11 -12
  4. devpi_web-5.0.1/devpi_web/__init__.py +1 -0
  5. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/doczip.py +6 -3
  6. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web.egg-info/PKG-INFO +11 -12
  7. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_indexing.py +51 -0
  8. devpi_web-5.0.0/devpi_web/__init__.py +0 -1
  9. {devpi_web-5.0.0 → devpi_web-5.0.1}/.flake8 +0 -0
  10. {devpi_web-5.0.0 → devpi_web-5.0.1}/LICENSE +0 -0
  11. {devpi_web-5.0.0 → devpi_web-5.0.1}/MANIFEST.in +0 -0
  12. {devpi_web-5.0.0 → devpi_web-5.0.1}/README.rst +0 -0
  13. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/clear_index.py +0 -0
  14. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/compat.py +0 -0
  15. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/config.py +0 -0
  16. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/description.py +0 -0
  17. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/hookspecs.py +0 -0
  18. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/indexing.py +0 -0
  19. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/macroregistry.py +0 -0
  20. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/macros.py +0 -0
  21. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/main.py +0 -0
  22. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/null_index.py +0 -0
  23. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/static/common.js +0 -0
  24. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/static/docview.js +0 -0
  25. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/static/favicon.ico +0 -0
  26. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/static/jquery-3.6.0.min.js +0 -0
  27. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/static/search.js +0 -0
  28. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/static/style.css +0 -0
  29. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/doc.pt +0 -0
  30. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/error.pt +0 -0
  31. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/favicon.pt +0 -0
  32. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/footer.pt +0 -0
  33. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/footer_versions.pt +0 -0
  34. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/head.pt +0 -0
  35. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/header.pt +0 -0
  36. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/header_breadcrumbs.pt +0 -0
  37. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/header_search.pt +0 -0
  38. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/header_status.pt +0 -0
  39. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/html_head_css.pt +0 -0
  40. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/html_head_scripts.pt +0 -0
  41. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/index.pt +0 -0
  42. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/logo.pt +0 -0
  43. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/notfound.pt +0 -0
  44. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/project.pt +0 -0
  45. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/query_docs.pt +0 -0
  46. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/root.pt +0 -0
  47. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/root_above_user_index_list.pt +0 -0
  48. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/root_below_user_index_list.pt +0 -0
  49. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/search.pt +0 -0
  50. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/search_help.pt +0 -0
  51. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/status.pt +0 -0
  52. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/status_badge.pt +0 -0
  53. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/toxresult.pt +0 -0
  54. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/toxresults.pt +0 -0
  55. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/user.pt +0 -0
  56. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/templates/version.pt +0 -0
  57. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/views.py +0 -0
  58. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web/whoosh_index.py +0 -0
  59. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web.egg-info/SOURCES.txt +0 -0
  60. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web.egg-info/dependency_links.txt +0 -0
  61. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web.egg-info/entry_points.txt +0 -0
  62. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web.egg-info/requires.txt +0 -0
  63. {devpi_web-5.0.0 → devpi_web-5.0.1}/devpi_web.egg-info/top_level.txt +0 -0
  64. {devpi_web-5.0.0 → devpi_web-5.0.1}/mypy.ini +0 -0
  65. {devpi_web-5.0.0 → devpi_web-5.0.1}/pyproject.toml +0 -0
  66. {devpi_web-5.0.0 → devpi_web-5.0.1}/setup.cfg +0 -0
  67. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/conftest.py +0 -0
  68. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_macro_registry.py +0 -0
  69. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_main.py +0 -0
  70. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_theme.py +0 -0
  71. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_views.py +0 -0
  72. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_views_docs.py +0 -0
  73. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_views_misc.py +0 -0
  74. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_views_search.py +0 -0
  75. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_views_toxresults.py +0 -0
  76. {devpi_web-5.0.0 → devpi_web-5.0.1}/tests/test_whoosh_index.py +0 -0
  77. {devpi_web-5.0.0 → devpi_web-5.0.1}/tox.ini +0 -0
@@ -2,6 +2,16 @@
2
2
 
3
3
  .. towncrier release notes start
4
4
 
5
+ 5.0.1 (2025-06-15)
6
+ ==================
7
+
8
+ Bug Fixes
9
+ ---------
10
+
11
+ - Fix traceback during unpacking of documentation in some cases.
12
+
13
+
14
+
5
15
  5.0.0 (2025-06-12)
6
16
  ==================
7
17
 
@@ -9,6 +9,16 @@ Changelog
9
9
 
10
10
  .. towncrier release notes start
11
11
 
12
+ 5.0.1 (2025-06-15)
13
+ ==================
14
+
15
+ Bug Fixes
16
+ ---------
17
+
18
+ - Fix traceback during unpacking of documentation in some cases.
19
+
20
+
21
+
12
22
  5.0.0 (2025-06-12)
13
23
  ==================
14
24
 
@@ -106,14 +116,3 @@ Bug Fixes
106
116
  - Fix #970: overwrite fixed html/body heights like ``100%`` in documentation iframe content.
107
117
 
108
118
 
109
-
110
- 4.2.1 (2023-07-02)
111
- ==================
112
-
113
- Bug Fixes
114
- ---------
115
-
116
- - Fix #953: Exception when browsers send ETag for documentation pages.
117
-
118
- - Fix #980: Remove long deprecated backward compatibility for old pluggy versions to fix error with pluggy 1.1.0.
119
-
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devpi-web
3
- Version: 5.0.0
3
+ Version: 5.0.1
4
4
  Summary: devpi-web: a web view for devpi-server
5
5
  Maintainer-email: Florian Schulze <mail@pyfidelity.com>
6
6
  License-Expression: MIT
@@ -87,6 +87,16 @@ Changelog
87
87
 
88
88
  .. towncrier release notes start
89
89
 
90
+ 5.0.1 (2025-06-15)
91
+ ==================
92
+
93
+ Bug Fixes
94
+ ---------
95
+
96
+ - Fix traceback during unpacking of documentation in some cases.
97
+
98
+
99
+
90
100
  5.0.0 (2025-06-12)
91
101
  ==================
92
102
 
@@ -184,14 +194,3 @@ Bug Fixes
184
194
  - Fix #970: overwrite fixed html/body heights like ``100%`` in documentation iframe content.
185
195
 
186
196
 
187
-
188
- 4.2.1 (2023-07-02)
189
- ==================
190
-
191
- Bug Fixes
192
- ---------
193
-
194
- - Fix #953: Exception when browsers send ETag for documentation pages.
195
-
196
- - Fix #980: Remove long deprecated backward compatibility for old pluggy versions to fix error with pluggy 1.1.0.
197
-
@@ -0,0 +1 @@
1
+ __version__ = "5.0.1"
@@ -33,7 +33,9 @@ def locked_unpack_path(stage, name, version, *, remove_lock_file=False):
33
33
  hash_path = unpack_path.with_suffix(".hash")
34
34
  try:
35
35
  hash_path.parent.mkdir(parents=True, exist_ok=True)
36
- with hash_path.open("a+") as hash_file:
36
+ with suppress(FileExistsError), hash_path.open("x"):
37
+ pass
38
+ with hash_path.open("r+") as hash_file:
37
39
  if fcntl:
38
40
  fcntl.flock(hash_file, fcntl.LOCK_EX)
39
41
  try:
@@ -90,12 +92,13 @@ def unpack_docs(stage, name, version, entry):
90
92
  # we are not losing the original zip file anyway
91
93
  with locked_unpack_path(stage, name, version) as (hash_file, unpack_path):
92
94
  hash_file.seek(0)
93
- if hash_file.read().strip() == entry.best_available_hash_spec:
95
+ hash_spec = hash_file.read().strip()
96
+ if hash_spec == entry.best_available_hash_spec:
94
97
  return unpack_path
95
98
  if unpack_path.exists():
96
99
  with suppress(FileNotFoundError):
97
100
  # there is a rare possibility of a race condition here
98
- unpack_path.unlink()
101
+ shutil.rmtree(unpack_path)
99
102
  if not entry.file_exists():
100
103
  return unpack_path
101
104
  with entry.file_open_read() as f, Archive(f) as archive:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devpi-web
3
- Version: 5.0.0
3
+ Version: 5.0.1
4
4
  Summary: devpi-web: a web view for devpi-server
5
5
  Maintainer-email: Florian Schulze <mail@pyfidelity.com>
6
6
  License-Expression: MIT
@@ -87,6 +87,16 @@ Changelog
87
87
 
88
88
  .. towncrier release notes start
89
89
 
90
+ 5.0.1 (2025-06-15)
91
+ ==================
92
+
93
+ Bug Fixes
94
+ ---------
95
+
96
+ - Fix traceback during unpacking of documentation in some cases.
97
+
98
+
99
+
90
100
  5.0.0 (2025-06-12)
91
101
  ==================
92
102
 
@@ -184,14 +194,3 @@ Bug Fixes
184
194
  - Fix #970: overwrite fixed html/body heights like ``100%`` in documentation iframe content.
185
195
 
186
196
 
187
-
188
- 4.2.1 (2023-07-02)
189
- ==================
190
-
191
- Bug Fixes
192
- ---------
193
-
194
- - Fix #953: Exception when browsers send ETag for documentation pages.
195
-
196
- - Fix #980: Remove long deprecated backward compatibility for old pluggy versions to fix error with pluggy 1.1.0.
197
-
@@ -65,6 +65,57 @@ def test_doc_unpack_cleanup(mapp, testapp):
65
65
  assert not path.joinpath("foo.html").exists()
66
66
 
67
67
 
68
+ @pytest.mark.with_notifier
69
+ def test_doc_unpack_hash_mismatch(caplog, mapp):
70
+ from devpi_web.doczip import get_unpack_path
71
+ from devpi_web.doczip import locked_unpack_path
72
+ from devpi_web.doczip import unpack_docs
73
+ api = mapp.create_and_use()
74
+ content = zip_dict({
75
+ "index.html": "<html><body>2.6</body></html>"})
76
+ mapp.set_versiondata({"name": "pkg1", "version": "2.6"})
77
+ mapp.upload_doc("pkg1.zip", content, "pkg1", "2.6", code=200,
78
+ waithooks=True)
79
+ with mapp.xom.keyfs.read_transaction():
80
+ stage = mapp.xom.model.getstage(api.stagename)
81
+ linkstore = stage.get_linkstore_perstage("pkg1", "2.6")
82
+ (link,) = linkstore.get_links(rel='doczip')
83
+ path = unpack_docs(stage, 'pkg1', '2.6', link.entry)
84
+ assert path.exists()
85
+ # make sure there is a path that is not existing in the zip,
86
+ # so we can test for its removal
87
+ foo_path = path.joinpath("foo.html")
88
+ assert not foo_path.exists()
89
+ foo_path.touch()
90
+ assert foo_path.exists()
91
+ with mapp.xom.keyfs.read_transaction():
92
+ # now mess with the hash file and make it bigger than the hash_spec,
93
+ # as there was a problem with writing the file correctly before
94
+ bad_hash = "foo" * 300
95
+ with locked_unpack_path(stage, "pkg1", "2.6") as (hash_file, _unpack_path):
96
+ hash_file.seek(0)
97
+ hash_file.write(bad_hash)
98
+ hash_path = get_unpack_path(stage, "pkg1", "2.6").with_suffix(".hash")
99
+ # make sure it is set correctly to the bad value
100
+ assert hash_path.read_text() == bad_hash
101
+ stage = mapp.xom.model.getstage(api.stagename)
102
+ linkstore = stage.get_linkstore_perstage("pkg1", "2.6")
103
+ (link,) = linkstore.get_links(rel='doczip')
104
+ caplog.clear()
105
+ unpack_docs(stage, 'pkg1', '2.6', link.entry)
106
+ assert len(caplog.getrecords("unpacked")) == 1
107
+ assert hash_path.read_text() == link.entry.best_available_hash_spec
108
+ # unpack again
109
+ new_path = unpack_docs(stage, 'pkg1', '2.6', link.entry)
110
+ assert len(caplog.getrecords("unpacked")) == 1
111
+ assert new_path == path
112
+ assert new_path.exists()
113
+ assert "2.6" in new_path.joinpath("index.html").read_text()
114
+ # the hash was written more than once
115
+ assert new_path.with_suffix(".hash").read_text() == link.entry.best_available_hash_spec
116
+ assert not foo_path.exists()
117
+
118
+
68
119
  @pytest.mark.with_notifier
69
120
  def test_empty_doczip(mapp):
70
121
  from devpi_server.filestore import get_hashes
@@ -1 +0,0 @@
1
- __version__ = "5.0.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes