Source code for utilipy.ipython.imports

# -*- coding: utf-8 -*-

"""IPython Imports.

Routine Listings
----------------
run_imports
    Import file, custom or provided, using ipython magic
import_from_file
    Run import(s) from a file(s)
aimport
    from `.autoreload` module
set_autoreload
    from `.autoreload` module

import_base
    ipython magic run `utilipy/imports/base.py`
import_extended
    ipython magic run `utilipy/imports/extended.py`
import_astropy
    ipython magic run `utilipy/imports/astropy.py`
import_matplotlib
    ipython magic run `utilipy/imports/matplotlib.py`
import_galpy
    ipython magic run `utilipy/imports/galpy.py`
import_amuse
    ipython magic run `utilipy/imports/amuse.py`

References
----------
IPython [#]_

.. [#] Fernando Pérez, Brian E. Granger, IPython: A System for Interactive
    Scientific Computing, Computing in Science and Engineering, vol. 9,
    no. 3, pp. 21-29, May/June 2007, doi:10.1109/MCSE.2007.53.
    URL: https://ipython.org

"""

__author__ = "Nathaniel Starkman"

__all__ = [
    "import_from_file",
    "run_imports",
    # specific importers
    "import_base",
    "import_extended",
    "import_astropy",
    "import_matplotlib",  # 'import_plotly',
    "import_galpy",
    "import_amuse",
]


##############################################################################
# IMPORTS

# GENERAL

import ast
import os.path
from pathlib import Path
from IPython import get_ipython
from typing import Optional, Dict


# PROJECT-SPECIFIC

from ..utils import functools
from ..config import use_import_verbosity
from ..utils.logging import LogFile

from .autoreload import aimport, set_autoreload


##############################################################################
# SETUP

_LOGFILE = LogFile(header=False, verbose=0)
_LOGGER_KW = {"print": False}


##############################################################################
# CODE


[docs]def import_from_file( *files: str, is_relative: bool = True, verbose_imports: Optional[bool] = None, logger: LogFile = _LOGFILE, verbose=None, logger_kw: Dict = _LOGGER_KW, ) -> None: """Run import(s) from a file(s). Parameters ---------- *files: str(s) strings for files to import need to include file suffix is_relative: bool or list of bools whether the `*files` paths are relative or absolute verbose_imports: bool or None Verbose_imports or not, use default if None. """ # Handle `relative` if isinstance(is_relative, bool): # broadcasting to same length as files relatives = [is_relative] * len(files) else: # already a list if len(is_relative) != len(files): # checking correct length raise ValueError("len(relative) != len(files)") relatives = is_relative # handle verbose-imports with use_import_verbosity(verbose_imports): # Importing for file, relative in zip(files, relatives): if relative: file = str(Path(file).resolve()) # get_ipython inbuilt to jupyter get_ipython().magic(f"run {file}") # logging # implemented separately b/c files often have own print statements logger.report(f"imported {file}", verbose=verbose, **logger_kw) return
# /def # ----------------------------------------------------------------------------
[docs]def run_imports( *files: str, is_relative: bool = True, # standard import files base: bool = False, extended: bool = False, # extra standard files astropy: bool = False, matplotlib: bool = False, plotly: bool = False, # additional, requires extra installs galpy: bool = False, amuse: bool = False, # autoreload set_autoreload_to: Optional[int] = None, verbose_imports: Optional[bool] = None, # logging logger: LogFile = _LOGFILE, verbose: Optional[int] = 0, logger_kw: Dict = {}, ) -> None: """Import file using IPython magic. if `astropy` and `matplotlib`, sets matplotlib style to astropy_mpl_style Parameters ---------- files: str(s) strings for files to import need to include file suffix base: bool a broad set of basic imports import_base -> `utilipy/imports/base.py` astropy: bool import_astropy -> `utilipy/imports/astropy.py` matplotlib: bool import_matplotlib -> `utilipy/imports/matplotlib.py` plotly: bool import_plotly -> `utilipy/imports/plotly.py` extended: bool import_extended -> `utilipy/imports/extended.py` galpy: bool import_galpy -> `utilipy/imports/galpy.py` amuse: bool import_amuse -> `utilipy/imports/amuse.py` Other Parameters ---------------- set_autoreload_to: int or None (default None) whether to change the autoreload state relative: bool or list of bools whether the `files` paths are relative or absolute verbose_imports: bool or None Verbose_imports or not, use ``.utilipyrc`` default if None. Examples -------- ``run_imports(base=True, astropy=True)`` imports from `utilipy/imports/base.py` and `utilipy/imports/astropy.py`, printing an import summary ``run_imports(base=True, verbose_imports=False)`` imports from `utilipy/imports/base.py`, without an import summary ``utilipy.config.set_import_verbosity(False)`` ``utilipy.ipython.imports.run_imports(base=True, verbose_imports=None)`` imports from `utilipy/imports/base.py` with default import-verbosity state """ kw = dict(verbose_imports=verbose_imports, logger=logger, verbose=verbose) # --------------------------------------------- # base if base: import_base(**kw) if extended: import_extended(**kw) # --------------------------------------------- # basic if astropy: import_astropy(**kw) if matplotlib: import_matplotlib(**kw) if plotly: import_plotly(**kw) # --------------------------------------------- # extras if galpy: import_galpy(**kw) if amuse: import_amuse(**kw) # --------------------------------------------- # when combined if astropy & matplotlib: from matplotlib import pyplot from astropy.visualization import astropy_mpl_style pyplot.style.use(astropy_mpl_style) if galpy & amuse: # TODO, embed in galpy_imports using argparse from galpy.potential import to_amuse # other import filess if files: # True if not empty import_from_file( *files, is_relative=is_relative, verbose_imports=verbose_imports, logger=logger, verbose=verbose, logger_kw=logger_kw, ) # --------------------------------------------- # autoreload set_autoreload(set_autoreload_to) return
# /def # ---------------------------------------------------------------------------- # UTILITIES TODO BETTER def _set_docstring_import_x(path: tuple) -> str: """Set docstring Returns section. takes a helper function for a module and adds the content of the modules' `Returns` section. Parameters ---------- path: str path of import module """ module = str(Path(__file__).parent.joinpath(os.path.join(*path))) # read docstring out of file with open(module, "r") as fd: module_doc = ast.get_docstring(ast.parse(fd.read())) # process docstring ind = module_doc.find("Returns") len_title = 2 * len("Returns") end_ind = ind + module_doc[ind + len_title :].find("---") + 2 # noqa doc = module_doc[ind:end_ind] # get section (+ next header) # modify function with a basic decorator def decorator(func): @functools.wraps(func, docstring=func.__doc__ + "\n\n" + doc) def wrapper(*args, **kwargs): return func(*args, **kwargs) # /def return wrapper # /def return decorator # /def ############################################################################## # Specific Imports # TODO make these with a function
[docs]@_set_docstring_import_x(("..", "imports", "base_imports.py")) def import_base( verbose_imports: Optional[bool] = None, logger: LogFile = _LOGFILE, verbose: Optional[int] = None, logger_kw: Dict = _LOGGER_KW, ) -> None: """Import base packages.""" import_from_file( ("..", "imports", "base_imports.py"), is_relative=False, verbose_imports=verbose_imports, logger=logger, verbose=verbose, logger_kw=logger_kw, ) return
# /def
[docs]@_set_docstring_import_x(("..", "imports", "extended_imports.py")) def import_extended( verbose_imports: Optional[bool] = None, logger: LogFile = _LOGFILE, verbose: Optional[int] = None, logger_kw: Dict = _LOGGER_KW, ) -> None: """Import extended packages.""" import_from_file( ("..", "imports", "extended_imports.py"), is_relative=False, verbose_imports=verbose_imports, logger=logger, verbose=verbose, logger_kw=logger_kw, ) return
# /def
[docs]@_set_docstring_import_x(("..", "imports", "astropy_imports.py")) def import_astropy( verbose_imports: Optional[bool] = None, logger: LogFile = _LOGFILE, verbose: Optional[int] = None, logger_kw: Dict = _LOGGER_KW, ) -> None: """Import basic astropy packages.""" import_from_file( ("..", "imports", "astropy_imports.py"), is_relative=False, verbose_imports=verbose_imports, logger=logger, verbose=verbose, logger_kw=logger_kw, ) return
# /def # ---------------------------------------------------------------------------- # plotting
[docs]@_set_docstring_import_x(("..", "imports", "matplotlib_imports.py")) def import_matplotlib( verbose_imports: Optional[bool] = None, logger: LogFile = _LOGFILE, verbose: Optional[int] = None, logger_kw: Dict = _LOGGER_KW, ) -> None: """Import basic Matplotlib packages.""" import_from_file( ("..", "imports", "matplotlib_imports.py"), is_relative=False, verbose_imports=verbose_imports, logger=logger, verbose=verbose, logger_kw=logger_kw, ) return
# /def @_set_docstring_import_x(("..", "imports", "plotly_imports.py")) def import_plotly( verbose_imports: Optional[bool] = None, logger: LogFile = _LOGFILE, verbose: Optional[int] = None, logger_kw: Dict = _LOGGER_KW, ) -> None: """Import basic Matplotlib packages.""" import_from_file( ("..", "imports", "plotly_imports.py"), is_relative=False, verbose_imports=verbose_imports, logger=logger, verbose=verbose, logger_kw=logger_kw, ) return # /def # ---------------------------------------------------------------------------- # extras
[docs]@_set_docstring_import_x(("..", "imports", "galpy_imports.py")) def import_galpy( verbose_imports: Optional[bool] = None, logger: LogFile = _LOGFILE, verbose: Optional[int] = None, logger_kw: Dict = _LOGGER_KW, ) -> None: """Import basic galpy packages.""" import_from_file( ("..", "imports", "galpy_imports.py"), is_relative=False, verbose_imports=verbose_imports, logger=logger, verbose=verbose, logger_kw=logger_kw, ) return
# /def
[docs]@_set_docstring_import_x(("..", "imports", "amuse_imports.py")) def import_amuse( verbose_imports: Optional[bool] = None, logger: LogFile = _LOGFILE, verbose: Optional[int] = None, logger_kw: Dict = _LOGGER_KW, ) -> None: """Import basic amuse packages.""" import_from_file( ("..", "imports", "amuse_imports.py"), is_relative=False, verbose_imports=verbose_imports, logger=logger, verbose=verbose, logger_kw=logger_kw, ) return
# /def ############################################################################## # END