Flask: постоянное отображение флеш-сообщений - PullRequest
0 голосов
/ 14 февраля 2019

Я разработал приложение для колб, которое запускает скрипт математической оптимизации (PuLP + Python) для ввода данных пользователем.Так как вычисления занимают довольно много времени, я хочу постоянно (без обновления) отображать операторы печати оптимизатора на своей веб-странице.

На основе этого решения Мне удалось запустить subprocess смой .py скрипт.В этом сценарии оператор print() делает то, что должен, однако я вижу только выходные данные в командной строке.С помощью flash() мне удалось отобразить вывод, но он отображается только после того, как вычисление завершено и страница перезагружена.Я пытаюсь вывести операторы print() в реальном времени в моем HTML.Есть ли способ достичь этого?

Спасибо!

Выдержка из routes.py:

@app.route('/optimize', methods=['GET', 'POST'])
    def solve():
    path = os.path.join(app.root_path, 'optimization', 'assets')
    file = "test.py"
    execute(file, path)

return redirect(url_for('home'))

Функция execute(file,path):

import os
import subprocess as sub

def execute(command, directory):

    # change directory to execute the command
    os.chdir(directory)

    proc = sub.Popen(['python','-u', command], stdout=sub.PIPE, universal_newlines=True) # Python 2: bufsize=1

    for stdout_line in proc.stdout:
        print(stdout_line.rstrip() + '\n')
        flash(stdout_line.rstrip(), 'python_print')
    proc.stdout.close()
    return_code = proc.wait()
    if return_code:
        raise sub.CalledProcessError(return_code, command)

И, наконец, мой HTML, который отображается в маршруте home:

{% with prints = get_flashed_messages(category_filter=["python_print"]) %}
{% if prints %}
<div class="content-section">
    <h3>Solver Status</h3>
    <ul>
        {%- for message in prints %}
        <li>{{ message }}</li>
        {% endfor -%}
    </ul>
</div>
{% endif %}
{% endwith %}

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

На основании предоставленных предложений я изменил свой подход и запустил его.Вместо использования subprocess решатель импортируется как модуль.Я генерирую .txt, используя модуль python logging, а не пытаюсь перехватить операторы print.Этот файл постоянно передается с помощью flask response + yield и анализируется с помощью AJAX.Получатель вызывается в jQuery через setInterval (здесь: 1Hz) и добавляется в мой HTML.Я опубликую некоторые фрагменты ниже для тех, кто имеет дело с той же проблемой.

Спасибо за вашу поддержку!

Оптимизация маршрута в колбе:

import supplierAllocation.optimization.optimizer as optimizer

@app.route('/optimize')
def optimize():

    if session.get('input_file') is not None:

        # Get input_file
        input_file = session.get('input_file')

        # Path to logfile
        log_file = os.path.join(
            app.config['LOG_FOLDER'], session.get('log_file'))

        # Assign random unique hex file name from session to output file
        out_file_fn = session.get('session_ID') + '.xlsx'
        output_file = os.path.join(app.config['DOWNLOAD_FOLDER'], out_file_fn)

        # Search for outdated output; if present: delete
        if session.get('output_file') is None:
            session['output_file'] = out_file_fn
        else:
            session_output = os.path.join(
                app.config['DOWNLOAD_FOLDER'], session.get('output_file'))
            silent_remove(session_output)

        # Pass input and output parameter to solver
        optimizer.launch_solver(input_file, output_file, log_file)

    else:
        flash("Please upload your data before launching the solver!", 'warning')

    return redirect(url_for('home'))

Потоковый маршрут колбы:

@app.route('/streamLog')
def stream_logfile():
    if session.get('log_file') is None:
        return Response(status=204)
    else:
        session_log = os.path.join(
            app.config['LOG_FOLDER'], session.get('log_file'))

        def stream():
            with open(session_log, "rb") as file:
                yield file.read()

        return Response(stream(), mimetype='text/plain')

Вызов запроса AJAX по нажатию кнопки:

// Print solver output with 1Hz
var session_log = setInterval(get_Log, 1000);

Запрос AJAX в jQuery:

// AJAX Request to download solutions
function get_Log() {
  console.log('Sending AJAX request...');
  $.ajax({
    url: "streamLog",
    dataType: "text",
    success: function(result) {
      $("#code-wrapper").html(result);
    },
    error: function() {
      console.log("ERROR! Logfile could not be retrieved.");
    }
  });
}

0 голосов
/ 15 февраля 2019

Насколько я знаю, именно так должно работать мигание сообщений, то есть оно будет отображать все сообщения для определенной конечной точки одновременно.

Я не уверен насчет точной реализации, так как я не смотрел исходный код для flash() и get_flash_messages(), но это мое понимание того, что может происходить в фоновом режиме, каждое сообщение, которое вы мигаетеflash функция в вашем коде Python добавляется к итерируемой, а когда вы вызываете get_flashed_messages(), она возвращает ту итерацию обратно, которую вы можете зациклить, чтобы получить сообщения.

Хотя ваш execute()функция добавляет сообщения к этой итерации до завершения процесса, но обратите внимание, что функция execute вызывается из представления solve, а фактическая redirect может произойти только после завершения функции execute,и тогда шаблон home получит итерацию со всеми перепрошившими сообщениями.

Надеюсь, что это имеет смысл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...