{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook demonstrates the `__path__` attribute. The `__path__` attribute is required to import \n", "modules within packages. Having a `__path__` in a running notebook will permit relative imports.\n", "\n", "The post builds off [The Simplest importer for a notebook](http://nbviewer.jupyter.org/github/deathbeds/deathbeds.github.io/blob/master/deathbeds/2018-07-08-The-simplest-path-hook-importer-for-a-notebook.ipynb)." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "('deathbeds.2018-07-08-The-simplest-path-hook-importer-for-a-notebook', ) {'origin': 'c:\\\\users\\\\deathbeds\\\\deathbeds.github.io\\\\deathbeds\\\\2018-07-08-The-simplest-path-hook-importer-for-a-notebook.ipynb', 'loader_state': None, 'is_package': False}\n" ] } ], "source": [ " from deathbeds import __The_simplest_path_hook_importer_for_a_notebook as importer\n", " import sys, importlib, pytest\n", " try: del __path__\n", " except: ..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Typically my notebook is filled with garbage. The snippet below resets the normal `sys.path_hooks` behavior." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ " sys.path_hooks[1] = importlib._bootstrap_external.FileFinder.path_hook(importlib._bootstrap_external._get_supported_file_loaders())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Add the simplest notebook importer as a `sys.path_hook`." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ " importer.new_loader((importer.NotebookLoader, ('.ipynb',)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Clear the importer cache (_forgetting this statement always slips me up_) and show the existing importers." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((deathbeds.2018-07-08-The-simplest-path-hook-importer-for-a-notebook.NotebookLoader,\n", " ('.ipynb',)),\n", " (_frozen_importlib_external.ExtensionFileLoader,\n", " ['.cp36-win_amd64.pyd', '.pyd']),\n", " (_frozen_importlib_external.SourceFileLoader, ['.py', '.pyw']),\n", " (_frozen_importlib_external.SourcelessFileLoader, ['.pyc']))" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ " sys.path_importer_cache.clear() or sys.path_hooks[1].__closure__[1].cell_contents" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Force remove the `__path__` from the namespace. " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ " if __name__ == '__main__': globals().pop('__path__', None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Demonstrate that `2018-11-26-Relative-imports` cannot be imported from `__main__`." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ " if __name__ == '__main__': \n", " with pytest.raises(ImportError): importlib.import_module('.2018-11-26-Relative-imports', '__main__')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Add the `__path__` back to the namespace." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ " __path__ = ['.']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Demonstrate that the module maybe imported." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ " module = importlib.import_module('.2018-11-26-Relative-imports', '__main__')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Test` that `module` is a package relative to `__main__` and notebook." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Trying:\n", " assert module.__package__ == '__main__'\n", "Expecting nothing\n", "ok\n", "Trying:\n", " assert module.__file__.endswith('.ipynb')\n", "Expecting nothing\n", "ok\n", "1 items had no tests:\n", " __main__\n", "1 items passed all tests:\n", " 2 tests in __main__.Test\n", "2 tests in 2 items.\n", "2 passed and 0 failed.\n", "Test passed.\n" ] } ], "source": [ " class Test:\n", " \"\"\">>> assert module.__package__ == '__main__'\n", " >>> assert module.__file__.endswith('.ipynb')\"\"\"\n", " if __name__ == '__main__': __import__('doctest').testmod(verbose=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.6" } }, "nbformat": 4, "nbformat_minor": 2 }