Skip to content

Commit

Permalink
Feat: install import hook by default
Browse files Browse the repository at this point in the history
  • Loading branch information
agoose77 committed May 11, 2022
1 parent a26428d commit 6f28cc8
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 128 deletions.
2 changes: 2 additions & 0 deletions literary-hook.pth
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Install notebook import hook
import literary.hook; literary.hook.install_import_hook()
26 changes: 13 additions & 13 deletions pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "literary"
version = "4.0.0a0"
version = "4.0.0a1"
description = "Literate package development with Jupyter"
authors = [
{name = "Angus Hollands", email = "[email protected]"},
Expand Down Expand Up @@ -64,14 +64,15 @@ exclude = ["lib"]

# Include generated package for wheels
[tool.hatch.build.targets.wheel.force-include]
# Unpack built lib into root
"lib" = "/"

# Install hook into environment
"literary-hook.pth" = "literary-hook.pth"

[tool.hatch.build.targets.wheel.shared-data]
"share/jupyter/nbconvert/templates/literary/conf.json" = "share/jupyter/nbconvert/templates/literary/conf.json"
"share/jupyter/nbconvert/templates/literary/index.py.j2" = "share/jupyter/nbconvert/templates/literary/index.py.j2"


[tool.hatch.build.targets.wheel.hooks.literary]
dependencies = ["literary-build-hatch>=0.2.0a3"]

Expand Down
52 changes: 26 additions & 26 deletions src/literary/config/__init__.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,28 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 6,
"id": "acoustic-prompt",
"metadata": {
"tags": []
},
"outputs": [],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The literary.module extension is already loaded. To reload it, use:\n",
" %reload_ext literary.module\n"
]
}
],
"source": [
"%load_ext literary.module"
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 7,
"id": "front-notion",
"metadata": {
"tags": [
Expand Down Expand Up @@ -53,7 +62,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 8,
"id": "8ed360c7-eef6-4707-804a-744225ecdd79",
"metadata": {
"tags": [
Expand All @@ -70,12 +79,12 @@
"id": "d92cece7-9d15-4986-9293-c4b806a99771",
"metadata": {},
"source": [
"To find the config file, we simply perform a depth-first search of each given path, and return the first file with the appropriate stem."
"To find the config file, we simply perform a breadth-first search of each given path, and return the first file with the appropriate stem."
]
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 13,
"id": "environmental-cooperation",
"metadata": {
"tags": [
Expand All @@ -85,24 +94,18 @@
"outputs": [],
"source": [
"@lru_cache()\n",
"def find_literary_config(path, *additional_paths) -> Path:\n",
"def find_literary_config(path) -> Path:\n",
" \"\"\"Load the configuration for the current Literary project.\n",
"\n",
" :param search_paths: starting search paths\n",
" :return:\n",
" \"\"\"\n",
" visited = set()\n",
"\n",
" for top_level_path in [path, *additional_paths]:\n",
" for search_path in (top_level_path, *top_level_path.parents):\n",
" # Avoid re-visiting paths\n",
" if search_path in visited:\n",
" break\n",
" visited.add(search_path)\n",
"\n",
" # Look for any config file\n",
" for p in search_path.glob(f\"{CONFIG_FILE_STEM}.*\"):\n",
" return p\n",
" # Look for any config file\n",
" for p in path.glob(f\"{CONFIG_FILE_STEM}.*\"):\n",
" return p\n",
" \n",
" # Visit parent\n",
" if path.parents:\n",
" return find_literary_config(path.parent)\n",
"\n",
" raise FileNotFoundError(\"Couldn't find config file\")"
]
Expand All @@ -117,7 +120,7 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 14,
"id": "131149c5-b284-4765-b079-abbd2054b350",
"metadata": {
"tags": [
Expand All @@ -135,14 +138,11 @@
" for loader_cls in JSONFileConfigLoader, PyFileConfigLoader:\n",
" loader = loader_cls(path.name, str(path.parent))\n",
" try:\n",
" config = loader.load_config()\n",
" break\n",
" return loader.load_config()\n",
" except ConfigFileNotFound:\n",
" continue\n",
" else:\n",
" raise ValueError(f\"{path!r} was not a recognised config file\")\n",
"\n",
" return config"
" raise ValueError(f\"{path!r} was not a recognised config file\")"
]
}
],
Expand Down
40 changes: 25 additions & 15 deletions src/literary/hook/__init__.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,46 @@
"outputs": [],
"source": [
"from .finder import extend_file_finder\n",
"from ..config import load_literary_config, find_literary_config\n",
"\n",
"import functools\n",
"import sys\n",
"import traceback\n",
"import pathlib"
]
},
{
"cell_type": "markdown",
"id": "fdab96e1-95b7-47d7-bba1-de073ea1b1a2",
"metadata": {},
"source": [
"We only want to lazy load once, to ensure that we always get the bootstrapping Literary's import hook"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "14cdff56-cb55-47d7-99f5-15ea91c84a09",
"id": "392c9424-1934-4a38-a636-f1f8c9623149",
"metadata": {
"tags": [
"export"
]
},
"outputs": [],
"source": [
"load_cached_config = functools.lru_cache()(load_literary_config)"
"def notebook_loader_factory(fullname, path):\n",
" try:\n",
" factory = notebook_loader_factory.factory\n",
" except AttributeError:\n",
" # Re-entrant guard\n",
" def noop_loader(fullname, path):\n",
" return None\n",
" notebook_loader_factory.factory = noop_loader\n",
" \n",
" # Actual importer\n",
" from .importer import get_loader\n",
" notebook_loader_factory.factory = get_loader\n",
" factory = get_loader\n",
" \n",
" return factory(fullname, path)"
]
},
{
Expand All @@ -56,17 +76,7 @@
"outputs": [],
"source": [
"def install_import_hook(set_except_hook=True):\n",
" # Inject notebook loader into path_hooks\n",
" def create_notebook_loader(fullname, path):\n",
" from .importer import NotebookImporter\n",
"\n",
" config = load_cached_config(\n",
" find_literary_config(pathlib.Path(path))\n",
" )\n",
" importer = NotebookImporter(config=config)\n",
" return importer.get_loader(fullname, path)\n",
"\n",
" extend_file_finder((create_notebook_loader, [\".ipynb\"]),)\n",
" extend_file_finder((notebook_loader_factory, [\".ipynb\"]),)\n",
"\n",
" if set_except_hook:\n",
" sys.excepthook = traceback.print_exception"
Expand Down
Loading

0 comments on commit 6f28cc8

Please sign in to comment.