用于定义分隔符的Python click参数导致CSV错误“分隔符”必须为1个字符的字符串

时间:2018-08-09 02:48:21

标签: python pandas python-click

我正在尝试构建一个简单的click命令行应用程序,以使用一种类型的定界符读取文件,并使用不同的定界符写出同一文件。我不想做类似查找和替换的操作,因为在列中可能有一些我不想触摸的转义分隔符。

我编写了一个简单的基于单击的CLI来执行此操作,但是在传递\t来创建制表符分隔的文件时遇到了一些问题。

如下面的错误所示,制表符分隔符未正确传递给pandas函数以写出新文件。当我在CLI的中间打印定界符时,一切看起来都很正确,所以我不确定这里发生了什么。

import click
import pandas as pd

@click.command()
@click.argument('filename')
@click.argument('in_delimiter')
@click.argument('out_delimiter')
def cli(filename, in_delimiter, out_delimiter):

    """
    Command line interface to change file delimiters
    """

    # read in CSV file
    df = pd.read_csv(filename, sep=in_delimiter)
    print(len(df))

    # write out CSV file
    df.to_csv('output.csv', sep=out_delimiter, index=False)
    print("transformation complete")


if __name__ == '__main__':
    cli()

这是我将输入和输出定界符传递到CLI的方式:

python cli.py data.csv "," "\t"

这是生成的错误:

Traceback (most recent call last):
  File "cli.py", line 24, in <module>
    cli()
  File "/home/curtis/Program_Files/miniconda3/envs/py36/lib/python3.6/site-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/home/curtis/Program_Files/miniconda3/envs/py36/lib/python3.6/site-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/home/curtis/Program_Files/miniconda3/envs/py36/lib/python3.6/site-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/curtis/Program_Files/miniconda3/envs/py36/lib/python3.6/site-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "cli.py", line 19, in cli
    df.to_csv('output.csv', sep=out_delimiter, index=False)
  File "/home/curtis/Program_Files/miniconda3/envs/py36/lib/python3.6/site-packages/pandas/core/frame.py", line 1745, in to_csv
    formatter.save()
  File "/home/curtis/Program_Files/miniconda3/envs/py36/lib/python3.6/site-packages/pandas/io/formats/csvs.py", line 169, in save
    self.writer = UnicodeWriter(f, **writer_kwargs)
  File "/home/curtis/Program_Files/miniconda3/envs/py36/lib/python3.6/site-packages/pandas/io/common.py", line 521, in UnicodeWriter
    return csv.writer(f, dialect=dialect, **kwds)
TypeError: "delimiter" must be a 1-character string

1 个答案:

答案 0 :(得分:2)

要处理转义字符,可以使用如下回调:

代码:

struct A

要使用回调,您可以执行以下操作:

import codecs

def unescape(ctx, param, value):
    return codecs.getdecoder("unicode_escape")(value)[0]

这是怎么工作的

这将使用@click.argument('escaped', callback=unescape) 编解码器处理传入的字符串。

Source

测试代码:

unicode_escape

结果:

import click

@click.command()
@click.argument('escaped', callback=unescape)
def cli(escaped):
    click.echo('len: {}, ord: {}'.format(len(escaped), ord(escaped)))


if __name__ == "__main__":
    commands = (
        r'\t',
        r'\n',
        '\t',
        ',',
        '--help',
    )

    import sys, time

    time.sleep(1)
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    for cmd in commands:
        try:
            time.sleep(0.1)
            print('-----------')
            print('> ' + cmd)
            time.sleep(0.1)
            cli(cmd.split())

        except BaseException as exc:
            if str(exc) != '0' and \
                    not isinstance(exc, (click.ClickException, SystemExit)):
                raise