2018-02-08 10:57:40 -08:00
# This file was part of Flask-CLI and was modified under the terms of
# its Revised BSD License. Copyright © 2015 CERN.
2016-06-05 10:32:00 -07:00
import os
2018-01-22 12:16:37 -08:00
import ssl
2016-06-05 10:32:00 -07:00
import sys
2018-01-22 12:16:37 -08:00
import types
2017-04-25 14:15:38 -07:00
from functools import partial
2021-05-16 22:34:32 -04:00
from pathlib import Path
2016-05-16 19:36:55 +02:00
import click
import pytest
2017-07-14 22:37:53 -07:00
from _pytest . monkeypatch import notset
2016-05-16 19:36:55 +02:00
from click . testing import CliRunner
2019-06-01 08:35:03 -07:00
from flask import Blueprint
from flask import current_app
from flask import Flask
from flask . cli import AppGroup
from flask . cli import find_best_app
from flask . cli import FlaskGroup
from flask . cli import get_version
from flask . cli import load_dotenv
from flask . cli import locate_app
from flask . cli import NoAppException
from flask . cli import prepare_import
from flask . cli import run_command
from flask . cli import ScriptInfo
from flask . cli import with_appcontext
2017-07-14 22:37:53 -07:00
2021-05-16 22:34:32 -04:00
cwd = Path . cwd ( )
test_path = ( Path ( __file__ ) / " .. " / " test_apps " ) . resolve ( )
2017-07-14 22:37:53 -07:00
2023-07-05 00:55:33 +00:00
# resuable setup and teardown logic for tests
2016-06-25 13:24:43 +02:00
@pytest.fixture
def runner ( ) :
2023-07-05 00:55:33 +00:00
# Runner fixture returns an instance of the CLIRunner Class
2016-06-25 13:24:43 +02:00
return CliRunner ( )
2016-05-16 19:36:55 +02:00
def test_cli_name ( test_apps ) :
2016-05-24 15:06:34 -04:00
""" Make sure the CLI object ' s name is the app ' s name and not the app itself """
2016-05-16 19:36:55 +02:00
from cliapp . app import testapp
2023-07-05 00:55:33 +00:00
# name assigned by CLI object within testapp module is equal to name attribute of testapp module itself
2016-05-16 19:36:55 +02:00
assert testapp . cli . name == testapp . name
2023-07-05 00:55:33 +00:00
# ensure function behaves as expected in different scenarios
2016-05-16 19:36:55 +02:00
def test_find_best_app ( test_apps ) :
2016-07-05 14:46:01 -05:00
class Module :
2019-05-06 15:39:41 -04:00
app = Flask ( " appname " )
2023-07-05 00:55:33 +00:00
# find_best_app function takes module as an argument, looks for Flask application objects within that module and applies criteria to determine the best application object before returning that best object
2021-11-12 06:46:54 -08:00
assert find_best_app ( Module ) == Module . app
2016-05-16 19:36:55 +02:00
2016-07-05 14:46:01 -05:00
class Module :
2019-05-06 15:39:41 -04:00
application = Flask ( " appname " )
2017-05-24 17:27:36 -07:00
2021-11-12 06:46:54 -08:00
assert find_best_app ( Module ) == Module . application
2016-05-16 19:36:55 +02:00
2016-07-05 14:46:01 -05:00
class Module :
2019-05-06 15:39:41 -04:00
myapp = Flask ( " appname " )
2017-05-24 17:27:36 -07:00
2021-11-12 06:46:54 -08:00
assert find_best_app ( Module ) == Module . myapp
2016-05-16 19:36:55 +02:00
2017-05-22 12:30:18 -07:00
class Module :
@staticmethod
def create_app ( ) :
2019-05-06 15:39:41 -04:00
return Flask ( " appname " )
2017-05-24 17:27:36 -07:00
2021-11-12 06:46:54 -08:00
app = find_best_app ( Module )
2020-04-07 15:54:36 -07:00
assert isinstance ( app , Flask )
assert app . name == " appname "
2017-05-23 13:46:45 -07:00
2021-06-25 11:39:13 +09:00
class Module :
@staticmethod
def create_app ( * * kwargs ) :
return Flask ( " appname " )
2021-11-12 06:46:54 -08:00
app = find_best_app ( Module )
2020-04-07 15:54:36 -07:00
assert isinstance ( app , Flask )
assert app . name == " appname "
2017-05-22 12:30:18 -07:00
class Module :
@staticmethod
def make_app ( ) :
2019-05-06 15:39:41 -04:00
return Flask ( " appname " )
2017-05-24 17:27:36 -07:00
2021-11-12 06:46:54 -08:00
app = find_best_app ( Module )
2020-04-07 15:54:36 -07:00
assert isinstance ( app , Flask )
assert app . name == " appname "
2017-05-22 12:30:18 -07:00
class Module :
2019-05-06 15:39:41 -04:00
myapp = Flask ( " appname1 " )
2017-05-24 17:27:36 -07:00
2017-05-22 12:30:18 -07:00
@staticmethod
def create_app ( ) :
2019-05-06 15:39:41 -04:00
return Flask ( " appname2 " )
2017-05-24 17:27:36 -07:00
2021-11-12 06:46:54 -08:00
assert find_best_app ( Module ) == Module . myapp
2017-05-22 12:30:18 -07:00
class Module :
2019-05-06 15:39:41 -04:00
myapp = Flask ( " appname1 " )
2017-05-24 17:27:36 -07:00
2017-05-22 12:30:18 -07:00
@staticmethod
2017-05-23 13:46:45 -07:00
def create_app ( ) :
2019-05-06 15:39:41 -04:00
return Flask ( " appname2 " )
2017-05-24 17:27:36 -07:00
2021-11-12 06:46:54 -08:00
assert find_best_app ( Module ) == Module . myapp
2017-05-22 12:30:18 -07:00
2016-07-05 14:46:01 -05:00
class Module :
pass
2017-05-24 17:27:36 -07:00
2021-11-12 06:46:54 -08:00
pytest . raises ( NoAppException , find_best_app , Module )
2016-05-16 19:36:55 +02:00
2016-07-05 14:46:01 -05:00
class Module :
2019-05-06 15:39:41 -04:00
myapp1 = Flask ( " appname1 " )
myapp2 = Flask ( " appname2 " )
2017-05-24 17:27:36 -07:00
2021-11-12 06:46:54 -08:00
pytest . raises ( NoAppException , find_best_app , Module )
2016-05-16 19:36:55 +02:00
2017-05-22 12:30:18 -07:00
class Module :
@staticmethod
2017-05-23 13:46:45 -07:00
def create_app ( foo , bar ) :
2019-05-06 15:39:41 -04:00
return Flask ( " appname2 " )
2017-05-24 17:27:36 -07:00
2021-11-12 06:46:54 -08:00
pytest . raises ( NoAppException , find_best_app , Module )
2017-05-22 12:30:18 -07:00
2017-11-25 00:05:57 +01:00
class Module :
@staticmethod
def create_app ( ) :
2019-05-06 15:39:41 -04:00
raise TypeError ( " bad bad factory! " )
2017-11-25 00:05:57 +01:00
2021-11-12 06:46:54 -08:00
pytest . raises ( TypeError , find_best_app , Module )
2017-11-25 00:05:57 +01:00
2016-05-16 19:36:55 +02:00
2019-05-06 15:39:41 -04:00
@pytest.mark.parametrize (
" value,path,result " ,
2017-07-14 19:27:45 -07:00
(
2019-05-06 15:39:41 -04:00
( " test " , cwd , " test " ) ,
( " test.py " , cwd , " test " ) ,
2021-05-16 22:34:32 -04:00
( " a/test " , cwd / " a " , " test " ) ,
2019-05-06 15:39:41 -04:00
( " test/__init__.py " , cwd , " test " ) ,
( " test/__init__ " , cwd , " test " ) ,
# nested package
(
2021-05-16 22:34:32 -04:00
test_path / " cliapp " / " inner1 " / " __init__ " ,
2019-05-06 15:39:41 -04:00
test_path ,
" cliapp.inner1 " ,
) ,
(
2021-05-16 22:34:32 -04:00
test_path / " cliapp " / " inner1 " / " inner2 " ,
2019-05-06 15:39:41 -04:00
test_path ,
" cliapp.inner1.inner2 " ,
) ,
# dotted name
( " test.a.b " , cwd , " test.a.b " ) ,
2021-05-16 22:34:32 -04:00
( test_path / " cliapp.app " , test_path , " cliapp.app " ) ,
2019-05-06 15:39:41 -04:00
# not a Python file, will be caught during import
2021-05-16 22:34:32 -04:00
( test_path / " cliapp " / " message.txt " , test_path , " cliapp.message.txt " ) ,
2017-07-14 19:27:45 -07:00
) ,
2019-05-06 15:39:41 -04:00
)
2017-07-14 19:27:45 -07:00
def test_prepare_import ( request , value , path , result ) :
""" Expect the correct path to be set and the correct import and app names
to be returned .
: func : ` prepare_exec_for_file ` has a side effect where the parent directory
of the given import is added to : data : ` sys . path ` . This is reset after the
test runs .
2016-06-05 10:32:00 -07:00
"""
2017-07-14 19:27:45 -07:00
original_path = sys . path [ : ]
def reset_path ( ) :
sys . path [ : ] = original_path
request . addfinalizer ( reset_path )
assert prepare_import ( value ) == result
2021-05-16 22:34:32 -04:00
assert sys . path [ 0 ] == str ( path )
2017-07-14 19:27:45 -07:00
2019-05-06 15:39:41 -04:00
@pytest.mark.parametrize (
" iname,aname,result " ,
(
( " cliapp.app " , None , " testapp " ) ,
( " cliapp.app " , " testapp " , " testapp " ) ,
( " cliapp.factory " , None , " app " ) ,
( " cliapp.factory " , " create_app " , " app " ) ,
( " cliapp.factory " , " create_app() " , " app " ) ,
( " cliapp.factory " , ' create_app2( " foo " , " bar " ) ' , " app2_foo_bar " ) ,
# trailing comma space
( " cliapp.factory " , ' create_app2( " foo " , " bar " , ) ' , " app2_foo_bar " ) ,
# strip whitespace
( " cliapp.factory " , " create_app () " , " app " ) ,
) ,
)
2017-07-14 19:27:45 -07:00
def test_locate_app ( test_apps , iname , aname , result ) :
2021-11-12 06:46:54 -08:00
assert locate_app ( iname , aname ) . name == result
2017-07-14 19:27:45 -07:00
2019-05-06 15:39:41 -04:00
@pytest.mark.parametrize (
" iname,aname " ,
(
( " notanapp.py " , None ) ,
( " cliapp/app " , None ) ,
( " cliapp.app " , " notanapp " ) ,
# not enough arguments
( " cliapp.factory " , ' create_app2( " foo " ) ' ) ,
# invalid identifier
( " cliapp.factory " , " create_app( " ) ,
# no app returned
( " cliapp.factory " , " no_app " ) ,
# nested import error
( " cliapp.importerrorapp " , None ) ,
# not a Python file
( " cliapp.message.txt " , None ) ,
) ,
)
2017-07-14 19:27:45 -07:00
def test_locate_app_raises ( test_apps , iname , aname ) :
2016-06-03 09:41:10 -07:00
with pytest . raises ( NoAppException ) :
2021-11-12 06:46:54 -08:00
locate_app ( iname , aname )
2016-06-03 09:41:10 -07:00
2020-07-30 18:36:55 -07:00
def test_locate_app_suppress_raise ( test_apps ) :
2021-11-12 06:46:54 -08:00
app = locate_app ( " notanapp.py " , None , raise_if_not_found = False )
2017-07-14 19:27:45 -07:00
assert app is None
# only direct import error is suppressed
with pytest . raises ( NoAppException ) :
2021-11-12 06:46:54 -08:00
locate_app ( " cliapp.importerrorapp " , None , raise_if_not_found = False )
2016-06-07 08:03:55 -04:00
2016-08-20 08:43:58 -07:00
def test_get_version ( test_apps , capsys ) :
2019-01-06 16:17:33 -08:00
from flask import __version__ as flask_version
from werkzeug import __version__ as werkzeug_version
from platform import python_version
2017-05-24 17:27:36 -07:00
2020-04-04 09:43:06 -07:00
class MockCtx :
2016-08-20 08:43:58 -07:00
resilient_parsing = False
color = None
2017-05-24 17:27:36 -07:00
2019-05-06 15:39:41 -04:00
def exit ( self ) :
return
2017-05-24 17:27:36 -07:00
2016-08-20 08:43:58 -07:00
ctx = MockCtx ( )
get_version ( ctx , None , " test " )
out , err = capsys . readouterr ( )
2020-04-04 11:39:03 -07:00
assert f " Python { python_version ( ) } " in out
assert f " Flask { flask_version } " in out
assert f " Werkzeug { werkzeug_version } " in out
2016-08-20 08:43:58 -07:00
2017-06-15 11:27:50 -07:00
def test_scriptinfo ( test_apps , monkeypatch ) :
2016-05-16 19:36:55 +02:00
obj = ScriptInfo ( app_import_path = " cliapp.app:testapp " )
2018-10-24 21:13:11 +08:00
app = obj . load_app ( )
assert app . name == " testapp "
assert obj . load_app ( ) is app
# import app with module's absolute path
2021-05-16 22:34:32 -04:00
cli_app_path = str ( test_path / " cliapp " / " app.py " )
2018-10-24 21:13:11 +08:00
obj = ScriptInfo ( app_import_path = cli_app_path )
app = obj . load_app ( )
2019-05-06 15:39:41 -04:00
assert app . name == " testapp "
2018-10-24 21:13:11 +08:00
assert obj . load_app ( ) is app
2020-04-04 11:39:03 -07:00
obj = ScriptInfo ( app_import_path = f " { cli_app_path } :testapp " )
2018-10-24 21:13:11 +08:00
app = obj . load_app ( )
2019-05-06 15:39:41 -04:00
assert app . name == " testapp "
2018-10-24 21:13:11 +08:00
assert obj . load_app ( ) is app
2016-05-16 19:36:55 +02:00
2020-04-07 15:54:36 -07:00
def create_app ( ) :
2016-05-16 19:36:55 +02:00
return Flask ( " createapp " )
obj = ScriptInfo ( create_app = create_app )
app = obj . load_app ( )
assert app . name == " createapp "
2018-10-24 21:13:11 +08:00
assert obj . load_app ( ) is app
2016-05-16 19:36:55 +02:00
2017-06-15 11:27:50 -07:00
obj = ScriptInfo ( )
2017-06-16 06:59:37 -07:00
pytest . raises ( NoAppException , obj . load_app )
2017-06-15 11:27:50 -07:00
# import app from wsgi.py in current directory
2021-05-16 22:34:32 -04:00
monkeypatch . chdir ( test_path / " helloworld " )
2017-06-15 11:27:50 -07:00
obj = ScriptInfo ( )
app = obj . load_app ( )
2019-05-06 15:39:41 -04:00
assert app . name == " hello "
2017-06-15 11:27:50 -07:00
# import app from app.py in current directory
2021-05-16 22:34:32 -04:00
monkeypatch . chdir ( test_path / " cliapp " )
2017-06-15 11:27:50 -07:00
obj = ScriptInfo ( )
app = obj . load_app ( )
2019-05-06 15:39:41 -04:00
assert app . name == " testapp "
2017-06-15 11:27:50 -07:00
2016-05-16 19:36:55 +02:00
2022-06-17 11:14:22 -07:00
def test_app_cli_has_app_context ( app , runner ) :
def _param_cb ( ctx , param , value ) :
# current_app should be available in parameter callbacks
return bool ( current_app )
@app.cli.command ( )
@click.argument ( " value " , callback = _param_cb )
def check ( value ) :
app = click . get_current_context ( ) . obj . load_app ( )
# the loaded app should be the same as current_app
same_app = current_app . _get_current_object ( ) is app
2022-06-29 21:11:58 -07:00
return same_app , value
2022-06-17 11:14:22 -07:00
cli = FlaskGroup ( create_app = lambda : app )
result = runner . invoke ( cli , [ " check " , " x " ] , standalone_mode = False )
2022-06-29 21:11:58 -07:00
assert result . return_value == ( True , True )
2022-06-17 11:14:22 -07:00
2016-06-25 13:24:43 +02:00
def test_with_appcontext ( runner ) :
2016-05-16 19:36:55 +02:00
@click.command ( )
@with_appcontext
def testcmd ( ) :
click . echo ( current_app . name )
2020-04-07 15:54:36 -07:00
obj = ScriptInfo ( create_app = lambda : Flask ( " testapp " ) )
2016-05-16 19:36:55 +02:00
result = runner . invoke ( testcmd , obj = obj )
assert result . exit_code == 0
2019-05-06 15:39:41 -04:00
assert result . output == " testapp \n "
2016-05-16 19:36:55 +02:00
2022-06-17 11:14:22 -07:00
def test_appgroup_app_context ( runner ) :
2016-05-16 19:36:55 +02:00
@click.group ( cls = AppGroup )
def cli ( ) :
pass
2022-06-17 11:14:22 -07:00
@cli.command ( )
2016-05-16 19:36:55 +02:00
def test ( ) :
click . echo ( current_app . name )
@cli.group ( )
def subgroup ( ) :
pass
2022-06-17 11:14:22 -07:00
@subgroup.command ( )
2016-05-16 19:36:55 +02:00
def test2 ( ) :
click . echo ( current_app . name )
2020-04-07 15:54:36 -07:00
obj = ScriptInfo ( create_app = lambda : Flask ( " testappgroup " ) )
2016-05-16 19:36:55 +02:00
2019-05-06 15:39:41 -04:00
result = runner . invoke ( cli , [ " test " ] , obj = obj )
2016-05-16 19:36:55 +02:00
assert result . exit_code == 0
2019-05-06 15:39:41 -04:00
assert result . output == " testappgroup \n "
2016-05-16 19:36:55 +02:00
2019-05-06 15:39:41 -04:00
result = runner . invoke ( cli , [ " subgroup " , " test2 " ] , obj = obj )
2016-05-16 19:36:55 +02:00
assert result . exit_code == 0
2019-05-06 15:39:41 -04:00
assert result . output == " testappgroup \n "
2016-05-16 19:36:55 +02:00
2022-06-17 11:14:22 -07:00
def test_flaskgroup_app_context ( runner ) :
2020-04-07 15:54:36 -07:00
def create_app ( ) :
2016-05-16 19:36:55 +02:00
return Flask ( " flaskgroup " )
@click.group ( cls = FlaskGroup , create_app = create_app )
def cli ( * * params ) :
pass
@cli.command ( )
def test ( ) :
click . echo ( current_app . name )
2019-05-06 15:39:41 -04:00
result = runner . invoke ( cli , [ " test " ] )
2016-05-16 19:36:55 +02:00
assert result . exit_code == 0
2019-05-06 15:39:41 -04:00
assert result . output == " flaskgroup \n "
2016-06-25 13:17:33 +02:00
2019-05-06 15:39:41 -04:00
@pytest.mark.parametrize ( " set_debug_flag " , ( True , False ) )
2018-05-08 18:05:55 +02:00
def test_flaskgroup_debug ( runner , set_debug_flag ) :
2020-04-07 15:54:36 -07:00
def create_app ( ) :
2018-05-08 18:05:55 +02:00
app = Flask ( " flaskgroup " )
app . debug = True
return app
@click.group ( cls = FlaskGroup , create_app = create_app , set_debug_flag = set_debug_flag )
def cli ( * * params ) :
pass
@cli.command ( )
def test ( ) :
click . echo ( str ( current_app . debug ) )
2019-05-06 15:39:41 -04:00
result = runner . invoke ( cli , [ " test " ] )
2018-05-08 18:05:55 +02:00
assert result . exit_code == 0
2020-04-04 11:39:03 -07:00
assert result . output == f " { not set_debug_flag } \n "
2018-05-08 18:05:55 +02:00
2022-06-15 14:07:00 -07:00
def test_flaskgroup_nested ( app , runner ) :
cli = click . Group ( " cli " )
flask_group = FlaskGroup ( name = " flask " , create_app = lambda : app )
cli . add_command ( flask_group )
@flask_group.command ( )
def show ( ) :
click . echo ( current_app . name )
result = runner . invoke ( cli , [ " flask " , " show " ] )
assert result . output == " flask_test \n "
2020-07-30 18:36:55 -07:00
def test_no_command_echo_loading_error ( ) :
from flask . cli import cli
2017-05-24 17:27:36 -07:00
2020-07-30 18:36:55 -07:00
runner = CliRunner ( mix_stderr = False )
result = runner . invoke ( cli , [ " missing " ] )
assert result . exit_code == 2
assert " FLASK_APP " in result . stderr
assert " Usage: " in result . stderr
def test_help_echo_loading_error ( ) :
from flask . cli import cli
runner = CliRunner ( mix_stderr = False )
result = runner . invoke ( cli , [ " --help " ] )
assert result . exit_code == 0
assert " FLASK_APP " in result . stderr
assert " Usage: " in result . stdout
def test_help_echo_exception ( ) :
2020-04-07 15:54:36 -07:00
def create_app ( ) :
2017-03-16 20:56:12 +01:00
raise Exception ( " oh no " )
2020-07-30 18:36:55 -07:00
cli = FlaskGroup ( create_app = create_app )
runner = CliRunner ( mix_stderr = False )
2019-05-06 15:39:41 -04:00
result = runner . invoke ( cli , [ " --help " ] )
2017-03-16 20:56:12 +01:00
assert result . exit_code == 0
2020-07-30 18:36:55 -07:00
assert " Exception: oh no " in result . stderr
assert " Usage: " in result . stdout
2017-04-25 13:13:10 -07:00
2016-06-25 13:17:33 +02:00
class TestRoutes :
2017-04-25 14:15:38 -07:00
@pytest.fixture
2022-07-02 21:02:00 -07:00
def app ( self ) :
app = Flask ( __name__ )
2023-04-14 09:34:26 -07:00
app . add_url_rule (
" /get_post/<int:x>/<int:y> " ,
methods = [ " GET " , " POST " ] ,
endpoint = " yyy_get_post " ,
)
app . add_url_rule ( " /zzz_post " , methods = [ " POST " ] , endpoint = " aaa_post " )
2022-07-02 21:02:00 -07:00
return app
2017-04-25 14:15:38 -07:00
2022-07-02 21:02:00 -07:00
@pytest.fixture
def invoke ( self , app , runner ) :
cli = FlaskGroup ( create_app = lambda : app )
2017-04-25 14:15:38 -07:00
return partial ( runner . invoke , cli )
def expect_order ( self , order , output ) :
# skip the header and match the start of each row
for expect , line in zip ( order , output . splitlines ( ) [ 2 : ] ) :
# do this instead of startswith for nicer pytest output
2019-05-06 15:39:41 -04:00
assert line [ : len ( expect ) ] == expect
2017-04-25 14:15:38 -07:00
def test_simple ( self , invoke ) :
2019-05-06 15:39:41 -04:00
result = invoke ( [ " routes " ] )
2016-06-25 13:17:33 +02:00
assert result . exit_code == 0
2019-05-06 15:39:41 -04:00
self . expect_order ( [ " aaa_post " , " static " , " yyy_get_post " ] , result . output )
2017-04-25 14:15:38 -07:00
2022-07-02 21:02:00 -07:00
def test_sort ( self , app , invoke ) :
2019-05-06 15:39:41 -04:00
default_output = invoke ( [ " routes " ] ) . output
endpoint_output = invoke ( [ " routes " , " -s " , " endpoint " ] ) . output
2017-04-25 14:15:38 -07:00
assert default_output == endpoint_output
self . expect_order (
2019-05-06 15:39:41 -04:00
[ " static " , " yyy_get_post " , " aaa_post " ] ,
invoke ( [ " routes " , " -s " , " methods " ] ) . output ,
2017-04-25 14:15:38 -07:00
)
self . expect_order (
2019-05-06 15:39:41 -04:00
[ " yyy_get_post " , " static " , " aaa_post " ] ,
invoke ( [ " routes " , " -s " , " rule " ] ) . output ,
2017-04-25 14:15:38 -07:00
)
2022-07-02 21:02:00 -07:00
match_order = [ r . endpoint for r in app . url_map . iter_rules ( ) ]
self . expect_order ( match_order , invoke ( [ " routes " , " -s " , " match " ] ) . output )
2017-04-25 14:15:38 -07:00
def test_all_methods ( self , invoke ) :
2019-05-06 15:39:41 -04:00
output = invoke ( [ " routes " ] ) . output
assert " GET, HEAD, OPTIONS, POST " not in output
output = invoke ( [ " routes " , " --all-methods " ] ) . output
assert " GET, HEAD, OPTIONS, POST " in output
2017-07-14 22:37:53 -07:00
2023-04-14 09:34:26 -07:00
def test_no_routes ( self , runner ) :
app = Flask ( __name__ , static_folder = None )
cli = FlaskGroup ( create_app = lambda : app )
result = runner . invoke ( cli , [ " routes " ] )
2018-05-31 11:43:51 +08:00
assert result . exit_code == 0
2019-05-06 15:39:41 -04:00
assert " No routes were registered. " in result . output
2018-05-31 11:43:51 +08:00
2023-04-14 09:34:26 -07:00
def test_subdomain ( self , runner ) :
app = Flask ( __name__ , static_folder = None )
app . add_url_rule ( " /a " , subdomain = " a " , endpoint = " a " )
app . add_url_rule ( " /b " , subdomain = " b " , endpoint = " b " )
cli = FlaskGroup ( create_app = lambda : app )
result = runner . invoke ( cli , [ " routes " ] )
assert result . exit_code == 0
assert " Subdomain " in result . output
def test_host ( self , runner ) :
app = Flask ( __name__ , static_folder = None , host_matching = True )
app . add_url_rule ( " /a " , host = " a " , endpoint = " a " )
app . add_url_rule ( " /b " , host = " b " , endpoint = " b " )
cli = FlaskGroup ( create_app = lambda : app )
result = runner . invoke ( cli , [ " routes " ] )
assert result . exit_code == 0
assert " Host " in result . output
2017-07-14 22:37:53 -07:00
2022-05-23 09:46:20 -07:00
def dotenv_not_available ( ) :
try :
import dotenv # noqa: F401
except ImportError :
return True
return False
need_dotenv = pytest . mark . skipif (
dotenv_not_available ( ) , reason = " dotenv is not installed "
)
2017-07-14 22:37:53 -07:00
@need_dotenv
def test_load_dotenv ( monkeypatch ) :
# can't use monkeypatch.delitem since the keys don't exist yet
2021-03-10 21:40:29 +08:00
for item in ( " FOO " , " BAR " , " SPAM " , " HAM " ) :
2017-07-14 22:37:53 -07:00
monkeypatch . _setitem . append ( ( os . environ , item , notset ) )
2019-05-06 15:39:41 -04:00
monkeypatch . setenv ( " EGGS " , " 3 " )
2020-04-07 21:46:53 +08:00
monkeypatch . chdir ( test_path )
2018-10-11 16:52:15 +05:30
assert load_dotenv ( )
2021-05-16 22:34:32 -04:00
assert Path . cwd ( ) == test_path
2017-07-14 22:37:53 -07:00
# .flaskenv doesn't overwrite .env
2019-05-06 15:39:41 -04:00
assert os . environ [ " FOO " ] == " env "
2017-07-14 22:37:53 -07:00
# set only in .flaskenv
2019-05-06 15:39:41 -04:00
assert os . environ [ " BAR " ] == " bar "
2017-07-14 22:37:53 -07:00
# set only in .env
2019-05-06 15:39:41 -04:00
assert os . environ [ " SPAM " ] == " 1 "
2017-07-14 22:37:53 -07:00
# set manually, files don't overwrite
2019-05-06 15:39:41 -04:00
assert os . environ [ " EGGS " ] == " 3 "
2021-03-10 21:40:29 +08:00
# test env file encoding
assert os . environ [ " HAM " ] == " 火腿 "
2018-10-11 16:52:15 +05:30
# Non existent file should not load
2019-05-31 11:57:28 +01:00
assert not load_dotenv ( " non-existent-file " )
2018-10-11 16:52:15 +05:30
2017-07-14 22:37:53 -07:00
@need_dotenv
def test_dotenv_path ( monkeypatch ) :
2019-05-06 15:39:41 -04:00
for item in ( " FOO " , " BAR " , " EGGS " ) :
2017-07-14 22:37:53 -07:00
monkeypatch . _setitem . append ( ( os . environ , item , notset ) )
2021-05-16 22:34:32 -04:00
load_dotenv ( test_path / " .flaskenv " )
assert Path . cwd ( ) == cwd
2019-05-06 15:39:41 -04:00
assert " FOO " in os . environ
2017-07-14 22:37:53 -07:00
def test_dotenv_optional ( monkeypatch ) :
2022-05-23 09:46:20 -07:00
monkeypatch . setitem ( sys . modules , " dotenv " , None )
2017-07-14 22:37:53 -07:00
monkeypatch . chdir ( test_path )
load_dotenv ( )
2019-05-06 15:39:41 -04:00
assert " FOO " not in os . environ
2018-01-22 12:16:37 -08:00
2018-04-28 08:07:53 -07:00
@need_dotenv
def test_disable_dotenv_from_env ( monkeypatch , runner ) :
monkeypatch . chdir ( test_path )
2019-05-06 15:39:41 -04:00
monkeypatch . setitem ( os . environ , " FLASK_SKIP_DOTENV " , " 1 " )
2018-04-28 08:07:53 -07:00
runner . invoke ( FlaskGroup ( ) )
2019-05-06 15:39:41 -04:00
assert " FOO " not in os . environ
2018-04-28 08:07:53 -07:00
2018-01-22 12:16:37 -08:00
def test_run_cert_path ( ) :
# no key
with pytest . raises ( click . BadParameter ) :
2019-05-06 15:39:41 -04:00
run_command . make_context ( " run " , [ " --cert " , __file__ ] )
2018-01-22 12:16:37 -08:00
# no cert
with pytest . raises ( click . BadParameter ) :
2019-05-06 15:39:41 -04:00
run_command . make_context ( " run " , [ " --key " , __file__ ] )
2018-01-22 12:16:37 -08:00
2022-04-18 08:52:01 -04:00
# cert specified first
2019-05-06 15:39:41 -04:00
ctx = run_command . make_context ( " run " , [ " --cert " , __file__ , " --key " , __file__ ] )
assert ctx . params [ " cert " ] == ( __file__ , __file__ )
2018-01-22 12:16:37 -08:00
2022-04-18 08:52:01 -04:00
# key specified first
ctx = run_command . make_context ( " run " , [ " --key " , __file__ , " --cert " , __file__ ] )
assert ctx . params [ " cert " ] == ( __file__ , __file__ )
2018-01-22 12:16:37 -08:00
def test_run_cert_adhoc ( monkeypatch ) :
2020-02-09 16:01:23 -08:00
monkeypatch . setitem ( sys . modules , " cryptography " , None )
2018-01-22 12:16:37 -08:00
2020-02-09 16:01:23 -08:00
# cryptography not installed
2018-01-22 12:16:37 -08:00
with pytest . raises ( click . BadParameter ) :
2019-05-06 15:39:41 -04:00
run_command . make_context ( " run " , [ " --cert " , " adhoc " ] )
2018-01-22 12:16:37 -08:00
2020-02-09 16:01:23 -08:00
# cryptography installed
monkeypatch . setitem ( sys . modules , " cryptography " , types . ModuleType ( " cryptography " ) )
2019-05-06 15:39:41 -04:00
ctx = run_command . make_context ( " run " , [ " --cert " , " adhoc " ] )
assert ctx . params [ " cert " ] == " adhoc "
2018-01-22 12:16:37 -08:00
# no key with adhoc
with pytest . raises ( click . BadParameter ) :
2019-05-06 15:39:41 -04:00
run_command . make_context ( " run " , [ " --cert " , " adhoc " , " --key " , __file__ ] )
2018-01-22 12:16:37 -08:00
def test_run_cert_import ( monkeypatch ) :
2019-05-06 15:39:41 -04:00
monkeypatch . setitem ( sys . modules , " not_here " , None )
2018-01-22 12:16:37 -08:00
# ImportError
with pytest . raises ( click . BadParameter ) :
2019-05-06 15:39:41 -04:00
run_command . make_context ( " run " , [ " --cert " , " not_here " ] )
2018-01-22 12:16:37 -08:00
2020-04-04 09:25:54 -07:00
with pytest . raises ( click . BadParameter ) :
run_command . make_context ( " run " , [ " --cert " , " flask " ] )
2018-01-22 12:16:37 -08:00
# SSLContext
2020-04-04 09:25:54 -07:00
ssl_context = ssl . SSLContext ( ssl . PROTOCOL_TLS_SERVER )
2018-01-22 12:16:37 -08:00
2019-05-06 15:39:41 -04:00
monkeypatch . setitem ( sys . modules , " ssl_context " , ssl_context )
ctx = run_command . make_context ( " run " , [ " --cert " , " ssl_context " ] )
assert ctx . params [ " cert " ] is ssl_context
2018-01-22 12:16:37 -08:00
# no --key with SSLContext
with pytest . raises ( click . BadParameter ) :
2019-05-06 15:39:41 -04:00
run_command . make_context ( " run " , [ " --cert " , " ssl_context " , " --key " , __file__ ] )
2018-05-14 22:05:54 -04:00
2019-05-31 11:45:38 -04:00
def test_run_cert_no_ssl ( monkeypatch ) :
2022-05-23 09:46:20 -07:00
monkeypatch . setitem ( sys . modules , " ssl " , None )
2019-05-31 11:45:38 -04:00
with pytest . raises ( click . BadParameter ) :
run_command . make_context ( " run " , [ " --cert " , " not_here " ] )
2018-05-14 22:05:54 -04:00
def test_cli_blueprints ( app ) :
""" Test blueprint commands register correctly to the application """
custom = Blueprint ( " custom " , __name__ , cli_group = " customized " )
nested = Blueprint ( " nested " , __name__ )
merged = Blueprint ( " merged " , __name__ , cli_group = None )
late = Blueprint ( " late " , __name__ )
@custom.cli.command ( " custom " )
def custom_command ( ) :
click . echo ( " custom_result " )
@nested.cli.command ( " nested " )
def nested_command ( ) :
click . echo ( " nested_result " )
@merged.cli.command ( " merged " )
def merged_command ( ) :
click . echo ( " merged_result " )
@late.cli.command ( " late " )
def late_command ( ) :
click . echo ( " late_result " )
app . register_blueprint ( custom )
app . register_blueprint ( nested )
app . register_blueprint ( merged )
app . register_blueprint ( late , cli_group = " late_registration " )
app_runner = app . test_cli_runner ( )
result = app_runner . invoke ( args = [ " customized " , " custom " ] )
assert " custom_result " in result . output
result = app_runner . invoke ( args = [ " nested " , " nested " ] )
assert " nested_result " in result . output
result = app_runner . invoke ( args = [ " merged " ] )
assert " merged_result " in result . output
result = app_runner . invoke ( args = [ " late_registration " , " late " ] )
assert " late_result " in result . output
2019-05-31 16:48:32 +01:00
def test_cli_empty ( app ) :
""" If a Blueprint ' s CLI group is empty, do not register it. """
bp = Blueprint ( " blue " , __name__ , cli_group = " blue " )
app . register_blueprint ( bp )
result = app . test_cli_runner ( ) . invoke ( args = [ " blue " , " --help " ] )
2020-04-04 11:39:03 -07:00
assert result . exit_code == 2 , f " Unexpected success: \n \n { result . output } "