Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,7 @@ MANIFEST
.vscode/*
examples/*.py
anaconda_credentials.txt

node_modules
yarn.lock
src/pyforest/static/extension*
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ When you are done with your script, you can export all import statements via:
active_imports()
```

You can also install the notebook/lab extensions to automatically add the imports to the first cell, as they're imported:

```
python -m pyforest install_extensions
```

![demo](examples/assets/pyforest_demo_extensions.gif)

Which libraries are available?
- We aim to add all popular Python Data Science libraries which should account for >99% of your daily imports. For example, `pandas` as `pd`, `numpy` as `np`, `seaborn` as `sns`, `matplotlib.pyplot` as `plt`, or `OneHotEncoder` from `sklearn` and many more. In addition, there are also helper modules like `os`, `re`, `tqdm`, or `Path` from `pathlib`.
- You can see an overview of all available lazy imports if you type `lazy_imports()` in Python.
Expand Down
Binary file added examples/assets/pyforest_demo_extensions.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 53 additions & 16 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,58 @@
# -*- coding: utf-8 -*-
"""
Setup file for pyforest.
Use setup.cfg to configure your project.
"""
import sys
from setuptools import setup, find_packages
from setuptools.command.sdist import sdist
from setuptools.command.build_py import build_py
from setuptools.command.egg_info import egg_info
from setuptools.command.install import install
from subprocess import check_call
import platform

from pkg_resources import VersionConflict, require
from setuptools import setup
from src.pyforest.auto_import import setup as setup_auto_import
from src.pyforest import auto_import
from src.pyforest._version import __version__

try:
require("setuptools>=38.3")
except VersionConflict:
print("Error: version of setuptools is too old (<38.3)!")
sys.exit(1)

def wrap_command(command, setup_auto_import=False):
class DecoratedCommand(command):
def run(self):
suffix = ('.cmd' if platform.system() == 'Windows' else '')
check_call(['npm' + suffix, 'install'], cwd='src/pyforest')
check_call(['webpack' + suffix], cwd='src/pyforest')
command.run(self)
if setup_auto_import:
auto_import.setup()
return DecoratedCommand


setup_args = {
'name': 'pyforest',
'version': __version__,
'include_package_data': True,
'package_data': {
'pyforest': ['static/*.js', 'package.json', 'package-lock.json'],
},
'packages': find_packages(),
'zip_safe': False,
'cmdclass': {
'install': wrap_command(install, setup_auto_import=True),
'build_py': wrap_command(build_py),
'egg_info': wrap_command(egg_info),
'sdist': wrap_command(sdist),
},
'author': '8080labs',
'url': 'https://github.com/8080labs/pyforest',
'keywords': [
'ipython',
'jupyter',
'jupyterlab',
],
'classifiers': [
'Development Status :: 4 - Beta',
'Framework :: IPython',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'Programming Language :: Python :: 3',
],
}


if __name__ == "__main__":
setup()
setup_auto_import()
setup(**setup_args)
16 changes: 16 additions & 0 deletions src/pyforest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,19 @@
__version__ = "unknown"
finally:
del get_distribution, DistributionNotFound


def _jupyter_nbextension_paths():
return [{
'section': 'notebook',
'src': 'static',
'dest': 'pyforest',
'require': 'pyforest/extension'
}]


def _jupyter_labextension_paths():
return [{
'name': 'pyforest',
'src': 'static',
}]
42 changes: 42 additions & 0 deletions src/pyforest/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
def main():
import sys

if len(sys.argv) != 2 or sys.argv[1] != "install_extensions":
print(USAGE)
sys.exit(-1)

install_nbextension()
install_labextension()

def install_nbextension():
try:
from notebook import nbextensions
except ImportError:
# No notebook
return

print("Installing nbextension...")
nbextensions.install_nbextension_python('pyforest')
nbextensions.enable_nbextension_python('pyforest')

def install_labextension():
try:
from jupyterlab import commands
except ImportError:
# No jupyterlab
return

from pathlib import Path
dir = Path(__file__).parent

print("Installing labextension...")
should_build = commands.install_extension(str(dir))
if should_build:
commands.build()

USAGE = """Usage: python -m pyforest install_extensions
installs notebook/lab extensions
"""

if __name__ == "__main__":
main()
22 changes: 22 additions & 0 deletions src/pyforest/_importable.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ def __maybe_import_complementary_imports__(self):
def __maybe_import__(self):
self.__maybe_import_complementary_imports__()
exec(self.__import_statement__, globals())
prev_imported = self.__was_imported__
# Attention: if the import fails, the next line will not be reached
self.__was_imported__ = True
if not prev_imported:
_update_import_cell()

# among others, called during auto-completion of IPython/Jupyter
def __dir__(self):
Expand Down Expand Up @@ -69,6 +72,25 @@ def __repr__(self, *args, **kwargs):
return f"lazy pyforest.LazyImport for '{self.__import_statement__}'"


def _update_import_cell():
try:
from IPython.display import display, Javascript
except ImportError:
return

import inspect
from .widget import PyforestWidget

statements = []
# TODO: Figure out why it's not at a fixed level/a less fragile way
for frame in inspect.stack()[2:]:
lazy_imports = {s for s in frame[0].f_globals.values() if isinstance(s, LazyImport)}
if lazy_imports:
statements = [s.__import_statement__ for s in lazy_imports if s.__was_imported__]
break
display(PyforestWidget(imports=statements))


def _import_statements(symbol_dict, was_imported=True):
statements = []
for _, symbol in symbol_dict.items():
Expand Down
8 changes: 8 additions & 0 deletions src/pyforest/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version_info = (0, 1, 2, 'final', 0)

_specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''}

__version__ = '{}.{}.{}{}'.format(
version_info[0], version_info[1], version_info[2],
'' if version_info[3]=='final' else _specifier_[version_info[3]]+str(version_info[4])
)
Loading