在jupyter notebook单元格中使用click库

时间:2017-12-14 18:36:36

标签: python-3.x jupyter-notebook

有没有办法在Jupyter笔记本单元格中使用点击库? 我想将标志传递给笔记本中​​的Jupyter笔记本代码 让它更顺畅地转换到独立的脚本。例如,使用 来自Jupyter笔记本电脑的OptionParser:

from optparse import OptionParser
import sys


def main():
    parser = OptionParser()
    parser.add_option('-f', '--fake',
                    default='False',
                help='Fake data')
    (options,args) = parser.parse_args()
    print('options:{} args: {}'.format(options, args))
    if options.fake:
        print('Fake detected')

def test_args():

    print('hello')

if __name__ == '__main__':

    sys.argv = ['--fake', 'True' '--help']
    main()

输出:     选项:{'假':'错误'} args:[' True - help']     检测到假冒

使用点击库,我收到一串错误。我运行了这个代码 Jupyter笔记本电池:

import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
            help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello %s!' % name)

if __name__ == '__main__':
    hello()

输出(截断):

UnsupportedOperation                      Traceback (most recent call last)
<ipython-input-6-ad31be7bf0fe> in <module>()
    12 if __name__ == '__main__':
    13     sys.argv = ['--count', '3']
---> 14     hello()

~/.local/lib/python3.6/site-packages/click/core.py in __call__(self, *args, **kwargs)
    720     def __call__(self, *args, **kwargs):
    721         """Alias for :meth:`main`."""
--> 722         return self.main(*args, **kwargs)
    723 
    724 
...
257 
    258     if message:
--> 259         file.write(message)
    260     file.flush()
    261 

UnsupportedOperation: not writable

2 个答案:

答案 0 :(得分:2)

您可以使用%%python magic命令启动新的Python propcess:

%%python

import sys
import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
            help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    with open('echo.txt', 'w') as fobj:
        for x in range(count):
            click.echo('Hello %s!' % name)

if __name__ == '__main__':
    # first element is the script name, use empty string instead
    sys.argv = ['', '--name', 'Max', '--count', '3']
    hello()

输出:

Hello Max!
Hello Max!
Hello Max!

答案 1 :(得分:2)

Jupyter劫持了stdout / stderr / stdin feed。您可以使用import sys; type(sys.stdin)来查看此内容,其中ipykernel.iostream.OutStream。让jupyter和click一起操作的解决方法是直接将sys.stdout传递给click。

def monkey_patch_jupyter_click_sreams():
    """see https://stackoverflow.com/a/49595790/221742 ."""
    import sys
    import ipykernel
    import click  
    if not click._compat.PY2 and isinstance(sys.stdout, ipykernel.iostream.OutStream):
        click._compat._force_correct_text_writer = lambda stream, encoding, errors: stream

monkey_patch_jupyter_click_sreams()
# your code here
hello()

这可以绕过stdout和其他流的click包装器,然后传递stdout._buffer。即使stdout已替换为ipythons ipykernel.iostream.OutStream,这也适用于点击。