2

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 ... >>>)

ddinchev
  • 33,683
  • 28
  • 88
  • 133
  • If the number of arguments to `python` itself stays constant you can just pass `argv[3:]` from `sys` – Wombatz Feb 10 '16 at 14:07
  • That was my first try but the Flask-Script Manager exits with an error if it sees "unrecognised" arguments, instead of ignoring them. A solution to my problem would be to make it ignore the rest of the arguments and be able to take them just like you suggested. – ddinchev Feb 10 '16 at 14:09
  • Well, i should read the question more carefully. I found a hacky way to do what you want. I will write an answer for that. – Wombatz Feb 10 '16 at 14:33

3 Answers3

4

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'"

Wombatz
  • 4,958
  • 1
  • 26
  • 35
4

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'])
davidism
  • 121,510
  • 29
  • 395
  • 339
0

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()
applewood
  • 391
  • 2
  • 11