Как я могу получить данные в моем приложении фляги, чтобы не показывать несуществующие значения JSON и обновлять соответственно через определенный интервал? - PullRequest
0 голосов
/ 02 апреля 2019

Я установил приложение-колбу, работающее на Heroku, которое проверяет API на информацию о поезде с помощью параметров, передаваемых в URL.

Основная поисковая часть функции находится в этой функции:

train_service_data = {}
train_station_data = {}

dest = 0
origin = 0
mytimes = 0
myurl = 0


def checker():
    global mytrains  # modifies the global copy of mytrains otherwise a new variable is created
    global myurl
    global mytimes
    # myurl = f"http://huxley.apphb.com/all/{origin}/to/{dest}/{mytimes}"
    response = requests.get(myurl, params={"accessToken": SECRET_KEY})
    response.raise_for_status()  # this makes an error if something failed
    data1 = response.json()
    mytrains['departure'] = str(data1['crs'])
    mytrains['arrival'] = str(data1['filtercrs'])
    try:
        found_service = 0
        for index, service in enumerate(data1['trainServices']):  # indexes data for pulling of previous values
            if service['std'].replace(':', '') in mytimes:n
                found_service += 1
                train = SimpleNamespace(
                    serviceID=str(service['serviceID']),
                    arrival_time=str(service['std']),
                    estimated_arrival=str(service['etd']),
                    status='On time'
                )
                prior_service = data1['trainServices'][index - 1]
                if train.estimated_arrival == 'Cancelled':
                    train.status = 'Cancelled'
                    train.alternate_service = str(prior_service['std'])
                    train.alternate_status = str(prior_service['etd'])
                elif train.estimated_arrival != 'On time':
                    train.status = 'Delayed'
                write_index = index
                for i, v in mytrains.items():
                    if isinstance(v, dict) and v['arrival_time'] == train.arrival_time:
                        write_index = i
                mytrains[write_index] = train.__dict__
            elif found_service == 0:  # if no service is found
                mytrains['state'] = 'The services currently available are not specified in user_time.'
    except (TypeError, AttributeError) as error:
        mytrains['errorMessage'] = 'There is no train service data'
    try:
        NRCCRegex = re.compile('^(.*?)[\.!\?](?:\s|$)')  # regex pulls all characters until hitting a . or ! or ?
        myline = NRCCRegex.search(data1['nrccMessages'][0]['value'])  # regex searches through nrccMessages
        mytrains['nrcc'] = myline.group(1)  # prints parsed NRCC message
    except (TypeError, AttributeError) as error:  # tuple catches multiple errors, AttributeError for None value
        mytrains['nrcc'] = 'No NRCC'
    return mytrains

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

def time_trains_services():  # splits data into train services lookup
    global train_service_data
    train_service_data = [j for i, j in mytrains.items() if isinstance(j, dict)]  # grabs train service data into dict
    return train_service_data


def time_trains_location():  # splits data into crs, filtercrs and nrcc queries
    global train_station_data
    train_station_data = {i: j for i, j in mytrains.items() if not isinstance(j, dict)}  # grabs [0] data into separate dict
    return train_station_data

Эти функции предоставляют подсказки, которые вводятся во Flask, но при обновлении страницы отображаются другие значения в json, которые не являются теми, которые я специально выделил для if service['std'].replace(':', '') in mytimes:

Моя шаблонная логика выглядит следующим образом:

        <div class="train_times">
            {% for services in trainservices %}
                {% if services.status != 'On time' and services.status != 'Cancelled' %}
                    <p>{{services.arrival_time}} -> {{services.estimated_arrival}}</p>
                    {% if not loop.last %}
                        |
                    {% endif %}
                {% endif %}
                {% if services.status == 'On time' %}
                    <p>{{services.arrival_time}} ({{services.status}})</p>
                    {% if not loop.last %}
                        |
                    {% endif %}
                {% endif %}
                {% if traindata.status == 'Cancelled' %}
                    <p>The previous service is: <span>{{ trainsevices.alternate_service }}</span></p>
                    <p>The previous train arrives at: <span>{{ alternate_status }}</span></p>
                {% endif %}
            {% endfor %}
        </div>

Почему появляются другие моменты, которые я не определил? Как я могу предотвратить это, я подумал dict.clear(), но я не уверен, что это правильный путь.

Время также остается на странице, когда json больше не содержит их, когда я обновляю страницу, я пытался настроить APScheduler для запуска каждую минуту, но это не решило мою проблему.

Любая помощь очень ценится! Как всегда, я могу предоставить больше кода, если что-то неясно.

РЕДАКТИРОВАТЬ: Добавлен полный код, как сейчас, чтобы заполнить все пропущенные пробелы: https://paste.pydis.com/inudurodah.py

1 Ответ

1 голос
/ 02 апреля 2019

Редактировать: взглянул на обновленный вопрос и обнаружил некоторые возможные проблемы.

Проблемы с обработкой параметров:

  • Приложение в настоящее время, похоже, не разделяет mytimes (строку через запятую) на фактический список. Он должен преобразовать mytimes в список и проверить, что элементы находятся в правильном формате (4-значное число, разделенное запятыми), предупреждая пользователя, если в противном случае.
  • Кроме того, если mytimes не указано, приложение сообщит, что «доступные в данный момент службы не указаны в user_time». Это вводит в заблуждение. Если время не выбрано, то должны быть указаны все доступные времена, или приложение должно ответить, что необходимо указать хотя бы один раз.
  • Нет подтверждения, что все параметры предоставлены, что необходимо, если все они будут вставлены в URL (необеспеченный параметр будет интерполирован как «Нет» в строке).
  • Если ключ доступа должен находиться в переменной среды DARWIN_KEY, то приложение должно пожаловаться, если оно не найдено. Использование только os.environ.get только позволит сбое случиться позже, что затруднит его обнаружение.

Проблемы с использованием глобальных переменных:

  • Используемые глобальные переменные могут в конечном итоге использоваться несколькими запросами. Это легко показать, выполняя один запрос за другим, когда во Flask включена многопоточность (что по умолчанию - см. http://flask.pocoo.org/docs/1.0/api/), и видно, что данные «загрязнены» предыдущими запросами.
  • Чтобы избежать глобальных переменных, разбейте поток на несколько функций, каждая из которых принимает несколько входных данных и возвращает то, что нужно
  • Вся необходимая информация уже имеется в поездах и информации о местоположении - поэтому нет необходимости также указывать вложенную и избыточную структуру, mytrains.

Другая возможная проблема:

  • service['std'] может быть Нет, в этом случае .replace не будет работать на нем

Вот руководство о том, как можно избежать всех globals (при условии, что вы не хотите делить это состояние между запросами, что выглядит так). Это не проверено, и только руководство:

# do all the imports 

app = Flask(__name__)


def retrieve_service_info(request_args):
    """request_args a Flask.request.args type"""
    origin = request_args.get('origin')
    dest = request_args.get('dest')
    mytimes = request_args.get('mytimes')

    url = f"http://huxley.apphb.com/all/{origin}/to/{dest}/{mytimes}"
    response = requests.get(url, params={"accessToken": get_secret_key()})
    response.raise_for_status()

    return response.json()


def get_secret_key():
    # fail here if key not found?
    return os.environ.get('DARWIN_KEY', None)


def processed_train_service(service):
    def get_status(estimated_arrival):
        if estimated_arrival in ('On time', 'Cancelled'):
            return estimated_arrival
        else:
            return 'Delayed'

    return {'serviceID': service['serviceID'],
            'arrival_time': service['std'],
            'estimated_arrival': service['etd'],
            'status': get_status(service['etd'])}


def get_train_summary(service_info):
    #service_info = retrieve_service_info(request_args)
    train_services = service_info['trainServices']
    summary = [processed_train_service(service) for service
               in train_services if service['std'] is not None]

    # fill in alternative service as previous service
    # for any cancelled service where there is a previous service
    for i, service in enumerate(summary[1:]):
        if service['status'] == 'Cancelled':
            previous_service = summary[i-1]
            service['alternate_service'] = str(previous_service['arrival_time'])
            service['alternate_status'] = str(previous_service['estimated_arrival'])
    return summary


def get_location_data(service_info):
    """function just to get data related to the station"""
    def get_nrcc(info):
        try:
            NRCCRegex = re.compile('^(.*?)[\.!\?](?:\s|$)')  # regex pulls all characters until hitting a . or ! or ?
            myline = NRCCRegex.search(info['nrccMessages'][0]['value'])  # regex searches through nrccMessages
            return myline.group(1)  # prints parsed NRCC message
        except (TypeError, AttributeError) as error:  # tuple catches multiple errors, AttributeError for None value
            print('error -> %s' % (error,))
            return 'No NRCC'

    return {'departure': service_info['crs'],
            'arrival': service_info['filtercrs'],
            'nrcc': get_nrcc(service_info)}


@app.route("/getstatus", methods=["GET"])
def status_check():
    service_info = retrieve_service_info(request.args)

    train_summary = get_train_summary(service_info)
    location_summary = get_location_data(service_info)

    return render_template('train_index.html', trainstation=location_summary, trainservices=train_summary)


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