跳转到主要内容

Python 模块,可轻松创建 nu shell 插件

项目描述

Nushell 插件 Python

PyPI version

这是一个允许轻松创建插件的 Python 模块。这已经相当容易了,但可以进一步改进!提供的每个示例都包括

  • Python 文件中的完整示例(无 .py 扩展名)
  • 带有 nushell 的容器,可以使用常规 Python 或(对于某些情况)独立二进制文件(通过 pyinstaller)运行
  • README.md 文件,用于说明用法

以下包含筛选器和接收器插件的快速入门示例,您应该查看 示例 文件夹以获取完整代码、makefile 和 Dockerfile。请贡献新的示例以及代码的调整!我在一天内就开发了这个模块,所以我们可能会做得更好,并且随着 nushell 的发展,我们确实需要这样做。

安装

您可以从 pip 安装

$ pip install nushell

或从这里从源代码安装

$ git clone https://github.com/vsoch/nushell-plugin-python
cd nushell-plugin-python
python setup.py install

插件类参数

以下参数是筛选器和接收器插件的共享参数。

名称 描述 必需或默认值
name 插件的名称 必需
用法 插件用法 必需
日志记录 将日志记录到 nu_plugin_<name>.log 默认为 True(启用)
add_help 添加 --help 标志 默认为 True
parse_params 从项目提取参数 默认为 True

参数

参数可以是您的插件中定义的命名或位置参数。实际上,您可以具有具有相同名称的位置和命名参数,并定义其中一个的帮助字符串(它将被另一个使用)。

命名参数

对于源或过滤器,您可以传递命名参数,这意味着您的插件将像这样解析它们:

$ <plugin> --<name> <value>

或者对于布尔值(称为开关)

$ <plugin> --<switch>

以下是一些添加各种命名参数的示例

# add_named_argument(name, argType, syntaxShape=None, usage=None)
plugin.add_named_argument("catch", "Switch", usage="catch a random pokemon")
plugin.add_named_argument("list", "Switch", usage="list pokemon names")
plugin.add_named_argument("list-sorted", "Switch", usage="list sorted names")
plugin.add_named_argument("avatar", "Optional", "String", "generate avatar")
plugin.add_named_argument("pokemon", "Optional", "String", "get pokemon")

若要使参数成为必需的,只需将“可选”更改为“必需”(上述插件不需要任何内容)。

位置参数

位置参数位于插件名称之后,但没有标志。例如

$ <plugin> <positional>

以下是一些添加位置参数的示例。每个都需要一个名称,如果它是必需的或可选的(没有开关),则需要语法形状(例如String,Int,Any)以及使用字符串。

# add_positional_argument(name, argType, syntaxShape=None, usage=None)
plugin.add_positional_argument("number", "Mandatory", "Int", usage="number to parse")
plugin.add_positional_argument("secondNumber", "Optional", "Any", usage="second number to parse")

过滤器插件

基本的过滤器插件将实例化FilterPlugin类,然后提供用于过滤器的函数。

#!/usr/bin/env python3

from nushell.filter import FilterPlugin

# Your filter function will be called by the FilterPlugin, and should
# accept the plugin and the dictionary of params
def runFilter(plugin, params):
    '''runFilter will be executed by the calling SinkPlugin when method is "sink"
    '''
    # Get the string primitive passed by the user
    value = plugin.get_string_primitive()

    # Calculate the length
    intLength = len(value)

    # Print an integer response (can also be print_string_response)
    plugin.print_int_response(intLength)


# The main function is where you create your plugin and run it.
def main():

    # Initialize a new plugin
    plugin = FilterPlugin(name="len", 
                          usage="Return the length of a string")


    # Run the plugin by passing your filter function
    plugin.run(runFilter)


if __name__ == '__main__':
    main()

值得注意的是,您的过滤器函数应接受一个插件和解析的命令行参数(字典)作为参数。您可以使用插件执行多个所需功能,向nushell发送响应或记录到/tmp/nushell-plugin-<name>.log

plugin.logger.<level>
plugin.get_string_primitive()
plugin.get_int_primitive()
plugin.print_int_response()
plugin.print_string_response()

示例

  • len 是一个基本函数,用于返回字符串的长度
  • plus 将两个整数相加,并且是一个带有位置参数的示例

源插件

源插件将实例化SinkPlugin类,然后将stdin(通过临时文件)传递给您编写的源函数。以下是一个示例。

#!/usr/bin/env python3

from nushell.sink import SinkPlugin

# Your sink function will be called by the sink Plugin, and should
# accept the plugin and the dictionary of params
def sink(plugin, params):
    '''sink will be executed by the calling SinkPlugin when method is "sink"
    '''
    message = "Hello"
    excited = params.get("excited", False)
    name = params.get("name", "")
    
    # If we have a name, add to message
    message = "%s %s" %(message, name)
    
    # Are we excited?
    if excited:
        message += "!"

    print(message)


# The main function is where you create your plugin and run it.
def main():

    # Initialize a new plugin
    plugin = SinkPlugin(name="hello", 
                        usage="A friendly plugin")


    # Add named arguments (notice we check for in params in sink function)
    # add_named_argument(name, argType, syntaxShape=None, usage=None)
    plugin.add_named_argument("excited", "Switch", usage="add an exclamation point!")
    plugin.add_named_argument("name", "Optional", "String", usage="say hello to...")

    # Run the plugin by passing your sink function
    plugin.run(sink)


if __name__ == '__main__':
    main()

参数

由于您可以将内容管道输入到源中,因此管道内容将被解析成一个列表,并作为带有_pipe键的参数传递。例如,如果我们做

> ls | get name | hello --name Dinosaur
Hello Dinosaur

然后查看输出文件,我们会看到解析的参数包括我们上面生成的所有列表名称的管道

PARAMS {'name': 'Dinosaur', '_pipe': ['Makefile', 'README.md', 'Dockerfile', 'nu_plugin_hello', 'Dockerfile.standalone']}

如果您不想解析管道,将您的插件.parse_pipe 设置为 False

plugin.parse_pipe = False
plugin.run(sink)

然后结果将包括包含条目和标签的完整列表。

PARAMS {'name': 'Dinosaur', '_pipe': [[{'tag': {'anchor': None, 'span': {'start': 0, 'end': 2}}, 'item': {'Primitive': {'String': 'Makefile'}}}, {'tag': {'anchor': None, 'span': {'start': 0, 'end': 2}}, 'item': {'Primitive': {'String': 'README.md'}}}, {'tag': {'anchor': None, 'span': {'start': 0, 'end': 2}}, 'item': {'Primitive': {'String': 'Dockerfile'}}}, {'tag': {'anchor': None, 'span': {'start': 0, 'end': 2}}, 'item': {'Primitive': {'String': 'nu_plugin_hello'}}}, {'tag': {'anchor': None, 'span': {'start': 0, 'end': 2}}, 'item': {'Primitive': {'String': 'Dockerfile.standalone'}}}]]}

示例

  • pokemon 按需提供ascii宝可梦!
  • hello 使用源说你好!

单个二进制文件

由于您可以使用 pyinstaller(例如,请参阅examples/len)编译您的模块,因此您可以构建一个简单的二进制文件,并且一个不需要将nushell作为模块安装的二进制文件。为什么您想这样做呢?这意味着您的插件是一个单独的文件(二进制文件),并且您不需要依赖于系统中的其他模块。我相信还有其他方法可以将Python编译成单个二进制文件(例如,cython),但这是我首先尝试的,而且相当简单。如果您找到不同的或更好的方法,请为此代码库做出贡献!

重要 我发现包含附加数据文件的模块表现不佳(这里有一个例子是 pokemon),这就是为什么我们无法卸载pokemon或nushell。然而,我认为您会在大多数基于文本的简单模块中取得成功。当然,您不必这样做!保留您的Python模块与nushell一起安装,并在您的插件执行时使用是完全可以接受的。

许可证

此代码根据MPL 2.0 LICENSE许可。

帮助和贡献

请为此软件包做出贡献,或作为问题发布反馈和提问。

项目详情


下载文件

下载您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源分布

nushell-0.0.16.tar.gz (34.9 kB 查看哈希值)

上传时间

构建分布

nushell-0.0.16-py3.7.egg (46.0 kB 查看哈希值)

上传时间

由以下支持