mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-12 11:07:13 +00:00
Minor updates from line drifts
This commit is contained in:
1 parent
04a703029c
commit
decaaf2f1b
10 files changed
+53
-51
No files matched your search
@@ -16,7 +16,7 @@
|
||||
- `page_count:>5`, `asn:<10`, `page_count:>=5`, `asn:[1 TO 10]`, `tag_id:1,2,3` parse OK (comparison operators produce correct `RangeQuery`).
|
||||
- `asn:[1 TO]` / `asn:[TO 10]` are a **Syntax Error** (open numeric ranges unsupported; only open _date_ ranges work via sentinels).
|
||||
- `scan()` only tokenizes fields in `KNOWN_FIELDS`; unknown `foobar:hello` stays a `Passthrough` and only fails at `parse_query` -> detected by the backstop, not proactively.
|
||||
- `difflib.get_close_matches("corespondent", pool)` -> `["correspondent"]`; `has_tags`/`http`/`12` -> `[]` (bare message).
|
||||
- `difflib.get_close_matches("correspondent", pool)` -> `["correspondent"]`; `has_tags`/`http`/`12` -> `[]` (bare message).
|
||||
- `tantivy.Schema` exposes no field-name list, so the drift guard is parse-based.
|
||||
|
||||
## File Structure
|
||||
@@ -74,7 +74,7 @@ class TestErrorClasses:
|
||||
assert str(err) == "Unknown search field 'has_tags'."
|
||||
|
||||
def test_unknown_field_message_with_suggestion(self):
|
||||
err = UnknownFieldError("corespondent", suggestion="correspondent")
|
||||
err = UnknownFieldError("correspondent", suggestion="correspondent")
|
||||
assert err.suggestion == "correspondent"
|
||||
assert str(err) == (
|
||||
"Unknown search field 'corespondent'. Did you mean 'correspondent'?"
|
||||
@@ -350,9 +350,9 @@ from documents.search._translate import map_tantivy_error
|
||||
class TestMapTantivyError:
|
||||
def test_unknown_field_maps_with_suggestion(self):
|
||||
exc = ValueError("Field does not exist: 'corespondent'")
|
||||
mapped = map_tantivy_error(exc, "corespondent:foo")
|
||||
mapped = map_tantivy_error(exc, "correspondent:foo")
|
||||
assert isinstance(mapped, UnknownFieldError)
|
||||
assert mapped.field == "corespondent"
|
||||
assert mapped.field == "correspondent"
|
||||
assert mapped.suggestion == "correspondent"
|
||||
|
||||
def test_unknown_field_maps_without_suggestion(self):
|
||||
@@ -481,7 +481,7 @@ git commit -m "feat(search): map tantivy parse errors to user-safe messages"
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/documents/search/_query.py` (import `map_tantivy_error`; add `_parse_query_friendly`; use it at lines 231-235 and 253-259)
|
||||
- Modify: `src/documents/search/_query.py` (import `map_tantivy_error`; add `_parse_query_friendly`; use it at lines 216-220 and 238-244)
|
||||
- Test: `src/documents/tests/search/test_error_shapes.py`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
@@ -506,7 +506,7 @@ class TestBackstopViaParseUserQuery:
|
||||
|
||||
def test_unknown_field_suggestion(self, index: tantivy.Index):
|
||||
with pytest.raises(UnknownFieldError) as exc_info:
|
||||
parse_user_query(index, "corespondent:bob", UTC)
|
||||
parse_user_query(index, "correspondent:bob", UTC)
|
||||
assert exc_info.value.suggestion == "correspondent"
|
||||
|
||||
def test_legacy_backend_field_is_unknown(self, index: tantivy.Index):
|
||||
@@ -555,13 +555,13 @@ Expected: FAIL — unknown-field/syntax cases currently raise the bare Tantivy `
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
In `src/documents/search/_query.py`, add the import alongside the existing translate imports (after line 20):
|
||||
In `src/documents/search/_query.py`, add the import alongside the existing translate imports (after line 13):
|
||||
|
||||
```python
|
||||
from documents.search._translate import map_tantivy_error
|
||||
```
|
||||
|
||||
Add a module-level helper (place it just above `parse_user_query`, before line 191):
|
||||
Add a module-level helper (place it just above `parse_user_query`, before line 176):
|
||||
|
||||
```python
|
||||
def _parse_query_friendly(
|
||||
@@ -584,7 +584,7 @@ def _parse_query_friendly(
|
||||
raise
|
||||
```
|
||||
|
||||
In `parse_user_query`, replace the exact-query parse (lines 231-235):
|
||||
In `parse_user_query`, replace the exact-query parse (lines 216-220):
|
||||
|
||||
```python
|
||||
exact = _parse_query_friendly(
|
||||
@@ -596,7 +596,7 @@ In `parse_user_query`, replace the exact-query parse (lines 231-235):
|
||||
)
|
||||
```
|
||||
|
||||
and the fuzzy parse (lines 253-259):
|
||||
and the fuzzy parse (lines 238-244):
|
||||
|
||||
```python
|
||||
fuzzy = _parse_query_friendly(
|
||||
@@ -610,7 +610,7 @@ and the fuzzy parse (lines 253-259):
|
||||
)
|
||||
```
|
||||
|
||||
(`SearchQueryError` is already imported in `_query.py` at line 19.)
|
||||
(`SearchQueryError` is already imported in `_query.py` at line 12.)
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
@@ -712,7 +712,7 @@ Expected: PASS. (These assert current truth; they guard against future drift. If
|
||||
|
||||
- [ ] **Step 4: Write the failing view-level test**
|
||||
|
||||
In `src/documents/tests/test_api_search.py`, locate `test_search_added_invalid_date` (around line 723) and add this test directly after it, inside the same `TestDocumentSearchApi` class (mirrors that test's structure):
|
||||
In `src/documents/tests/test_api_search.py`, locate `test_search_added_invalid_date` (around line 765) and add this test directly after it, inside the same `TestDocumentSearchApi` class (mirrors that test's structure):
|
||||
|
||||
```python
|
||||
def test_search_unknown_field_returns_400(self) -> None:
|
||||
|
||||
@@ -95,7 +95,7 @@ class TestBulkEditPermissionMatrix:
|
||||
Notes:
|
||||
|
||||
- Mock the underlying `bulk_edit.<fn>` (patch `documents.views.bulk_edit.<fn>`) so the operations don't actually run — this test is purely about the permission gate returning 200 vs 403.
|
||||
- A superuser short-circuits to allowed (`views.py:2697`); include one superuser row to pin that.
|
||||
- A superuser short-circuits to allowed (`views.py:2833`); include one superuser row to pin that.
|
||||
- This is verbose by design; the matrix is the security contract. Prefer one parametrized test over hand-written methods.
|
||||
- **Cover the six moved single-action endpoints too (REQUIRED — C2).** `/api/documents/rotate/`, `/merge/`, `/delete/`, `/reprocess/`, `/edit_pdf/`, `/remove_password/` run the **same** `_has_document_permissions` gate via `_execute_document_action`, and that path is rewritten in Task 3 (C1). Add a parallel parametrized test that POSTs to each (their request bodies are the dedicated serializers' fields — e.g. `{"documents": [...], "degrees": 90}` for rotate — **not** a `method`+`parameters` envelope). The existing `test_api_bulk_edit.py` already covers these endpoints' permission gates (`test_rotate_insufficient_permissions:1320`, `test_merge_and_delete_insufficient_permissions:1381`, `test_edit_pdf_insufficient_permissions:1635`, `test_remove_password_insufficient_permissions:1719`), so this is hardening rather than the sole net — but make the moved-endpoint matrix explicit here so the `_execute_document_action` rewrite is guarded by a parametrized characterization, not scattered one-offs.
|
||||
- **`edit_pdf` test docs need a `page_count` (M3).** `clean_parameters` for `edit_pdf` bounds-checks `op["page"]` against `Document.page_count` (`serialisers.py:2052-2059`); this test mocks execution but **not** validation, so an `edit_pdf` row with `page: 1` needs its target doc created with `page_count >= 1`, else it fails with a 400 (out-of-bounds) instead of the expected 200/403.
|
||||
@@ -103,7 +103,7 @@ Notes:
|
||||
- [ ] **Step 2: Run it against CURRENT code — it must PASS**
|
||||
|
||||
Run: `bash /c/Users/tholmes/Documents/Coding/paperless/vmtest.sh "src/documents/tests/test_bulk_operations.py -v"`
|
||||
Expected: PASS. If any row is red, the spec matrix is misread — reconcile against `views.py:2713-2760` before writing any production code.
|
||||
Expected: PASS. If any row is red, the spec matrix is misread — reconcile against `views.py:2843-2906` before writing any production code.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
|
||||
@@ -519,7 +519,7 @@ git commit -m "Feature: consume_file owns and cleans the staged work_root"
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/documents/management/commands/document_consumer.py:340-353`
|
||||
- Modify: `src/documents/management/commands/document_consumer.py:344-357`
|
||||
- Test: `src/documents/tests/test_management_consumer.py:99-103`
|
||||
|
||||
- [ ] **Step 1: Repoint the consumer test fixture**
|
||||
@@ -548,7 +548,7 @@ Expected: FAIL — the folder site still calls `consume_file.apply_async`, not t
|
||||
|
||||
- [ ] **Step 3: Migrate the folder enqueue site**
|
||||
|
||||
In `src/documents/management/commands/document_consumer.py`, add `from documents import ingest` at the top, and replace the enqueue block (lines ~340-353):
|
||||
In `src/documents/management/commands/document_consumer.py`, add `from documents import ingest` at the top, and replace the enqueue block (lines ~344-357):
|
||||
|
||||
```python
|
||||
# Queue for consumption
|
||||
@@ -594,7 +594,7 @@ rewrite and the site migration land together.
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/documents/tests/utils.py:242-274`
|
||||
- Modify: `src/documents/views.py:3149-3192` (PostDocumentView) and `:1917-1976` (update_version)
|
||||
- Modify: `src/documents/views.py:3275-3338` (PostDocumentView) and `:2036-2098` (update_version)
|
||||
- Modify: `src/documents/tests/test_api_document_versions.py` (patch target)
|
||||
|
||||
- [ ] **Step 1: Rewrite `ConsumeTaskMixin` to patch the seam**
|
||||
@@ -643,7 +643,7 @@ Expected: FAIL — `PostDocumentView` still calls `consume_file.apply_async`, so
|
||||
- [ ] **Step 3: Migrate `PostDocumentView.post`**
|
||||
|
||||
In `src/documents/views.py`, ensure `from documents import ingest` is imported,
|
||||
then replace the staging + dispatch (lines ~3149-3192) with a `stage_document`
|
||||
then replace the staging + dispatch (lines ~3275-3338) with a `stage_document`
|
||||
block:
|
||||
|
||||
```python
|
||||
@@ -687,7 +687,7 @@ The old `SCRATCH_DIR.mkdir` + `mkdtemp` + `write_bytes` + the explicit
|
||||
|
||||
- [ ] **Step 4: Migrate `update_version`**
|
||||
|
||||
In `src/documents/views.py` `update_version` (lines ~1917-1976), replace its
|
||||
In `src/documents/views.py` `update_version` (lines ~2036-2098), replace its
|
||||
`mkdtemp`/`write`/`consume_file.apply_async` with the same pattern, preserving its
|
||||
specific fields (`root_document_id`, `version_label`, `actor_id`):
|
||||
|
||||
@@ -732,7 +732,7 @@ git commit -m "Refactor: route API/WebUI/version ingest through the staging seam
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/paperless_mail/mail.py` (`_handle_message` ~716-760, `_process_attachments` ~861-908, `_process_eml` ~952-1006)
|
||||
- Modify: `src/paperless_mail/mail.py` (`_handle_message` ~790-835, `_process_attachments` ~893-1024, `_process_eml` ~1026-1097)
|
||||
- Test: `src/paperless_mail/tests/test_mail.py`, `test_mail_nfc.py` (verify, likely no change)
|
||||
|
||||
- [ ] **Step 1: Wrap the message's staging in an `ExitStack`**
|
||||
@@ -774,7 +774,7 @@ work_root for the message.)
|
||||
|
||||
- [ ] **Step 2: Stage each attachment via the stack**
|
||||
|
||||
Replace the attachment staging (`mail.py:861-908`) inside `_process_attachments`:
|
||||
Replace the attachment staging (`mail.py:893-1024`) inside `_process_attachments`:
|
||||
|
||||
```python
|
||||
staged = staging_stack.enter_context(
|
||||
@@ -804,7 +804,7 @@ Replace the attachment staging (`mail.py:861-908`) inside `_process_attachments`
|
||||
|
||||
The old `SCRATCH_DIR.mkdir` + `mkdtemp` + `write_bytes` + `consume_file.s(...).set(...)`
|
||||
are gone; `stage_document` handles the temp dir and `build_consume_signature` the
|
||||
header. Do the analogous replacement in `_process_eml` (`mail.py:952-1006`),
|
||||
header. Do the analogous replacement in `_process_eml` (`mail.py:1026-1097`),
|
||||
staging the `.eml` bytes and building the signature the same way.
|
||||
|
||||
- [ ] **Step 3: Run the mail suites**
|
||||
@@ -885,14 +885,14 @@ folder source needs it (its loose file in `CONSUMPTION_DIR` is removed on succes
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/documents/consumer.py:417-422`
|
||||
- Modify: `src/documents/consumer.py:408-414`
|
||||
- Test: `src/documents/tests/test_consumer.py`
|
||||
|
||||
- [ ] **Step 1: Use the handed-in working dir instead of a second `TemporaryDirectory`**
|
||||
|
||||
`ConsumerPlugin` already receives the task's working dir as `self.base_tmp_dir`
|
||||
(the `tmp_dir` arg from `tasks.py:227-233`). Replace its own
|
||||
`tempfile.TemporaryDirectory(...)` (`consumer.py:417`) with a subfolder of that
|
||||
`tempfile.TemporaryDirectory(...)` (`consumer.py:408`) with a subfolder of that
|
||||
handed-in dir:
|
||||
|
||||
```python
|
||||
|
||||
@@ -389,7 +389,7 @@ git commit -m "Add HybridRetriever: lexical fallback for archive AI chat retriev
|
||||
|
||||
**Files:**
|
||||
|
||||
- Modify: `src/paperless_ai/chat.py:95-112`
|
||||
- Modify: `src/paperless_ai/chat.py:149-177`
|
||||
- Modify: `src/paperless_ai/tests/test_chat.py`
|
||||
|
||||
**Interfaces:**
|
||||
@@ -436,7 +436,7 @@ Expected: FAIL — `HybridRetriever` is never constructed yet (`chat.py` still b
|
||||
|
||||
- [ ] **Step 3: Wire `HybridRetriever` into `_stream_chat_with_documents`**
|
||||
|
||||
In `src/paperless_ai/chat.py`, inside `_stream_chat_with_documents` (currently lines 95-112), add the `HybridRetriever` import alongside the other lazy llama-index imports and replace the retriever construction:
|
||||
In `src/paperless_ai/chat.py`, inside `_stream_chat_with_documents` (currently lines 149-177), add the `HybridRetriever` import alongside the other lazy llama-index imports and replace the retriever construction:
|
||||
|
||||
```python
|
||||
from llama_index.core.prompts import PromptTemplate
|
||||
|
||||
Reference in new issue
Block a user