#19 Support Jupyter Notebooks - #182
Conversation
|
@roskakori I've merged the recent changes from |
|
@Iain-S Thanks for the contribution. As you noticed, I'm just in the process of merging some older pull requests (embarrassingly enough from a sprint performed last summer at the EuroPython 2024 conference 🤫). I hope I get to reviewing yours some time within the next couple of days. |
There was a problem hiding this comment.
@Iain-S Parsing the notebook as JSON and accessing dictionary keys seems a bit risky to me concerning robustness. Probably we could improve this with some error handling that turn low lever errors like KeyError, JSONDecodeError, or TypeError into something a bit more descriptive.
The concept with peek() and checking for isinstance(..., DynamicLexerMixin) looks a bit clumsy.
I did some research and penned a concept for a Jupyter notebook lexer based on nbformat.reads() and a custom pygments Lexer that seems cleaner and more future-proof to me. See #19 for details.
What are your thought about this? Are you interested in implementing that?
|
|
||
|
|
||
| def _delined_tokens(tokens: Iterator[tuple[TokenType, str]]) -> Iterator[TokenType]: | ||
| def _delined_tokens(tokens: Iterator[Tuple[TokenType, str]]) -> Iterator[Tuple[TokenType, str]]: |
There was a problem hiding this comment.
| def _delined_tokens(tokens: Iterator[Tuple[TokenType, str]]) -> Iterator[Tuple[TokenType, str]]: | |
| def _delined_tokens(tokens: Iterator[tuple[TokenType, str]]) -> Iterator[tuple[TokenType, str]]: |
The modern, lower case type hints are supported since Python 3.9, which is the lowest version pygount supports.
|
|
||
|
|
||
| def _pythonized_comments(tokens: Iterator[tuple[TokenType, str]]) -> Iterator[TokenType]: | ||
| def _pythonized_comments(tokens: Iterator[Tuple[TokenType, str]]) -> Iterator[Tuple[TokenType, str]]: |
There was a problem hiding this comment.
| def _pythonized_comments(tokens: Iterator[Tuple[TokenType, str]]) -> Iterator[Tuple[TokenType, str]]: | |
| def _pythonized_comments(tokens: Iterator[tuple[TokenType, str]]) -> Iterator[tuple[TokenType, str]]: |
Again, Python 3.9 syntax.
| def peek(self, text) -> None: | ||
| """Look at the text to determine the language.""" | ||
| self.json_dict = json.loads(text) | ||
| self.lexer = pygments.lexers.get_lexer_by_name(self.json_dict["metadata"]["language_info"]["name"]) |
There was a problem hiding this comment.
Several ways to fail with KeyError, and the lines below, if the dict is incomplete.
Also, if text did not describe a JSON map but for example a string like json.loads('"hello"'), attempting to access it with a key will result in
TypeError: string indices must be integers, not 'str'
|
@roskakori, by all means leave this in limbo or archive it if you prefer. I would like to think that I would have some time to try the nbformat-based lexer suggestion but I'm not sure when that will be, realistically. Regarding the
Yes, it's not ideal. The problem I was trying to work around is that I believe the language needs to be known by the lexer by this line but the lexer won't have seen the source code by that point. Therefore, you would be stuck with a language of "IPython Notebook" or similar. If you want the language of the lexer to reflext the actual language used in the notebook, the lexer needs to be able to inspect the json. It would probably be useful if you outlined, either here or in the linked issue, where you think language resolution should be done. For example, you call your So the nbformat lexer may be more robust but I'm not sure it entirely solves the issue. Also, you may (or may not) want to merge in my (or some other) unit tests just so anyone else who tries to implement notebook parsing has some concrete tests to verify against. |
I added a note to #19 about adding the new lexer to IIRC lexers in this mapping take priority before
Yes, the tests look good. We should use them no matter the rest of the implementation. |
Summary
Adds support for counting lines of code in Jupyter notebooks, as mentioned in #19.
Changes
.ipynbfiles to it.self.nameso I added the DynamicLexerMixin to indicate a lexer that needs to preview the data.Further Work?
Jupyter+Python, which will becomeJupyterifmerge_embedded_language=True. Is that OK?rawnotebook cells. Would it be better to treat them as documentation?