Skip to content

Commit 0cce16a

Browse files
committed
fix #203 fix #186
1 parent 86f1778 commit 0cce16a

File tree

22 files changed

+686
-24
lines changed

22 files changed

+686
-24
lines changed

doc/source/changelog.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@
44
Change Log
55
==========
66

7-
v3.1.0 (2024-03-xx)
7+
v3.1.0 (2024-03-31)
88
===================
99

10-
* Implemented `Prompt before writing to dotfiles when installing completions <https://github.com/django-commons/django-typer/issues/189>`_
10+
* Implemented `Add completer for settings names. <https://github.com/django-commons/django-typer/issues/203>`_
1111
* Fixed `Shell completion tests let failures through in CI <https://github.com/django-commons/django-typer/issues/194>`_
1212
* Fixed `fish completion installs should respect XDG_CONFIG_HOME <https://github.com/django-commons/django-typer/issues/193>`_
1313
* Fixed `zsh completion installs should respect ZDOTDIR <https://github.com/django-commons/django-typer/issues/192>`_
14+
* Implemented `Prompt before writing to dotfiles when installing completions <https://github.com/django-commons/django-typer/issues/189>`_
1415
* Implemented `Support Django 5.2 <https://github.com/django-commons/django-typer/issues/188>`_
1516
* Implemented `Use intersphinx for external document references. <https://github.com/django-commons/django-typer/issues/187>`_
17+
* Implemented `Add completer for language codes. <https://github.com/django-commons/django-typer/issues/186>`_
1618
* Implemented `Switch poetry -> uv <https://github.com/django-commons/django-typer/issues/185>`_
19+
* Implemented `Model object completers should handle fields with choices appropriately <https://github.com/django-commons/django-typer/issues/182>`_
1720
* Implemented `Require tests to pass before release action runs. <https://github.com/django-commons/django-typer/issues/173>`_
1821

1922

doc/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
sys.path.append(str(Path(__file__).parent / 'ext'))
1212

1313
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tests.settings.base')
14-
settings.configure()
14+
#settings.configure()
1515
django.setup()
1616

1717
import django_typer

doc/source/reference/completers.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,6 @@ Completers
2323

2424
.. automodule:: django_typer.completers.path
2525
:members:
26+
27+
.. automodule:: django_typer.completers.settings
28+
:members:

doc/source/reference/shells.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
Shells
77
======
88

9+
.. automodule:: django_typer.shells
10+
:members: DjangoTyperShellCompleter, register_completion_class
11+
912
.. autoclass:: django_typer.shells.bash.BashComplete
1013
:members: name, template, color, supports_scripts
1114

doc/source/shell_completion.rst

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,38 @@ parameter and the :class:`~django_typer.parsers.model.ReturnType` enumeration:
512512
...
513513
514514
515+
Fields with Choices
516+
~~~~~~~~~~~~~~~~~~~
517+
518+
The above examples using :func:`~django_typer.utils.model_parser_completer` will work for fields
519+
with choices. You may however want to avoid the database lookup given that the choice list is
520+
readily available. To do this you could use :func:`~django_typer.completers.these_strings` in
521+
combination with the :class:`~django_typer.parsers.model.ModelObjectParser`:
522+
523+
.. code-block:: python
524+
525+
from django_typer.parsers.model import ModelObjectParser, ReturnType
526+
527+
class Command(TyperCommand):
528+
def handle(
529+
self,
530+
query: Annotated[
531+
QuerySet[ModelClass],
532+
typer.Option(
533+
parser=ModelObjectParser(
534+
ModelClass,
535+
"choice_field,
536+
return_type=ReturnType.QUERY_SET,
537+
),
538+
shell_complete=these_strings(
539+
ModelClass.FIELD_CHOICES,
540+
allow_duplicates=False,
541+
),
542+
help="Fetch objects by their choices for field choice_field.",
543+
),
544+
] = ModelClass.objects.none(),
545+
):
546+
...
515547
516548
Completer Chains
517549
----------------
@@ -542,6 +574,14 @@ be returned, or only the first completer that generates matches.
542574
]
543575
)
544576
577+
Settings
578+
--------
579+
580+
A number of completers are provided that complete values involving settings. These include:
581+
582+
* setting: :func:`~django_typer.completers.settings.setting`
583+
* languages: :func:`~django_typer.completers.settings.languages`
584+
545585

546586
Customizing/Adding Shells
547587
==========================

src/django_typer/completers/__init__.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@
1717
:func:`~django_typer.completers.cmd.commands`.
1818
- **databases**: Complete Django database names using
1919
:func:`~django_typer.completers.db.databases`.
20-
- **import paths**: Complete Django database names using
20+
- **import paths**: Complete python import paths using
2121
:func:`~django_typer.completers.path.import_paths`.
22-
- **paths**: Complete Django database names using
22+
- **paths**: Complete file and directory paths using
2323
:func:`~django_typer.completers.path.paths`.
24-
- **directories**: Complete Django database names using
24+
- **directories**: Complete directories using
2525
:func:`~django_typer.completers.path.directories`.
2626
- **media paths**: Complete Django media paths using
2727
:func:`~django_typer.completers.path.media_paths`.
2828
- **static paths**: Complete Django static paths using
2929
:func:`~django_typer.completers.path.static_paths`.
30+
- **languages**: Complete Django language names using
31+
:func:`~django_typer.completers.settings.languages`.
32+
- **settings**: Complete Django settings variable names using
33+
:func:`~django_typer.completers.settings.setting`.
3034
"""
3135

3236
import typing as t
@@ -36,7 +40,15 @@
3640
from click.shell_completion import CompletionItem
3741

3842
Completer = t.Callable[[Context, Parameter, str], t.List[CompletionItem]]
39-
Strings = t.Union[t.Sequence[str], t.KeysView[str], t.Generator[str, None, None]]
43+
44+
ItemTuple = t.Union[t.Any, t.Tuple[t.Any, t.Any]]
45+
Strings = t.Union[
46+
t.Sequence[ItemTuple],
47+
t.KeysView[t.Any],
48+
t.ValuesView[t.Any],
49+
t.ItemsView[t.Any, t.Any],
50+
t.Generator[ItemTuple, None, None],
51+
]
4052

4153

4254
def these_strings(
@@ -47,25 +59,30 @@ def these_strings(
4759
Get a completer that provides completion logic that matches the allowed strings.
4860
4961
:param strings: A sequence of allowed strings or a callable that generates a
50-
sequence of allowed strings.
62+
sequence of allowed strings. If the sequence contains 2-tuples the second
63+
element is used as the help text for the completion item.
5164
:param allow_duplicates: Whether or not to allow duplicate values. Defaults to
5265
False.
5366
:return: A completer function.
5467
"""
5568

5669
def complete(ctx: Context, param: Parameter, incomplete: str):
5770
present = []
71+
items = []
5872
if (
5973
not allow_duplicates
6074
and param.name
6175
and ctx.get_parameter_source(param.name) is not ParameterSource.DEFAULT
6276
):
6377
present = [value for value in (ctx.params.get(param.name) or [])]
64-
return [
65-
CompletionItem(item)
66-
for item in (strings() if callable(strings) else strings)
67-
if item.startswith(incomplete) and item not in present
68-
]
78+
79+
for item in strings() if callable(strings) else strings:
80+
help = None
81+
if isinstance(item, tuple):
82+
item, help = str(item[0]), str(item[1])
83+
if item.startswith(incomplete) and item not in present:
84+
items.append(CompletionItem(item, help=help))
85+
return items
6986

7087
return complete
7188

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""
2+
Completers that complete items involving Django's settings.
3+
"""
4+
5+
from django.conf import settings
6+
7+
from . import these_strings
8+
9+
setting = these_strings(
10+
lambda: (setting for setting in dir(settings) if setting.isupper()),
11+
allow_duplicates=False,
12+
)
13+
"""
14+
Completes Django :ref:`ref/settings:settings` names. Duplicates are not allowed.
15+
"""
16+
17+
languages = these_strings(
18+
lambda: getattr(settings, "LANGUAGES", []) or [],
19+
allow_duplicates=False,
20+
)
21+
"""
22+
Completes Django language codes using :setting:`LANGUAGES`. Duplicates are not allowed.
23+
"""

src/django_typer/shells/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
from django.template.loader import TemplateDoesNotExist, get_template
1616
from django.utils.translation import gettext as _
1717

18+
__all__ = ["DjangoTyperShellCompleter", "register_completion_class"]
19+
1820
if t.TYPE_CHECKING: # pragma: no cover
1921
from django_typer.management.commands.shellcompletion import (
2022
Command as ShellCompletion,

tests/apps/completion/management/commands/completion.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
static_paths,
1919
media_paths,
2020
)
21+
from django_typer.completers.settings import setting, languages
2122
from django_typer.completers.db import databases
2223
from django_typer.completers.cmd import commands
2324
from django_typer.completers import these_strings, chain
@@ -158,6 +159,22 @@ def handle(
158159
show_default=False,
159160
),
160161
] = "",
162+
languages: Annotated[
163+
t.List[str],
164+
typer.Option(
165+
"--lang",
166+
help=t.cast(str, _("One or more languages.")),
167+
shell_complete=languages,
168+
),
169+
] = [],
170+
setting: Annotated[
171+
t.List[str],
172+
typer.Option(
173+
"--setting",
174+
help=t.cast(str, _("One or more Django setting variables.")),
175+
shell_complete=setting,
176+
),
177+
] = [],
161178
):
162179
assert self.__class__ is Command
163180
for app in django_apps:

tests/apps/dj5plus/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)