简体   繁体   English

在 jupyter/ipython notebook 中将命令行参数传递给 argv

[英]Passing command line arguments to argv in jupyter/ipython notebook

I'm wondering if it's possible to populate sys.argv (or some other structure) with command line arguments in a jupyter/ipython notebook, similar to how it's done through a python script.我想知道是否可以在 jupyter/ipython 笔记本中使用命令行参数填充sys.argv (或其他一些结构),类似于通过 python 脚本完成的方式。

For instance, if I were to run a python script as follows:例如,如果我要按如下方式运行 python 脚本:

python test.py False

Then sys.argv would contain the argument False .然后sys.argv将包含参数False But if I run a jupyter notebook in a similar manner:但是如果我以类似的方式运行 jupyter notebook:

jupyter notebook test.ipynb False

Then the command line argument gets lost.然后命令行参数丢失。 Is there any way to access this argument from within the notebook itself?有没有办法从笔记本内部访问这个参数?

After a lot of looking around I found very cumbersome, custom libraries, but solved it with a few lines of code which I thought was pretty slick.环顾四周后,我发现非常麻烦的自定义库,但我用几行代码解决了它,我认为这些代码非常巧妙。 I used nbconvert to end up with an html report as output that contains all graphics and markdown from the notebook, but accepts command line parameters just as always through a minimal python wrapper:我使用 nbconvert 最终得到一个 html 报告作为输出,其中包含笔记本中的所有图形和降价,但像往常一样通过最小的 python 包装器接受命令行参数:

The python file test_args.py (which takes command line params as normal): python 文件 test_args.py(它正常使用命令行参数):

import sys,os
IPYNB_FILENAME = 'test_argv.ipynb'
CONFIG_FILENAME = '.config_ipynb'

def main(argv):
    with open(CONFIG_FILENAME,'w') as f:
        f.write(' '.join(argv))
    os.system('jupyter nbconvert --execute {:s} --to html'.format(IPYNB_FILENAME))
    return None

if __name__ == '__main__':
    main(sys.argv)

The notebook contains:笔记本包含:

import sys,os,argparse
from IPython.display import HTML
CONFIG_FILE = '.config_ipynb'
if os.path.isfile(CONFIG_FILE):
    with open(CONFIG_FILE) as f:
        sys.argv = f.read().split()
else:
    sys.argv = ['test_args.py', 'input_file', '--int_param', '12']

parser = argparse.ArgumentParser()
parser.add_argument("input_file",help="Input image, directory, or npy.")
parser.add_argument("--int_param", type=int, default=4, help="an optional integer parameter.")
args = parser.parse_args()
p = args.int_param
print(args.input_file,p)

and I can run the python notebook with arguments parsed as usual:我可以像往常一样运行带有解析参数的python笔记本:

python test_args.py my_input_file --int_param 12

I tend to paste the block with argparse calls into the python wrapper so that command line errors are caught by the python script and -h works properly.我倾向于将带有 argparse 调用的块粘贴到 python 包装器中,以便 python 脚本捕获命令行错误并且 -h 正常工作。

There are two projects I've found that do what you ask for我发现有两个项目可以满足您的要求

  • Papermill , will add a cell to your notebook with arguments that you pass to it on the command line. Papermill ,将向您的笔记本添加一个单元格,其中包含您在命令行中传递给它的参数。 So this is quite straightforward, you define your defaults in the first cell (the should have parameters tag)所以这很简单,你在第一个单元格中定义你的默认值(应该有parameters标签)
  • nbparameterise it is a similar concept but you don't tag your cell with defaults, it has to be first. nbparameterise它是一个类似的概念,但你没有用默认值标记你的单元格,它必须是第一个。

Here is a good resource discussing the issue: https://github.com/jupyter/help/issues/218这是讨论该问题的好资源: https : //github.com/jupyter/help/issues/218

I think this Gist may help you : https://gist.github.com/gbishop/acf40b86a9bca2d571fa我认为这个要点可以帮助你: https : //gist.github.com/gbishop/acf40b86a9bca2d571fa

This is an attempt at a simple argument parser for mostly key=value pairs that can be used both on the command line and in IPython notebooks.这是一个简单的参数解析器的尝试,主要用于键=值对,可以在命令行和 IPython 笔记本中使用。 It support query parameters in notebook URLs and a Run command for notebooks.它支持笔记本 URL 中的查询参数和笔记本的运行命令。

If you use iPython for testing, transforming argparse into class format can be a quick dummy solution like this.如果您使用 iPython 进行测试,那么将 argparse 转换为类格式可能是一个像这样的快速虚拟解决方案。

class Args:
  data = './data/penn'
  model = 'LSTM'
  emsize = 200
  nhid = 200

args=Args()

Github page offers web transformation service. Github 页面提供网络转换服务。 http://35.192.144.192:8000/arg2cls.html http://35.192.144.192:8000/arg2cls.html
Hope that it would be helpful for your testing.希望对您的测试有所帮助。 Jan 9/19 many bugs are fixed. 2019 年 1 月 9 日修复了许多错误。

Transform argparse module into class format.将 argparse 模块转换为类格式。 Python3 is required.需要 Python3。

python3 [arg2cls.py] [argparse_script.py]

then copy & paste class format to replace argparse functions.然后复制和粘贴类格式以替换 argparse 函数。

#!/usr/bin/env python3
from collections import OrderedDict
import sys
import re
DBG = False

#add_argument(), set_defaults() only available.
ListStartPatt = re.compile(r'\s*\[.*')
ListStartPatt2 = re.compile(r'\).*\[.*') # list out of function scope.
ListPatt = re.compile(r'(\[.*?\])')
GbgPatt = re.compile(r'(.*?)\)[^\)]+') # for float('inf') cmplx.
GbgPatt2 = re.compile(r'(.*?)\).*') # general gbg, ? for non greedy.
LpRegex = re.compile(r'\({1,}\s{0,}')
RpRegex = re.compile(r'\s{0,}\){1,}')
PrRegex = re.compile(r'\((.*)(\))(?!.*\))') # from \( to last \).
CmRegex = re.compile(r'\s{0,},\s{0,}')
StrRegex = re.compile(r'\'(.*?)\'')

# Argument dict : {arg_name : value}
argDct=OrderedDict()

# process 'default=' value.
def default_value(tval, dtype=''):
  # string pattern.
  regres = StrRegex.match(tval) 
  if regres and not re.search('int|float|long|bool|complex', dtype):
    if DBG:
      print('default_value: str patt found')
    tval = regres.group(0)
    return tval

  # typed pattern.
  CommaSeparated = CmRegex.split(tval)[0]
  if DBG:
    print('comma sepearated value:', CommaSeparated)

  if ListStartPatt.match(CommaSeparated) and not ListStartPatt2.match(CommaSeparated):
    lres = ListPatt.search(tval)
    if lres:
      tval = lres.group(1)
    if DBG:
      print('list patt exist tval: ', tval)
  else :
    tval = CmRegex.split(tval)[0]
    if DBG:
      print('no list format tval: ', tval)

  # if default value is not like - int('inf') , remove characters after ')' garbage chars.
  ires = RpRegex.split(tval)[0]
  if not (re.search('int|float|long|bool|complex', ires) and re.search(r'[a-z]+\(',ires)):
    if DBG:
      print('not int("inf") format. Rp removed tval : ', tval)
    tval = re.split(r'\s{0,}\){1,}',tval)[0]
    gbg = GbgPatt2.search(tval)
    if gbg:
      tval = gbg.group(1)  
      if DBG:
        print('garbage exist & removed. tval : ', tval)

  # int('inf') patt.
  else:
    if DBG:
      print('type("inf") value garbaging!')
    gbg = GbgPatt.search(tval)
    if gbg:
      if DBG:
        print('garbage found, extract!')
      tval = gbg.group(1)

  return tval

# Handling add_argument()
def add_argument(arg_line):
  global argDct
  if DBG:
    print('\nin add_argument : **Pre regex: ', arg_line)

  '''    
  argument name
  '''
  # argname = DdRegex.split(arg_line)[1] # Dash or regex for arg name.
  argname = re.search('\'--(.*?)\'', arg_line)
  if not argname:
    argname = re.search('\'-+(.*?)\'', arg_line)

  # dest= keyword handling.
  dest = re.search(r',\s*dest\s*=(.*)', arg_line)
  if dest:
    dval = dest.group(1)
    dval = default_value(dval)
    argname = StrRegex.search(dval)

  # hyphen(-) to underscore(_)
  if argname:
    argname = argname.group(1).replace('-', '_')
  else :
    # naive str argname.
    sres = StrRegex.match(arg_line)
    if sres:
      argname = sres.group(1)
    if not argname:
      return # no argument name 

  '''
  check for syntaxes (type=, default=, required=, action=, help=, choices=)
  '''
  dtype = ''
  dres = re.search(r',\s*type\s*=\s*(.*)', arg_line)
  if dres:
    dtype = dres.group(1)
    dtype = CmRegex.split(dtype)[0]

  dfult = re.search(r',\s*default\s*=\s*(.*)', arg_line)
  rquird = re.search(r',\s*required\s*=\s*(.*)', arg_line)
  action = re.search(r',\s*action\s*=\s*(.*)', arg_line)
  hlp = re.search(r',\s*help\s*=\s*(.*)', arg_line)
  chice = re.search(r',\s*choices\s*=\s*(.*)', arg_line)

  # help message
  hlp_msg = ''
  if hlp:
    thl = hlp.group(1)
    if DBG:
      print('handling help=')
    hlp_msg = default_value(thl)
    if hlp_msg:
      hlp_msg = 'help='+hlp_msg

  # choice message
  choice_msg = ''
  if chice:
    tch = chice.group(1)
    if DBG:
      print('handling choices=')
    choice_msg = default_value(tch)
    if choice_msg:
      choice_msg = 'choices='+choice_msg+' '

  '''
  argument value
  '''
  # tval: argument value.
  tval = ''
  # default exist.
  if dfult:
    tval = dfult.group(1)
    tval = default_value(tval, dtype)
    if DBG:
      print('value determined : ', tval)

  # action or required syntaxes exist.
  elif action or rquird:
    if DBG:
      print('in action/required handling')
    msg_str = ''
    if action:
      tval = action.group(1)
      msg_str = 'action'
    elif rquird:
      tval = rquird.group(1)
      msg_str = 'required'

    tval = default_value(tval)
    tval = ' ** ' + msg_str + ' '+tval+'; '+choice_msg+ hlp_msg

  # no default, action, required.
  else : 
    argDct[argname] = ' ** default not found; '+choice_msg+ hlp_msg

  # value found.
  if tval:
    argDct[argname] = tval

# Handling set_defaults()
def set_defaults(arg_line):
  global argDct
  if DBG:
    print('\nin set_defaults arg_line: ', arg_line)

  # arguments to process.
  tv='' 
  # arguments of set_default()
  SetPatt = re.compile(r'(.+=.+\)?)')
  sres = SetPatt.match(arg_line)
  if sres:
    tv = sres.group(1)
    if DBG:
      print("setPatt res: ", tv)
    tv = re.sub(r'\s+','', tv)
    if DBG:
      print('\nset_default values: ', tv)

  # one arguemnt regex.
  SetArgPatt = re.compile(r',?([^=]+=)[^=,]+,?')
  # handling multiple set_default() arguments. (may have a bug)
  while True:
    tname=''
    tval =''
    tnv=''
    # func closed.
    if re.match(r',*\).*',tv):
      tv=''
      break
    if DBG:
      print('set_default remaining: ', tv)

    nres = SetArgPatt.match(tv)
    if nres:
      tname = nres.group(1)
      if len(tv.split(tname, 1)) > 1:
        tval = tv.split(tname,1)[1]
        tval = default_value(tval)
        tnv=tname+tval
        tname = tname.rsplit('=',1)[0]

      if DBG:
        print('set_default tnam: ', tname)
        print('set_default tval: ', tval)
      if tname:
        argDct[tname] = tval

      # split with processed argument.
      tv = tv.split(tnv)
      if len(tv) > 1:
        tv = tv[1]
      # no more value to process
      else:
        break

    # no arg=value pattern found.
    else:
      break

# Remove empty line & Concatenate line-separated syntax.
def preprocess(fname):
  try :
    with open(fname, 'r', encoding='UTF8') as f:
      txt = f.read()
      t = txt.splitlines(True)
      t = list( filter(None, t) )

      # remove empty line
      t = [x for x in t if not re.match(r'\s{0,}\n',x)]
      # concatenate multiple lined arguments.
      # empl : lines to be deleted from t[].
      empl = []
      for i in range(len(t)-1, 0, -1):
        if not re.search('add_argument|set_defaults', t[i]):
          t[i-1] += t[i]
          t[i-1]=re.sub(r'\n{0,}','',t[i-1])
          t[i-1]=re.sub(r'\s{1,}',' ',t[i-1])
          empl.append(t[i])

      for d in empl:
        t.remove(d)
      for i, line in enumerate(t):
        t[i] = line.replace('\"', '\'').split('parse_args()')[0]
      return t

  except IOError:
    print('IOError : no such file.', fname)
    sys.exit()

def transform(fname):
  # t : list() contains add_argument|set_defaults lines.
  arg_line_list = preprocess(fname)

  for i, arg_line in enumerate(arg_line_list):
    t = PrRegex.search(arg_line)

    if t:
      t = t.group(1) # t: content of add_argument Parentheses.
    else :
      continue # nothing to parse.

    if re.search(r'add_argument\s*\(', arg_line):
      add_argument(t)
    elif re.search(r'set_defaults\s*\(',arg_line):
      set_defaults(t)
    else :
      # Nothing to parse.
      continue

  print('\nclass Args:')
  for i in argDct:
    print(' ',i, '=', argDct[i])
  print()
  print('args=Args()')

def main():
  if len(sys.argv) <2:
    print('Usage : python arg2cls.py [target.py] [target2.py(optional)] ...')
    sys.exit(0)
  sys.argv.pop(0)

  #handling multiple file input.
  for fname in sys.argv:
    transform(fname)

if(__name__ == "__main__"):
  main()

If the goal is to run a notebook with configurable arguments passed from commandline, I think the easiest way is to use environment variables, like this:如果目标是运行带有从命令行传递的可配置参数的笔记本,我认为最简单的方法是使用环境变量,如下所示:

NB_ARGS=some_args jupyter nbconvert --execute --to html --template full some_notebook.ipynb

Then in the notebook, you can import os and use os.environ['NB_ARGS'] .然后在笔记本中,您可以import os并使用os.environ['NB_ARGS'] The variable value can be some text that contains key-value pairs or json for example.变量值可以是一些包含键值对或 json 的文本。

At the top of the Jupyter cell, put a line like:在 Jupyter 单元格的顶部,放置如下一行:

%%python - --option1 value1 --option2 value2 --etc

In your example:在你的例子中:

%%python - True

This will run your script like in a command line with the args provided.这将像在命令行中使用提供的参数一样运行您的脚本。

Example:例子:

%%python - --option1 value1 --option2 value2 --etc

import sys

if __name__ == '__main__':
    print(sys.argv)

will output:将输出:

['-', '--option1', 'value1', '--option2', 'value2', '--etc']

Hope it helps.希望能帮助到你。

sys.argv yields a list , so I used sys.argv产生一个list ,所以我使用

sys.argv.append('hello')

in a jupyter notebook, which allowed me to append extra members and pretend like I'm passing in arguments from the command line.在 jupyter 笔记本中,它允许我附加额外的成员并假装我是从命令行传递参数。

A workaround is to make the jupyter notebook read the arguments from a file.解决方法是让 jupyter notebook 从文件中读取参数。 From the command line, modify the file and run the notebook.从命令行修改文件并运行笔记本。

I assume that you just want to parse some arguments to the notebooks, but it's not necessary to use the command line.我假设您只想解析笔记本的一些参数,但没有必要使用命令行。

If you want to parse commands like.如果你想解析类似的命令。

python script.py --a A --b B

You can use the following code in the notebook:您可以在笔记本中使用以下代码:

cmd = '--a A --b B'
args = args = parser.parse_args(cmd)

For parse_args , you can find more information here .对于parse_args ,您可以在此处找到更多信息。

you can use Jupyter build-in magic command %run within the notebook. 您可以在笔记本中使用Jupyter内置的魔术命令%run

From this link , you can use: 在此链接中 ,您可以使用:

%run -p [prof_opts] filename.py [args to program]

Or something like %run -i script.py False 或类似%run -i script.py False东西%run -i script.py False

Or if you are parsing the arguments %run -i script.py --flag1 False --flag2 True 或者,如果您正在解析参数%run -i script.py --flag1 False --flag2 True

A simple and naïve solution is to put the following snippet at the first line of your program:一个简单而天真的解决方案是将以下代码段放在程序的第一行:

import sys
sys.argv = "your expected command line arguments here".split()

After executing this command, packages like argparse will work well.执行此命令后,像argparse这样的包将运行良好。

So, you can just run your scripts in the jupyter lab server, without opening a terminal and typing your arguments.因此,您只需在 jupyter 实验室服务器中运行您的脚本,而无需打开终端并输入您的参数。

I tried out the answers listed above, and came up with a different solution.我尝试了上面列出的答案,并提出了不同的解决方案。

My original code was我的原始代码是

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True, help="path to input image")
ap.add_argument("-y", "--yolo", required=True, help="base path to YOLO directory")
ap.add_argument("-c", "--confidence", type=float, default=0.5, help="minimum probability to filter weak detections")
ap.add_argument("-t", "--threshold", type=float, default=0.3, help="threshold when applying non-maxima suppression")
args = vars(ap.parse_args())

I tried to make a Class as我试图将一个类作为

Class Args():
    image='photo.jpg'
    yolo='yolo-coco'
    confidence=0.5
    threshold=0.3

args=Args()

but futher code snippets were producing an error.但进一步的代码片段产生了错误。

So I printed args after vars(ap.parse_args()) and found that it was a dictionary.所以我在vars(ap.parse_args())之后打印了args ,发现是字典。

So just create a dictionary for the original args:所以只需为原始参数创建一个字典:

args={"image":  'photo.jpg', "yolo":  'yolo-coco', "confidence": 0.5,"threshold": 0.3}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM