Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.3.2 (November 22, 2021)
* Bug Fixes
* Fixed issue where a `ns_provider` could be passed `None` instead of its correct `cmd2.Cmd` or `CommandSet` value.

## 2.3.1 (November 18, 2021)
* Bug Fixes
* Fixed issue introduced in 2.3.0 with `AlternatingTable`, `BorderedTable`, and `SimpleTable` that caused
Expand Down
1 change: 0 additions & 1 deletion cmd2/cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -5418,7 +5418,6 @@ def _resolve_func_self(

:param cmd_support_func: command support function. This could be a completer or namespace provider
:param cmd_self: The `self` associated with the command or subcommand
:return:
"""
# figure out what class the command support function was defined in
func_class: Optional[Type[Any]] = get_defining_class(cmd_support_func)
Expand Down
8 changes: 4 additions & 4 deletions cmd2/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,9 @@ def with_argparser(
with the given instance of argparse.ArgumentParser.

:param parser: unique instance of ArgumentParser
:param ns_provider: An optional function that accepts a cmd2.Cmd object as an argument and returns an
argparse.Namespace. This is useful if the Namespace needs to be prepopulated with
state data that affects parsing.
:param ns_provider: An optional function that accepts a cmd2.Cmd or cmd2.CommandSet object as an argument and returns an
argparse.Namespace. This is useful if the Namespace needs to be prepopulated with state data that
affects parsing.
:param preserve_quotes: if ``True``, then arguments passed to argparse maintain their quotes
:param with_unknown_args: if true, then capture unknown args
:return: function that gets passed argparse-parsed args in a ``Namespace``
Expand Down Expand Up @@ -351,7 +351,7 @@ def cmd_wrapper(*args: Any, **kwargs: Dict[str, Any]) -> Optional[bool]:
# functions are registered with the command argparser before anything is instantiated, we
# need to find an instance at runtime that matches the types during declaration
provider_self = cmd2_app._resolve_func_self(ns_provider, args[0])
namespace = ns_provider(provider_self if not None else cmd2_app)
namespace = ns_provider(provider_self if provider_self is not None else cmd2_app)

try:
new_args: Union[Tuple[argparse.Namespace], Tuple[argparse.Namespace, List[str]]]
Expand Down
43 changes: 43 additions & 0 deletions tests_isolated/test_commandset/test_commandset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1104,3 +1104,46 @@ def __init__(self):
settable_attrib_name='some_value',
)
)


class NsProviderSet(cmd2.CommandSet):
# CommandSet which implements a namespace provider
def __init__(self, dummy):
# Use dummy argument so this won't be autoloaded by other tests
super(NsProviderSet, self).__init__()

def ns_provider(self) -> argparse.Namespace:
ns = argparse.Namespace()
# Save what was passed as self from with_argparser().
ns.self = self
return ns


class NsProviderApp(cmd2.Cmd):
# Used to test namespace providers in CommandSets
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
super(NsProviderApp, self).__init__(*args, **kwargs)

@cmd2.with_argparser(cmd2.Cmd2ArgumentParser(), ns_provider=NsProviderSet.ns_provider)
def do_test_ns(self, args: argparse.Namespace) -> None:
# Save args.self so the unit tests can read it.
self.last_result = args.self


def test_ns_provider():
"""This exercises code in with_argparser() decorator that calls namespace providers"""
ns_provider_set = NsProviderSet(1)
app = NsProviderApp(auto_load_commands=False)

# First test the case in which a namespace provider function resides in a CommandSet class which is registered.
# with_argparser() will pass the CommandSet instance to the ns_provider() function.
app.register_command_set(ns_provider_set)
run_cmd(app, "test_ns")
assert app.last_result == ns_provider_set

# Now test the case in which a namespace provider function resides in a CommandSet class which is not registered.
# with_argparser() will receive None from cmd2.Cmd._resolve_func_self() and therefore pass app as self to ns_provider().
app.unregister_command_set(ns_provider_set)
run_cmd(app, "test_ns")
assert app.last_result == app