Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error handling in _build_lookup_table entry points #1474

Merged
merged 2 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions nbdev/doclinks.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,11 @@ def _build_lookup_table(strip_libs=None, incl_libs=None, skip_mods=None):
skip_mods = setify(skip_mods)
strip_libs = L(strip_libs)
if incl_libs is not None: incl_libs = (L(incl_libs)+strip_libs).unique()
entries = {o.name: _qual_syms(o.resolve()) for o in list(pkg_resources.iter_entry_points(group='nbdev'))
if incl_libs is None or o.dist.key in incl_libs}
entries = {}
for o in pkg_resources.iter_entry_points(group='nbdev'):
if incl_libs is not None and o.dist.key not in incl_libs: continue
try: entries[o.name] = _qual_syms(o.resolve())
except Exception: pass
py_syms = merge(*L(o['syms'].values() for o in entries.values()).concat())
for m in strip_libs:
if m in entries:
Expand Down
136 changes: 97 additions & 39 deletions nbs/api/05_doclinks.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"source": [
"#|hide\n",
"from IPython.display import Markdown,display\n",
"from unittest.mock import patch as xpatch\n",
"from fastcore.test import *\n",
"from pdb import set_trace\n",
"from importlib import reload\n",
Expand Down Expand Up @@ -534,8 +535,11 @@
" skip_mods = setify(skip_mods)\n",
" strip_libs = L(strip_libs)\n",
" if incl_libs is not None: incl_libs = (L(incl_libs)+strip_libs).unique()\n",
" entries = {o.name: _qual_syms(o.resolve()) for o in list(pkg_resources.iter_entry_points(group='nbdev'))\n",
" if incl_libs is None or o.dist.key in incl_libs}\n",
" entries = {}\n",
" for o in pkg_resources.iter_entry_points(group='nbdev'):\n",
" if incl_libs is not None and o.dist.key not in incl_libs: continue\n",
" try: entries[o.name] = _qual_syms(o.resolve())\n",
" except Exception: pass\n",
" py_syms = merge(*L(o['syms'].values() for o in entries.values()).concat())\n",
" for m in strip_libs:\n",
" if m in entries:\n",
Expand All @@ -547,6 +551,84 @@
" return entries,py_syms"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#|hide\n",
"_build_lookup_table.cache_clear()\n",
"\n",
"# Test _build_lookup_table caching\n",
"initial = _build_lookup_table.cache_info()\n",
"_ = _build_lookup_table() # First call should miss\n",
"after_first = _build_lookup_table.cache_info()\n",
"_ = _build_lookup_table() # Second call should hit\n",
"after_second = _build_lookup_table.cache_info()\n",
"\n",
"test_eq(after_first.misses, initial.misses + 1)\n",
"test_eq(after_first.hits, initial.hits)\n",
"test_eq(after_second.hits, after_first.hits + 1)\n",
"test_eq(after_second.misses, after_first.misses)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's test out our error handling when one of the entry points throws an error:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Create mock entry points\n",
"class BadEntryPoint:\n",
" name = 'bad_entry'\n",
" dist = type('Dist', (), {'key': 'bad_lib'})()\n",
" def resolve(self): raise AttributeError(\"Simulated error\")\n",
"\n",
"class GoodEntryPoint:\n",
" name = 'good_entry'\n",
" dist = type('Dist', (), {'key': 'good_lib'})()\n",
" def resolve(self): return {'syms': {}, 'settings': {}}"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'good_entry': {'syms': {}, 'settings': {}}}"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Clear the cache before testing\n",
"_build_lookup_table.cache_clear()\n",
"\n",
"# Patch iter_entry_points\n",
"with xpatch('pkg_resources.iter_entry_points', return_value=[BadEntryPoint(), GoodEntryPoint()]):\n",
" entries, py_syms = _build_lookup_table()\n",
" \n",
" # Should only contain the good entry\n",
" assert 'bad_entry' not in entries\n",
" assert 'good_entry' in entries\n",
" assert len(entries) == 1\n",
"entries"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down Expand Up @@ -599,37 +681,6 @@
" return '\\n'.join(lines)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/nathan/miniconda3/lib/python3.12/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"
]
}
],
"source": [
"#|hide\n",
"_build_lookup_table.cache_clear()\n",
"\n",
"# Test _build_lookup_table caching\n",
"initial = _build_lookup_table.cache_info()\n",
"_ = _build_lookup_table() # First call should miss\n",
"after_first = _build_lookup_table.cache_info()\n",
"_ = _build_lookup_table() # Second call should hit\n",
"after_second = _build_lookup_table.cache_info()\n",
"\n",
"test_eq(after_first.misses, initial.misses + 1)\n",
"test_eq(after_first.hits, initial.hits)\n",
"test_eq(after_second.hits, after_first.hits + 1)\n",
"test_eq(after_second.misses, after_first.misses)"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down Expand Up @@ -670,7 +721,7 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L234){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L241){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### NbdevLookup.doc\n",
"\n",
Expand All @@ -681,7 +732,7 @@
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L234){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L241){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### NbdevLookup.doc\n",
"\n",
Expand All @@ -699,6 +750,13 @@
"show_doc(NbdevLookup.doc)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here's a test suite that verifies the error handling behavior:"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down Expand Up @@ -765,7 +823,7 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L239){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L246){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### NbdevLookup.code\n",
"\n",
Expand All @@ -776,7 +834,7 @@
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L239){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L246){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### NbdevLookup.code\n",
"\n",
Expand Down Expand Up @@ -824,7 +882,7 @@
"text/markdown": [
"---\n",
"\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L257){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L264){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### NbdevLookup.linkify\n",
"\n",
Expand All @@ -833,7 +891,7 @@
"text/plain": [
"---\n",
"\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L257){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L264){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
"\n",
"### NbdevLookup.linkify\n",
"\n",
Expand Down