我正在使用 Typer 使用 python 编写命令行程序。
这是我遇到麻烦的示例脚本。
import typer
app = typer.Typer()
@app.command()
def hello(name):
typer.echo(f'Hello!')
@app.command()
def goodbye():
typer.echo(f'Goodbye.')
class Grettings:
@app.command()
def aloha(self):
typer.echo('Aloha!')
@app.command()
def bonjour(self):
typer.echo('Bonjour!')
if __name__ == '__main__':
app()
当在终端中输入以下命令时,会给出预期的输出。
python main.py hello
python main.py goodbye
但是,当调用类方法时,出现以下异常。
python main.py aloha
python main.py bonjour
Usage: main.py aloha [OPTIONS] SELF
Try 'main.py aloha --help' for help.
Error: Missing argument 'SELF'.
显然,这是因为类尚未初始化。但这似乎是一个常见问题,所以我认为这个问题有一个简单的解决方案。
我发现的可能的解决方案包括在正在使用的类/方法上使用装饰器,或者使用需要继承的特殊类来“公开”类方法。
任何装饰器都会在类构建之前被调用,因此装饰器不知道。
Typer 尝试以 Grettings().aloha()
的形式调用回调。 这在 Python 中会失败并出现错误:
类型错误:hallo() 缺少 1 个必需的位置参数:'self'
第 1 部分:它是如何工作的(使用静态函数,无自变量)
>>> import typer
>>> app = typer.Typer()
>>> app
<typer.main.Typer object at 0x7f0713f59c18>
>>> app.__dict__
{'_add_completion': True, 'info': <typer.models.TyperInfo object at 0x7f0713f59c50>, 'registered_groups': [], 'registered_commands': [], 'registered_callback': None}
>>> @app.command()
... def hello():
... typer.echo('hello')
...
>>> app.__dict__['registered_commands']
[<typer.models.CommandInfo object at 0x7f0711e69cf8>]
>>> app.__dict__['registered_commands'][0].cls
<class 'typer.core.TyperCommand'>
>>> app.__dict__['registered_commands'][0].callback
<function hello at 0x7f070f539378>
>>> app.__dict__['registered_commands'][0].callback()
hello
第 2 部分:它如何不起作用(使用实例方法,需要 self 参数)
>>> class German:
... @app.command()
... def hallo(self):
... typer.echo('Hallo')
...
>>> app.__dict__['registered_commands'][1]
<typer.models.CommandInfo object at 0x7f070f59ccf8>
>>> app.__dict__['registered_commands'][1].callback
<function German.hallo at 0x7f070f539158>
>>> app.__dict__['registered_commands'][1].callback()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: hallo() missing 1 required positional argument: 'self'
>>> app.__dict__['registered_commands'][1].callback(German())
Hallo
注意:在最后一个语句中,我将一个新实例作为参数 self
传递给回调,并且调用成功并获得预期输出。固定代码
Grettings
重命名为
Greetings
(拼写)
nihao(self)
来演示失败。
import typer
app = typer.Typer()
@app.command()
def hello(name):
typer.echo(f'Hello!')
@app.command()
def goodbye():
typer.echo(f'Goodbye.')
class Greetings:
@app.command()
def aloha(): # function or class-method (implicitly static)
typer.echo('Aloha!')
@staticmethod # explicitly static
@app.command()
def bonjour(): # no self argument!
typer.echo('Bonjour!')
@app.command()
def nihao(self): # callback invocation fails because missing self argument
typer.echo('Nihao!')
if __name__ == '__main__':
app()
行为和输出符合预期nihao
列为可用,但它的调用将像您所经历的一样失败。但是现在可以调用命令修饰的静态方法了。
$ python3 SO_typer.py --help
Usage: SO_typer.py [OPTIONS] COMMAND [ARGS]...
Options:
--install-completion [bash|zsh|fish|powershell|pwsh]
Install completion for the specified shell.
--show-completion [bash|zsh|fish|powershell|pwsh]
Show completion for the specified shell, to
copy it or customize the installation.
--help Show this message and exit.
Commands:
aloha
bonjour
goodbye
hello
nihao
🇨🇳️中文问候语失败,因为没有参数self
通过调用:
$ python3 SO_typer.py nihao
Usage: SO_typer.py nihao [OPTIONS] SELF
Try 'SO_typer.py nihao --help' for help.
Error: Missing argument 'SELF'.
🏴筛选 筛选 夏威夷问候语有效,因为现在可以静态调用:
$ python3 SO_typer.py aloha
Aloha!
另请参阅skycaptain
正在回复它 -https://github.com/tiangolo/typer/issues/309#issuecomment-1934028088 我已经实现了一种模式来自动获取命令方法。
import inspect
import typer
class MyKlass:
some_default_value: str
def __init__(self, some_default_value: str):
self.some_default_value = some_default_value
self.app = typer.Typer()
for method, _ in inspect.getmembers(self, predicate=inspect.ismethod):
if not method.startswith('cmd'):
continue
cmd_name = method.strip('cmd_')
self.app.command(
name=cmd_name,
help=self.some_default_value
)(eval(f'self.{method}'))
def cmd_run(self):
print("Running")
def cmd_sleep(self):
print("sleep")
if __name__ == "__main__":
MyKlass(some_default_value="it's a command").app()
Usage: python -m legalops_commons.utils.foo [OPTIONS] COMMAND [ARGS]...
Options:
--install-completion Install completion for the current shell.
--show-completion Show completion for the current shell, to copy it or
customize the installation.
--help Show this message and exit.
Commands:
run it's a command
sleep it's a command