Skip to content

Commit

Permalink
Move from kedro.extras.extensions.ipython to kedro.ipython
Browse files Browse the repository at this point in the history
Signed-off-by: Antony Milne <[email protected]>
  • Loading branch information
antonymilne committed Sep 7, 2022
1 parent 6a2c27c commit e059acf
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 159 deletions.
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ include LICENSE.md
include requirements.txt
include test_requirements.txt
include kedro/framework/project/default_logging.yml
include kedro/extras/extensions/*.png
include kedro/ipython/*.png
recursive-include templates *
146 changes: 9 additions & 137 deletions kedro/extras/extensions/ipython.py
Original file line number Diff line number Diff line change
@@ -1,139 +1,11 @@
# pylint: disable=import-outside-toplevel,global-statement,invalid-name,too-many-locals
"""
This script creates an IPython extension to load Kedro-related variables in
local scope.
This file and directory exists purely for backwards compatibility of the following:
%load_ext kedro.extras.extensions.ipython
from kedro.extras.extensions.ipython import reload_kedro
Any modifications to the IPython extension should now be made in kedro/ipython/.
The Kedro IPython extension should always be loaded as %load_ext kedro.ipython.
Line magics such as reload_kedro should always be called as line magics rather than
importing the underlying Python functions.
"""
import logging
import sys
from pathlib import Path
from typing import Any, Dict

from kedro.framework.cli.project import PARAMS_ARG_HELP
from kedro.framework.cli.utils import ENV_HELP, _split_params

logger = logging.getLogger(__name__)
default_project_path = Path.cwd()


def _remove_cached_modules(package_name):
to_remove = [mod for mod in sys.modules if mod.startswith(package_name)]
# `del` is used instead of `reload()` because: If the new version of a module does not
# define a name that was defined by the old version, the old definition remains.
for module in to_remove:
del sys.modules[module] # pragma: no cover


def _find_kedro_project(current_dir: Path): # pragma: no cover
from kedro.framework.startup import _is_project

while current_dir != current_dir.parent:
if _is_project(current_dir):
return current_dir
current_dir = current_dir.parent

return None


def reload_kedro(
path: str = None, env: str = None, extra_params: Dict[str, Any] = None
):
"""Line magic which reloads all Kedro default variables.
Setting the path will also make it default for subsequent calls.
"""
from IPython import get_ipython
from IPython.core.magic import needs_local_scope, register_line_magic

from kedro.framework.cli import load_entry_points
from kedro.framework.project import LOGGING # noqa # pylint:disable=unused-import
from kedro.framework.project import configure_project, pipelines
from kedro.framework.session import KedroSession
from kedro.framework.startup import bootstrap_project

# If a path is provided, set it as default for subsequent calls
global default_project_path
if path:
default_project_path = Path(path).expanduser().resolve()
logger.info("Updated path to Kedro project: %s", default_project_path)
else:
logger.info("No path argument was provided. Using: %s", default_project_path)

metadata = bootstrap_project(default_project_path)
_remove_cached_modules(metadata.package_name)
configure_project(metadata.package_name)

session = KedroSession.create(
metadata.package_name, default_project_path, env=env, extra_params=extra_params
)
context = session.load_context()
catalog = context.catalog

get_ipython().push(
variables={
"context": context,
"catalog": catalog,
"session": session,
"pipelines": pipelines,
}
)

logger.info("Kedro project %s", str(metadata.project_name))
logger.info(
"Defined global variable 'context', 'session', 'catalog' and 'pipelines'"
)

for line_magic in load_entry_points("line_magic"):
register_line_magic(needs_local_scope(line_magic))
logger.info("Registered line magic '%s'", line_magic.__name__) # type: ignore


def load_ipython_extension(ipython):
"""
Main entry point when %load_ext is executed.
IPython will look for this function specifically.
See https://ipython.readthedocs.io/en/stable/config/extensions/index.html
This function is called when users do `%load_ext kedro.extras.extensions.ipython`.
When user use `kedro jupyter notebook` or `jupyter ipython`, this extension is
loaded automatically.
"""
from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring

@magic_arguments()
@argument(
"path",
type=str,
help=(
"Path to the project root directory. If not given, use the previously set"
"project root."
),
nargs="?",
default=None,
)
@argument("-e", "--env", type=str, default=None, help=ENV_HELP)
@argument(
"--params",
type=lambda value: _split_params(None, None, value),
default=None,
help=PARAMS_ARG_HELP,
)
def magic_reload_kedro(line: str):
"""
The `%reload_kedro` IPython line magic. See
https://kedro.readthedocs.io/en/stable/tools_integration/ipython.html for more.
"""
args = parse_argstring(magic_reload_kedro, line)
reload_kedro(args.path, args.env, args.params)

global default_project_path

ipython.register_magic_function(magic_reload_kedro, magic_name="reload_kedro")
default_project_path = _find_kedro_project(Path.cwd())

if default_project_path is None:
logger.warning(
"Kedro extension was registered but couldn't find a Kedro project. "
"Make sure you run '%reload_kedro <project_root>'."
)
return

reload_kedro(default_project_path)
from ...ipython import load_ipython_extension, reload_kedro
6 changes: 3 additions & 3 deletions kedro/framework/cli/jupyter.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ def _create_kernel(kernel_name: str, display_name: str) -> None:
# ipykernel.write_kernel_spec).
kernel_json.write_text(json.dumps(kernel_spec, indent=1), encoding="utf-8")

kedro_extensions_dir = Path(__file__).parents[2] / "extras" / "extensions"
shutil.copy(kedro_extensions_dir / "logo-32x32.png", kernel_path)
shutil.copy(kedro_extensions_dir / "logo-64x64.png", kernel_path)
kedro_ipython_dir = Path(__file__).parents[2] / "ipython"
shutil.copy(kedro_ipython_dir / "logo-32x32.png", kernel_path)
shutil.copy(kedro_ipython_dir / "logo-64x64.png", kernel_path)
except Exception as exc:
raise KedroCliError(
f"Cannot setup kedro kernel for Jupyter.\nError: {exc}"
Expand Down
139 changes: 139 additions & 0 deletions kedro/ipython/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# pylint: disable=import-outside-toplevel,global-statement,invalid-name,too-many-locals
"""
This script creates an IPython extension to load Kedro-related variables in
local scope.
"""
import logging
import sys
from pathlib import Path
from typing import Any, Dict

from kedro.framework.cli.project import PARAMS_ARG_HELP
from kedro.framework.cli.utils import ENV_HELP, _split_params

logger = logging.getLogger(__name__)
default_project_path = Path.cwd()


def _remove_cached_modules(package_name):
to_remove = [mod for mod in sys.modules if mod.startswith(package_name)]
# `del` is used instead of `reload()` because: If the new version of a module does not
# define a name that was defined by the old version, the old definition remains.
for module in to_remove:
del sys.modules[module] # pragma: no cover


def _find_kedro_project(current_dir: Path): # pragma: no cover
from kedro.framework.startup import _is_project

while current_dir != current_dir.parent:
if _is_project(current_dir):
return current_dir
current_dir = current_dir.parent

return None


def reload_kedro(
path: str = None, env: str = None, extra_params: Dict[str, Any] = None
):
"""Line magic which reloads all Kedro default variables.
Setting the path will also make it default for subsequent calls.
"""
from IPython import get_ipython
from IPython.core.magic import needs_local_scope, register_line_magic

from kedro.framework.cli import load_entry_points
from kedro.framework.project import LOGGING # noqa # pylint:disable=unused-import
from kedro.framework.project import configure_project, pipelines
from kedro.framework.session import KedroSession
from kedro.framework.startup import bootstrap_project

# If a path is provided, set it as default for subsequent calls
global default_project_path
if path:
default_project_path = Path(path).expanduser().resolve()
logger.info("Updated path to Kedro project: %s", default_project_path)
else:
logger.info("No path argument was provided. Using: %s", default_project_path)

metadata = bootstrap_project(default_project_path)
_remove_cached_modules(metadata.package_name)
configure_project(metadata.package_name)

session = KedroSession.create(
metadata.package_name, default_project_path, env=env, extra_params=extra_params
)
context = session.load_context()
catalog = context.catalog

get_ipython().push(
variables={
"context": context,
"catalog": catalog,
"session": session,
"pipelines": pipelines,
}
)

logger.info("Kedro project %s", str(metadata.project_name))
logger.info(
"Defined global variable 'context', 'session', 'catalog' and 'pipelines'"
)

for line_magic in load_entry_points("line_magic"):
register_line_magic(needs_local_scope(line_magic))
logger.info("Registered line magic '%s'", line_magic.__name__) # type: ignore


def load_ipython_extension(ipython):
"""
Main entry point when %load_ext is executed.
IPython will look for this function specifically.
See https://ipython.readthedocs.io/en/stable/config/extensions/index.html
This function is called when users do `%load_ext kedro.extras.extensions.ipython`.
When user use `kedro jupyter notebook` or `jupyter ipython`, this extension is
loaded automatically.
"""
from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring

@magic_arguments()
@argument(
"path",
type=str,
help=(
"Path to the project root directory. If not given, use the previously set"
"project root."
),
nargs="?",
default=None,
)
@argument("-e", "--env", type=str, default=None, help=ENV_HELP)
@argument(
"--params",
type=lambda value: _split_params(None, None, value),
default=None,
help=PARAMS_ARG_HELP,
)
def magic_reload_kedro(line: str):
"""
The `%reload_kedro` IPython line magic. See
https://kedro.readthedocs.io/en/stable/tools_integration/ipython.html for more.
"""
args = parse_argstring(magic_reload_kedro, line)
reload_kedro(args.path, args.env, args.params)

global default_project_path

ipython.register_magic_function(magic_reload_kedro, magic_name="reload_kedro")
default_project_path = _find_kedro_project(Path.cwd())

if default_project_path is None:
logger.warning(
"Kedro extension was registered but couldn't find a Kedro project. "
"Make sure you run '%reload_kedro <project_root>'."
)
return

reload_kedro(default_project_path)
File renamed without changes
File renamed without changes
File renamed without changes.
Loading

0 comments on commit e059acf

Please sign in to comment.