Я хочу создать приложение Python Dash для просмотра каталога по ftp, извлечения данных из файла и отображения их в режиме реального времени

#python #python-3.x #ftp #plotly #plotly-dash

#python #python-3.x #ftp #сюжет #plotly-dash

Вопрос:

Я работаю над проектом, в котором я должен отслеживать каталог ftp на наличие любых новых файлов, которые появляются, как только появляется новый файл, я хочу извлечь данные и отобразить результаты в режиме реального времени. пока я разобрался с функцией ftp, которая отслеживает каталог, для целей тестирования, которые я использую мой телефон в качестве тестового ftp-сервера, и я создал функцию, которая загружает новый файл каждые n секунд :

 from ftplib import FTP
from time import sleep
import os


ftp = FTP()
ftp.connect('192.168.1.109', 2221)
ftp.login('android', 'android')
ftp.cwd('/test_folder')
folder = 'C:\Users\QC\Desktop\sample_files_to_upload'

for file in os.listdir(folder):
    fp = open(folder   file,'rb')
    ftp.storbinary('STOR %s' % os.path.basename(file), fp, 1024)
    sleep(2)
    fp.close()
    sleep(2)
    print("File {} uploaded sucessfully".format(file))
 

У меня также есть функция которая отслеживает каталог на наличие любых новых файлов которые появляются в каталоге и как только появляется файл копирует его на локальном компьютере выполняет извлечение данных распечатывает выходные данные и удаляет файл:

 from ftplib import FTP
from time import sleep
import time
import os

def monitor_ftp():
    ftp = FTP()
    ftp.connect('192.168.1.109', 2221', 21)
    ftp.login('android', 'android)
    ftp.cwd('/test_folder')
    print("Connection Established {}".format(ftp.getwelcome()))
    direct = 'C:\Users\QC\Desktop\local_temp_directory\'
    old_files = ['1']
    #print(old_files)
    while True:
        try:
            new_files = ftp.nlst()
            #print(new_files)
            #print(new_files)
            if len(old_files) != 0 and new_files != old_files:
                changes = [i for i in new_files if i not in old_files]
                #
                # print(changes)
                for x in changes:
                    filename = str(direct   x)
                    localfile = open(filename, 'wb')
                    ftp.retrbinary('RETR' ' '   x , localfile.write, 1024)
                    localfile.close()
                    
                    xcorr = extract_function(filename)
                    
                    print("updating data ***************************************************")
                    print("found new file---> {}".format(str(filename).split('\')[-1]))
                    print("Calculating cross-correlation")
                    print("*****************************************************************")
                    print(" ")
                    sleep(3)
                    os.remove(filename)
                    
                a = time.perf_counter()
            
            if time.perf_counter() > a   20:
                print("Done Waiting")
                break
            old_files = new_files
            
        except KeyboardInterrupt:
            ftp.quit()
            
 

Я также создал базовое приложение test_dash :

 import dash
import plotly.graph_objects as go
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc

from app import app



app = dash.Dash(__name__) 


app.layout = html.Div( 
    [ 
        dcc.Graph(id = 'live-graph', animate = True), 
        dcc.Interval( 
            id = 'graph-update', 
            interval = 10000, 
            n_intervals = 0
        ), 
        html.Div(dbc.Row([
        dbc.Col(html.H2(id='check_update_div', children='check ' ))
        ]) )
    ] 
) 

@app.callback( 
    Output('check_update_div', 'children'), 
    [ Input('graph-update', 'n_intervals') ] 
) 
  
def update_graph_scatter(n): 
    
    print('one loop done ')
    
    a = monitor_ftp()
    return ("this is  X {}".format(a))
 

Я хочу связать все вместе и создать приложение dash, которое отслеживает каталог ftp и отображает результат извлечения данных, в настоящее время у меня нет графика в моем приложении, я только что поместил div, который я хочу обновить с именем файла для каждого нового файла, который появляется в папке, но я не уверен, как объединить эти функции вместе. Не могли бы вы помочь.

Редактировать:

У меня есть рабочий пример, который показывает, что ftp внутри функции обратного вызова не позволяет функции возвращать что-либо, если ftp находится вне функции возврата, тогда обратный вызов возвращает и обновляет div каждые n_intervals

 import dash 
from dash.dependencies import Output, Input
import dash_core_components as dcc 
import dash_html_components as html 
import plotly 
import random 
import plotly.graph_objs as go 
from collections import deque 
from ftplib import FTP 
from time import sleep

#ftp otside the function and function works fine 
#Deactivae this part and activate ftp inside the function , and function 
#stops returning anything and div is not updated every n_interval 
ftp = FTP()
ftp.connect('10.199.44.240', 21)
ftp.login('display')
ftp.cwd('/home/display/test_qc')
print("Connection Established {}".format(ftp.getwelcome()))
direct = 'C:\Users\QC\Desktop\Gunlink_local\'

app = dash.Dash(__name__)

app.layout = html.Div([
    html.Div([
        dcc.Interval( 
            id = 'graph-update', 
            interval = 10000, 
            n_intervals = 0
        )
    ]),
    html.Div([
        html.H1(id='print_value', children="Output Value"),
    ])
])


@app.callback( 
    Output('print_value', 'children'), 
    [ Input('graph-update', 'n_intervals') ] 
) 
  
def update_value(n):
    
    # ftp inside the function prevents the function from returning anything
    # Div is not updated every n_interval
    '''
    ftp = FTP()
    ftp.connect('10.199.44.240', 21)
    ftp.login('display')
    ftp.cwd('/home/display/test_qc')
    print("Connection Established {}".format(ftp.getwelcome()))
    a = ftp.nlst()
    '''

    a = ftp.nlst()

    sleep(2)
    print('one loop done ')
    return ("this is  X {}".format(a))


if __name__ == '__main__': 
    app.run_server()
 

Ответ №1:

Вам нужен компонент интервала.

Dash не может выполнять постоянные обновления, например, запускать этот while цикл без остановки, но вы можете установить интервал для запуска обратного вызова каждые X секунд. Используя этот обратный вызов, вы можете проверить наличие обновлений на FTP-сервере в этом расписании.

Ознакомьтесь с этой страницей документации, чтобы найти несколько хороших примеров ее использования для создания страницы обновления в реальном времени.

Комментарии:

1. У меня есть рабочий пример, который показывает, что ftp внутри функции обратного вызова не позволяет функции возвращать что-либо, если ftp находится вне функции возврата, тогда обратный вызов возвращает и обновляет div каждые n_intervals

2. Я отредактировал свой вопрос, чтобы добавить пример, который показывает, что выполнение ftp внутри обратного вызова каждые n_intervals не позволяет обратному вызову возвращать что-либо

3. Выдает ли это ошибку или завершается беззвучно? Интервал выглядит как 10 секунд, что, я думаю, достаточно, но, возможно, это не так. Если вы измените его на 60 секунд, он будет работать? Если вы можете запустить отладчик и установить точку останова, с которой начинается вызов FTP, попробуйте пошагово просмотреть каждую строку, чтобы увидеть, что происходит.

4. На самом деле это не сбой, он просто ничего не возвращает, иногда количество файлов может быть больше, и функции потребуется гораздо больше времени, чем 10 секунд, для обработки и извлечения данных, есть ли какой-нибудь способ, которым я могу сказать dash, чтобы он запускал счетчик n_interval только после завершения функции, или в качестве альтернативы я могу запустить обратный вызов только один раз, который просматривает каталог в цикле while и выполняет извлечение, выдавая выходные данные в скрытый div, добавляя извлеченные данные к фреймам данных, и я могу написать dcc. Интервальные вызываемые функции только для обновления моих графиков, отображающих эти фреймы данных?

5. Можно ли будет запустить функцию, основанную на цикле while True, из dash?