Behave v1.2.7.dev3 breaks management command
behave-django currently depends on behave v1.2.7.dev2 and we're unable to upgrade to v1.2.7.dev3 (which, for example, sports TOML support), because our code depends on a symbol imported from behave.configuration that was removed in https://github.com/behave/behave/commit/596f339ab9ee8ea9608b08dc826560b9474acc28. The related code was a validation function for argparse:
def valid_python_module(path):
try:
module_path, class_name = path.rsplit('.', 1)
module = import_module(module_path)
return getattr(module, class_name)
except (ValueError, AttributeError, ImportError):
raise argparse.ArgumentTypeError("No module named '%s' was found." % path)
To fix the issue quickly, I'm tempted to add the code removed from behave to our codebase. OTOH, there doesn't seem to be any validation of this kind in the codebase for behave at all anymore. I'm wondering why.
Should we add it back in or did you remove it for a reason, @jenisys?
In addition, this new development version changes the --runner-class option (--behave-runner-class for behave-django) to -r and --runner, which adds both a conflict (for -r == "reverse" in behave-django) and a backward-incompatible change.
To keep confusion low, I'll align our --runner-class option with the change applied to the behave codebase. This will introduce two new options --behave-runner and --runner, and drop --behave-runner-class and --runner-class.
Both options (they were added with PR #130) were not part of a release on PyPI, so I won't implement a deprecation path.
@bittner
I removed it on purpose because behave.configuration does not need it and
I stumbled over a number of problems and deficiencies while testing the runner as extension-point:
-
The above implementation of
valid_python_module()does not really help the user when something is wrong. Meaning, the user does not get the real reason what is wrong and what he/she should change/correct. Possible failure reasons are:ModuleNotFound,ClassNotFound,InvalidClass, ... (see: BAD CASES below) -
I wanted to support
runner aliasesin the config-file (to simplify the use of a runner-class on the command-line). In this case, the command-line option value is a string/name but not a scoped-class-name (withmoduleprefix) and cannot be directly imported. Therefore, it was better to post-pone the runner-import until just before it is used (in theRunnerPlugin). -
All extension-points in
behavethat load classes-by-name, use the schema:<DOTTED_MODULE_NAME>:<CLASS_NAME>(like:pytest) Therefore, I did not want to support the dotted-only-module-and-class-name-schema here.
THEREFORE:
If you really need the valid_python_module() function, you should add the code to your code base.
Alternatives are:
- use the
RunnerPluginclass or - implement the
valid_python_module()function by using theRunnerPluginclass
SEE ALSO:
Okay, I understand. Thanks for explaining.
I'll try to restore the state that was working earlier for now, changing the CLI options as mentioned above. What we get by this is better than a broken state albeit not ideal: Similar-sounding options that accept a different syntax for "the same thing".
@kingbuzzman Would you have time (and motivation) to look into the RunnerPlugin route?
Hello. Not really sure if this is related to this comment https://github.com/behave/behave-django/issues/147#issuecomment-1538915715
It seems that using a runner configuration on .behaverc is not working. I can run it fine using the management command
python manage.py behave --runner "tests.integration.runner:BehaveAzionRunner"
but if I try to configure on .behaverc like this
[behave]
runner=tests.integration.runner:BehaveCustomRunner
and run just with python manage.py behave
then I get the following error:
BAD_RUNNER_CLASS: FAILED to load runner.class=tests.integration.runner:BehaveCustomRunner (InvalidClassError)
InvalidClassError: is not a subclass-of 'behave.api.runner:ITestRunner'
Is there something I'm doing wrong over here?
The error message clearly states what you are doing wrong.
Your test runner should inherit from behave.api.runner:ITestRunner interface class (which it does not).
BACKGROUND:
The first implementation of the runner-classes as extension point hat some limitations. It did not catch some problems that people run into.
The current implementation checks for these problems. To be able to do that you must implement the interface for a runner-class.