Compare commits

..

1 Commits

Author SHA1 Message Date
Trenton H
f79a0ae899 Updates the baselines for the latest code changes 2026-03-03 10:28:12 -08:00
17 changed files with 3290 additions and 4024 deletions

View File

@@ -264,6 +264,7 @@ src/documents/management/commands/document_exporter.py:0: error: Function is mis
src/documents/management/commands/document_exporter.py:0: error: Incompatible types in assignment (expression has type "str", variable has type "Path") [assignment]
src/documents/management/commands/document_exporter.py:0: error: Invalid index type "str" for "str"; expected type "SupportsIndex | slice[Any, Any, Any]" [index]
src/documents/management/commands/document_exporter.py:0: error: Invalid index type "str" for "str"; expected type "SupportsIndex | slice[Any, Any, Any]" [index]
src/documents/management/commands/document_exporter.py:0: error: Library stubs not installed for "tqdm" [import-untyped]
src/documents/management/commands/document_exporter.py:0: error: Missing type parameters for generic type "QuerySet" [type-arg]
src/documents/management/commands/document_exporter.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/management/commands/document_exporter.py:0: error: Missing type parameters for generic type "dict" [type-arg]
@@ -282,23 +283,18 @@ src/documents/management/commands/document_importer.py:0: error: Function is mis
src/documents/management/commands/document_importer.py:0: error: Incompatible types in assignment (expression has type "str | None", base class "CryptMixin" defined the type as "str") [assignment]
src/documents/management/commands/document_importer.py:0: error: Invalid index type "str" for "str"; expected type "SupportsIndex | slice[Any, Any, Any]" [index]
src/documents/management/commands/document_importer.py:0: error: Invalid index type "str" for "str"; expected type "SupportsIndex | slice[Any, Any, Any]" [index]
src/documents/management/commands/document_importer.py:0: error: Library stubs not installed for "tqdm" [import-untyped]
src/documents/management/commands/document_importer.py:0: error: Missing type parameters for generic type "Generator" [type-arg]
src/documents/management/commands/document_importer.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/management/commands/document_importer.py:0: error: Need type annotation for "manifest_paths" (hint: "manifest_paths: list[<type>] = ...") [var-annotated]
src/documents/management/commands/document_importer.py:0: error: Skipping analyzing "auditlog.registry": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/documents/management/commands/document_index.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_index.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_llmindex.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_llmindex.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_renamer.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_renamer.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_retagger.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_retagger.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_sanity_checker.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_sanity_checker.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_retagger.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/management/commands/document_retagger.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/management/commands/document_thumbnails.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/document_thumbnails.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/management/commands/document_thumbnails.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/management/commands/loaddata_stdin.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/loaddata_stdin.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/loaddata_stdin.py:0: error: Incompatible types in assignment (expression has type "tuple[Callable[[Any, Any], TextIO | Any], None]", target has type "tuple[Callable[[str, Literal['r', 'rb']], BufferedReader[_BufferedReaderStream]]]") [assignment]
@@ -308,11 +304,8 @@ src/documents/management/commands/mixins.py:0: error: Attribute "kdf_algorithm"
src/documents/management/commands/mixins.py:0: error: Attribute "key_iterations" already defined on line 0 [no-redef]
src/documents/management/commands/mixins.py:0: error: Attribute "key_size" already defined on line 0 [no-redef]
src/documents/management/commands/mixins.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/management/commands/mixins.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/management/commands/mixins.py:0: error: Incompatible types in assignment (expression has type "list[dict[str, Sequence[str]]]", variable has type "CryptFields") [assignment]
src/documents/management/commands/mixins.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/management/commands/mixins.py:0: error: Unsupported operand types for // ("None" and "int") [operator]
src/documents/management/commands/prune_audit_logs.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/prune_audit_logs.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/management/commands/prune_audit_logs.py:0: error: Skipping analyzing "auditlog.models": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/documents/matching.py:0: error: Argument 1 to "existing_document_matches_workflow" has incompatible type "ConsumableDocument | Document"; expected "Document" [arg-type]
@@ -448,18 +441,7 @@ src/documents/plugins/helpers.py:0: error: Function is missing a type annotation
src/documents/plugins/helpers.py:0: error: Skipping analyzing "channels_redis.pubsub": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/documents/regex.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/regex.py:0: error: Library stubs not installed for "regex" [import-untyped]
src/documents/sanity_checker.py:0: error: Argument 1 to "Path" has incompatible type "Path | None"; expected "str | PathLike[str]" [arg-type]
src/documents/sanity_checker.py:0: error: Cannot use Final inside a loop [misc]
src/documents/sanity_checker.py:0: error: Cannot use Final inside a loop [misc]
src/documents/sanity_checker.py:0: error: Cannot use Final inside a loop [misc]
src/documents/sanity_checker.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/sanity_checker.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/sanity_checker.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/sanity_checker.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/sanity_checker.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/sanity_checker.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/sanity_checker.py:0: error: Incompatible type for "task_id" of "PaperlessTask" (got "UUID", expected "str | int | Combinable") [misc]
src/documents/sanity_checker.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/schema.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/schema.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/schema.py:0: error: Function is missing a type annotation [no-untyped-def]
@@ -550,6 +532,8 @@ src/documents/serialisers.py:0: error: Function is missing a type annotation [n
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/serialisers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
@@ -640,6 +624,7 @@ src/documents/serialisers.py:0: error: Missing type parameters for generic type
src/documents/serialisers.py:0: error: Missing type parameters for generic type "Serializer" [type-arg]
src/documents/serialisers.py:0: error: Missing type parameters for generic type "Serializer" [type-arg]
src/documents/serialisers.py:0: error: Missing type parameters for generic type "Serializer" [type-arg]
src/documents/serialisers.py:0: error: Missing type parameters for generic type "Serializer" [type-arg]
src/documents/serialisers.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/serialisers.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/serialisers.py:0: error: Need type annotation for "document" [var-annotated]
@@ -664,9 +649,6 @@ src/documents/signals/handlers.py:0: error: Argument 2 to "match_storage_paths"
src/documents/signals/handlers.py:0: error: Argument 2 to "match_tags" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type]
src/documents/signals/handlers.py:0: error: Argument 2 to "validate_move" has incompatible type "Path | Any | None"; expected "Path" [arg-type]
src/documents/signals/handlers.py:0: error: Argument 3 to "validate_move" has incompatible type "Path | Any | None"; expected "Path" [arg-type]
src/documents/signals/handlers.py:0: error: Argument 5 to "_suggestion_printer" has incompatible type "Any | None"; expected "MatchingModel" [arg-type]
src/documents/signals/handlers.py:0: error: Argument 5 to "_suggestion_printer" has incompatible type "Any | None"; expected "MatchingModel" [arg-type]
src/documents/signals/handlers.py:0: error: Argument 5 to "_suggestion_printer" has incompatible type "Any | None"; expected "MatchingModel" [arg-type]
src/documents/signals/handlers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/signals/handlers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/signals/handlers.py:0: error: Function is missing a type annotation [no-untyped-def]
@@ -686,12 +668,6 @@ src/documents/signals/handlers.py:0: error: Function is missing a type annotatio
src/documents/signals/handlers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/signals/handlers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/signals/handlers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/signals/handlers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/signals/handlers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/signals/handlers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/signals/handlers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/signals/handlers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/signals/handlers.py:0: error: Incompatible types in assignment (expression has type "list[Tag]", variable has type "set[Tag]") [assignment]
src/documents/signals/handlers.py:0: error: Incompatible types in assignment (expression has type "tuple[Any, Any, Any]", variable has type "tuple[Any, Any]") [assignment]
src/documents/signals/handlers.py:0: error: Item "ConsumableDocument" of "Document | ConsumableDocument" has no attribute "save" [union-attr]
src/documents/signals/handlers.py:0: error: Item "ConsumableDocument" of "Document | ConsumableDocument" has no attribute "source_path" [union-attr]
@@ -719,7 +695,6 @@ src/documents/tasks.py:0: error: Function is missing a type annotation for one o
src/documents/tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tasks.py:0: error: Incompatible type for "task_id" of "PaperlessTask" (got "UUID", expected "str | int | Combinable") [misc]
src/documents/tasks.py:0: error: Incompatible type for "task_id" of "PaperlessTask" (got "UUID", expected "str | int | Combinable") [misc]
src/documents/tasks.py:0: error: Incompatible types in assignment (expression has type "Path", variable has type "str") [assignment]
@@ -746,8 +721,80 @@ src/documents/templating/utils.py:0: error: Function is missing a type annotatio
src/documents/templating/workflows.py:0: error: Incompatible return value type (got "None", expected "str") [return-value]
src/documents/tests/conftest.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/conftest.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/conftest.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/conftest.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/conftest.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/conftest.py:0: error: Incompatible return value type (got "DocumentFactory", expected "Document") [return-value]
src/documents/tests/factories.py:0: error: Missing type parameters for generic type "DjangoModelFactory" [type-arg]
src/documents/tests/factories.py:0: error: Missing type parameters for generic type "DjangoModelFactory" [type-arg]
src/documents/tests/factories.py:0: error: Missing type parameters for generic type "DjangoModelFactory" [type-arg]
src/documents/tests/factories.py:0: error: Missing type parameters for generic type "DjangoModelFactory" [type-arg]
src/documents/tests/factories.py:0: error: Missing type parameters for generic type "DjangoModelFactory" [type-arg]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Incompatible types in assignment (expression has type "StringIO", variable has type "OutputWrapper") [assignment]
src/documents/tests/management/test_management_base_cmd.py:0: error: Missing type parameters for generic type "QuerySet" [type-arg]
src/documents/tests/management/test_management_base_cmd.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/tests/management/test_management_base_cmd.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/tests/management/test_management_base_cmd.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/tests/management/test_management_base_cmd.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/tests/management/test_management_base_cmd.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/tests/management/test_management_base_cmd.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/documents/tests/management/test_management_base_cmd.py:0: error: Missing type parameters for generic type "list" [type-arg]
src/documents/tests/management/test_management_base_cmd.py:0: error: Need type annotation for "result" [var-annotated]
src/documents/tests/management/test_management_base_cmd.py:0: error: Need type annotation for "result" (hint: "result: list[<type>] = ...") [var-annotated]
src/documents/tests/management/test_management_base_cmd.py:0: error: Need type annotation for "results" [var-annotated]
src/documents/tests/management/test_management_sanity_checker.py:0: error: "DocumentFactory" has no attribute "source_path"; maybe "storage_path"? [attr-defined]
src/documents/tests/management/test_management_sanity_checker.py:0: error: "DocumentFactory" has no attribute "thumbnail_path" [attr-defined]
src/documents/tests/test_admin.py:0: error: "PaperlessUserForm" has no attribute "request" [attr-defined]
src/documents/tests/test_admin.py:0: error: "PaperlessUserForm" has no attribute "request" [attr-defined]
src/documents/tests/test_admin.py:0: error: Function is missing a type annotation [no-untyped-def]
@@ -775,6 +822,7 @@ src/documents/tests/test_api_app_config.py:0: error: Item "None" of "Application
src/documents/tests/test_api_bulk_download.py:0: error: Value of type variable "_StrPathT" of "copy" cannot be "Path | None" [type-var]
src/documents/tests/test_api_bulk_edit.py:0: error: "type[MatchingModel]" has no attribute "objects" [attr-defined]
src/documents/tests/test_api_bulk_edit.py:0: error: "type[MatchingModel]" has no attribute "objects" [attr-defined]
src/documents/tests/test_api_bulk_edit.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/test_api_bulk_edit.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_api_bulk_edit.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_api_bulk_edit.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
@@ -827,8 +875,10 @@ src/documents/tests/test_api_custom_fields.py:0: error: Value of type "Any | Non
src/documents/tests/test_api_documents.py:0: error: "None" object is not iterable [misc]
src/documents/tests/test_api_documents.py:0: error: "object" has no attribute "get" [attr-defined]
src/documents/tests/test_api_documents.py:0: error: Argument 1 to "Path" has incompatible type "Path | None"; expected "str | PathLike[str]" [arg-type]
src/documents/tests/test_api_documents.py:0: error: Argument 1 to "Path" has incompatible type "Path | None"; expected "str | PathLike[str]" [arg-type]
src/documents/tests/test_api_documents.py:0: error: Argument 1 to "assertCountEqual" of "TestCase" has incompatible type "list[int] | None"; expected "Iterable[Any]" [arg-type]
src/documents/tests/test_api_documents.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/test_api_documents.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/test_api_documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/tests/test_api_documents.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/tests/test_api_documents.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
@@ -1173,7 +1223,20 @@ src/documents/tests/test_management_exporter.py:0: error: Function is missing a
src/documents/tests/test_management_exporter.py:0: error: Item "None" of "MailAccount | None" has no attribute "password" [union-attr]
src/documents/tests/test_management_exporter.py:0: error: Skipping analyzing "allauth.socialaccount.models": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/documents/tests/test_management_fuzzy.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/tests/test_management_retagger.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/test_management_retagger.py:0: error: "DocumentFactory" has no attribute "refresh_from_db" [attr-defined]
src/documents/tests/test_management_retagger.py:0: error: "DocumentFactory" has no attribute "refresh_from_db" [attr-defined]
src/documents/tests/test_management_retagger.py:0: error: "DocumentFactory" has no attribute "refresh_from_db" [attr-defined]
src/documents/tests/test_management_retagger.py:0: error: "DocumentFactory" has no attribute "tags" [attr-defined]
src/documents/tests/test_management_retagger.py:0: error: "DocumentFactory" has no attribute "tags" [attr-defined]
src/documents/tests/test_management_retagger.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_management_retagger.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_management_retagger.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_management_retagger.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_management_retagger.py:0: error: Incompatible return value type (got "tuple[CorrespondentFactory, CorrespondentFactory]", expected "tuple[Correspondent, Correspondent]") [return-value]
src/documents/tests/test_management_retagger.py:0: error: Incompatible return value type (got "tuple[DocumentFactory, DocumentFactory, DocumentFactory, DocumentFactory]", expected "tuple[Document, Document, Document, Document]") [return-value]
src/documents/tests/test_management_retagger.py:0: error: Incompatible return value type (got "tuple[DocumentTypeFactory, DocumentTypeFactory]", expected "tuple[DocumentType, DocumentType]") [return-value]
src/documents/tests/test_management_retagger.py:0: error: Incompatible return value type (got "tuple[StoragePathFactory, StoragePathFactory, StoragePathFactory]", expected "tuple[StoragePath, StoragePath, StoragePath]") [return-value]
src/documents/tests/test_management_retagger.py:0: error: Incompatible return value type (got "tuple[TagFactory, TagFactory, TagFactory, TagFactory, TagFactory]", expected "tuple[Tag, Tag, Tag, Tag, Tag]") [return-value]
src/documents/tests/test_management_superuser.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/tests/test_migration_share_link_bundle.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_migration_share_link_bundle.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
@@ -1190,9 +1253,10 @@ src/documents/tests/test_parsers.py:0: error: Function is missing a type annotat
src/documents/tests/test_parsers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_parsers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_parsers.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_sanity_check.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/documents/tests/test_sanity_check.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_sanity_check.py:0: error: Invalid index type "None" for "dict[int, list[dict[Any, Any]]]"; expected type "int" [index]
src/documents/tests/test_sanity_check.py:0: error: Argument 1 to "Path" has incompatible type "Path | None"; expected "str | PathLike[str]" [arg-type]
src/documents/tests/test_sanity_check.py:0: error: Argument 1 to "Path" has incompatible type "Path | None"; expected "str | PathLike[str]" [arg-type]
src/documents/tests/test_sanity_check.py:0: error: Argument 1 to "Path" has incompatible type "Path | None"; expected "str | PathLike[str]" [arg-type]
src/documents/tests/test_sanity_check.py:0: error: Unsupported right operand type for in ("str | None") [operator]
src/documents/tests/test_share_link_bundles.py:0: error: "_MonkeyPatchedResponse" has no attribute "streaming_content" [attr-defined]
src/documents/tests/test_share_link_bundles.py:0: error: Argument 1 to "ZipFile" has incompatible type "Path | None"; expected "str | PathLike[str] | IO[bytes]" [arg-type]
src/documents/tests/test_share_link_bundles.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
@@ -1223,10 +1287,6 @@ src/documents/tests/test_tasks.py:0: error: Function is missing a type annotatio
src/documents/tests/test_tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_tasks.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/tests/test_views.py:0: error: "_MonkeyPatchedWSGIResponse" has no attribute "render" [attr-defined]
src/documents/tests/test_views.py:0: error: "_MonkeyPatchedWSGIResponse" has no attribute "render" [attr-defined]
src/documents/tests/test_views.py:0: error: "_MonkeyPatchedWSGIResponse" has no attribute "url" [attr-defined]
@@ -1534,7 +1594,6 @@ src/documents/views.py:0: error: "get_serializer_context" undefined in superclas
src/documents/views.py:0: error: "object" not callable [operator]
src/documents/views.py:0: error: "type[Model]" has no attribute "objects" [attr-defined]
src/documents/views.py:0: error: Argument "path" to "EmailAttachment" has incompatible type "Path | None"; expected "Path" [arg-type]
src/documents/views.py:0: error: Argument 1 to "int" has incompatible type "str | None"; expected "str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc" [arg-type]
src/documents/views.py:0: error: Argument 2 to "match_correspondents" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type]
src/documents/views.py:0: error: Argument 2 to "match_document_types" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type]
src/documents/views.py:0: error: Argument 2 to "match_storage_paths" has incompatible type "DocumentClassifier | None"; expected "DocumentClassifier" [arg-type]
@@ -1609,6 +1668,8 @@ src/documents/views.py:0: error: Function is missing a type annotation [no-unty
src/documents/views.py:0: error: Function is missing a type annotation [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/views.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/documents/views.py:0: error: Incompatible type for lookup 'owner': (got "User | AnonymousUser", expected "User | int | None") [misc]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "Any | None", variable has type "dict[Any, Any]") [assignment]
src/documents/views.py:0: error: Incompatible types in assignment (expression has type "QuerySet[Any, Any]", variable has type "list[Any]") [assignment]
@@ -1864,39 +1925,54 @@ src/paperless/serialisers.py:0: error: Skipping analyzing "allauth.mfa.adapter":
src/paperless/serialisers.py:0: error: Skipping analyzing "allauth.mfa.models": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/paperless/serialisers.py:0: error: Skipping analyzing "allauth.mfa.totp.internal.auth": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/paperless/serialisers.py:0: error: Skipping analyzing "allauth.socialaccount.models": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/paperless/settings.py:0: error: "Sequence[str]" has no attribute "append" [attr-defined]
src/paperless/settings.py:0: error: "Sequence[str]" has no attribute "insert" [attr-defined]
src/paperless/settings.py:0: error: "object" has no attribute "update" [attr-defined]
src/paperless/settings.py:0: error: "object" has no attribute "update" [attr-defined]
src/paperless/settings.py:0: error: "object" has no attribute "update" [attr-defined]
src/paperless/settings.py:0: error: "object" has no attribute "update" [attr-defined]
src/paperless/settings.py:0: error: Argument 1 to "_parse_ignore_dates" has incompatible type "str | None"; expected "str" [arg-type]
src/paperless/settings.py:0: error: Argument 1 to "append" of "list" has incompatible type "str | None"; expected "str" [arg-type]
src/paperless/settings.py:0: error: Argument 1 to "int" has incompatible type "str | None"; expected "str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc" [arg-type]
src/paperless/settings.py:0: error: Argument 1 to "int" has incompatible type "str | None"; expected "str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc" [arg-type]
src/paperless/settings.py:0: error: Argument 1 to "int" has incompatible type "str | None"; expected "str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc" [arg-type]
src/paperless/settings.py:0: error: Argument 1 to "int" has incompatible type "str | None"; expected "str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc" [arg-type]
src/paperless/settings.py:0: error: Argument 2 to "__get_path" has incompatible type "str | None"; expected "PathLike[Any] | str" [arg-type]
src/paperless/settings.py:0: error: Argument 2 to "getenv" has incompatible type "None"; expected "Collection[str]" [arg-type]
src/paperless/settings.py:0: error: Argument 2 to "getenv" has incompatible type "None"; expected "Collection[str]" [arg-type]
src/paperless/settings.py:0: error: Argument 2 to "getenv" has incompatible type "None"; expected "Collection[str]" [arg-type]
src/paperless/settings.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/settings.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/settings.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/settings.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/settings.py:0: error: Function is missing a type annotation [no-untyped-def]
src/paperless/settings.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/paperless/settings.py:0: error: Incompatible return value type (got "set[date]", expected "set[datetime]") [return-value]
src/paperless/settings.py:0: error: Incompatible return value type (got "tuple[str | None, str, str, str, str]", expected "tuple[str, str, str, str, str]") [return-value]
src/paperless/settings.py:0: error: Incompatible types in assignment (expression has type "bool", variable has type "str") [assignment]
src/paperless/settings.py:0: error: Incompatible types in assignment (expression has type "set[datetime]", variable has type "set[date]") [assignment]
src/paperless/settings.py:0: error: Missing type parameters for generic type "PathLike" [type-arg]
src/paperless/settings.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/paperless/settings.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/paperless/settings.py:0: error: No overload variant of "getenv" matches argument types "Collection[str]", "Collection[str]" [call-overload]
src/paperless/settings.py:0: error: Skipping analyzing "compression_middleware.middleware": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/paperless/settings/__init__.py:0: error: "Sequence[str]" has no attribute "append" [attr-defined]
src/paperless/settings/__init__.py:0: error: "Sequence[str]" has no attribute "insert" [attr-defined]
src/paperless/settings/__init__.py:0: error: Argument 1 to "_parse_ignore_dates" has incompatible type "str | None"; expected "str" [arg-type]
src/paperless/settings/__init__.py:0: error: Argument 1 to "append" of "list" has incompatible type "str | None"; expected "str" [arg-type]
src/paperless/settings/__init__.py:0: error: Argument 2 to "__get_path" has incompatible type "str | None"; expected "PathLike[Any] | str" [arg-type]
src/paperless/settings/__init__.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/settings/__init__.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/settings/__init__.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/settings/__init__.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/settings/__init__.py:0: error: Function is missing a type annotation [no-untyped-def]
src/paperless/settings/__init__.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/paperless/settings/__init__.py:0: error: Incompatible return value type (got "set[date]", expected "set[datetime]") [return-value]
src/paperless/settings/__init__.py:0: error: Incompatible return value type (got "tuple[str | None, str, str, str, str]", expected "tuple[str, str, str, str, str]") [return-value]
src/paperless/settings/__init__.py:0: error: Incompatible types in assignment (expression has type "bool", variable has type "str") [assignment]
src/paperless/settings/__init__.py:0: error: Incompatible types in assignment (expression has type "set[datetime]", variable has type "set[date]") [assignment]
src/paperless/settings/__init__.py:0: error: Missing type parameters for generic type "PathLike" [type-arg]
src/paperless/settings/__init__.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/paperless/settings/__init__.py:0: error: No overload variant of "getenv" matches argument types "Collection[str]", "Collection[str]" [call-overload]
src/paperless/settings/__init__.py:0: error: Skipping analyzing "compression_middleware.middleware": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/paperless/settings/parsers.py:0: error: Incompatible types in assignment (expression has type "Path", variable has type "bool") [assignment]
src/paperless/settings/parsers.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/paperless/settings/parsers.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/paperless/settings/parsers.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/paperless/signals.py:0: error: Function is missing a type annotation [no-untyped-def]
src/paperless/signals.py:0: error: Function is missing a type annotation [no-untyped-def]
src/paperless/tests/settings/test_custom_parsers.py:0: error: Missing type parameters for generic type "dict" [type-arg]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a return type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/paperless/tests/settings/test_environment_parsers.py:0: error: Function is missing a type annotation [no-untyped-def]
src/paperless/tests/test_adapter.py:0: error: Cannot assign to a method [method-assign]
src/paperless/tests/test_adapter.py:0: error: Cannot assign to a method [method-assign]
src/paperless/tests/test_adapter.py:0: error: Cannot assign to a method [method-assign]
@@ -1904,6 +1980,12 @@ src/paperless/tests/test_adapter.py:0: error: Function is missing a type annotat
src/paperless/tests/test_adapter.py:0: error: Skipping analyzing "allauth.account.adapter": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/paperless/tests/test_adapter.py:0: error: Skipping analyzing "allauth.core": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/paperless/tests/test_adapter.py:0: error: Skipping analyzing "allauth.socialaccount.adapter": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/paperless/tests/test_checks.py:0: error: Generator has incompatible item type "str | None"; expected "str" [misc]
src/paperless/tests/test_checks.py:0: error: Unsupported right operand type for in ("str | None") [operator]
src/paperless/tests/test_checks.py:0: error: Unsupported right operand type for in ("str | None") [operator]
src/paperless/tests/test_checks.py:0: error: Unsupported right operand type for in ("str | None") [operator]
src/paperless/tests/test_checks.py:0: error: Unsupported right operand type for in ("str | None") [operator]
src/paperless/tests/test_checks.py:0: error: Unsupported right operand type for in ("str | None") [operator]
src/paperless/tests/test_db_cache.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]
src/paperless/tests/test_db_cache.py:0: error: Skipping analyzing "cachalot.settings": module is installed, but missing library stubs or py.typed marker [import-untyped]
src/paperless/tests/test_settings.py:0: error: Function is missing a type annotation for one or more arguments [no-untyped-def]

File diff suppressed because it is too large Load Diff

View File

@@ -305,7 +305,6 @@ markers = [
"greenmail: Tests requiring Greenmail service",
"date_parsing: Tests which cover date parsing from content or filename",
"management: Tests which cover management commands/functionality",
"profiling: Benchmarks that profile and compare implementation performance",
]
[tool.pytest_env]

View File

@@ -1238,8 +1238,8 @@
<context context-type="linenumber">82</context>
</context-group>
</trans-unit>
<trans-unit id="7860582931776068318" datatype="html">
<source>Add document version</source>
<trans-unit id="8035757452478567832" datatype="html">
<source>Update existing document</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
<context context-type="linenumber">280</context>
@@ -8411,8 +8411,8 @@
<context context-type="linenumber">832</context>
</context-group>
</trans-unit>
<trans-unit id="5203024009814367559" datatype="html">
<source>This operation will add rotated versions of the <x id="PH" equiv-text="this.list.selected.size"/> document(s).</source>
<trans-unit id="6390006284731990222" datatype="html">
<source>This operation will permanently rotate the original version of <x id="PH" equiv-text="this.list.selected.size"/> document(s).</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-list/bulk-editor/bulk-editor.component.ts</context>
<context context-type="linenumber">833</context>

View File

@@ -277,7 +277,7 @@
<div class="col">
<select class="form-select" formControlName="pdfEditorDefaultEditMode">
<option [ngValue]="PdfEditorEditMode.Create" i18n>Create new document(s)</option>
<option [ngValue]="PdfEditorEditMode.Update" i18n>Add document version</option>
<option [ngValue]="PdfEditorEditMode.Update" i18n>Update existing document</option>
</select>
</div>
</div>

View File

@@ -84,7 +84,7 @@
<input type="radio" class="btn-check" [(ngModel)]="editMode" [value]="PdfEditorEditMode.Update" id="editModeUpdate" name="editmode" [disabled]="hasSplit()">
<label for="editModeUpdate" class="btn btn-outline-primary btn-sm">
<i-bs name="pencil"></i-bs>
<span class="form-check-label ms-2" i18n>Add document version</span>
<span class="form-check-label ms-2" i18n>Update existing document</span>
</label>
</div>
@if (editMode === PdfEditorEditMode.Create) {

View File

@@ -830,7 +830,7 @@ export class BulkEditorComponent
})
const rotateDialog = modal.componentInstance as RotateConfirmDialogComponent
rotateDialog.title = $localize`Rotate confirm`
rotateDialog.messageBold = $localize`This operation will add rotated versions of the ${this.list.selected.size} document(s).`
rotateDialog.messageBold = $localize`This operation will permanently rotate the original version of ${this.list.selected.size} document(s).`
rotateDialog.btnClass = 'btn-danger'
rotateDialog.btnCaption = $localize`Proceed`
rotateDialog.documentID = Array.from(this.list.selected)[0]

View File

@@ -3,8 +3,6 @@ import json
import os
import shutil
import tempfile
from itertools import chain
from itertools import islice
from pathlib import Path
from typing import TYPE_CHECKING
@@ -21,7 +19,6 @@ from django.contrib.contenttypes.models import ContentType
from django.core import serializers
from django.core.management.base import BaseCommand
from django.core.management.base import CommandError
from django.core.serializers.json import DjangoJSONEncoder
from django.db import transaction
from django.utils import timezone
from filelock import FileLock
@@ -29,8 +26,6 @@ from guardian.models import GroupObjectPermission
from guardian.models import UserObjectPermission
if TYPE_CHECKING:
from collections.abc import Generator
from django.db.models import QuerySet
if settings.AUDIT_LOG_ENABLED:
@@ -65,22 +60,6 @@ from paperless_mail.models import MailAccount
from paperless_mail.models import MailRule
def serialize_queryset_batched(
queryset: "QuerySet",
*,
batch_size: int = 500,
) -> "Generator[list[dict], None, None]":
"""Yield batches of serialized records from a QuerySet.
Each batch is a list of dicts in Django's Python serialization format.
Uses QuerySet.iterator() to avoid loading the full queryset into memory,
and islice to collect chunk-sized batches serialized in a single call.
"""
iterator = queryset.iterator(chunk_size=batch_size)
while chunk := list(islice(iterator, batch_size)):
yield serializers.serialize("python", chunk)
class Command(CryptMixin, BaseCommand):
help = (
"Decrypt and rename all files in our collection into a given target "
@@ -207,17 +186,6 @@ class Command(CryptMixin, BaseCommand):
help="If provided, is used to encrypt sensitive data in the export",
)
parser.add_argument(
"--batch-size",
type=int,
default=500,
help=(
"Number of records to process per batch during serialization. "
"Lower values reduce peak memory usage; higher values improve "
"throughput. Default: 500."
),
)
def handle(self, *args, **options) -> None:
self.target = Path(options["target"]).resolve()
self.split_manifest: bool = options["split_manifest"]
@@ -232,7 +200,6 @@ class Command(CryptMixin, BaseCommand):
self.data_only: bool = options["data_only"]
self.no_progress_bar: bool = options["no_progress_bar"]
self.passphrase: str | None = options.get("passphrase")
self.batch_size: int = options["batch_size"]
self.files_in_export_dir: set[Path] = set()
self.exported_files: set[str] = set()
@@ -327,13 +294,8 @@ class Command(CryptMixin, BaseCommand):
# Build an overall manifest
for key, object_query in manifest_key_to_object_query.items():
manifest_dict[key] = list(
chain.from_iterable(
serialize_queryset_batched(
object_query,
batch_size=self.batch_size,
),
),
manifest_dict[key] = json.loads(
serializers.serialize("json", object_query),
)
self.encrypt_secret_fields(manifest_dict)
@@ -550,24 +512,14 @@ class Command(CryptMixin, BaseCommand):
self.files_in_export_dir.remove(target)
if self.compare_json:
target_checksum = hashlib.md5(target.read_bytes()).hexdigest()
src_str = json.dumps(
content,
cls=DjangoJSONEncoder,
indent=2,
ensure_ascii=False,
)
src_str = json.dumps(content, indent=2, ensure_ascii=False)
src_checksum = hashlib.md5(src_str.encode("utf-8")).hexdigest()
if src_checksum == target_checksum:
perform_write = False
if perform_write:
target.write_text(
json.dumps(
content,
cls=DjangoJSONEncoder,
indent=2,
ensure_ascii=False,
),
json.dumps(content, indent=2, ensure_ascii=False),
encoding="utf-8",
)

View File

@@ -1,4 +1,4 @@
# Generated by Django 5.2.11 on 2026-03-03 16:27
# Generated by Django 5.2.7 on 2026-01-15 22:08
import datetime
@@ -21,207 +21,6 @@ class Migration(migrations.Migration):
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
replaces = [
("documents", "0001_initial"),
("documents", "0002_auto_20151226_1316"),
("documents", "0003_sender"),
("documents", "0004_auto_20160114_1844"),
(
"documents",
"0004_auto_20160114_1844_squashed_0011_auto_20160303_1929",
),
("documents", "0005_auto_20160123_0313"),
("documents", "0006_auto_20160123_0430"),
("documents", "0007_auto_20160126_2114"),
("documents", "0008_document_file_type"),
("documents", "0009_auto_20160214_0040"),
("documents", "0010_log"),
("documents", "0011_auto_20160303_1929"),
("documents", "0012_auto_20160305_0040"),
("documents", "0013_auto_20160325_2111"),
("documents", "0014_document_checksum"),
("documents", "0015_add_insensitive_to_match"),
(
"documents",
"0015_add_insensitive_to_match_squashed_0018_auto_20170715_1712",
),
("documents", "0016_auto_20170325_1558"),
("documents", "0017_auto_20170512_0507"),
("documents", "0018_auto_20170715_1712"),
("documents", "0019_add_consumer_user"),
("documents", "0020_document_added"),
("documents", "0021_document_storage_type"),
("documents", "0022_auto_20181007_1420"),
("documents", "0023_document_current_filename"),
("documents", "1000_update_paperless_all"),
("documents", "1001_auto_20201109_1636"),
("documents", "1002_auto_20201111_1105"),
("documents", "1003_mime_types"),
("documents", "1004_sanity_check_schedule"),
("documents", "1005_checksums"),
("documents", "1006_auto_20201208_2209"),
(
"documents",
"1006_auto_20201208_2209_squashed_1011_auto_20210101_2340",
),
("documents", "1007_savedview_savedviewfilterrule"),
("documents", "1008_auto_20201216_1736"),
("documents", "1009_auto_20201216_2005"),
("documents", "1010_auto_20210101_2159"),
("documents", "1011_auto_20210101_2340"),
("documents", "1012_fix_archive_files"),
("documents", "1013_migrate_tag_colour"),
("documents", "1014_auto_20210228_1614"),
("documents", "1015_remove_null_characters"),
("documents", "1016_auto_20210317_1351"),
(
"documents",
"1016_auto_20210317_1351_squashed_1020_merge_20220518_1839",
),
("documents", "1017_alter_savedviewfilterrule_rule_type"),
("documents", "1018_alter_savedviewfilterrule_value"),
("documents", "1019_storagepath_document_storage_path"),
("documents", "1019_uisettings"),
("documents", "1020_merge_20220518_1839"),
("documents", "1021_webp_thumbnail_conversion"),
("documents", "1022_paperlesstask"),
(
"documents",
"1022_paperlesstask_squashed_1036_alter_savedviewfilterrule_rule_type",
),
("documents", "1023_add_comments"),
("documents", "1024_document_original_filename"),
("documents", "1025_alter_savedviewfilterrule_rule_type"),
("documents", "1026_transition_to_celery"),
(
"documents",
"1027_remove_paperlesstask_attempted_task_and_more",
),
(
"documents",
"1028_remove_paperlesstask_task_args_and_more",
),
("documents", "1029_alter_document_archive_serial_number"),
("documents", "1030_alter_paperlesstask_task_file_name"),
(
"documents",
"1031_remove_savedview_user_correspondent_owner_and_more",
),
(
"documents",
"1032_alter_correspondent_matching_algorithm_and_more",
),
(
"documents",
"1033_alter_documenttype_options_alter_tag_options_and_more",
),
("documents", "1034_alter_savedviewfilterrule_rule_type"),
("documents", "1035_rename_comment_note"),
("documents", "1036_alter_savedviewfilterrule_rule_type"),
("documents", "1037_webp_encrypted_thumbnail_conversion"),
("documents", "1038_sharelink"),
("documents", "1039_consumptiontemplate"),
(
"documents",
"1040_customfield_customfieldinstance_and_more",
),
("documents", "1041_alter_consumptiontemplate_sources"),
(
"documents",
"1042_consumptiontemplate_assign_custom_fields_and_more",
),
("documents", "1043_alter_savedviewfilterrule_rule_type"),
(
"documents",
"1044_workflow_workflowaction_workflowtrigger_and_more",
),
(
"documents",
"1045_alter_customfieldinstance_value_monetary",
),
(
"documents",
"1045_alter_customfieldinstance_value_monetary_squashed_1049_document_deleted_at_document_restored_at",
),
(
"documents",
"1046_workflowaction_remove_all_correspondents_and_more",
),
("documents", "1047_savedview_display_mode_and_more"),
("documents", "1048_alter_savedviewfilterrule_rule_type"),
(
"documents",
"1049_document_deleted_at_document_restored_at",
),
("documents", "1050_customfield_extra_data_and_more"),
(
"documents",
"1051_alter_correspondent_owner_alter_document_owner_and_more",
),
("documents", "1052_document_transaction_id"),
("documents", "1053_document_page_count"),
(
"documents",
"1054_customfieldinstance_value_monetary_amount_and_more",
),
("documents", "1055_alter_storagepath_path"),
(
"documents",
"1056_customfieldinstance_deleted_at_and_more",
),
("documents", "1057_paperlesstask_owner"),
(
"documents",
"1058_workflowtrigger_schedule_date_custom_field_and_more",
),
(
"documents",
"1059_workflowactionemail_workflowactionwebhook_and_more",
),
(
"documents",
"1060_alter_customfieldinstance_value_select",
),
("documents", "1061_workflowactionwebhook_as_json"),
("documents", "1062_alter_savedviewfilterrule_rule_type"),
(
"documents",
"1063_paperlesstask_type_alter_paperlesstask_task_name_and_more",
),
("documents", "1064_delete_log"),
(
"documents",
"1065_workflowaction_assign_custom_fields_values",
),
(
"documents",
"1066_alter_workflowtrigger_schedule_offset_days",
),
("documents", "1067_alter_document_created"),
("documents", "1068_alter_document_created"),
(
"documents",
"1069_workflowtrigger_filter_has_storage_path_and_more",
),
(
"documents",
"1070_customfieldinstance_value_long_text_and_more",
),
(
"documents",
"1071_tag_tn_ancestors_count_tag_tn_ancestors_pks_and_more",
),
(
"documents",
"1072_workflowtrigger_filter_custom_field_query_and_more",
),
("documents", "1073_migrate_workflow_title_jinja"),
(
"documents",
"1074_workflowrun_deleted_at_workflowrun_restored_at_and_more",
),
]
operations = [
migrations.CreateModel(
name="WorkflowActionEmail",
@@ -386,6 +185,70 @@ class Migration(migrations.Migration):
"abstract": False,
},
),
migrations.CreateModel(
name="CustomField",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"created",
models.DateTimeField(
db_index=True,
default=django.utils.timezone.now,
editable=False,
verbose_name="created",
),
),
("name", models.CharField(max_length=128)),
(
"data_type",
models.CharField(
choices=[
("string", "String"),
("url", "URL"),
("date", "Date"),
("boolean", "Boolean"),
("integer", "Integer"),
("float", "Float"),
("monetary", "Monetary"),
("documentlink", "Document Link"),
("select", "Select"),
("longtext", "Long Text"),
],
editable=False,
max_length=50,
verbose_name="data type",
),
),
(
"extra_data",
models.JSONField(
blank=True,
help_text="Extra data for the custom field, such as select options",
null=True,
verbose_name="extra data",
),
),
],
options={
"verbose_name": "custom field",
"verbose_name_plural": "custom fields",
"ordering": ("created",),
"constraints": [
models.UniqueConstraint(
fields=("name",),
name="documents_customfield_unique_name",
),
],
},
),
migrations.CreateModel(
name="DocumentType",
fields=[
@@ -870,6 +733,17 @@ class Migration(migrations.Migration):
verbose_name="correspondent",
),
),
(
"owner",
models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
verbose_name="owner",
),
),
(
"document_type",
models.ForeignKey(
@@ -893,14 +767,12 @@ class Migration(migrations.Migration):
),
),
(
"owner",
models.ForeignKey(
"tags",
models.ManyToManyField(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
verbose_name="owner",
related_name="documents",
to="documents.tag",
verbose_name="tags",
),
),
],
@@ -910,140 +782,6 @@ class Migration(migrations.Migration):
"ordering": ("-created",),
},
),
migrations.AddField(
model_name="document",
name="tags",
field=models.ManyToManyField(
blank=True,
related_name="documents",
to="documents.tag",
verbose_name="tags",
),
),
migrations.CreateModel(
name="Note",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("deleted_at", models.DateTimeField(blank=True, null=True)),
("restored_at", models.DateTimeField(blank=True, null=True)),
("transaction_id", models.UUIDField(blank=True, null=True)),
(
"note",
models.TextField(
blank=True,
help_text="Note for the document",
verbose_name="content",
),
),
(
"created",
models.DateTimeField(
db_index=True,
default=django.utils.timezone.now,
verbose_name="created",
),
),
(
"document",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="notes",
to="documents.document",
verbose_name="document",
),
),
(
"user",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="notes",
to=settings.AUTH_USER_MODEL,
verbose_name="user",
),
),
],
options={
"verbose_name": "note",
"verbose_name_plural": "notes",
"ordering": ("created",),
},
),
migrations.CreateModel(
name="CustomField",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"created",
models.DateTimeField(
db_index=True,
default=django.utils.timezone.now,
editable=False,
verbose_name="created",
),
),
("name", models.CharField(max_length=128)),
(
"data_type",
models.CharField(
choices=[
("string", "String"),
("url", "URL"),
("date", "Date"),
("boolean", "Boolean"),
("integer", "Integer"),
("float", "Float"),
("monetary", "Monetary"),
("documentlink", "Document Link"),
("select", "Select"),
("longtext", "Long Text"),
],
editable=False,
max_length=50,
verbose_name="data type",
),
),
(
"extra_data",
models.JSONField(
blank=True,
help_text="Extra data for the custom field, such as select options",
null=True,
verbose_name="extra data",
),
),
],
options={
"verbose_name": "custom field",
"verbose_name_plural": "custom fields",
"ordering": ("created",),
"constraints": [
models.UniqueConstraint(
fields=("name",),
name="documents_customfield_unique_name",
),
],
},
),
migrations.CreateModel(
name="CustomFieldInstance",
fields=[
@@ -1142,6 +880,66 @@ class Migration(migrations.Migration):
"ordering": ("created",),
},
),
migrations.CreateModel(
name="Note",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("deleted_at", models.DateTimeField(blank=True, null=True)),
("restored_at", models.DateTimeField(blank=True, null=True)),
("transaction_id", models.UUIDField(blank=True, null=True)),
(
"note",
models.TextField(
blank=True,
help_text="Note for the document",
verbose_name="content",
),
),
(
"created",
models.DateTimeField(
db_index=True,
default=django.utils.timezone.now,
verbose_name="created",
),
),
(
"document",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="notes",
to="documents.document",
verbose_name="document",
),
),
(
"user",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="notes",
to=settings.AUTH_USER_MODEL,
verbose_name="user",
),
),
],
options={
"verbose_name": "note",
"verbose_name_plural": "notes",
"ordering": ("created",),
},
),
migrations.CreateModel(
name="PaperlessTask",
fields=[
@@ -1188,6 +986,7 @@ class Migration(migrations.Migration):
("train_classifier", "Train Classifier"),
("check_sanity", "Check Sanity"),
("index_optimize", "Index Optimize"),
("llmindex_update", "LLM Index Update"),
],
help_text="Name of the task that was run",
max_length=255,
@@ -1581,7 +1380,6 @@ class Migration(migrations.Migration):
verbose_name="Workflow Action Type",
),
),
("order", models.PositiveIntegerField(default=0, verbose_name="order")),
(
"assign_title",
models.TextField(

View File

@@ -1,4 +1,4 @@
# Generated by Django 5.2.11 on 2026-03-03 16:27
# Generated by Django 5.2.9 on 2026-01-20 18:46
import django.db.models.deletion
from django.db import migrations
@@ -9,14 +9,8 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
("documents", "0001_squashed"),
("paperless_mail", "0001_squashed"),
]
# This migration needs a "replaces", but it doesn't matter which.
# Chose the last 2.20.x migration
replaces = [
("documents", "1075_workflowaction_order"),
("documents", "0001_initial"),
("paperless_mail", "0001_initial"),
]
operations = [

View File

@@ -6,7 +6,7 @@ from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0002_squashed"),
("documents", "0002_initial"),
]
operations = [

View File

@@ -1,30 +0,0 @@
# Generated by Django 5.2.11 on 2026-03-03 16:42
from django.db import migrations
from django.db import models
class Migration(migrations.Migration):
dependencies = [
("documents", "0013_document_root_document"),
]
operations = [
migrations.AlterField(
model_name="paperlesstask",
name="task_name",
field=models.CharField(
choices=[
("consume_file", "Consume File"),
("train_classifier", "Train Classifier"),
("check_sanity", "Check Sanity"),
("index_optimize", "Index Optimize"),
("llmindex_update", "LLM Index Update"),
],
help_text="Name of the task that was run",
max_length=255,
null=True,
verbose_name="Task Name",
),
),
]

View File

@@ -1,71 +0,0 @@
"""
Temporary profiling utilities for comparing implementations.
Usage in a management command or shell::
from documents.profiling import profile_block
with profile_block("new check_sanity"):
messages = check_sanity()
with profile_block("old check_sanity"):
messages = check_sanity_old()
Drop this file when done.
"""
from __future__ import annotations
import tracemalloc
from contextlib import contextmanager
from time import perf_counter
from typing import TYPE_CHECKING
from django.db import connection
from django.db import reset_queries
from django.test.utils import override_settings
if TYPE_CHECKING:
from collections.abc import Generator
@contextmanager
def profile_block(label: str = "block") -> Generator[None, None, None]:
"""Profile memory, wall time, and DB queries for a code block.
Prints a summary to stdout on exit. Requires no external packages.
Enables DEBUG temporarily to capture Django's query log.
"""
tracemalloc.start()
snapshot_before = tracemalloc.take_snapshot()
with override_settings(DEBUG=True):
reset_queries()
start = perf_counter()
yield
elapsed = perf_counter() - start
queries = list(connection.queries)
snapshot_after = tracemalloc.take_snapshot()
_, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
# Compare snapshots for top allocations
stats = snapshot_after.compare_to(snapshot_before, "lineno")
query_time = sum(float(q["time"]) for q in queries)
mem_diff = sum(s.size_diff for s in stats)
print(f"\n{'=' * 60}") # noqa: T201
print(f" Profile: {label}") # noqa: T201
print(f"{'=' * 60}") # noqa: T201
print(f" Wall time: {elapsed:.4f}s") # noqa: T201
print(f" Queries: {len(queries)} ({query_time:.4f}s)") # noqa: T201
print(f" Memory delta: {mem_diff / 1024:.1f} KiB") # noqa: T201
print(f" Peak memory: {peak / 1024:.1f} KiB") # noqa: T201
print("\n Top 5 allocations:") # noqa: T201
for stat in stats[:5]:
print(f" {stat}") # noqa: T201
print(f"{'=' * 60}\n") # noqa: T201

View File

@@ -204,61 +204,6 @@ def audit_log_check(app_configs, **kwargs):
return result
@register()
def check_v3_minimum_upgrade_version(
app_configs: object,
**kwargs: object,
) -> list[Error]:
"""Enforce that upgrades to v3 must start from v2.20.9.
v3 squashes all prior migrations into 0001_squashed and 0002_squashed.
If a user skips v2.20.9, the data migration in 1075_workflowaction_order
never runs and the squash may apply schema changes against an incomplete
database state.
"""
from django.db import DatabaseError
from django.db import OperationalError
try:
all_tables = connections["default"].introspection.table_names()
if "django_migrations" not in all_tables:
return []
with connections["default"].cursor() as cursor:
cursor.execute(
"SELECT name FROM django_migrations WHERE app = %s",
["documents"],
)
applied: set[str] = {row[0] for row in cursor.fetchall()}
if not applied:
return []
# Already in a valid v3 state
if {"0001_squashed", "0002_squashed"} & applied:
return []
# On v2.20.9 exactly — squash will pick up cleanly from here
if "1075_workflowaction_order" in applied:
return []
except (DatabaseError, OperationalError):
return []
return [
Error(
"Cannot upgrade to Paperless-ngx v3 from this version.",
hint=(
"Upgrading to v3 can only be performed from v2.20.9."
"Please upgrade to v2.20.9, run migrations, then upgrade to v3."
"See https://docs.paperless-ngx.com/setup/#upgrading for details."
),
id="paperless.E002",
),
]
@register()
def check_deprecated_db_settings(
app_configs: object,

View File

@@ -3,7 +3,6 @@ from pathlib import Path
from unittest import mock
import pytest
from django.core.checks import Error
from django.core.checks import Warning
from django.test import TestCase
from django.test import override_settings
@@ -14,7 +13,6 @@ from documents.tests.utils import FileSystemAssertsMixin
from paperless.checks import audit_log_check
from paperless.checks import binaries_check
from paperless.checks import check_deprecated_db_settings
from paperless.checks import check_v3_minimum_upgrade_version
from paperless.checks import debug_mode_check
from paperless.checks import paths_check
from paperless.checks import settings_values_check
@@ -397,240 +395,3 @@ class TestDeprecatedDbSettings:
assert len(result) == 1
assert "PAPERLESS_DBSSLCERT" in result[0].msg
class TestV3MinimumUpgradeVersionCheck:
"""Test suite for check_v3_minimum_upgrade_version system check."""
@pytest.fixture
def build_conn_mock(self, mocker: MockerFixture):
"""Factory fixture that builds a connections['default'] mock.
Usage::
conn = build_conn_mock(tables=["django_migrations"], applied=["1075_..."])
"""
def _build(tables: list[str], applied: list[str]) -> mock.MagicMock:
conn = mocker.MagicMock()
conn.introspection.table_names.return_value = tables
cursor = conn.cursor.return_value.__enter__.return_value
cursor.fetchall.return_value = [(name,) for name in applied]
return conn
return _build
def test_no_migrations_table_fresh_install(
self,
mocker: MockerFixture,
build_conn_mock,
) -> None:
"""
GIVEN:
- No django_migrations table exists in the database
WHEN:
- The v3 upgrade check runs
THEN:
- No errors are reported (fresh install, nothing to enforce)
"""
mocker.patch.dict(
"paperless.checks.connections",
{"default": build_conn_mock([], [])},
)
assert check_v3_minimum_upgrade_version(None) == []
def test_no_documents_migrations_fresh_install(
self,
mocker: MockerFixture,
build_conn_mock,
) -> None:
"""
GIVEN:
- django_migrations table exists but has no documents app rows
WHEN:
- The v3 upgrade check runs
THEN:
- No errors are reported (fresh install, nothing to enforce)
"""
mocker.patch.dict(
"paperless.checks.connections",
{"default": build_conn_mock(["django_migrations"], [])},
)
assert check_v3_minimum_upgrade_version(None) == []
def test_v3_state_with_0001_squashed(
self,
mocker: MockerFixture,
build_conn_mock,
) -> None:
"""
GIVEN:
- 0001_squashed is recorded in django_migrations
WHEN:
- The v3 upgrade check runs
THEN:
- No errors are reported (DB is already in a valid v3 state)
"""
mocker.patch.dict(
"paperless.checks.connections",
{
"default": build_conn_mock(
["django_migrations"],
["0001_squashed", "0002_squashed", "0003_workflowaction_order"],
),
},
)
assert check_v3_minimum_upgrade_version(None) == []
def test_v3_state_with_0002_squashed_only(
self,
mocker: MockerFixture,
build_conn_mock,
) -> None:
"""
GIVEN:
- Only 0002_squashed is recorded in django_migrations
WHEN:
- The v3 upgrade check runs
THEN:
- No errors are reported (0002_squashed alone confirms a valid v3 state)
"""
mocker.patch.dict(
"paperless.checks.connections",
{"default": build_conn_mock(["django_migrations"], ["0002_squashed"])},
)
assert check_v3_minimum_upgrade_version(None) == []
def test_v2_20_9_state_ready_to_upgrade(
self,
mocker: MockerFixture,
build_conn_mock,
) -> None:
"""
GIVEN:
- 1075_workflowaction_order (the last v2.20.9 migration) is in the DB
WHEN:
- The v3 upgrade check runs
THEN:
- No errors are reported (squash will pick up cleanly from this state)
"""
mocker.patch.dict(
"paperless.checks.connections",
{
"default": build_conn_mock(
["django_migrations"],
[
"1074_workflowrun_deleted_at_workflowrun_restored_at_and_more",
"1075_workflowaction_order",
],
),
},
)
assert check_v3_minimum_upgrade_version(None) == []
def test_v2_20_8_raises_error(
self,
mocker: MockerFixture,
build_conn_mock,
) -> None:
"""
GIVEN:
- 1074 (last v2.20.8 migration) is applied but 1075 is not
WHEN:
- The v3 upgrade check runs
THEN:
- An Error with id paperless.E002 is returned
"""
mocker.patch.dict(
"paperless.checks.connections",
{
"default": build_conn_mock(
["django_migrations"],
["1074_workflowrun_deleted_at_workflowrun_restored_at_and_more"],
),
},
)
result = check_v3_minimum_upgrade_version(None)
assert len(result) == 1
assert isinstance(result[0], Error)
assert result[0].id == "paperless.E002"
def test_very_old_version_raises_error(
self,
mocker: MockerFixture,
build_conn_mock,
) -> None:
"""
GIVEN:
- Only old migrations (well below v2.20.9) are applied
WHEN:
- The v3 upgrade check runs
THEN:
- An Error with id paperless.E002 is returned
"""
mocker.patch.dict(
"paperless.checks.connections",
{
"default": build_conn_mock(
["django_migrations"],
["1000_update_paperless_all", "1022_paperlesstask"],
),
},
)
result = check_v3_minimum_upgrade_version(None)
assert len(result) == 1
assert isinstance(result[0], Error)
assert result[0].id == "paperless.E002"
def test_error_hint_mentions_v2_20_9(
self,
mocker: MockerFixture,
build_conn_mock,
) -> None:
"""
GIVEN:
- DB is on an old v2 version (pre-v2.20.9)
WHEN:
- The v3 upgrade check runs
THEN:
- The error hint explicitly references v2.20.9 so users know what to do
"""
mocker.patch.dict(
"paperless.checks.connections",
{"default": build_conn_mock(["django_migrations"], ["1022_paperlesstask"])},
)
result = check_v3_minimum_upgrade_version(None)
assert len(result) == 1
assert "v2.20.9" in result[0].hint
def test_db_error_is_swallowed(self, mocker: MockerFixture) -> None:
"""
GIVEN:
- A DatabaseError is raised when querying the DB
WHEN:
- The v3 upgrade check runs
THEN:
- No exception propagates and an empty list is returned
"""
from django.db import DatabaseError
conn = mocker.MagicMock()
conn.introspection.table_names.side_effect = DatabaseError("connection refused")
mocker.patch.dict("paperless.checks.connections", {"default": conn})
assert check_v3_minimum_upgrade_version(None) == []
def test_operational_error_is_swallowed(self, mocker: MockerFixture) -> None:
"""
GIVEN:
- An OperationalError is raised when querying the DB
WHEN:
- The v3 upgrade check runs
THEN:
- No exception propagates and an empty list is returned
"""
from django.db import OperationalError
conn = mocker.MagicMock()
conn.introspection.table_names.side_effect = OperationalError("DB unavailable")
mocker.patch.dict("paperless.checks.connections", {"default": conn})
assert check_v3_minimum_upgrade_version(None) == []

View File

@@ -1,4 +1,4 @@
# Generated by Django 5.2.11 on 2026-03-03 16:27
# Generated by Django 5.2.9 on 2026-01-20 18:46
import django.db.models.deletion
import django.utils.timezone
@@ -15,50 +15,6 @@ class Migration(migrations.Migration):
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
replaces = [
("paperless_mail", "0001_initial"),
("paperless_mail", "0001_initial_squashed_0009_mailrule_assign_tags"),
("paperless_mail", "0002_auto_20201117_1334"),
("paperless_mail", "0003_auto_20201118_1940"),
("paperless_mail", "0004_mailrule_order"),
("paperless_mail", "0005_help_texts"),
("paperless_mail", "0006_auto_20210101_2340"),
("paperless_mail", "0007_auto_20210106_0138"),
("paperless_mail", "0008_auto_20210516_0940"),
("paperless_mail", "0009_alter_mailrule_action_alter_mailrule_folder"),
("paperless_mail", "0009_mailrule_assign_tags"),
("paperless_mail", "0010_auto_20220311_1602"),
("paperless_mail", "0011_remove_mailrule_assign_tag"),
(
"paperless_mail",
"0011_remove_mailrule_assign_tag_squashed_0024_alter_mailrule_name_and_more",
),
("paperless_mail", "0012_alter_mailrule_assign_tags"),
("paperless_mail", "0013_merge_20220412_1051"),
("paperless_mail", "0014_alter_mailrule_action"),
("paperless_mail", "0015_alter_mailrule_action"),
("paperless_mail", "0016_mailrule_consumption_scope"),
("paperless_mail", "0017_mailaccount_owner_mailrule_owner"),
("paperless_mail", "0018_processedmail"),
("paperless_mail", "0019_mailrule_filter_to"),
("paperless_mail", "0020_mailaccount_is_token"),
("paperless_mail", "0021_alter_mailaccount_password"),
("paperless_mail", "0022_mailrule_assign_owner_from_rule_and_more"),
("paperless_mail", "0023_remove_mailrule_filter_attachment_filename_and_more"),
("paperless_mail", "0024_alter_mailrule_name_and_more"),
(
"paperless_mail",
"0025_alter_mailaccount_owner_alter_mailrule_owner_and_more",
),
("paperless_mail", "0026_mailrule_enabled"),
(
"paperless_mail",
"0027_mailaccount_expiration_mailaccount_account_type_and_more",
),
("paperless_mail", "0028_alter_mailaccount_password_and_more"),
("paperless_mail", "0029_mailrule_pdf_layout"),
]
operations = [
migrations.CreateModel(
name="MailAccount",

View File

@@ -6,7 +6,7 @@ from django.db import models
class Migration(migrations.Migration):
dependencies = [
("paperless_mail", "0001_squashed"),
("paperless_mail", "0001_initial"),
]
operations = [