garetjax / django-click Goto Github PK
View Code? Open in Web Editor NEWWrite Django management command using the click CLI library
License: MIT License
Write Django management command using the click CLI library
License: MIT License
A couple of days ago, Click 8 was released. I've since tried using this with a project that has a dependency on Click 8, which led to some invalid dependency resolution due to the fact that django-click
specifies a strict upper bound smaller than 7.2
. Is there any reason why that limit is enforced, or can it be removed? Alternatively, is there more work that's needed to check that it runs with Click 8 and enable that?
click==6.6, django-click==1.2.0, django==1.5.12
If the one required parameter is omitted from the following management command, the user sees the error message in the subject of this issue
import djclick as click
@click.command()
@click.argument('name')
def command(name):
click.secho('Hello, {}'.format(name), fg='red')
If the one required parameter is omitted from the following command, the user sees a better error message.
import click
@click.command()
@click.argument('name')
def hello(name):
click.secho('Hello, {}'.format(name), fg='red')
if __name__ == '__main__':
hello()
$ python foo.py
Usage: foo.py [OPTIONS] NAME
Error: Missing argument "name".
Any ideas? This would seem to be a django-click issue?
I'm trying to call a djclick based management command using the traditional Django API, django.core.management.call_command
and I'm getting this traceback:
Traceback (most recent call last):
File "_log.py", line 34, in <module>
call_command('sync_models')
File "/home/user/.cache/pypoetry/virtualenvs/ht-ZBbfQ9hA-py3.8/lib/python3.8/site-packages/django/core/management/__init__.py", line 135, in call_command
for group in parser._mutually_exclusive_groups
AttributeError: 'ArgumentParserAdapter' object has no attribute '_mutually_exclusive_groups'
I could do from myproject.myapp.management.commands.my_command import command
although the command I'm using is the grouping feature.
What would be the advised methodology to run the command in a programmatic fashion?
When installing a version of click
later than 7.0, the djclick import fails with an error:
import djclick
/usr/local/lib/python3.6/site-packages/djclick/__init__.py:16: in <module>
__all__ = click.__all__ + ['pass_verbosity']
E AttributeError: module 'click' has no attribute '__all__'
The click
module does not define __all__
as of 7.1 and later.
I migrated a project using django-click from Django 1.9 to Django 2.2
In Django 1.9 the following command worked:
@click.command(help='Mailer send mail')
@click.argument('schema_url')
@click.argument('token')
@click.argument('subject')
@click.argument('body')
@click.argument('to', nargs=-1)
def command(schema_url, token, subject, body, to):
click.echo(f'send "{subject}" to "{to}')
when called like this
./manage.py mailer_send http://mailer:8000/mailer/api/schema $token "hello subject" "hello body" [email protected]
With Django 2.2 the same command results in
subject = 'hello'
body = 'subject'
to = ['hello', 'body', '[email protected]']
django-click does not respect the quotes
This will allow getting rid of this rediculous deep directory structure and lots of files. It should be still possible to split commands into several files, but python way:
commands/
__init__.py
command1.py
command2.py
filecommands.py
utils.py
with commands/__init__.py
:
from .command1 import Command1
from .command2 import Command2
from .filecommands import *
Different splitting srategies are possible this way: single file for command or file for some logical command group or just no splitting. Also this resembles how models.py
was split.
Caling a django-click management command with --help incorrectly prints the command name twice. For example, using the official django-click example:
import djclick as click
@click.command()
@click.argument('name')
def command(name):
click.secho('Hello, {}'.format(name), fg='red')
and calling it
./manage.py testdjclick --help
results in
Usage: manage.py testdjclick testdjclick [OPTIONS] NAME
...
note that testdjclick
is repeated?! It should presumably be
Usage: manage.py testdjclick [OPTIONS] NAME
Am using:
Click 7.0
Django 2.1.3
django-click 2.1.0
on a Mac under pipenv, Python 3.6.6
Django commands by default support the options skip_checks
, stderr
, and stdout
. However, django-click
commands do not. This incompatibility with the basic command contract causes problems particularly in testing.
Since June earlier this year, Travis CI no longer supports free open source CI. If you look at the Travis builds, you can see they haven't been running since then.
Github Actions has become the defacto standard for CI for open source projects. This repository offers a good template for using a testing matrix against all the different versions of Python & Django this package needs to support.
When either sending a SIGINT
or using raise click.Abort
, I would expect the application to shut down cleanly with the appropriate error code. Instead, I get the following stack trace:
Traceback (most recent call last):
File "./manage.py", line 24, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.8/site-packages/django/core/management/__init__.py", line 375, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.8/site-packages/djclick/adapter.py", line 68, in run_from_argv
exit_code = self.main(
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
File "/usr/local/lib/python3.8/site-packages/djclick/adapter.py", line 50, in invoke
return super(DjangoCommandMixin, self).invoke(ctx)
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
File "/srv/service/vite_frontend/management/commands/frontend.py", line 157, in dev
f.write(f"{app.name}\n{process.pid}\n")
File "/usr/local/lib/python3.8/contextlib.py", line 120, in __exit__
next(self.gen)
File "/srv/service/vite_frontend/management/commands/frontend.py", line 70, in run_vite
yield process
File "/usr/local/lib/python3.8/contextlib.py", line 120, in __exit__
next(self.gen)
File "/srv/service/vite_frontend/management/commands/frontend.py", line 47, in run_in_app
raise click.Abort()
We have worked around this by instead throwing a SystemExit
exception, but it would be nice to be able to use Abort
I am usually using Typer on top of Click for command line. This gives a nice way to use Type hints to define variables.
https://typer.tiangolo.com
How complex do you think it would be to have a Typer adopter for django-click?
Assuming we have a command named foo
...
import io
buffer = io.StringIO()
from django.core.management import call_command
call_command("foo", stdout=buffer)
out = buffer.getvalue()
assert "whatever" in out
This is not possible with django-click, instead saying:
TypeError: Unknown option(s) for dumb command: stdout. Valid options are: color, h, help, pythonpath, settings, traceback, v, verbosity, version.
The recent changes in #27, to support Click 8, have not been released.
@FlipperPA Could you issue a new release on PyPI please?
The following script works with the base click
library but raises an exception with the django-click
library.
import djclick as click
@click.command()
@click.argument("name", help="Some name")
def command(name):
click.echo(f"Hi {name}!")
Exception:
Traceback (most recent call last):
File "/app/./manage.py", line 22, in <module>
main()
File "/app/./manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 244, in fetch_command
klass = load_command_class(app_name, subcommand)
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 37, in load_command_class
module = import_module('%s.management.commands.%s' % (app_name, name))
File "/usr/local/lib/python3.9/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 790, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/app/core/management/commands/click1.py", line 6, in <module>
def command(name):
File "/usr/local/lib/python3.9/site-packages/click/decorators.py", line 168, in decorator
_param_memo(f, ArgumentClass(param_decls, **attrs))
File "/usr/local/lib/python3.9/site-packages/click/core.py", line 1984, in __init__
Parameter.__init__(self, param_decls, required=required, **attrs)
TypeError: __init__() got an unexpected keyword argument 'help'
Doing something as simple as raise ClickException('my error message')
results in an error being thrown during the handling of the ClickException
:
Traceback (most recent call last):
File "/home/daniel.chiquito/envs/dandi-api/lib/python3.8/site-packages/djclick/adapter.py", line 69, in run_from_argv
exit_code = self.main(
File "/home/daniel.chiquito/envs/dandi-api/lib/python3.8/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/home/daniel.chiquito/envs/dandi-api/lib/python3.8/site-packages/djclick/adapter.py", line 51, in invoke
return super(DjangoCommandMixin, self).invoke(ctx)
File "/home/daniel.chiquito/envs/dandi-api/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/daniel.chiquito/envs/dandi-api/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/home/daniel.chiquito/git/dandi-api/dandiapi/api/management/commands/collect_garbage.py", line 26, in collect_garbage
raise click.ClickException('my error message')
click.exceptions.ClickException: my error message
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./manage.py", line 20, in <module>
main()
File "./manage.py", line 16, in main
execute_from_command_line(sys.argv)
File "/home/daniel.chiquito/envs/dandi-api/lib/python3.8/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/home/daniel.chiquito/envs/dandi-api/lib/python3.8/site-packages/django/core/management/__init__.py", line 413, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/daniel.chiquito/envs/dandi-api/lib/python3.8/site-packages/djclick/adapter.py", line 76, in run_from_argv
if getattr(e.ctx, "traceback", False): # NOCOV
AttributeError: 'ClickException' object has no attribute 'ctx'
The error is occurring here:
django-click/djclick/adapter.py
Lines 73 to 77 in 73be8fb
ClickException
include a ctx
, but not all: https://github.com/pallets/click/blob/9da166957f5848b641231d485467f6140bca2bc0/src/click/exceptions.pyLinks in README and on PyPI link to ReadTheDocs, but it 404s.
It would be cool if these commands could be available via Django admin with auto generated form fields to provide inputs based on the click command definition. This likely falls out of the scope of this project but would come in handy for discoverability and ease of use. Output from the command could be downloaded after run or dumped in the browser window potentially.
Hi and thanks for maintaining this convenient library. It really makes our management commands look a lot cleaner.
What's missing for us at the moment, though, is typing annotations, since we're running mypy on all of our code.
Right now we're working around this by creating a stub for mypy to use, but it would obviously be much better to have first party type annotations. Is this something that's planned/you're interested in adding?
Thanks for considering :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.