Interoperability with asyncclick
overclockworked64 opened this issue · 2 comments
I apologize if I'm knocking on the wrong door.
This is a minimal example that reproduces my issue:
import asyncclick as click
from click_option_group import optgroup
from click_option_group import RequiredAnyOptionGroup
class PortRange(click.ParamType):
...
@click.command()
@click.argument('target')
@click.option('--interface', '-i', type=str, required=True)
@optgroup.group('Ports and/or port ranges', cls=RequiredAnyOptionGroup)
@optgroup.option('--port', '-p', type=click.IntRange(min=0, max=65535), multiple=True)
@optgroup.option('--range', '-r', 'range_', type=PortRange(), multiple=True)
async def main(*args, **kwargs) -> None:
...
if __name__ == '__main__':
main(_anyio_backend='trio')
This is the full traceback:
❯ poetry run python -m wrath 192.168.1.1 -i enp5s0
Traceback (most recent call last):
File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/home/alex/Repositories/overclockworked64/wrath/wrath/__main__.py", line 11, in <module>
async def main(*args, **kwargs) -> None:
File "/home/alex/.cache/pypoetry/virtualenvs/wrath-NjAFd-T0-py3.8/lib/python3.8/site-packages/click_option_group/_decorators.py", line 137, in decorator
func = option_group.option(*item.param_decls, **item.attrs)(func)
File "/home/alex/.cache/pypoetry/virtualenvs/wrath-NjAFd-T0-py3.8/lib/python3.8/site-packages/click_option_group/_core.py", line 174, in decorator
func = click.option(*param_decls, group=self, **option_attrs)(func)
File "/home/alex/.cache/pypoetry/virtualenvs/wrath-NjAFd-T0-py3.8/lib/python3.8/site-packages/click/decorators.py", line 247, in decorator
_param_memo(f, OptionClass(param_decls, **option_attrs))
File "/home/alex/.cache/pypoetry/virtualenvs/wrath-NjAFd-T0-py3.8/lib/python3.8/site-packages/click_option_group/_core.py", line 31, in __init__
super().__init__(param_decls, **attrs)
File "/home/alex/.cache/pypoetry/virtualenvs/wrath-NjAFd-T0-py3.8/lib/python3.8/site-packages/click/core.py", line 2465, in __init__
super().__init__(param_decls, type=type, multiple=multiple, **attrs)
File "/home/alex/.cache/pypoetry/virtualenvs/wrath-NjAFd-T0-py3.8/lib/python3.8/site-packages/click/core.py", line 2032, in __init__
self.type = types.convert_type(type, default)
File "/home/alex/.cache/pypoetry/virtualenvs/wrath-NjAFd-T0-py3.8/lib/python3.8/site-packages/click/types.py", line 1019, in convert_type
return FuncParamType(ty)
File "/home/alex/.cache/pypoetry/virtualenvs/wrath-NjAFd-T0-py3.8/lib/python3.8/site-packages/click/types.py", line 158, in __init__
self.name = func.__name__
AttributeError: 'IntRange' object has no attribute '__name__'
This happens only if I'm using asyncclick; if I use regular click
(and, of course, make the function sync) the issue vanishes.
Thanks for the report.
It seems, asyncclick re-implements click data types including ParamType
, IntRange
and Option
. I don't know why they do it, but it does not work with options from click_option_group
because click_option_group
uses click.Option
as base class for GroupedOption
. We cannot use asyncclick.Option
in this place. asyncclick.ParamType
, asyncclick.IntRange
are incompatible with the current click.Option
class.
I think re-implementing types from click is very strange and hard approach. A lot of hard work and endless incompatibility. And for what? Just to write async CLI functions, is it? What for? I would just use explicit creating/getting event loop or running async func (or anyio wrapper) inside CLI function. Something like this:
import asyncio
import click
...
async def do_something(foo, bar):
pass
@click.command()
@click.option('--foo')
@click.option('--bar')
def cli(foo, bar):
asyncio.run(do_something(foo, bar))
Okay, I see that the issue is beyond the realm of click-option-group
, as I initially suspected. Thanks for the response.