Relative imports in Jupyter notebooks

How do we import a module from a .py or a .ipynb file into a Jupyter notebook from a different directory?
I wrote this post after answering a question on stackoverflow:
https://stackoverflow.com/questions/49282122/import-modules-in-jupyter-notebook-path/

For example, if we have the directory structure:

analysis.ipynb
/src/configuration.py
/src/configuration_nb.ipynb

How do we access the file configuration.py or the notebook configuration_nb.ipynb in the notebook analysis.ipynb?

The nbimporter module helps us here:

pip install nbimporter

contents of /src/configuration.py:

class Configuration():
    def __init__(self):
        print('hello from configuration.py')

contents of analysis.ipynb::

import nbimporter
from src import configuration

new = configuration.Configuration()

if we run this notebook, the output is:

hello from configuration.py

We can also import and use modules from other notebooks. If you have configuration_nb.ipynb in the /src module:

contents of src/configuration_nb.ipynb:

class Configuration_nb():
    def __init__(self):
        print('hello from configuration notebook')

contents of analysis.ipynb:

import nbimporter
from src import configuration_nb

new = configuration_nb.Configuration_nb()

if we run this notebook, the output is:

Importing Jupyter notebook from ......\src\configuration_nb.ipynb
hello from configuration notebook