Source code for biweeklybudget.flaskapp.cli_commands

"""
The latest version of this package is available at:
<http://github.com/jantman/biweeklybudget>

################################################################################
Copyright 2016 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>

    This file is part of biweeklybudget, also known as biweeklybudget.

    biweeklybudget is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    biweeklybudget is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with biweeklybudget.  If not, see <http://www.gnu.org/licenses/>.

The Copyright and Authors attributions contained herein may not be removed or
otherwise altered, except to add the Author attribution of a contributor to
this work. (Additional Terms pursuant to Section 7b of the AGPL v3)
################################################################################
While not legally required, I sincerely request that anyone who finds
bugs please submit them at <https://github.com/jantman/biweeklybudget> or
to me via email, and that you send any contributions or improvements
either as a pull request on GitHub, or to me via email.
################################################################################

AUTHORS:
Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
################################################################################
"""

import os
import time
from werkzeug.serving import run_simple, WSGIRequestHandler
from flask.cli import pass_script_info, DispatchingApp

import click


[docs]class CustomLoggingWSGIRequestHandler(WSGIRequestHandler): """Extend werkzeug request handler to include processing time in logs"""
[docs] def handle(self): self._time_started = time.time() rv = super(CustomLoggingWSGIRequestHandler, self).handle() return rv
[docs] def send_response(self, *args, **kw): self._time_finished = time.time() super(CustomLoggingWSGIRequestHandler, self).send_response(*args, **kw)
[docs] def log_request(self, code='-', size='-'): duration = int((self._time_finished - self._time_started) * 1000) self.log( 'info', '"%s" %s %s [%sms]', self.requestline, code, size, duration )
[docs]def template_paths(): """ Return a list of all Flask app template paths, to auto-reload on change. from http://stackoverflow.com/a/41666467/211734 :return: list of all template paths :rtype: list """ extra_dirs = [ os.path.join( os.path.dirname(os.path.abspath(__file__)), 'templates' ), ] extra_files = extra_dirs[:] for extra_dir in extra_dirs: for dirname, dirs, files in os.walk(extra_dir): for filename in files: filename = os.path.join(dirname, filename) if os.path.isfile(filename): extra_files.append(filename) return extra_files
@click.command('rundev', short_help='Runs a development server with reloading') @click.option('--host', '-h', default='127.0.0.1', help='The interface to bind to.') @click.option('--port', '-p', default=5000, help='The port to bind to.') @click.option('--eager-loading/--lazy-loader', default=None, help='Enable or disable eager loading. By default eager ' 'loading is enabled if the reloader is disabled.') @click.option('--with-threads/--without-threads', default=False, help='Enable or disable multithreading.') @pass_script_info def rundev_command(info, host, port, eager_loading, with_threads): """ Modified from the upstream ``flask.cli.run_command`` to add some debugging and reloading features """ # Set a global flag that indicates that we were invoked from the # command line interface provided server command. This is detected # by Flask.run to make the call into a no-op. This is necessary to # avoid ugly errors when the script that is loaded here also attempts # to start a server. os.environ['FLASK_RUN_FROM_CLI_SERVER'] = '1' os.environ['FLASK_DEBUG'] = '1' debug = True reload = True debugger = True if eager_loading is None: eager_loading = not reload app = DispatchingApp(info.load_app, use_eager_loading=eager_loading) # Extra startup messages. This depends a bit on Werkzeug internals to # not double execute when the reloader kicks in. if os.environ.get('WERKZEUG_RUN_MAIN') != 'true': # If we have an import path we can print it out now which can help # people understand what's being served. If we do not have an # import path because the app was loaded through a callback then # we won't print anything. if info.app_import_path is not None: print(' * Serving Flask app "%s"' % info.app_import_path) if debug is not None: print(' * Forcing debug mode %s' % (debug and 'on' or 'off')) run_simple( host, port, app, use_reloader=reload, use_debugger=debugger, threaded=with_threads, extra_files=template_paths(), request_handler=CustomLoggingWSGIRequestHandler )