Skip to content

Commit 47e652f

Browse files
Initial support for argcomplete for KVArgParseConfigLoader (#811)
* Initial support for argcomplete for KVArgParseConfigLoader After enabling argcomplete shell completion for a traitlets.Application based script (e.g. via activate-global-python-argcomplete), this commit sets up tab auto-completion for command-line flags and aliases. Argcomplete completers can be added for a trait by using an "argcompleter" metadata tag, which should have a function that takes keyword arguments (passed down from argcomplete) and returns a list of string completions. Completers are also set up for Bool ("true", "false", "1", "0") & Enum. This commit does *not* add general support for arbitrary class traits of the form --Class.trait=xyz, as these are currently not added to the ArgumentParser instance, but rather directly parsed. It is probably possible to add this support for the classes in Application.classes. Issue: #539 Example: ~/dev/traitlets$ python examples/myapp.py --[TAB] --debug --disable --enable --enabled --help --i --j --log_level --mode --name --running ~/dev/traitlets$ python examples/myapp.py --running [TAB] 0 1 false true ~/dev/traitlets$ python examples/myapp.py --running true --[TAB] --debug --disable --enable --enabled --help --i --j --log_level --mode --name --running ~/dev/traitlets$ python examples/myapp.py --running true --mode o[TAB] off on other * Custom argcomplete.CompletionFinder for class traits This custom finder mainly adds 2 functionalities: 1. When completing options, it will add --Class. to the list of completions, for each class in Application.classes that could complete the current option. 2. If it detects that we are currently trying to complete an option related to --Class., it will add the corresponding config traits of Class to the ArgumentParser instance, so that the traits' completers can be used. (This is currently done in a bit of a hacky manner.) Note that we are avoiding adding all config traits of all classes to the ArgumentParser, which would be easier but would add more runtime overhead and would also make completions appear more spammy. It also does not support nested class options like --Class1.Class2.trait. Example: ~/dev/traitlets$ examples/myapp.py --mode on --[TAB] --Application. --Foo. --debug --enable --help --j --mode --running --Bar. --MyApp. --disable --enabled --i --log_level --name ~/dev/traitlets$ examples/myapp.py --mode on --F[TAB] ~/dev/traitlets$ examples/myapp.py --mode on --Foo.[TAB] --Foo.i --Foo.j --Foo.mode --Foo.name ~/dev/traitlets$ examples/myapp.py --mode on --Foo.m[TAB] ~/dev/traitlets$ examples/myapp.py --mode on --Foo.mode [TAB] ~/dev/traitlets$ examples/myapp.py --mode on --Foo.mode o[TAB] off on other * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Example application for testing argcomplete Added an example application for testing argcomplete, under examples/argcomplete_app.py, with several examples of completions provided in the docstring. Fixed using completers --Class.trait arg1 arg2 [TAB] for config traits with nargs/multiplicity="+". Note that currently traitlets does not support multiplicity even though it is used in the code; refer to issue GH#690 for discussion. Add more comments since we're using argcomplete internals, and add argcomplete as dependency for coverage/mypy tests. Some other minor fixes such as minor mypy annotations fixes. Another example: add # PYTHON_ARGCOMPLETE_OK to bin/ipython, and tab-complete away: $ ipython --[TAB] --Application. --help --BaseFormatter. --i --BaseIPythonApplication. --ignore-cwd --Completer. --init --HistoryAccessor. --ipython-dir --HistoryManager. --log-level --IPCompleter. --logappend --InteractiveShell. --logfile --InteractiveShellApp. --m ... $ ipython --gui=[TAB] asyncio gtk gtk3 pyglet qt4 tk glut gtk2 osx qt qt5 wx To-do still: support subcommands. This may still take some work as traitlets does subcommand parsing independently of argparse. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Initial traitlets subcommand support for argcomplete argcomplete's strategy is to call the python script with no arguments e.g. len(sys.argv) == 1, run until the ArgumentParser is constructed and determine what completions are available. On the other hand, traitlet's subcommand-handling strategy is to check sys.argv[1] and see if it matches a subcommand, and if so then dynamically load the subcommand app and initialize it with sys.argv[1:]. Write a couple of helper functions to reconcile this by: 1. retrieving tokens from $COMP_LINES, etc, and setting it to argv 2. if traitlets descends into a subcommand, increment index passed via env var to argcomplete to mark where command starts There's quite a few caveats to this approach. For example, it only is evaluated currently when `App.initialize()` is passed with `argv=None` (the default). If `argv` is explicitly passed, then the `argcomplete`-specific handling is skipped currently. More details in: #811 (comment) Some additional minor cleanup with respect to subcommands typing, examples, and documentation. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Documentation updates Add docs for argcomplete, and various fixes and improvements to other docs such as examples for flags/aliases/subcommands. Update docs for building docs. Also fix a bug when argcomplete is not installed * noqa for import argcomplete, more doc updates * Fix ruff removing argcomplete import check * Add example scripts corresponding to examples in docs * Add new sections to docs to further explain Application configuration, methods, and philosophy. Closes: #707, #708, #709, #712 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add unit tests for argcomplete & Application Borrow argcomplete's unit test fixtures to set up unit testing for completion of Application commands. Test a few cases of custom completers; caught a bug with Enum.argcompleter() * Lint fixes Fix some errors from hatch run typing:test and some other minor formatting / CI fixes. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix argcomplete unit tests for argcomplete >= 2.0 argcomplete >= 2.0 was very recently released, and changes internal output_stream to text mode instead of bytes; fix unit test for this and some other minor fixes. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Skip failing unit tests? These tests run for me locally, but currently CI raises OSError: Bad file descriptor. Something with temp files perhaps? * More fixes to appease ruff * Restore argcomplete unit tests They were failing on some issue with TemporaryFile, trying again now. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Minor, fix mdformat lint sourcecode -> code-block * Use StringIO instead of TemporaryFile for argcomplete unit tests TemporaryFile was causing some OSError(9) Bad file descriptor on flush, not sure why but using StringIO seems to work perfectly fine instead. * Require argcomplete>=2.0 for tests Only use StringIO instead of BytesIO for argcomplete >= 2.0. Stop relying on SystemExit which might be messing with pytest, instead raise a CustomError. Other minor doc fixes. * Disable _ARC_DEBUG still trying to get pytest to not crash at the end .. * Add pytest-mock and mock os.fdopen for argcomplete argcomplete==2.0.0 always calls fdopen(9, "w") to open a debug stream, however this could conflict with file descriptors used by pytest and lead to obscure errors. Since we are not looking at debug stream in these tests, just mock this fdopen call out. * Fix pyproject.toml changes, a few more examples/docs Polish up a bit more docs about Application and commit corresponding examples. * Ignore examples/docs/configs/ from pytest, mypy config.py files have get_config, load_subconfig injected so have to get them ignored from pytest collection and mypy checking. Also minor, added some pathlib support to load_config_file(). * Update corresponding example configs paths in docs Also link to some examples and add initial CHANGELOG entry. * Undo changelog.md for release Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 928ec87 commit 47e652f

22 files changed

+1331
-104
lines changed

docs/readme-docs.md

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,38 @@
11
# Documenting traitlets
22

3-
[Documentation for `traitlets`](https://traitlets.readthedocs.io/en/latest/)
4-
is hosted on ReadTheDocs.
3+
[Documentation for `traitlets`](https://traitlets.readthedocs.io/en/latest/) is hosted on ReadTheDocs.
54

65
## Build documentation locally
76

8-
#### Change directory to documentation root:
7+
With [`hatch`](https://hatch.pypa.io/), one can build environments, docs, and serve it in one command:
98

109
```
11-
cd docs
10+
pip install hatch
11+
hatch run docs:build
1212
```
1313

14-
#### Create environment
14+
#### Build documentation manually
1515

16-
- \[**conda**\] Create conda env (and install relevant dependencies):
16+
Otherwise to build docs manually,
1717

18-
```
19-
conda env create -f environment.yml
20-
```
18+
```
19+
cd docs
20+
```
2121

22-
- \[**pip**\] Create virtual environment (and install relevant dependencies):
22+
Create virtual environment (and install relevant dependencies):
2323

24-
```
24+
```
2525
virtualenv traitlets_docs -p python3
26-
pip install -r requirements.txt
27-
```
28-
29-
#### Activate the newly built environment `traitlets_docs`
30-
31-
- \[**conda**\] Activate conda env:
32-
33-
```
34-
source activate traitlets_docs
35-
```
26+
pip install -r traitlets[docs]
27+
```
3628

37-
- \[**pip**\] The virtualenv should have been automatically activated. If
38-
not:
29+
The virtualenv should have been automatically activated. If not:
3930

40-
```
41-
source activate
42-
```
31+
```
32+
source activate
33+
```
4334

44-
#### Build documentation using:
35+
##### Build documentation using:
4536

4637
- Makefile for Linux and OS X:
4738

@@ -55,7 +46,7 @@ cd docs
5546
make.bat html
5647
```
5748

58-
#### Display the documentation locally
49+
##### Display the documentation locally
5950

6051
- Navigate to `build/html/index.html` in your browser.
6152

@@ -77,5 +68,3 @@ cd docs
7768
- `source/conf.py` - Sphinx build configuration file
7869
- `source` directory - source for documentation
7970
- `source/index.rst` - Main landing page of the Sphinx documentation
80-
- `requirements.txt` - list of packages to install when using pip
81-
- `environment.yml` - list of packages to install when using conda

0 commit comments

Comments
 (0)