Flask-Script command that passes all remaining args to nose?

3.1k Views Asked by At

I use a simple command to run my tests with nose:

@manager.command
def test():
    """Run unit tests."""
    import nose
    nose.main(argv=[''])

However, nose supports many useful arguments that now I could not pass.

Is there a way to run nose with manager command (similar to the call above) and still be able to pass arguments to nose? For example:

python manage.py test --nose-arg1 --nose-arg2

Right now I'd get an error from Manager that --nose-arg1 --nose-arg2 are not recognised as valid arguments. I want to pass those args as nose.main(argv= <<< args comming after python manage.py test ... >>>)

3

There are 3 best solutions below

0
On BEST ANSWER

Flask-Script has an undocumented capture_all_flags flag, which will pass remaining args to the Command.run method. This is demonstrated in the tests.

@manager.add_command
class NoseCommand(Command):
    name = 'test'
    capture_all_args = True

    def run(self, remaining):
        nose.main(argv=remaining)
python manage.py test --nose-arg1 --nose-arg2
# will call nose.main(argv=['--nose-arg1', '--nose-arg2'])
0
On

In the sources of flask_script you can see that the "too many arguments" error is prevented when the executed Command has the attribute capture_all_args set to True which isn't documented anywhere.

You can set that attribute on the class just before you run the manager

if __name__ == "__main__":
    from flask.ext.script import Command
    Command.capture_all_args = True
    manager.run()

Like this additional arguments to the manager are always accepted.

The downside of this quick fix is that you cannot register options or arguments to the commands the normal way anymore.

If you still need that feature you could subclass the Manager and override the command decorator like this

class MyManager(Manager):
    def command(self, capture_all=False):
        def decorator(func):
            command = Command(func)
            command.capture_all_args = capture_all
            self.add_command(func.__name__, command)

            return func
        return decorator

Then you can use the command decorator like this

@manager.command(True)  # capture all arguments
def use_all(*args):
    print("args:", args[0])

@manager.command()  # normal way of registering arguments
def normal(name):
    print("name", name)

Note that for some reason flask_script requires use_all to accept a varargs but will store the list of arguments in args[0] which is a bit strange. def use_all(args): does not work and fails with TypeError "got multiple values for argument 'args'"

0
On

Ran into an issue with davidism's soln where only some of the args were being received

Looking through the docs a bit more it is documented that nose.main automatically picks up the stdin

http://nose.readthedocs.io/en/latest/api/core.html

So we are now just using:

@manager.add_command
class NoseCommand(Command):
    name = 'nose'
    capture_all_args = True

    def run(self, remaining):
        nose.main()