PyCharm 中的调试烧瓶

Debugging Flask in PyCharm

我正在尝试弄清楚如何在使用 Flask (Werkzeug) 调试器调试我的 Flask 应用程序和使用 PyCharm 的调试器之间轻松切换。我已经有两个 PyCharm 运行配置

  1. 我用 "Run" 和 --debug 标志调用的一个提供给应用程序脚本;和
  2. 我使用 "Debug" 和提供给应用程序脚本的 --pydebug 标志调用的一个

使用我的应用程序脚本中支持的标志

if __name__ == "__main__":

    import argparse
    parser = argparse.ArgumentParser(description='Runs Web application with options for debugging')
    parser.add_argument('-d', '--debug', action='store_true', 
                        dest='debug_mode', default=False,
                        help='run in Werkzeug debug mode')
    parser.add_argument('-p', '--pydebug', action='store_true') 
                        dest='debug_pycharm', default=False,
                        help='for use with PyCharm debugger')

    cmd_args = parser.parse_args()
    app_options = dict()

    app_options["debug"] = cmd_args.debug_mode or cmd_args.debug_pycharm
    if cmd_args.debug_pycharm:
        app_options["use_debugger"] = False
        app_options["use_reloader"] = False

    application.run(**app_options)

这有效,并且满足我不需要编辑任何代码即可部署到服务器的要求;但我不确定这是最好的方法。首先,我需要记住第二个配置是用 "Debug"(而不是 "Run")启动的,而第一个配置是用 "Run"(不是 "Debug") 在 PyCharm.

是否有更好的方法来支持 PyCharm 中的这两种调试方法,使用 PyCharm 的某些功能(例如,它允许我检测何时调用 "Debug"而不是 "Run") 或更智能地使用 Flask 的功能。

在 PyCharm 调试器下检查您的应用程序是否 运行 的一种非常简单的方法是:

'pydevd' in sys.modules

在 Pycharm Professional 2020.1 上,现在有一个 Flask Server run/debug 配置选项,我让它可以使用以下输入(在断点处停止,单步执行等)。

这是针对结构如下的项目:

main.py 看起来像这样:


import warnings
from flask import Flask
from flask_mongoengine import MongoEngine
from flask_script import Server, Manager
from flask_bootstrap import Bootstrap
from flask_user import UserManager
from flask_mail import Mail
from flask_wtf.csrf import CSRFProtect

# for importing module from parent dir
import os, sys, inspect
current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parent_dir = os.path.dirname(current_dir)
sys.path.insert(0, parent_dir)
import cnf.settings as settings
import cnf.scripts.scripts as scripts


# pymongo has issues...
warnings.filterwarnings("ignore", category=DeprecationWarning, module='mongoengine')

#instantiate Flask extensions
#csrf_protect = CSRFProtect()
#mail = Mail()

config = settings.config


def setup_app(config_name, extra_config_settings={} ):
    app = Flask(
        __name__, # special variable that gets string val of __main__ when executing script
        #static_url_path='',
        #static_folder='static',
        static_folder=settings.Config.STATIC_FOLDER,
        template_folder=settings.Config.TEMPLATE_FOLDER,
    )

    app.config.from_object(config[config_name])
    # load extra settings from extra config settings param
    app.config.update(extra_config_settings)

    with app.app_context():
        app.db = MongoEngine(app)

        #csrf_protect.init_app(cnf)
        app.CSRFProtect = CSRFProtect(app)
        #register blueprints
        from cnf.views import register_blueprints
        register_blueprints(app)

        # Define bootstrap is hidden_field for flask bootstrap's
        # bootstrap wtf.html
        from wtforms.fields import HiddenField

        def is_hidden_field_filter(field):
            return isinstance(field, HiddenField)

        app.jinja_env.globals['bootstrap_is_hidden_field'] = is_hidden_field_filter
        app.mail = Mail(app)
        #init_email_error_handler(cnf)

        # setup Flask-User to handle user account related forms
        from cnf.models.user_models import User
        user_manager = UserManager(app, app.db, User)

        @app.context_processor
        def context_processor():
            return dict(user_manager=user_manager)

        app.bootstrap = Bootstrap(app)
        '''
        app.manager = Manager(app)
        app.manager.add_command(
            'runserver',
            Server(
                host=app.config['FLASK_BIND'],
                port=app.config['FLASK_PORT']
            )
        )
        '''
        # import csv files
        #app.manager.add_command('import', scripts.Import())
        #Importer = scripts.Import()
        #Importer.run()

    return app

'''
def main():  # pragma: no cover
    app = setup_app('default') #with default dev configs

    # Import your views!
    with app.app_context():
        import cnf.views
    app.manager.run()

'''


if __name__ == "__main__":  # pragma: no cover
    #add_path()
    app = setup_app('default')

    # Import your views!
    with app.app_context():
        pass
    app.run()
    #app.manager.run()


# python cnf/main.py runserver