|
26 | 26 | from uuid import UUID |
27 | 27 |
|
28 | 28 | from click import Context, Parameter |
| 29 | +from click.core import ParameterSource |
29 | 30 | from click.shell_completion import CompletionItem |
30 | 31 | from django.apps import apps |
31 | 32 | from django.conf import settings |
@@ -321,7 +322,12 @@ def __call__( |
321 | 322 | return [] |
322 | 323 |
|
323 | 324 | excluded: t.List[t.Type[Model]] = [] |
324 | | - if self.distinct and parameter.name: |
| 325 | + if ( |
| 326 | + self.distinct |
| 327 | + and parameter.name |
| 328 | + and context.get_parameter_source(parameter.name) |
| 329 | + is not ParameterSource.DEFAULT |
| 330 | + ): |
325 | 331 | excluded = context.params.get(parameter.name, []) or [] |
326 | 332 |
|
327 | 333 | return [ |
@@ -380,7 +386,12 @@ def handle( |
380 | 386 | :return: A list of matching app labels or names. Labels already present for the |
381 | 387 | parameter on the command line will be filtered out. |
382 | 388 | """ |
383 | | - present = [app.label for app in (ctx.params.get(param.name or "") or [])] |
| 389 | + present = [] |
| 390 | + if ( |
| 391 | + param.name |
| 392 | + and ctx.get_parameter_source(param.name) is not ParameterSource.DEFAULT |
| 393 | + ): |
| 394 | + present = [app.label for app in (ctx.params.get(param.name) or [])] |
384 | 395 | ret = [ |
385 | 396 | CompletionItem(app.label) |
386 | 397 | for app in apps.get_app_configs() |
@@ -503,29 +514,38 @@ def exists(pth: Path) -> bool: |
503 | 514 | """ |
504 | 515 |
|
505 | 516 |
|
506 | | -def these_strings(strings: t.List[str], allow_duplicates: bool = False): |
| 517 | +def these_strings( |
| 518 | + strings: t.Union[t.Callable[[], t.Sequence[str]], t.Sequence[str]], |
| 519 | + allow_duplicates: bool = False, |
| 520 | +): |
507 | 521 | """ |
508 | 522 | Get a completer that provides completion logic that matches the allowed strings. |
509 | 523 |
|
510 | | - :param strings: A list of allowed strings. |
| 524 | + :param strings: A sequence of allowed strings or a callable that generates a sequence of |
| 525 | + allowed strings. |
511 | 526 | :param allow_duplicates: Whether or not to allow duplicate values. Defaults to False. |
512 | 527 | :return: A completer function. |
513 | 528 | """ |
514 | 529 |
|
515 | 530 | def complete(ctx: Context, param: Parameter, incomplete: str): |
516 | 531 | present = [] |
517 | | - if not allow_duplicates: |
518 | | - present = [value for value in (ctx.params.get(param.name or "") or [])] |
| 532 | + if ( |
| 533 | + not allow_duplicates |
| 534 | + and param.name |
| 535 | + and ctx.get_parameter_source(param.name) is not ParameterSource.DEFAULT |
| 536 | + ): |
| 537 | + present = [value for value in (ctx.params.get(param.name) or [])] |
519 | 538 | return [ |
520 | 539 | CompletionItem(item) |
521 | | - for item in strings |
| 540 | + for item in (strings() if callable(strings) else strings) |
522 | 541 | if item.startswith(incomplete) and item not in present |
523 | 542 | ] |
524 | 543 |
|
525 | 544 | return complete |
526 | 545 |
|
527 | 546 |
|
528 | | -databases = these_strings([alias for alias in settings.DATABASES.keys()]) |
| 547 | +# use a function that returns a generator because we should not access settings on import |
| 548 | +databases = these_strings(lambda: settings.DATABASES.keys()) |
529 | 549 | """ |
530 | 550 | A completer that provides completion logic for the Django database aliases |
531 | 551 | configured in settings.DATABASES. |
|
0 commit comments