-
Notifications
You must be signed in to change notification settings - Fork 8
Implemented argcomplete for tab-completion #127
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
Changes from all commits
cd4d6e9
bf2612a
5886961
1e419fe
63882d3
9598696
5db75ba
bd7e659
87f947f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |
| installation | ||
| philosophy | ||
| usage | ||
| tab-completion | ||
| contributing | ||
| api | ||
| changelog | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| ============== | ||
| Tab-Completion | ||
| ============== | ||
|
|
||
| ``mdacli`` includes built-in support for command-line tab-completion | ||
|
|
||
| Activation | ||
| ========== | ||
|
|
||
| The activation method depends on your shell: | ||
|
|
||
| Bash | ||
| ---- | ||
|
|
||
| **Temporary (current session only)**:: | ||
|
|
||
| eval "$(register-python-argcomplete mda)" | ||
|
|
||
| **Permanent (recommended)** | ||
|
|
||
| Add to your ``~/.bashrc``:: | ||
|
|
||
| echo 'eval "$(register-python-argcomplete mda)"' >> ~/.bashrc | ||
| source ~/.bashrc | ||
|
|
||
| Zsh | ||
| --- | ||
|
|
||
| Add to your ``~/.zshrc``:: | ||
|
|
||
| autoload -U bashcompinit | ||
| bashcompinit | ||
| eval "$(register-python-argcomplete mda)" | ||
|
|
||
| Then reload:: | ||
|
|
||
| source ~/.zshrc | ||
|
|
||
| Fish | ||
| ---- | ||
|
|
||
| Generate the completion file:: | ||
|
|
||
| register-python-argcomplete --shell fish mda > ~/.config/fish/completions/mda.fish | ||
|
|
||
| Restart your Fish shell or run:: | ||
|
|
||
| source ~/.config/fish/config.fish | ||
|
|
||
| Tcsh | ||
| ---- | ||
|
|
||
| Add to your shell startup file:: | ||
|
|
||
| eval `register-python-argcomplete --shell tcsh mda` | ||
|
|
||
| Usage Examples | ||
| ============== | ||
|
|
||
| Once enabled, tab-completion works for: | ||
|
|
||
| **Module names**:: | ||
|
|
||
| mda <TAB> | ||
| # Shows: AlignTraj, AverageStructure, Contacts, DensityAnalysis, ... | ||
|
|
||
| **Partial module names**:: | ||
|
|
||
| mda RM<TAB> | ||
| # Shows: RMSD, RMSF | ||
|
|
||
| **Options and flags**:: | ||
|
|
||
| mda RMSD -<TAB> | ||
| # Shows: -s, -f, -atomgroup, -b, -e, -dt, -v, --debug, --version, ... | ||
|
|
||
| **Case insensitive**:: | ||
|
|
||
| mda rmsd<TAB> # Also works | ||
| mda RmSd<TAB> # Also works | ||
|
|
||
| Troubleshooting | ||
| =============== | ||
|
|
||
| Tab-completion not working | ||
| -------------------------- | ||
|
|
||
| 1. **Verify argcomplete is installed**:: | ||
|
|
||
| python -c "import argcomplete; print(argcomplete.__version__)" | ||
|
|
||
| 2. **Check if activation command was added**:: | ||
|
|
||
| grep "register-python-argcomplete mda" ~/.bashrc | ||
|
|
||
| 3. **Reload your shell**:: | ||
|
|
||
| source ~/.bashrc # or restart terminal | ||
|
|
||
| 4. **Test basic completion**:: | ||
|
|
||
| mda <TAB> | ||
|
|
||
| Still not working | ||
| ----------------- | ||
|
|
||
| - Make sure you've restarted your terminal or sourced the configuration file | ||
| - For Zsh, ensure ``bashcompinit`` is loaded before argcomplete | ||
| - Check that ``mda`` is in your PATH: ``which mda`` | ||
| - Try running the registration command manually in your current shell | ||
|
|
||
| Global activation (for all Python scripts) | ||
| ------------------------------------------- | ||
|
|
||
| To enable argcomplete for all Python scripts at once:: | ||
|
|
||
| activate-global-python-argcomplete | ||
|
|
||
| This requires root/admin privileges and will enable completion system-wide. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #!/usr/bin/env python3 | ||
| # PYTHON_ARGCOMPLETE_OK | ||
| # | ||
| # Copyright (c) 2021 Authors and contributors | ||
| # | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the tests you added didn't really fail even when before the completion was not working we should maybe think about more robust test cases.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous one was checking for setup |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ | |
|
|
||
| import subprocess | ||
| import sys | ||
| from contextlib import suppress | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
|
|
@@ -47,6 +48,83 @@ def test_case_insensitive_with_flags(args): | |
| subprocess.check_call(["mda", "--debug", args, "-h"]) | ||
|
|
||
|
|
||
| def test_subparser_setup_for_tab_completion(): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a nice test. But I think we should also have a test that the argcompletion is really setup. Maybe check the argcomplete repo how they do it.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| """Test that subparsers are correctly set up for tab-completion. | ||
|
|
||
| This verifies that RMSF and RMSD modules are registered as subcommands, | ||
| which is what argcomplete needs for tab-completion to work. | ||
| """ | ||
| from MDAnalysis.analysis.base import AnalysisBase | ||
|
|
||
| from src.mdacli.libcli import find_cls_members, init_base_argparse, setup_clients | ||
|
|
||
| modules = find_cls_members(AnalysisBase, ["MDAnalysis.analysis.rms"]) | ||
|
|
||
| parser = init_base_argparse( | ||
| name="MDAnalysis", version="0.1.0", description="Test CLI" | ||
| ) | ||
|
|
||
| setup_clients(parser, title="MDAnalysis Analysis Modules", members=modules) | ||
|
|
||
| subparser_action = [ | ||
| a for a in parser._subparsers._group_actions if hasattr(a, "choices") | ||
| ][0] | ||
|
|
||
| choices = list(subparser_action.choices.keys()) | ||
| assert "RMSF" in choices | ||
| assert "RMSD" in choices | ||
|
|
||
|
|
||
| def test_argcomplete_working(): | ||
| """Test that argcomplete is properly registered and working.""" | ||
| import argparse | ||
| from unittest.mock import patch | ||
|
|
||
| from MDAnalysis.analysis import __all__ | ||
|
|
||
| import src.mdacli | ||
| from src.mdacli.cli import cli | ||
|
|
||
| skip_mods = [ | ||
| "AnalysisFromFunction", | ||
| "HydrogenBondAnalysis", | ||
| "WaterBridgeAnalysis", | ||
| "Contacts", | ||
| "PersistenceLength", | ||
| "InterRDF_s", | ||
| ] | ||
|
|
||
| with ( | ||
| patch("src.mdacli.cli.argcomplete.autocomplete") as mock_autocomplete, | ||
| patch("sys.argv", ["mda", "--help"]), | ||
| suppress(SystemExit), | ||
| ): | ||
| cli( | ||
| name="MDAnalysis", | ||
| module_list=[f"MDAnalysis.analysis.{m}" for m in __all__], | ||
| version=src.mdacli.__version__, | ||
| description="Test", | ||
| skip_modules=skip_mods, | ||
| ignore_warnings=True, | ||
| ) | ||
|
|
||
| # Verify that argcomplete.autocomplete was called | ||
| assert mock_autocomplete.called, "argcomplete.autocomplete() was not called" | ||
|
|
||
| # Verify it was called with an ArgumentParser instance | ||
| call_args = mock_autocomplete.call_args | ||
| assert call_args is not None, ( | ||
| "argcomplete.autocomplete() was called with no arguments" | ||
| ) | ||
|
|
||
| parser_arg = call_args[0][0] | ||
| msg = ( | ||
| "argcomplete.autocomplete() should be called with ArgumentParser, " | ||
| f"got {type(parser_arg)}" | ||
| ) | ||
| assert isinstance(parser_arg, argparse.ArgumentParser), msg | ||
|
|
||
|
|
||
| def test_running_analysis(tmpdir): | ||
| """Test running a complete analysis.""" | ||
| with tmpdir.as_cwd(): | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.