From 2a66459055227601fa0574055cfd43ae153046a0 Mon Sep 17 00:00:00 2001 From: ncoop57 Date: Tue, 19 Nov 2024 10:15:34 -0600 Subject: [PATCH 1/2] Improve backtick regex matching for function names --- nbdev/doclinks.py | 2 +- nbs/api/05_doclinks.ipynb | 40 +++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/nbdev/doclinks.py b/nbdev/doclinks.py index 18c6fd74b..6eceec596 100644 --- a/nbdev/doclinks.py +++ b/nbdev/doclinks.py @@ -195,7 +195,7 @@ def _qual_syms(entries): return {'syms': {mod:_qual_mod(d, settings) for mod,d in entries['syms'].items()}, 'settings':settings} # %% ../nbs/api/05_doclinks.ipynb -_re_backticks = re.compile(r'`([^`\s]+)`') +_re_backticks = re.compile(r'`([^`\s]+?)(?:\(\))?`') # %% ../nbs/api/05_doclinks.ipynb @lru_cache(None) diff --git a/nbs/api/05_doclinks.ipynb b/nbs/api/05_doclinks.ipynb index f075c2327..458d2d2bc 100644 --- a/nbs/api/05_doclinks.ipynb +++ b/nbs/api/05_doclinks.ipynb @@ -469,7 +469,23 @@ "outputs": [], "source": [ "#|export\n", - "_re_backticks = re.compile(r'`([^`\\s]+)`')" + "_re_backticks = re.compile(r'`([^`\\s]+?)(?:\\(\\))?`')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#|hide\n", + "test_eq(_re_backticks.findall('test `foo` here'), ['foo'])\n", + "test_eq(_re_backticks.findall('test `foo()` here'), ['foo'])\n", + "test_eq(_re_backticks.findall('multiple `foo` and `bar()` matches'), ['foo', 'bar'])\n", + "test_eq(_re_backticks.findall('no match'), [])\n", + "test_eq(_re_backticks.findall('`weird``thing`'), ['weird', 'thing'])\n", + "test_eq(_re_backticks.findall('`spaces not allowed `'), [])\n", + "test_eq(_re_backticks.findall('`sym.with.dots`'), ['sym.with.dots'])" ] }, { @@ -549,6 +565,14 @@ "execution_count": null, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/nathan/miniconda3/envs/main/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + }, { "data": { "text/plain": [ @@ -577,7 +601,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L226){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L227){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### NbdevLookup.doc\n", "\n", @@ -588,7 +612,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L226){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L227){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### NbdevLookup.doc\n", "\n", @@ -671,7 +695,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L231){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L232){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### NbdevLookup.code\n", "\n", @@ -682,7 +706,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L231){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L232){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### NbdevLookup.code\n", "\n", @@ -730,7 +754,7 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L248){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L249){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### NbdevLookup.linkify\n", "\n", @@ -739,7 +763,7 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L248){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L249){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", "\n", "### NbdevLookup.linkify\n", "\n", @@ -761,7 +785,7 @@ "metadata": {}, "outputs": [], "source": [ - "md = \"\"\"This is a link to `numpy.array` and to `get_config` but not a link to `foobar`.\n", + "md = \"\"\"This is a link to `numpy.array` and to `get_config()` but not a link to `foobar`.\n", "And not a link to dict2nb.\n", "\n", " This is not a link to `get_config`\n", From 9ca103fa94ca9f734cf79a390856c6613bbf6055 Mon Sep 17 00:00:00 2001 From: ncoop57 Date: Tue, 19 Nov 2024 10:37:50 -0600 Subject: [PATCH 2/2] Enhance doclinks to handle function calls and improve symbol detection --- nbdev/doclinks.py | 3 ++- nbs/api/05_doclinks.ipynb | 35 ++++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/nbdev/doclinks.py b/nbdev/doclinks.py index 6eceec596..2f3baa8ae 100644 --- a/nbdev/doclinks.py +++ b/nbdev/doclinks.py @@ -236,12 +236,13 @@ def code(self, sym): _,py,gh = res line = _lineno(sym, py) return f'{gh}#L{line}' - + def _link_sym(self, m): l = m.group(1) s = self.doc(l) if s is None: return m.group(0) l = l.replace('\\', r'\\') + if m.group(0).endswith('()`'): l += '()' return rf"[`{l}`]({s})" def link_line(self, l): return _re_backticks.sub(self._link_sym, l) diff --git a/nbs/api/05_doclinks.ipynb b/nbs/api/05_doclinks.ipynb index 458d2d2bc..9aead8807 100644 --- a/nbs/api/05_doclinks.ipynb +++ b/nbs/api/05_doclinks.ipynb @@ -485,7 +485,12 @@ "test_eq(_re_backticks.findall('no match'), [])\n", "test_eq(_re_backticks.findall('`weird``thing`'), ['weird', 'thing'])\n", "test_eq(_re_backticks.findall('`spaces not allowed `'), [])\n", - "test_eq(_re_backticks.findall('`sym.with.dots`'), ['sym.with.dots'])" + "test_eq(_re_backticks.findall('`sym.with.dots`'), ['sym.with.dots'])\n", + "test_eq(_re_backticks.findall('unicode `αβγ`'), ['αβγ'])\n", + "test_eq(_re_backticks.findall('long `extremely.long.module.name.with.many.dots.function`'), \n", + " ['extremely.long.module.name.with.many.dots.function'])\n", + "test_eq(_re_backticks.findall('special chars `foo[bar]` `foo$bar`'), ['foo[bar]', 'foo$bar'])\n", + "test_eq(_re_backticks.findall('consecutive `foo``bar``baz`'), ['foo', 'bar', 'baz'])" ] }, { @@ -533,12 +538,13 @@ " _,py,gh = res\n", " line = _lineno(sym, py)\n", " return f'{gh}#L{line}'\n", - "\n", + " \n", " def _link_sym(self, m):\n", " l = m.group(1)\n", " s = self.doc(l)\n", " if s is None: return m.group(0)\n", " l = l.replace('\\\\', r'\\\\')\n", + " if m.group(0).endswith('()`'): l += '()'\n", " return rf\"[`{l}`]({s})\"\n", "\n", " def link_line(self, l): return _re_backticks.sub(self._link_sym, l)\n", @@ -565,14 +571,6 @@ "execution_count": null, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/nathan/miniconda3/envs/main/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" - ] - }, { "data": { "text/plain": [ @@ -664,6 +662,7 @@ "outputs": [], "source": [ "assert c.doc('numpy.array').startswith('http')\n", + "assert not c.doc('numpy.Array')\n", "assert c.doc('NbdevLookup').endswith('#nbdevlookup')\n", "assert not c.doc('array')" ] @@ -804,7 +803,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "This is a link to [`numpy.array`](https://numpy.org/doc/stable/reference/generated/numpy.array.html#numpy.array) and to [`get_config`](https://nbdev.fast.ai/api/config.html#get_config) but not a link to `foobar`.\n", + "This is a link to [`numpy.array`](https://numpy.org/doc/stable/reference/generated/numpy.array.html#numpy.array) and to [`get_config()`](https://nbdev.fast.ai/api/config.html#get_config) but not a link to `foobar`.\n", "And not a link to dict2nb.\n", "\n", " This is not a link to `get_config`\n", @@ -820,6 +819,20 @@ "print(NbdevLookup('nbdev').linkify(md))" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test code blocks\n", + "md = \"\"\"```python\n", + "def foo():\n", + " return `bar`\n", + "```\"\"\"\n", + "assert NbdevLookup().linkify(md) == md" + ] + }, { "cell_type": "markdown", "metadata": {},