Read a notebook cell's source as text, not as characters - #2549
Open
Anish Mehta (anishmehta24) wants to merge 1 commit into
Open
Anish Mehta (anishmehta24) wants to merge 1 commit into
Anish Mehta (anishmehta24) wants to merge 1 commit into
Conversation
nbformat's `multiline_string` is a string *or* a list of lines. Both validate,
and `nbformat.reads` keeps whichever the file used. The converter walked the
raw value looking for a heading:
for line in source_lines:
if line.startswith("# "):
With a list that iterates lines, which is what was intended. With a string it
iterates characters, and no single character starts with "# ", so a notebook
written that way came out with no title at all. The markdown body was fine,
because "".join() over a string reassembles it.
Take the cell's text once, then split it for the heading scan. That also picks
up a heading in a list entry that holds several lines, which the per-entry
check could not see.
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.
Motivation and Context
nbformat's
multiline_stringis a string or a list of lines, and both are valid.nbformat.validateaccepts either, andnbformat.readskeeps whichever spelling the file used. The converter walked the raw value to find the title:With a list that iterates lines, which is what was intended. With a string it iterates characters — and no single character starts with
"# "— so a notebook written that way comes out with no title at all:The same notebook written with
"source": ["# My Notebook\n", "intro text\n"]gives"My Notebook".The markdown body is unaffected either way, which is why this is easy to miss:
"".join(...)over a string reassembles the string, so only the title is lost.nbformat.writesnormalises to lists, so notebooks saved by Jupyter itself aren't affected. Notebooks assembled as JSON and written directly — generated notebooks, tooling that builds cells programmatically and callsjson.dumprather thannbformat.writes— are.Description
Take the cell's text once, then split it for the heading scan:
The body uses
source_textdirectly, so its output is byte-identical to before for list sources.The title scan now runs over
source_text.splitlines(). Besides fixing the string case, that also picks up a heading in a list entry holding several lines (["intro\n# My Notebook\n"]), which the per-entry check couldn't see — same root cause, so I fixed it in the same place rather than leaving a second shape broken.No behaviour changes for notebooks that already worked; the existing
#hashtagtitle regression test still passes.Tests
Three tests in
packages/markitdown/tests/test_module_misc.py, next to the existing ipynb ones:test_ipynb_string_source_is_read_as_text_not_characters— a string source now yields the titletest_ipynb_string_and_list_sources_agree— the two spellings of the same notebook produce identical title and markdowntest_ipynb_heading_below_the_first_line_of_a_source_entry— a heading after the first line of a list entryAll three fail on
main.test_module_misc.pyis 84 passed, 3 skipped, 1 failed — the failure istest_speech_transcription, which fails identically on a clean checkout here (it needs audio dependencies I don't have installed).