Open macfire opened 7 years ago
View the help for the users
command:
> flask users --help
Starting tsa_postgres_1 ... done
Usage: flask users [OPTIONS] COMMAND [ARGS]...
User commands.
Options:
--help Show this message and exit.
Commands:
activate Activate a user.
create Create a user.
deactivate Deactivate a user.
View the help for the users create
command:
> flask users create --help
Usage: flask users create [OPTIONS] IDENTITY
Create a user.
Options:
--password TEXT
-a, --active
--help Show this message and exit.
In our setup both username and email address are required (on the User
model). This means that for users create
to work I need to use config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = ['email', 'username']
. Otherwise I receive an error that email is invalid, or username is null.
Create a user:
> flask users create dev@mafro.net --password password1 -a
User created successfully.
{'email': 'dev@mafro.net', 'username': 'dev@mafro.net', 'password': '****', 'active': True}
Thanks, @mafrosis
I was accessing my own commands by using setup.py, but was confused why I couldn't access cli commands in installed packages (in this case, Flask-Security).
Then, finally realized I needed to create a method for flask to find the app because my app uses factory pattern
# run_cmds.py
from MyApp import app
application = app.create_app()
Then in terminal:
$ export FLASK_APP=/path/to/my_app/run_cmds.py
So, now your examples works:
$ flask users create --help
Usage: flask users create [OPTIONS] IDENTITY
Create a user.
Options:
--password TEXT
-a, --active
--help Show this message and exit.
However, I ran into another issue when trying to create a user:
$ flask users create kermit@muppets.com --password password1 -a
/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/flask_security/forms.py:261: FlaskWTFDeprecationWarning: "csrf_enabled" is deprecated and will be removed in 1.0. Set "meta.csrf" instead.
super(RegisterForm, self).__init__(*args, **kwargs)
Traceback (most recent call last):
File "/Users/macfire/dev/__venv/my_venv/bin/flask", line 11, in <module>
sys.exit(main())
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/flask/cli.py", line 513, in main
cli.main(args=args, prog_name=name)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/flask/cli.py", line 380, in main
return AppGroup.main(self, *args, **kwargs)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/Users/macfire/dev/__venv/clear_app_3_6/lib/python3.6/site-packages/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Users/macfire/dev/__venv/clear_app_3_6/lib/python3.6/site-packages/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/click/decorators.py", line 17, in new_func
return f(get_current_context(), *args, **kwargs)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/flask/cli.py", line 257, in decorator
return __ctx.invoke(f, *args, **kwargs)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/flask_security/cli.py", line 36, in wrapper
fn(*args, **kwargs)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/flask_security/cli.py", line 63, in users_create
MultiDict(kwargs), csrf_enabled=False
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/wtforms/form.py", line 212, in __call__
return type.__call__(cls, *args, **kwargs)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/flask_security/forms.py", line 263, in __init__
self.next.data = request.args.get('next', '')
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/werkzeug/local.py", line 347, in __getattr__
return getattr(self._get_current_object(), name)
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/werkzeug/local.py", line 306, in _get_current_object
return self.__local()
File "/Users/macfire/dev/__venv/my_venv/lib/python3.6/site-packages/flask/globals.py", line 37, in _lookup_req_object
raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
@macfire can you please check that you have provided correct application to Click. There is a really good tutorial on Flask website http://flask.pocoo.org/docs/0.12/cli/ about CLI and factory pattern.
Given a
hello.py
file with the application in it namedapp
this is how it can be run.
Hence, you should try with:
# run_cmds.py
from MyApp.app import create_app
app = create_app()
@jirikuncar , yes, the correct app is being passed to Click.
I am able to use the create roles command successfully:
$ flask roles create superadmin -d "Super administrator"
When running the create user command, it is looking like the error RuntimeError: Working outside of request context.
may be happening with call to form=_security.confirm_register_form()
.
# from flask_security.cli.py
# ~line 51
@users.command('create')
@click.argument('identity')
@click.password_option()
@click.option('-a', '--active', default=False, is_flag=True)
@with_appcontext
@commit
def users_create(identity, password, active):
"""Create a user."""
kwargs = {attr: identity for attr in _security.user_identity_attributes}
kwargs.update(**{'password': password, 'active': 'y' if active else ''})
form = _security.confirm_register_form(
MultiDict(kwargs), csrf_enabled=False
)
if form.validate():
kwargs['password'] = hash_password(kwargs['password'])
kwargs['active'] = active
_datastore.create_user(**kwargs)
click.secho('User created successfully.', fg='green')
kwargs['password'] = '****'
click.echo(kwargs)
else:
raise click.UsageError('Error creating user. %s' % form.errors)
I've narrowed down the issue.
The error RuntimeError: Working outside of request context.
occurs because of the call request.args.get('next','')
command in RegisterForm()
# flask_security/forms.py` ~265
class RegisterForm(ConfirmRegisterForm, PasswordConfirmFormMixin, NextFormMixin):
def __init__(self, *args, **kwargs):
super(RegisterForm, self).__init__(*args, **kwargs)
if not self.next.data:
self.next.data = request.args.get('next', '') # <-- LOOKING FOR REQUEST CONTEXT
If I comment out the test for self.next.data
, I can successfully register a user via CLI.
QUESTION:
How can the flask_security.cli command def users_create()
be modified to use the Flask request_context
(or app.test_request_context( ...)
) ? or is that what is needed?
I've looked at http://flask.pocoo.org/docs/0.12/reqcontext/ but don't understand how I would pass the context in this case.
@macfire thanks! This indeed looks like a problem in the form. We should add has_request_context()
test before accessing request
proxy. Moreover it looks like the tests are creating test request context so this issue has not been caught.
Could anyone please share an example of using the click commands in terminal? Thanks.