Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-argcomplete for 
openSUSE:Factory checked in at 2026-10-23 20:20:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-argcomplete (Old)
 and      /work/SRC/openSUSE:Factory/.python-argcomplete.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-argcomplete"

Fri Oct 23 20:20:55 2026 rev:46 rq:1386544 version:3.7.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-argcomplete/python-argcomplete.changes    
2026-02-11 18:53:31.313171699 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-argcomplete.new.2252680/python-argcomplete.changes
       2026-10-23 20:21:05.442477055 +0200
@@ -1,0 +2,15 @@
+Sat Oct 17 15:42:36 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to 3.7.2:
+  * Require Python 3.10+
+  * Fix zsh global completion with zsh 5.9.0.1; expand ~ in
+    _FilteredFilesCompleter
+  * Escape glob and brace metacharacters in quote_completions;
+    quote compgen prefix in FilesCompleter
+  * Remove deprecated easy_install script detection
+- Drop python-argcomplete-check-easy-install-script and its
+  libalternatives registrations, removed upstream
+- Remove the /usr/bin/env python3 shebang from the non-executable
+  argcomplete/scripts modules
+
+-------------------------------------------------------------------

Old:
----
  argcomplete-3.6.3.tar.gz

New:
----
  argcomplete-3.7.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-argcomplete.spec ++++++
--- /var/tmp/diff_new_pack.Fskhsq/_old  2026-10-23 20:21:06.096504425 +0200
+++ /var/tmp/diff_new_pack.Fskhsq/_new  2026-10-23 20:21:06.098504508 +0200
@@ -33,13 +33,13 @@
 %{?pythons_for_pypi}
 %{?sle15_python_module_pythons}
 Name:           python-argcomplete%{psuffix}
-Version:        3.6.3
+Version:        3.7.2
 Release:        0
 Summary:        Bash tab completion for argparse
 License:        Apache-2.0
 URL:            https://github.com/kislyuk/argcomplete
 Source:         
https://files.pythonhosted.org/packages/source/a/argcomplete/argcomplete-%{version}.tar.gz
-BuildRequires:  %{python_module base >= 3.8}
+BuildRequires:  %{python_module base >= 3.10}
 BuildRequires:  %{python_module hatchling}
 BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module setuptools >= 67.2}
@@ -80,6 +80,8 @@
 
 %prep
 %autosetup -p1 -n argcomplete-%{version}
+# imported via the entry points and installed non-executable
+sed -i '1{/^#!/d}' argcomplete/scripts/*.py
 
 %build
 %if %{without test}
@@ -91,7 +93,6 @@
 %pyproject_install
 %python_clone -a %{buildroot}%{_bindir}/activate-global-python-argcomplete
 %python_clone -a %{buildroot}%{_bindir}/register-python-argcomplete
-%python_clone -a 
%{buildroot}%{_bindir}/python-argcomplete-check-easy-install-script
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 %python_expand chmod -x %{buildroot}%{$python_sitelib}/argcomplete/scripts/*.py
 %endif
@@ -118,17 +119,14 @@
 %pre
 %python_libalternatives_reset_alternative activate-global-python-argcomplete
 %python_libalternatives_reset_alternative register-python-argcomplete
-%python_libalternatives_reset_alternative 
python-argcomplete-check-easy-install-script
 
 %post
 %python_install_alternative activate-global-python-argcomplete
 %python_install_alternative register-python-argcomplete
-%python_install_alternative python-argcomplete-check-easy-install-script
 
 %postun
 %python_uninstall_alternative activate-global-python-argcomplete
 %python_uninstall_alternative register-python-argcomplete
-%python_uninstall_alternative python-argcomplete-check-easy-install-script
 
 %files %{python_files}
 %doc README.rst
@@ -136,7 +134,6 @@
 %{python_sitelib}/argcomplete-%{version}.dist-info
 %{python_sitelib}/argcomplete
 %python_alternative %{_bindir}/activate-global-python-argcomplete
-%python_alternative %{_bindir}/python-argcomplete-check-easy-install-script
 %python_alternative %{_bindir}/register-python-argcomplete
 %endif
 

++++++ argcomplete-3.6.3.tar.gz -> argcomplete-3.7.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/.github/workflows/ci.yml 
new/argcomplete-3.7.2/.github/workflows/ci.yml
--- old/argcomplete-3.6.3/.github/workflows/ci.yml      2020-02-02 
01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/.github/workflows/ci.yml      2020-02-02 
01:00:00.000000000 +0100
@@ -3,17 +3,17 @@
 on: [push, pull_request]
 
 jobs:
-  build:
+  ci:
     runs-on: ${{matrix.os}}
     strategy:
       fail-fast: false
       matrix:
-        os: [ubuntu-20.04, ubuntu-latest, macos-13, macos-latest]
-        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
+        os: [ubuntu-22.04, ubuntu-latest, macos-14, macos-latest]
+        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
 
     steps:
-    - uses: actions/checkout@v4
-    - uses: actions/setup-python@v4
+    - uses: actions/checkout@v7
+    - uses: actions/setup-python@v6
       with:
         python-version: ${{matrix.python-version}}
         allow-prereleases: true
@@ -31,15 +31,15 @@
     - uses: codecov/codecov-action@v5
       if: ${{matrix.python-version == '3.12' && matrix.os == 'ubuntu-22.04'}}
   isort:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-24.04
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v7
       - uses: isort/[email protected]
   ruff:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v4
-      - uses: astral-sh/ruff-action@v1
-      - uses: astral-sh/ruff-action@v1
+      - uses: actions/checkout@v7
+      - uses: astral-sh/[email protected]
+      - uses: astral-sh/[email protected]
         with:
           args: "format --check"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/Changes.rst 
new/argcomplete-3.7.2/Changes.rst
--- old/argcomplete-3.6.3/Changes.rst   2020-02-02 01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/Changes.rst   2020-02-02 01:00:00.000000000 +0100
@@ -1,3 +1,24 @@
+Changes for v3.7.2 (2026-08-05)
+===============================
+
+Require Python 3.10+ (#558)
+
+Changes for v3.7.1 (2026-08-04)
+===============================
+
+-  Fix for kislyuk#544 => TestZshGlobalExplicit tests are failing after
+   upgrade to zsh 5.9.0.1 (#557)
+
+-  Expand ~ in \_FilteredFilesCompleter (DirectoriesCompleter) (#553)
+
+Changes for v3.7.0 (2026-06-30)
+===============================
+
+-  Escape glob and brace metacharacters in quote_completions (#552)
+-  Quote prefix passed to compgen in FilesCompleter (#551)
+-  Remove deprecated easy_install script detection
+-  Type hinting improvements
+
 Changes for v3.6.3 (2025-10-19)
 ===============================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/PKG-INFO 
new/argcomplete-3.7.2/PKG-INFO
--- old/argcomplete-3.6.3/PKG-INFO      2020-02-02 01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/PKG-INFO      2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: argcomplete
-Version: 3.6.3
+Version: 3.7.2
 Summary: Bash tab completion for argparse
 Project-URL: Homepage, https://github.com/kislyuk/argcomplete
 Project-URL: Documentation, https://kislyuk.github.io/argcomplete
@@ -22,19 +22,18 @@
 Classifier: Operating System :: POSIX
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Software Development
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
 Classifier: Topic :: System :: Shells
 Classifier: Topic :: Terminals
-Requires-Python: >=3.8
+Requires-Python: >=3.10
 Provides-Extra: test
 Requires-Dist: coverage; extra == 'test'
 Requires-Dist: mypy; extra == 'test'
@@ -298,7 +297,7 @@
 
 Python Support
 --------------
-Argcomplete requires Python 3.9+.
+Argcomplete requires Python 3.10+.
 
 Support for other shells
 ------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/README.rst 
new/argcomplete-3.7.2/README.rst
--- old/argcomplete-3.6.3/README.rst    2020-02-02 01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/README.rst    2020-02-02 01:00:00.000000000 +0100
@@ -253,7 +253,7 @@
 
 Python Support
 --------------
-Argcomplete requires Python 3.9+.
+Argcomplete requires Python 3.10+.
 
 Support for other shells
 ------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/argcomplete/__init__.py 
new/argcomplete-3.7.2/argcomplete/__init__.py
--- old/argcomplete-3.6.3/argcomplete/__init__.py       2020-02-02 
01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/argcomplete/__init__.py       2020-02-02 
01:00:00.000000000 +0100
@@ -9,5 +9,5 @@
 from .lexers import split_line
 from .shell_integration import shellcode
 
-autocomplete = CompletionFinder()
+autocomplete: CompletionFinder = CompletionFinder()
 autocomplete.__doc__ = """ Use this to access argcomplete. See 
:meth:`argcomplete.CompletionFinder.__call__()`. """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/argcomplete-3.6.3/argcomplete/bash_completion.d/_python-argcomplete 
new/argcomplete-3.7.2/argcomplete/bash_completion.d/_python-argcomplete
--- old/argcomplete-3.6.3/argcomplete/bash_completion.d/_python-argcomplete     
2020-02-02 01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/argcomplete/bash_completion.d/_python-argcomplete     
2020-02-02 01:00:00.000000000 +0100
@@ -145,9 +145,13 @@
         req_argv=( "" "${COMP_WORDS[@]:1}" )
         __python_argcomplete_expand_tilde_by_ref executable
     else
-        executable="${words[1]}"
+        # Reconstruct the unshifted words array from BUFFER to handle cases 
where
+        # a helper completion function (like _python) has shifted the words 
array.
+        local -a local_words
+        local_words=( ${(z)BUFFER} )
+        executable="${local_words[1]}"
         __python_argcomplete_expand_tilde_by_ref executable
-        req_argv=( "${words[@]:1}" )
+        req_argv=( "${local_words[@]:1}" )
     fi
 
     local ARGCOMPLETE=0
@@ -190,10 +194,7 @@
                 interpreter=($interpreter)
             fi
 
-            if (__python_argcomplete_scan_head_noerr "$SCRIPT_NAME" 
easy_install \
-                && "${interpreter[@]}" "$(__python_argcomplete_which 
python-argcomplete-check-easy-install-script)" "$SCRIPT_NAME") >/dev/null 2>&1; 
then
-                ARGCOMPLETE=1
-            elif ([[ "${interpreter[@]}" == *python* ]] || [[ 
"${interpreter[@]}" == *pypy* ]])\
+            if ([[ "${interpreter[@]}" == *python* ]] || [[ 
"${interpreter[@]}" == *pypy* ]])\
                 && __python_argcomplete_run "${interpreter[@]}" -m 
argcomplete._check_console_script "$SCRIPT_NAME"; then
                 ARGCOMPLETE=1
             fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/argcomplete/completers.py 
new/argcomplete-3.7.2/argcomplete/completers.py
--- old/argcomplete-3.6.3/argcomplete/completers.py     2020-02-02 
01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/argcomplete/completers.py     2020-02-02 
01:00:00.000000000 +0100
@@ -4,6 +4,11 @@
 import argparse
 import os
 import subprocess
+from collections.abc import Callable, Generator, Iterable, Mapping
+from shlex import quote
+from typing import Final
+
+_Ignored = object
 
 
 def _call(*args, **kwargs):
@@ -22,12 +27,14 @@
 
     def __call__(
         self, *, prefix: str, action: argparse.Action, parser: 
argparse.ArgumentParser, parsed_args: argparse.Namespace
-    ) -> None:
+    ) -> Iterable[str]:
         raise NotImplementedError("This method should be implemented by a 
subclass.")
 
 
 class ChoicesCompleter(BaseCompleter):
-    def __init__(self, choices):
+    choices: Final[Mapping[str, str | bytes]]
+
+    def __init__(self, choices: Mapping[str, str | bytes]) -> None:
         self.choices = choices
 
     def _convert(self, choice):
@@ -35,11 +42,11 @@
             choice = str(choice)
         return choice
 
-    def __call__(self, **kwargs):
+    def __call__(self, **kwargs: _Ignored) -> Iterable[str]:
         return (self._convert(c) for c in self.choices)
 
 
-EnvironCompleter = ChoicesCompleter(os.environ)
+EnvironCompleter: Final[ChoicesCompleter] = ChoicesCompleter(os.environ)
 
 
 class FilesCompleter(BaseCompleter):
@@ -47,7 +54,10 @@
     File completer class, optionally takes a list of allowed extensions
     """
 
-    def __init__(self, allowednames=(), directories=True):
+    allowednames: Final[list[str]]
+    directories: Final[bool]
+
+    def __init__(self, allowednames: Iterable[str] | str = (), directories: 
bool = True) -> None:
         # Fix if someone passes in a string instead of a list
         if isinstance(allowednames, (str, bytes)):
             allowednames = [allowednames]
@@ -55,8 +65,8 @@
         self.allowednames = [x.lstrip("*").lstrip(".") for x in allowednames]
         self.directories = directories
 
-    def __call__(self, prefix, **kwargs):
-        completion = []
+    def __call__(self, prefix: str, **kwargs: _Ignored) -> list[str]:
+        completion: list[str] = []
         if self.allowednames:
             if self.directories:
                 # Using 'bind' in this and the following commands is a 
workaround to a bug in bash
@@ -64,20 +74,22 @@
                 # correctly in older versions and calling bind makes them 
available. For details, see
                 # https://savannah.gnu.org/support/index.php?111125
                 files = _call(
-                    ["bash", "-c", "bind; compgen -A directory -- 
'{p}'".format(p=prefix)], stderr=subprocess.DEVNULL
+                    ["bash", "-c", "bind; compgen -A directory -- 
{p}".format(p=quote(prefix))],
+                    stderr=subprocess.DEVNULL,
                 )
                 completion += [f + "/" for f in files]
             for x in self.allowednames:
                 completion += _call(
-                    ["bash", "-c", "bind; compgen -A file -X '!*.{0}' -- 
'{p}'".format(x, p=prefix)],
+                    ["bash", "-c", "bind; compgen -A file -X '!*.{0}' -- 
{p}".format(x, p=quote(prefix))],
                     stderr=subprocess.DEVNULL,
                 )
         else:
             completion += _call(
-                ["bash", "-c", "bind; compgen -A file -- 
'{p}'".format(p=prefix)], stderr=subprocess.DEVNULL
+                ["bash", "-c", "bind; compgen -A file -- 
{p}".format(p=quote(prefix))], stderr=subprocess.DEVNULL
             )
             anticomp = _call(
-                ["bash", "-c", "bind; compgen -A directory -- 
'{p}'".format(p=prefix)], stderr=subprocess.DEVNULL
+                ["bash", "-c", "bind; compgen -A directory -- 
{p}".format(p=quote(prefix))],
+                stderr=subprocess.DEVNULL,
             )
             completion = list(set(completion) - set(anticomp))
 
@@ -87,26 +99,31 @@
 
 
 class _FilteredFilesCompleter(BaseCompleter):
-    def __init__(self, predicate):
+    predicate: Final[Callable[[str], bool]]
+
+    def __init__(self, predicate: Callable[[str], bool]) -> None:
         """
         Create the completer
 
         A predicate accepts as its only argument a candidate path and either
         accepts it or rejects it.
         """
-        assert predicate, "Expected a callable predicate"
+        assert predicate, "Expected a callable predicate"  # type: 
ignore[truthy-function]
         self.predicate = predicate
 
-    def __call__(self, prefix, **kwargs):
+    def __call__(self, prefix: str, **kwargs: _Ignored) -> Generator[str]:
         """
         Provide completions on prefix
         """
-        target_dir = os.path.dirname(prefix)
+        # Expand a leading "~" so that filesystem operations below work on a
+        # real path (os.listdir("~") would otherwise raise FileNotFoundError).
+        expanded_prefix = os.path.expanduser(prefix)
+        target_dir = os.path.dirname(expanded_prefix)
         try:
             names = os.listdir(target_dir or ".")
         except Exception:
             return  # empty iterator
-        incomplete_part = os.path.basename(prefix)
+        incomplete_part = os.path.basename(expanded_prefix)
         # Iterate on target_dir entries and filter on given predicate
         for name in names:
             if not name.startswith(incomplete_part):
@@ -118,7 +135,7 @@
 
 
 class DirectoriesCompleter(_FilteredFilesCompleter):
-    def __init__(self):
+    def __init__(self) -> None:
         _FilteredFilesCompleter.__init__(self, predicate=os.path.isdir)
 
 
@@ -127,10 +144,10 @@
     A completer used to suppress the completion of specific arguments
     """
 
-    def __init__(self):
+    def __init__(self) -> None:
         pass
 
-    def suppress(self):
+    def suppress(self) -> bool:
         """
         Decide if the completion should be suppressed
         """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/argcomplete/finders.py 
new/argcomplete-3.7.2/argcomplete/finders.py
--- old/argcomplete-3.6.3/argcomplete/finders.py        2020-02-02 
01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/argcomplete/finders.py        2020-02-02 
01:00:00.000000000 +0100
@@ -6,8 +6,8 @@
 import argparse
 import os
 import sys
-from collections.abc import Mapping
-from typing import Callable, Dict, List, Optional, Sequence, TextIO, Union
+from collections.abc import Container, Mapping
+from typing import Callable, Literal, TextIO
 
 from . import io as _io
 from .completers import BaseCompleter, ChoicesCompleter, FilesCompleter, 
SuppressCompleter
@@ -26,28 +26,42 @@
 }
 
 
-def default_validator(completion, prefix):
+def default_validator(completion: str, prefix: str) -> bool:
     return completion.startswith(prefix)
 
 
-class CompletionFinder(object):
+class CompletionFinder:
     """
     Inherit from this class if you wish to override any of the stages below. 
Otherwise, use
     ``argcomplete.autocomplete()`` directly (it's a convenience instance of 
this class). It has the same signature as
     :meth:`CompletionFinder.__call__()`.
     """
 
+    _parser: argparse.ArgumentParser | None
+    _formatter: argparse.HelpFormatter | None
+    always_complete_options: bool | Literal["long", "short"]
+    exclude: Container[str] | None
+    validator: Callable[[str, str], bool]
+    print_suppressed: bool
+    completing: bool
+    _display_completions: dict[str, str]
+    default_completer: BaseCompleter
+    append_space: bool
+
+    active_parsers: list[argparse.ArgumentParser]
+    visited_positionals: list[argparse.Action]
+
     def __init__(
         self,
-        argument_parser=None,
-        always_complete_options=True,
-        exclude=None,
-        validator=None,
-        print_suppressed=False,
-        default_completer=FilesCompleter(),
-        append_space=None,
-    ):
-        self._parser = argument_parser
+        argument_parser: argparse.ArgumentParser | None = None,
+        always_complete_options: bool | Literal["long", "short"] = True,
+        exclude: Container[str] | None = None,
+        validator: Callable[[str, str], bool] | None = None,
+        print_suppressed: bool = False,
+        default_completer: BaseCompleter = FilesCompleter(),
+        append_space: bool | None = None,
+    ) -> None:
+        self._parser = argument_parser  # type: ignore[assignment]
         self._formatter = None
         self.always_complete_options = always_complete_options
         self.exclude = exclude
@@ -56,7 +70,7 @@
         self.validator = validator
         self.print_suppressed = print_suppressed
         self.completing = False
-        self._display_completions: Dict[str, str] = {}
+        self._display_completions = {}
         self.default_completer = default_completer
         if append_space is None:
             append_space = os.environ.get("_ARGCOMPLETE_SUPPRESS_SPACE") != "1"
@@ -65,13 +79,13 @@
     def __call__(
         self,
         argument_parser: argparse.ArgumentParser,
-        always_complete_options: Union[bool, str] = True,
+        always_complete_options: bool | str = True,
         exit_method: Callable = os._exit,
-        output_stream: Optional[TextIO] = None,
-        exclude: Optional[Sequence[str]] = None,
-        validator: Optional[Callable] = None,
+        output_stream: TextIO | None = None,
+        exclude: Container[str] | None = None,
+        validator: Callable[[str, str], bool] | None = None,
         print_suppressed: bool = False,
-        append_space: Optional[bool] = None,
+        append_space: bool | None = None,
         default_completer: BaseCompleter = FilesCompleter(),
     ) -> None:
         """
@@ -158,6 +172,7 @@
         start = int(os.environ["_ARGCOMPLETE"]) - 1
         comp_words = comp_words[start:]
 
+        assert self._parser is not None
         if cword_prefix and cword_prefix[0] in self._parser.prefix_chars and 
"=" in cword_prefix:
             # Special case for when the current word is 
"--optional=PARTIAL_VALUE". Give the optional to the parser.
             comp_words.append(cword_prefix.split("=", 1)[0])
@@ -211,6 +226,7 @@
         try:
             debug("invoking parser with", comp_words[1:])
             with mute_stderr():
+                assert self._parser is not None
                 a = self._parser.parse_known_args(comp_words[1:], 
namespace=parsed_args)
             debug("parsed args:", a)
         except BaseException as e:
@@ -233,8 +249,8 @@
         figure out which subparsers need to be activated (then recursively 
monkey-patch those).
         We save all active ArgumentParsers to extract all their possible 
option names later.
         """
-        self.active_parsers: List[argparse.ArgumentParser] = []
-        self.visited_positionals: List[argparse.Action] = []
+        self.active_parsers = []
+        self.visited_positionals = []
 
         completer = self
 
@@ -289,12 +305,14 @@
             return ""
         if "%" not in action.help:
             return action.help
-        if self._formatter is None:
-            self._formatter = 
self._parser.formatter_class(prog=self._parser.prog)
-        return self._formatter._expand_help(action)
+        formatters = self._formatter
+        if formatters is None:
+            assert self._parser is not None
+            self._formatter = formatters = 
self._parser.formatter_class(prog=self._parser.prog)
+        return formatters._expand_help(action)
 
     def _get_subparser_completions(self, parser, cword_prefix):
-        aliases_by_parser: Dict[argparse.ArgumentParser, List[str]] = {}
+        aliases_by_parser: dict[argparse.ArgumentParser, list[str]] = {}
         for key in parser.choices.keys():
             p = parser.choices[key]
             aliases_by_parser.setdefault(p, []).append(key)
@@ -433,15 +451,15 @@
         return completions
 
     def collect_completions(
-        self, active_parsers: List[argparse.ArgumentParser], parsed_args: 
argparse.Namespace, cword_prefix: str
-    ) -> List[str]:
+        self, active_parsers: list[argparse.ArgumentParser], parsed_args: 
argparse.Namespace, cword_prefix: str
+    ) -> list[str]:
         """
         Visits the active parsers and their actions, executes their completers 
or introspects them to collect their
         option strings. Returns the resulting completions as a list of strings.
 
         This method is exposed for overriding in subclasses; there is no need 
to use it directly.
         """
-        completions: List[str] = []
+        completions: list[str] = []
 
         debug("all active parsers:", active_parsers)
         active_parser = active_parsers[-1]
@@ -488,7 +506,7 @@
 
         return None
 
-    def filter_completions(self, completions: List[str]) -> List[str]:
+    def filter_completions(self, completions: list[str]) -> list[str]:
         """
         De-duplicates completions and excludes those specified by ``exclude``.
         Returns the filtered completions as a list.
@@ -505,8 +523,8 @@
         return filtered_completions
 
     def quote_completions(
-        self, completions: List[str], cword_prequote: str, last_wordbreak_pos: 
Optional[int]
-    ) -> List[str]:
+        self, completions: list[str], cword_prequote: str, last_wordbreak_pos: 
int | None
+    ) -> list[str]:
         """
         If the word under the cursor started with a quote (as indicated by a 
nonempty ``cword_prequote``), escapes
         occurrences of that quote character in the completions, and adds the 
quote to the beginning of each completion.
@@ -527,7 +545,7 @@
             # (extended to characters other than the colon).
             if last_wordbreak_pos is not None:
                 completions = [c[last_wordbreak_pos + 1 :] for c in 
completions]
-            special_chars += "();<>|&!`$* \t\n\"'"
+            special_chars += "();<>|&!`$*?[]{} \t\n\"'"
         elif cword_prequote == '"':
             special_chars += '"`$!'
 
@@ -570,7 +588,7 @@
 
         return escaped_completions
 
-    def rl_complete(self, text, state):
+    def rl_complete(self, text: str, state: int) -> str | None:
         """
         Alternate entry point for using the argcomplete completer in a 
readline-based REPL. See also
         `rlcompleter 
<https://docs.python.org/3/library/rlcompleter.html#completer-objects>`_.
@@ -598,7 +616,7 @@
         else:
             return None
 
-    def get_display_completions(self):
+    def get_display_completions(self) -> dict[str, str]:
         """
         This function returns a mapping of completions to their help strings 
for displaying to the user.
         """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/argcomplete/io.py 
new/argcomplete-3.7.2/argcomplete/io.py
--- old/argcomplete-3.6.3/argcomplete/io.py     2020-02-02 01:00:00.000000000 
+0100
+++ new/argcomplete-3.7.2/argcomplete/io.py     2020-02-02 01:00:00.000000000 
+0100
@@ -1,19 +1,20 @@
 import contextlib
 import os
 import sys
+from collections.abc import Generator
 
 _DEBUG = "_ARC_DEBUG" in os.environ
 
 debug_stream = sys.stderr
 
 
-def debug(*args):
+def debug(*args: object) -> None:
     if _DEBUG:
         print(file=debug_stream, *args)
 
 
 @contextlib.contextmanager
-def mute_stdout():
+def mute_stdout() -> Generator[None]:
     stdout = sys.stdout
     sys.stdout = open(os.devnull, "w")
     try:
@@ -23,7 +24,7 @@
 
 
 @contextlib.contextmanager
-def mute_stderr():
+def mute_stderr() -> Generator[None]:
     stderr = sys.stderr
     sys.stderr = open(os.devnull, "w")
     try:
@@ -33,7 +34,7 @@
         sys.stderr = stderr
 
 
-def warn(*args):
+def warn(*args: object) -> None:
     """
     Prints **args** to standard error when running completions. This will 
interrupt the user's command line interaction;
     use it to indicate an error condition that is preventing your completer 
from working.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/argcomplete/lexers.py 
new/argcomplete-3.7.2/argcomplete/lexers.py
--- old/argcomplete-3.6.3/argcomplete/lexers.py 2020-02-02 01:00:00.000000000 
+0100
+++ new/argcomplete-3.7.2/argcomplete/lexers.py 2020-02-02 01:00:00.000000000 
+0100
@@ -5,7 +5,7 @@
 from .packages import _shlex
 
 
-def split_line(line, point=None):
+def split_line(line: str, point: int | None = None) -> tuple[str, str, str, 
list[str], int | None]:
     if point is None:
         point = len(line)
     line = line[:point]
@@ -14,7 +14,7 @@
     lexer.wordbreaks = os.environ.get("_ARGCOMPLETE_COMP_WORDBREAKS", "")
     words = []
 
-    def split_word(word):
+    def split_word(word: str) -> tuple[str, str, str, list[str], int | None]:
         # TODO: make this less ugly
         point_in_word = len(word) + point - lexer.instream.tell()
         if isinstance(lexer.state, (str, bytes)) and lexer.state in 
lexer.whitespace:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/argcomplete/packages/_argparse.py 
new/argcomplete-3.7.2/argcomplete/packages/_argparse.py
--- old/argcomplete-3.6.3/argcomplete/packages/_argparse.py     2020-02-02 
01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/argcomplete/packages/_argparse.py     2020-02-02 
01:00:00.000000000 +0100
@@ -19,7 +19,13 @@
     _SubParsersAction,
 )
 from gettext import gettext
-from typing import Dict, List, Set, Tuple
+from typing import Dict, List, Optional, Set, Tuple, Union, cast
+
+_OptionTuple = Union[
+    Tuple[Optional[Action], str, Optional[str]],
+    Tuple[Optional[Action], str, Optional[str], Optional[str]],
+]
+_OptionTupleEntry = Union[_OptionTuple, List[_OptionTuple]]
 
 _num_consumed_args: Dict[Action, int] = {}
 
@@ -97,7 +103,7 @@
         # find all option indices, and determine the arg_string_pattern
         # which has an 'O' if there is an option at an index,
         # an 'A' if there is an argument, or a '-' if there is a '--'
-        option_string_indices = {}
+        option_string_indices: Dict[int, _OptionTupleEntry] = {}
         arg_string_pattern_parts = []
         arg_strings_iter = iter(arg_strings)
         for i, arg_string in enumerate(arg_strings_iter):
@@ -114,7 +120,7 @@
                 if option_tuple is None:
                     pattern = 'A'
                 else:
-                    option_string_indices[i] = option_tuple
+                    option_string_indices[i] = cast(_OptionTupleEntry, 
option_tuple)
                     pattern = 'O'
                 arg_string_pattern_parts.append(pattern)
 
@@ -161,9 +167,11 @@
         # function to convert arg_strings into an optional action
         def consume_optional(start_index):
             # get the optional identified at this index
-            option_tuple = option_string_indices[start_index]
-            if isinstance(option_tuple, list):  # Python 3.12.7+
-                option_tuple = option_tuple[0]
+            raw_option_tuple = option_string_indices[start_index]
+            if isinstance(raw_option_tuple, list):  # Python 3.12.7+
+                option_tuple = raw_option_tuple[0]
+            else:
+                option_tuple = raw_option_tuple
             if len(option_tuple) == 3:
                 action, option_string, explicit_arg = option_tuple
             else:  # Python 3.11.9+, 3.12.3+, 3.13+
@@ -241,8 +249,8 @@
             # add the Optional to the list and return the index at which
             # the Optional's string args stopped
             assert action_tuples
-            for action, args, option_string in action_tuples:
-                take_action(action, args, option_string)
+            for optional_action, args, option_string in action_tuples:
+                take_action(optional_action, args, option_string)
             return stop
 
         # the list of Positionals left to be parsed; this is modified
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/argcomplete-3.6.3/argcomplete/scripts/activate_global_python_argcomplete.py 
new/argcomplete-3.7.2/argcomplete/scripts/activate_global_python_argcomplete.py
--- 
old/argcomplete-3.6.3/argcomplete/scripts/activate_global_python_argcomplete.py 
    2020-02-02 01:00:00.000000000 +0100
+++ 
new/argcomplete-3.7.2/argcomplete/scripts/activate_global_python_argcomplete.py 
    2020-02-02 01:00:00.000000000 +0100
@@ -32,7 +32,9 @@
 # End added by argcomplete
 """
 
-parser = argparse.ArgumentParser(description=__doc__, 
formatter_class=argparse.RawDescriptionHelpFormatter)
+parser: argparse.ArgumentParser = argparse.ArgumentParser(
+    description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
+)
 parser.add_argument("-y", "--yes", help="automatically answer yes for all 
questions", action="store_true")
 parser.add_argument("--dest", help='Specify the shell completion modules 
directory to install into, or "-" for stdout')
 parser.add_argument("--user", help="Install into user directory", 
action="store_true")
@@ -40,18 +42,18 @@
 args = None
 
 
-def get_local_dir():
+def get_local_dir() -> str:
     try:
         return subprocess.check_output(["brew", "--prefix"]).decode().strip()
     except (FileNotFoundError, subprocess.CalledProcessError):
         return "/usr/local"
 
 
-def get_zsh_system_dir():
+def get_zsh_system_dir() -> str:
     return f"{get_local_dir()}/share/zsh/site-functions"
 
 
-def get_bash_system_dir():
+def get_bash_system_dir() -> str:
     if "BASH_COMPLETION_COMPAT_DIR" in os.environ:
         return os.environ["BASH_COMPLETION_COMPAT_DIR"]
     elif sys.platform == "darwin":
@@ -60,15 +62,15 @@
         return "/etc/bash_completion.d"  # created by bash-completion
 
 
-def get_activator_dir():
+def get_activator_dir() -> str:
     return 
os.path.join(os.path.abspath(os.path.dirname(argcomplete.__file__)), 
"bash_completion.d")
 
 
-def get_activator_path():
+def get_activator_path() -> str:
     return os.path.join(get_activator_dir(), "_python-argcomplete")
 
 
-def install_to_destination(dest):
+def install_to_destination(dest: str) -> None:
     activator = get_activator_path()
     if dest == "-":
         with open(activator) as fh:
@@ -92,7 +94,7 @@
         )
 
 
-def get_consent():
+def get_consent() -> bool:
     assert args is not None
     if args.yes is True:
         return True
@@ -106,7 +108,7 @@
             return False
 
 
-def append_to_config_file(path, shellcode):
+def append_to_config_file(path: str | os.PathLike[str], shellcode: str) -> 
None:
     if os.path.exists(path):
         with open(path, 'r') as fh:
             if shellcode in fh.read():
@@ -124,23 +126,23 @@
     print("Added.", file=sys.stderr)
 
 
-def link_zsh_user_rcfile(zsh_fpath=None):
+def link_zsh_user_rcfile(zsh_fpath: str | None = None) -> None:
     zsh_rcfile = os.path.join(os.path.expanduser(os.environ.get("ZDOTDIR", 
"~")), ".zshenv")
     append_to_config_file(zsh_rcfile, zsh_shellcode.format(zsh_fpath=zsh_fpath 
or get_activator_dir()))
 
 
-def link_bash_user_rcfile():
+def link_bash_user_rcfile() -> None:
     bash_completion_user_file = os.path.expanduser("~/.bash_completion")
     append_to_config_file(bash_completion_user_file, 
bash_shellcode.format(activator=get_activator_path()))
 
 
-def link_user_rcfiles():
+def link_user_rcfiles() -> None:
     # TODO: warn if running as superuser
     link_zsh_user_rcfile()
     link_bash_user_rcfile()
 
 
-def add_zsh_system_dir_to_fpath_for_user():
+def add_zsh_system_dir_to_fpath_for_user() -> None:
     if "zsh" not in os.environ.get("SHELL", ""):
         return
     try:
@@ -154,7 +156,7 @@
         pass
 
 
-def main():
+def main() -> None:
     global args
     args = parser.parse_args()
 
@@ -190,4 +192,4 @@
 
 
 if __name__ == "__main__":
-    sys.exit(main())
+    sys.exit(main())  # type: ignore[func-returns-value]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/argcomplete-3.6.3/argcomplete/scripts/python_argcomplete_check_easy_install_script.py
 
new/argcomplete-3.7.2/argcomplete/scripts/python_argcomplete_check_easy_install_script.py
--- 
old/argcomplete-3.6.3/argcomplete/scripts/python_argcomplete_check_easy_install_script.py
   2020-02-02 01:00:00.000000000 +0100
+++ 
new/argcomplete-3.7.2/argcomplete/scripts/python_argcomplete_check_easy_install_script.py
   1970-01-01 01:00:00.000000000 +0100
@@ -1,84 +0,0 @@
-#!/usr/bin/env python3
-
-# Copyright 2012-2023, Andrey Kislyuk and argcomplete contributors.
-# Licensed under the Apache License. See 
https://github.com/kislyuk/argcomplete for more info.
-
-"""
-This script is part of the Python argcomplete package 
(https://github.com/kislyuk/argcomplete).
-It is used to check if an EASY-INSTALL-SCRIPT wrapper redirects to a script 
that contains the string
-"PYTHON_ARGCOMPLETE_OK". If you have enabled global completion in argcomplete, 
the completion hook will run it every
-time you press <TAB> in your shell.
-
-Usage:
-    python-argcomplete-check-easy-install-script <input executable file>
-"""
-
-import sys
-
-# PEP 366
-__package__ = "argcomplete.scripts"
-
-
-def main():
-    if len(sys.argv) != 2:
-        sys.exit(__doc__)
-
-    sys.tracebacklimit = 0
-
-    with open(sys.argv[1]) as fh:
-        line1, head = fh.read(1024).split("\n", 1)[:2]
-        if line1.startswith("#") and ("py" in line1 or "Py" in line1):
-            import re
-
-            lines = head.split("\n", 12)
-            for line in lines:
-                if line.startswith("# EASY-INSTALL-SCRIPT"):
-                    import pkg_resources  # type: ignore
-
-                    re_match = re.match("# EASY-INSTALL-SCRIPT: 
'(.+)','(.+)'", line)
-                    assert re_match is not None
-                    dist, script = re_match.groups()
-                    if "PYTHON_ARGCOMPLETE_OK" in 
pkg_resources.get_distribution(dist).get_metadata(
-                        "scripts/" + script
-                    ):
-                        return 0
-                elif line.startswith("# EASY-INSTALL-ENTRY-SCRIPT"):
-                    re_match = re.match("# EASY-INSTALL-ENTRY-SCRIPT: 
'(.+)','(.+)','(.+)'", line)
-                    assert re_match is not None
-                    dist, group, name = re_match.groups()
-                    import pkgutil
-
-                    import pkg_resources  # type: ignore
-
-                    entry_point_info = 
pkg_resources.get_distribution(dist).get_entry_info(group, name)
-                    assert entry_point_info is not None
-                    module_name = entry_point_info.module_name
-                    with open(pkgutil.get_loader(module_name).get_filename()) 
as mod_fh:  # type: ignore
-                        if "PYTHON_ARGCOMPLETE_OK" in mod_fh.read(1024):
-                            return 0
-                elif line.startswith("# EASY-INSTALL-DEV-SCRIPT"):
-                    for line2 in lines:
-                        if line2.startswith("__file__"):
-                            re_match = re.match("__file__ = '(.+)'", line2)
-                            assert re_match is not None
-                            filename = re_match.group(1)
-                            with open(filename) as mod_fh:
-                                if "PYTHON_ARGCOMPLETE_OK" in 
mod_fh.read(1024):
-                                    return 0
-                elif line.startswith("# PBR Generated"):
-                    re_match = re.search("from (.*) import", head)
-                    assert re_match is not None
-                    module = re_match.groups()[0]
-                    import pkgutil
-
-                    import pkg_resources  # type: ignore
-
-                    with open(pkgutil.get_loader(module).get_filename()) as 
mod_fh:  # type: ignore
-                        if "PYTHON_ARGCOMPLETE_OK" in mod_fh.read(1024):
-                            return 0
-
-    return 1
-
-
-if __name__ == "__main__":
-    sys.exit(main())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/argcomplete-3.6.3/argcomplete/scripts/register_python_argcomplete.py 
new/argcomplete-3.7.2/argcomplete/scripts/register_python_argcomplete.py
--- old/argcomplete-3.6.3/argcomplete/scripts/register_python_argcomplete.py    
2020-02-02 01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/argcomplete/scripts/register_python_argcomplete.py    
2020-02-02 01:00:00.000000000 +0100
@@ -32,7 +32,7 @@
 __package__ = "argcomplete.scripts"
 
 
-def main():
+def main() -> None:
     parser = argparse.ArgumentParser(description=__doc__, 
formatter_class=argparse.RawDescriptionHelpFormatter)
 
     parser.add_argument(
@@ -76,4 +76,4 @@
 
 
 if __name__ == "__main__":
-    sys.exit(main())
+    sys.exit(main())  # type: ignore[func-returns-value]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/argcomplete/shell_integration.py 
new/argcomplete-3.7.2/argcomplete/shell_integration.py
--- old/argcomplete-3.6.3/argcomplete/shell_integration.py      2020-02-02 
01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/argcomplete/shell_integration.py      2020-02-02 
01:00:00.000000000 +0100
@@ -3,6 +3,7 @@
 # files with source copies of this package and derivative works is 
**REQUIRED** as specified by the Apache License.
 # See https://github.com/kislyuk/argcomplete for more info.
 
+from collections.abc import Iterable
 from shlex import quote
 
 bashcode = r"""#compdef %(executables)s
@@ -135,7 +136,13 @@
 shell_codes = {"bash": bashcode, "tcsh": tcshcode, "fish": fishcode, 
"powershell": powershell_code}
 
 
-def shellcode(executables, use_defaults=True, shell="bash", 
complete_arguments=None, argcomplete_script=None):
+def shellcode(
+    executables: Iterable[str],
+    use_defaults: bool = True,
+    shell: str = "bash",
+    complete_arguments: Iterable[str] | None = None,
+    argcomplete_script: str | None = None,
+) -> str:
     """
     Provide the shell code required to register a python executable for use 
with the argcomplete module.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/pyproject.toml 
new/argcomplete-3.7.2/pyproject.toml
--- old/argcomplete-3.6.3/pyproject.toml        2020-02-02 01:00:00.000000000 
+0100
+++ new/argcomplete-3.7.2/pyproject.toml        2020-02-02 01:00:00.000000000 
+0100
@@ -2,7 +2,7 @@
 name = "argcomplete"
 description = "Bash tab completion for argparse"
 readme = "README.rst"
-requires-python = ">=3.8"
+requires-python = ">=3.10"
 license = { text = "Apache Software License" }
 authors = [{ name = "Andrey Kislyuk"}, {email = "[email protected]" }]
 maintainers = [{ name = "Andrey Kislyuk"}, {email = "[email protected]" }]
@@ -15,12 +15,11 @@
   "Operating System :: POSIX",
   "Programming Language :: Python",
   "Programming Language :: Python :: 3",
-  "Programming Language :: Python :: 3.8",
-  "Programming Language :: Python :: 3.9",
   "Programming Language :: Python :: 3.10",
   "Programming Language :: Python :: 3.11",
   "Programming Language :: Python :: 3.12",
   "Programming Language :: Python :: 3.13",
+  "Programming Language :: Python :: 3.14",
   "Programming Language :: Python :: Implementation :: CPython",
   "Programming Language :: Python :: Implementation :: PyPy",
   "Development Status :: 5 - Production/Stable",
@@ -32,7 +31,6 @@
 
 [project.scripts]
 activate-global-python-argcomplete = 
"argcomplete.scripts.activate_global_python_argcomplete:main"
-python-argcomplete-check-easy-install-script = 
"argcomplete.scripts.python_argcomplete_check_easy_install_script:main"
 register-python-argcomplete = 
"argcomplete.scripts.register_python_argcomplete:main"
 
 [project.optional-dependencies]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/argcomplete-3.6.3/test/test.py 
new/argcomplete-3.7.2/test/test.py
--- old/argcomplete-3.6.3/test/test.py  2020-02-02 01:00:00.000000000 +0100
+++ new/argcomplete-3.7.2/test/test.py  2020-02-02 01:00:00.000000000 +0100
@@ -356,6 +356,15 @@
                 fp.write("test")
             self.assertEqual(set(fc("a")), set(["abcdefж/", "abcaha/", 
"abcxyz"]))
 
+    def test_file_completion_quotes_prefix(self):
+        with TempDir(prefix="test_dir_fc_quote", dir="."):
+            marker = "should_not_exist"
+            prefix = "'; touch {0}; echo '".format(marker)
+
+            self.assertFalse(os.path.exists(marker))
+            self.assertEqual(FilesCompleter()(prefix), [])
+            self.assertFalse(os.path.exists(marker))
+
     def test_filescompleter_filetype_integration(self):
         def make_parser():
             parser = ArgumentParser()
@@ -405,6 +414,44 @@
             self.assertEqual(c("def/k"), set([]))
         return
 
+    def test_directory_completion_with_tilde(self):
+        # Regression test for https://github.com/kislyuk/argcomplete/issues/529
+        # "~/<TAB>" should expand the home directory instead of yielding 
nothing
+        # (os.listdir("~") would otherwise raise FileNotFoundError).
+        completer = DirectoriesCompleter()
+
+        def c(prefix):
+            return set(completer(prefix))
+
+        old_home = os.environ.get("HOME")
+        old_userprofile = os.environ.get("USERPROFILE")
+        with TempDir(prefix="test_dir_tilde", dir=".") as tmp_dir:
+            home = os.path.realpath(tmp_dir)
+            os.environ["HOME"] = home
+            os.environ["USERPROFILE"] = home
+            try:
+                # Create some directories and files (files must be ignored)
+                os.makedirs(os.path.join(home, "abc", "baz"))
+                os.makedirs(os.path.join(home, "abb"))
+                with open(os.path.join(home, "abc1"), "w") as fp:
+                    fp.write("A test")
+                # "~/" lists the home directory
+                self.assertEqual(c("~/"), set([os.path.join(home, "abb") + 
"/", os.path.join(home, "abc") + "/"]))
+                # "~/ab" filters within the home directory
+                self.assertEqual(c("~/ab"), set([os.path.join(home, "abb") + 
"/", os.path.join(home, "abc") + "/"]))
+                # "~/abc/" recurses into a subdirectory
+                self.assertEqual(c("~/abc/"), set([os.path.join(home, "abc", 
"baz") + "/"]))
+            finally:
+                if old_home is None:
+                    os.environ.pop("HOME", None)
+                else:
+                    os.environ["HOME"] = old_home
+                if old_userprofile is None:
+                    os.environ.pop("USERPROFILE", None)
+                else:
+                    os.environ["USERPROFILE"] = old_userprofile
+        return
+
     def test_default_completer(self):
         def make_parser():
             parser = ArgumentParser(add_help=False)
@@ -828,6 +875,7 @@
             parser.add_argument("-1", choices=["bar<$>baz"])
             parser.add_argument("-2", choices=[r"\* "])
             parser.add_argument("-3", choices=["\"'"])
+            parser.add_argument("-4", choices=["data?", "file[1]", 
"{x,--flag}"])
             return parser
 
         self.assertEqual(set(self.run_completer(make_parser(), "prog -1 ")), 
{r"bar\<\$\>baz "})
@@ -835,6 +883,10 @@
         self.assertEqual(set(self.run_completer(make_parser(), "prog -3 ")), 
{r"\"\' "})
         self.assertEqual(set(self.run_completer(make_parser(), 'prog -3 "')), 
{r"\"'"})
         self.assertEqual(set(self.run_completer(make_parser(), "prog -3 '")), 
{"\"'\\''"})
+        self.assertEqual(
+            set(self.run_completer(make_parser(), "prog -4 ")),
+            {r"data\?", r"file\[1\]", r"\{x,--flag\}"},
+        )
 
         self.assertEqual(set(self.run_completer(make_parser(), "prog -1 ", 
shell="tcsh")), {"bar<$>baz "})
         # The trailing space won't actually work correctly in tcsh.

Reply via email to