Skip to content

← Parallel Python with Process Pools step 3 of 24

Medium Framework

Find Every Unpicklable Value in a Nested Payload

In the last exercise, pickle.dumps rejected a list that held a lock. Real job arguments nest deeper, like a settings dictionary that holds lists of callbacks. On Python 3.14 and later, the error's notes name the path to the bad value, but pickle.dumps stops at the first one. You fix it, run again, and get the next error. Write a function that reports every bad value at once.

solve({"retries": 3, "hooks": ["@module_function", "@lambda"], "lock": "@lock"})
# ["$.hooks[1]", "$.lock"]

The payload

The payload is a tree of JSON-like values. The starter defines its type:

type Recipe = str | int | float | bool | None | list[Recipe] | dict[str, Recipe]

A leaf is any value in the tree that is not a list or a dictionary.

Test inputs arrive as JSON, which cannot hold a lock or a lambda. So the starter's SPECIMENS table maps names such as "@lock" to factories, functions that build the real object. Its 13 entries include a lambda, a generator, a lock and a module. Keep the table as it is.

What to write

Fill in solve(payload). It returns the path of every leaf that fails.

  • Visit every list element and every dictionary value. Don't test dictionary keys, and don't test a list or a dictionary as a whole. An empty one has no leaves, so it adds nothing.
  • If a leaf is a string that exactly matches a key in SPECIMENS, call that factory and test the object it returns. Test every other leaf as itself, including an unknown name such as "@unknown".
  • To test an object, call pickle.dumps(obj) with the default protocol. If it raises any Exception, record the leaf's path.
  • Don't change the payload or the table. Don't unpickle anything or start a process. The grader cannot run a process pool, so pickle.dumps is the whole check.

How to write a path

  • The root is $.
  • Add .key for a dictionary value and [i] for a list element. So ["@lock", {"x": "@generator"}] gives ["$[0]", "$[1].x"].
  • Write each key as it is, with no quotes or escaping.
  • Sort the finished paths as strings, so "$[10]" comes before "$[2]".
  • Keep duplicates. With keys written as they are, {"a.b": ...} and {"a": {"b": ...}} both give the path $.a.b.

Going further

A value that pickles here can still fail in a worker. For example, a function from a module the worker cannot import pickles in your program and fails to load in the worker. Test real pool code with the start method you will use. See what can be pickled.