8000 How can I reuse the function that iv made as a command? · Issue #330 · pallets/click · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

How can I reuse the function that iv made as a command? #330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
chainn opened this issue Apr 22, 2015 · 9 comments
Closed

How can I reuse the function that iv made as a command? #330

chainn opened this issue Apr 22, 2015 · 9 comments

Comments

@chainn
Copy link
chainn commented Apr 22, 2015

i have the following code:

pass_config = click.make_pass_decorator(Config, ensure=True)

@click.group()
init(config):
    pass

@init.group()
@pass_config
def a(config):
    pass

@a.command('print')
@pass_config
def print_a(config):
    print "yes"

@init.group()
@pass_config
def b(config):
    pass

@b.command('print')
@pass_config
def print_a_again(config):
    print_a(config)

i made :init as my entry point and name it as MYCLI in setup,py
then i run MYCLI b print - i got console error:

Traceback (most recent call last):
  File "C:\python27\Scripts\CHAINCLITEST-script.py", line 9, in <module>
    load_entry_point('CHAINCLITOOL==1.0', 'console_scripts', 'CHAINCLITEST')()
  File "C:\Python27\lib\site-packages\click\core.py", line 664, in __call__
    return self.main(*args, **kwargs)
  File "C:\Python27\lib\site-packages\click\core.py", line 644, in main
    rv = self.invoke(ctx)
  File "C:\Python27\lib\site-packages\click\core.py", line 991, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "C:\Python27\lib\site-packages\click\core.py", line 991, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "C:\Python27\lib\site-packages\click\core.py", line 837, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "C:\Python27\lib\site-packages\click\core.py", line 464, in invoke
    return callback(*args, **kwargs)
  File "C:\Python27\lib\site-packages\click\decorators.py", line 64, in new_func

    return ctx.invoke(f, obj, *args[1:], **kwargs)
  File "C:\Python27\lib\site-packages\click\core.py", line 464, in invoke
    return callback(*args, **kwargs)
  File "d:\myCLI.py", line 56, i
n print_a_again
    print_a(config)
  File "C:\Python27\lib\site-packages\click\core.py", line 664, in __call__
    return self.main(*args, **kwargs)
  File "C:\Python27\lib\site-packages\click\core.py", line 631, in main
    args = list(args)
TypeError: 'Config' object is not iterable

if i remove the decorator above print_a, then everything will be fine.
Could anyone help? ... Why this is happening?

@nchammas
Copy link
Contributor

I think when you make a function a command, that's it, it can only be used via the command line. Typically these functions will just do some minor CLI-related logic and then dispatch to a function that does the real work.

So I would suggest moving any reusable logic into separate, regular functions so you can call them elsewhere.

@chainn
Copy link
Author
chainn commented Apr 24, 2015

Thanks @nchammas

@chainn chainn closed this as completed Apr 24, 2015
@timcera
Copy link
timcera commented Jun 3, 2015

I first used 'baker', then 'mando' for my command line interface helper, and both allow the same function to be used at the command line and via an API. This was nice to have.

I would like to use 'click', because of other features, but this one missing feature I have come to rely on.

Here is what I thought of:

  1. Use different function names. Easiest, but not preferred since I have already established the current names as being available from the command line and from within the Python API.
  2. Use a multiple dispatch library. Another dependency is a concern. Haven't tried yet, but some deep stuff would have to go on in the back ground which makes me a little nervous.
  3. An option in 'click.command' to map command line arguments to the function arguments. So something like:
@click.command(from_function_signature=True)
def func(path, overwrite=True):
    print(path, overwrite)

Instead of being specified, the 'from_function_signature' would automatically create the parameter entries:

@click.argument('path')
@click.option('--overwrite', type=click.BOOL)

Is there any other work around?

Is something like 3 a viable idea to be added to click? If so I may take a stab at making it happen.

I also use *args and **kwds in a couple functions which might be difficult to handle.

@untitaker
Copy link
Contributor

Option 1 is the only realistic one. Exposing your click function 1:1 is a very bad idea because those might rely on e.g. click closing files, click's special objects being passed etc. You can use the name parameter on click.command to choose something other than the function name as your command name, and can suffix the functions with _cmd.

@yarikoptic
Copy link

In 1. fashion, could may be click store and expose original decorated function, so for above example I could use something like func._original if I want to use it directly via it's original python interface?

Then it would be cool if it's __doc__ was populated with documentation of the parameters in one of the styles (configurable eg numpy etc) so that function was a full fledged function without developers needing to duplicate the signature and docs if to maintain it separately.

@davidism
Copy link
Member

Click does store and expose the original function: command.callback

See #1054 for explanation

@yarikoptic
Copy link

Thank you @davidism !!

@iiLaurens
Copy link

Click does store and expose the original function: command.callback

See #1054 for explanation

It does not expose just the original function in command.callback. For example if you have used the decorator @pass_obj then it modifies the original function and stores that under callback and it would essentially be impossible to call the function outside of the CLI.

@davidism
Copy link
Member

pass_context is not the same thing. It's a regular decorator, presumably the function requires a context if it's decorated with it.

@pallets pallets locked and limited conversation to collaborators Aug 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants
0