Repository navigation
Allow null execution_count in execute_result. [API change] - #4
Open
JayOfTheKeyboard wants to merge 1 commit into
Open
JayOfTheKeyboard wants to merge 1 commit into
JayOfTheKeyboard wants to merge 1 commit into
Conversation
The nbformat v4 schema gives an execute_result's execution_count the type ["integer", "null"], the same as a code cell's. Such notebooks failed to decode as v4. executeCount is now Maybe Int, like codeExecutionCount, and null is written back as null. For v3, a pyout's prompt_number is now handled like a code cell's: it is read with .:? and left out when there is no count.
JayOfTheKeyboard
added a commit
to JayOfTheKeyboard/JayOfTheKeyboard
that referenced
this pull request
Oct 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See jgm/pandoc#12008.
The nbformat v4 schema allows
nullfor anexecute_result'sexecution_count, as it does for a code cell's ("type": ["integer", "null"]in every schema from nbformat.v4.0 to v4.5).executeCountis anInt, so a notebook with one of these fails to decode as v4, and pandoc then reports the error from its v3 attempt:with this input:
{"nbformat": 4, "nbformat_minor": 5, "metadata": {}, "cells": [{"cell_type": "code", "id": "a1", "execution_count": null, "metadata": {}, "source": ["1+1"], "outputs": [{"output_type": "execute_result", "execution_count": null, "metadata": {}, "data": {"text/plain": ["2"]}}]}]}That was pandoc 3.13. The file passes
nbformat.validate(nbformat 5.11.1). Four of the Ray project's Lightning and Tune example notebooks have such outputs (for exampledoc/source/tune/examples/tune-pytorch-lightning.ipynb), and all four validate.executeCountis nowMaybe Int, likecodeExecutionCount. In v4,nullreads asNothingand is written back asnull, so the key the schema requires stays in place. In v3, apyout'sprompt_numbernow works the way a code cell's does: it is read with.:?and left out when there is no count. Writingnullthere would break the v3 schema, which wants an integer, and the reader can still read what the writer produces.Because this changes an exported type, pandoc needs two edits. The writer stops compiling, which makes that one easy to spot. The reader still compiles but would quietly produce
execution_count="Just 3":Readers/Ipynb.hs,outputToBlock: replace[("execution_count",tshow ec)]withmaybe [] (\n -> [("execution_count", tshow n)]) ec, as the code-cell case already does.Writers/Ipynb.hs,blockToOutput: drop thefromMaybe 0, so anexecute_resultdiv with no count is written asnullrather than0. None of the files intest/ipynbhas anexecute_resultwithout a count.I didn't touch the version or Changelog.md, since you have always updated those yourself at release.
Test:
test/rt-files/test4execute_result_null.ipynb, a one-cell v4.5 notebook, goes through the existing round trip. The round trip compares decoded values, so it can't see whethernullsurvives in the JSON. I added two small cases totest/roundtrip.hsfor that: one checks that encoding the new notebook gives"execution_count": nullon the output, and one checks that a v3pyoutwith"prompt_number": nullis written withoutprompt_numberand reads back the same. Without the change all three fail withparsing Int failed, expected Number, but encountered Null. With it, all 8 tests pass (GHC 9.6.7, aeson 2.3.2.0), and-Wallreports only the existing unusedxat line 241. I also broke the change four ways (v4 writes0, v4 leaves out the key, v3 writesnull, v3 reads with.:), and each one makes a test fail. The four Ray notebooks decode and round-trip with the change and fail without it.Prepared with Claude Code.