Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ValidationError can be pickled, but cannot be unpickled #959

Closed
1 task done
cuu508 opened this issue Sep 11, 2023 · 4 comments
Closed
1 task done

ValidationError can be pickled, but cannot be unpickled #959

cuu508 opened this issue Sep 11, 2023 · 4 comments
Assignees

Comments

@cuu508
Copy link

cuu508 commented Sep 11, 2023

Initial Checks

  • I confirm that I'm using Pydantic V2

Description

It seems that instances of ValidationError can be pickled with the pickle module, but unpickling fails with a "No constructor defined" error – see example code below.

I ran into this while using Pydantic inside a Django project, and running Django tests in parallel (manage.py test --parallel). In parallel mode, tests are run in multiple processes. If a test fails, the failure is pickled and reported back to the parent process. If test fails by throwing an uncaught ValidationError, in the console output I do not see the Validation error itself, instead I see a less helpful error about the the failed unpickling.

A workaround is to run Django tests sequentially, but it would be nice to be able to use the parallel mode.

Example Code

from __future__ import annotations

import pickle

from pydantic import BaseModel, ValidationError


class A(BaseModel):
    name: str


try:
    A.model_validate_json("this is not JSON")
except ValidationError as e:
    print(pickle.loads(pickle.dumps(e)))


# Produces:
# Traceback (most recent call last):
#   File "/home/foo/example.py", line 15, in <module>
#     print(pickle.loads(pickle.dumps(e)))
# TypeError: No constructor defined

Python, Pydantic & OS Version

pydantic version: 2.3.0
        pydantic-core version: 2.6.3
          pydantic-core build: profile=release pgo=true
                 install path: /home/cepe/venvs/healthchecks/lib/python3.10/site-packages/pydantic
               python version: 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0]
                     platform: Linux-5.15.0-79-generic-x86_64-with-glibc2.35
     optional deps. installed: ['typing-extensions']
@adriangb
Copy link
Member

Indeed I don't think that ValidationError is picklable. In general, I'd say to use ValidationError.errors() and serialize that but I understand that doesn't make sense in the context of the problem you're facing. I will transfer this issue to pydantic-core for now. It should be possible to pickle and unpickle without a constructor.

@adriangb adriangb transferred this issue from pydantic/pydantic Sep 11, 2023
@somnam
Copy link

somnam commented Oct 4, 2023

Facing the same issue when retrieving exception from a Celery task that failed due to pydantic model validation.
In V1 Celery reported ValidationError with a list of errors.
In V2 Celery reports a generic ValueError with no additional info.
Celery uses pickle to serialize task exceptions, which for V2 ValidationError breaks with # TypeError: No constructor defined error.
Is there a possibility to support pickle in V2 Validation Errors?

@abhishek-ram
Copy link

abhishek-ram commented Dec 5, 2023

Is there any update on this issue?
we are facing this error when running django tests in parallel, django uses pickle to collect all errors from the different threads and that is where this fails.

2023-12-05T06:04:59.1128178Z Traceback (most recent call last):
2023-12-05T06:04:59.1129113Z   File "/opt/bitnami/python/lib/python3.8/multiprocessing/pool.py", line 125, in worker
2023-12-05T06:04:59.1130045Z     result = (True, func(*args, **kwds))
2023-12-05T06:04:59.1131178Z   File "/opt/env/lib/python3.8/site-packages/django/test/runner.py", line 347, in _run_subsuite
2023-12-05T06:04:59.1132165Z     result = runner.run(subsuite)
2023-12-05T06:04:59.1133170Z   File "/opt/env/lib/python3.8/site-packages/django/test/runner.py", line 294, in run
2023-12-05T06:04:59.1134057Z     test(result)
2023-12-05T06:04:59.1134752Z   File "/opt/bitnami/python/lib/python3.8/unittest/suite.py", line 84, in __call__
2023-12-05T06:04:59.1135667Z     return self.run(*args, **kwds)
2023-12-05T06:04:59.1136529Z   File "/opt/bitnami/python/lib/python3.8/unittest/suite.py", line 122, in run
2023-12-05T06:04:59.1137428Z     test(result)
2023-12-05T06:04:59.1138422Z   File "/opt/env/lib/python3.8/site-packages/django/test/testcases.py", line 245, in __call__
2023-12-05T06:04:59.1139394Z     self._setup_and_call(result)
2023-12-05T06:04:59.1140537Z   File "/opt/env/lib/python3.8/site-packages/django/test/testcases.py", line 281, in _setup_and_call
2023-12-05T06:04:59.1141591Z     super().__call__(result)
2023-12-05T06:04:59.1142394Z   File "/opt/bitnami/python/lib/python3.8/unittest/case.py", line 736, in __call__
2023-12-05T06:04:59.1143303Z     return self.run(*args, **kwds)
2023-12-05T06:04:59.1144192Z   File "/opt/bitnami/python/lib/python3.8/unittest/case.py", line 684, in run
2023-12-05T06:04:59.1145160Z     self._feedErrorsToResult(result, outcome.errors)
2023-12-05T06:04:59.1146187Z   File "/opt/bitnami/python/lib/python3.8/unittest/case.py", line 602, in _feedErrorsToResult
2023-12-05T06:04:59.1147205Z     result.addError(test, exc_info)
2023-12-05T06:04:59.1148692Z   File "/opt/env/lib/python3.8/site-packages/django/test/runner.py", line 235, in addError
2023-12-05T06:04:59.1149961Z     self.check_picklable(test, err)
2023-12-05T06:04:59.1151186Z   File "/opt/env/lib/python3.8/site-packages/django/test/runner.py", line 168, in check_picklable
2023-12-05T06:04:59.1152300Z     self._confirm_picklable(err)
2023-12-05T06:04:59.1153522Z   File "/opt/env/lib/python3.8/site-packages/django/test/runner.py", line 142, in _confirm_picklable
2023-12-05T06:04:59.1154636Z     pickle.loads(pickle.dumps(obj))
2023-12-05T06:04:59.1155873Z   File "/opt/env/lib/python3.8/site-packages/tblib/pickling_support.py", line 26, in unpickle_exception
2023-12-05T06:04:59.1156952Z     inst = func(*args)
2023-12-05T06:04:59.1157408Z TypeError: No constructor defined
2023-12-05T06:04:59.1157914Z """```

@davidhewitt
Copy link
Contributor

Fixed in #1119

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants