Модульное тестирование токенизатора Python: вставьте один токен в сгенерированный список токенов

Я реализую токенизатор Python для извлечения токенов из текстового файла. Токены относятся к строкам, которые «соответствуют» шаблону (регулярному выражению), который я определил для каждого токена. Я использую функциональность лексера из пакета python для реализации токенизатора. После сканирования текстового файла все найденные токены возвращаются в виде генератора. Для модульного тестирования я хотел бы вставить дополнительные токены в определенные места в «списке возвращенных токенов», чтобы проверить, правильно ли работает токенизатор в такой плохой ситуации.

Как я могу создать «поддельный» объект токена с помощью ply (модуль python ply.lex), который я могу вставить в список токенов.


person thinwybk    schedule 03.12.2015    source источник
comment
Используете ли вы встроенную поддержку итерации сгенерированного лексера? (Если это так, ваше описание неверно, потому что итератор не сканирует весь файл перед предоставлением первого токена.)   -  person rici    schedule 04.12.2015
comment
Нет. Токенизатор выполняет лексический анализ, буферизует все токены (в объекте лексера), но затем происходит некоторая обработка и цикл по объекту лексера (for .. in ..: yield). Но вы правы, это генератор так.   -  person thinwybk    schedule 04.12.2015
comment
Кроме того, вы создаете список токенов и хотите добавить в него какие-то другие токены. Все это звучит разумно, но я не понимаю, почему вы тогда ожидаете, что ply поможет вам со списком.   -  person rici    schedule 04.12.2015
comment
Мой вопрос заключается в том, как я могу создать поддельный объект токена с помощью слоя, который я могу вставить в список токенов.   -  person thinwybk    schedule 04.12.2015
comment
Хорошо, я ответил на вопрос, который вы только что задали, хотя это, очевидно, не было очевидно для меня из вашего вопроса. Я бы предложил отредактировать исходный вопрос, чтобы добавить предложение выше.   -  person rici    schedule 04.12.2015
comment
вопрос был улучшен соответственно   -  person thinwybk    schedule 05.12.2015


Ответы (1)


Вы можете легко создать свои собственные токены, если хотите вставить токен в поток lex. (Как вы на самом деле вставляете токен, конечно, зависит от вас.)

Из документации ply:

Токены, возвращаемые lexer.token(), являются экземплярами LexToken. Этот объект имеет атрибуты tok.type, tok.value, tok.lineno и tok.lexpos.…

Атрибуты tok.type и tok.value содержат тип и значение самого токена. tok.line и tok.lexpos содержат информацию о расположении токена. tok.lexpos — это индекс токена относительно начала вводимого текста.

Кроме того, токен имеет атрибут lexer, значением которого является объект лексера, создавший токен.

Вот пример создания LexToken (адаптированного из lex.py) для синтезированного токена error (self на данный момент является объектом лексера):

tok = LexToken()
tok.value = self.lexdata[lexpos:]
tok.lineno = self.lineno
tok.type = 'error'
tok.lexer = self
tok.lexpos = lexpos
person rici    schedule 04.12.2015
comment
Поскольку tok.lexpos — это индекс токена относительно начала входного текста, нужно ли мне увеличивать атрибут tok.lexpos всех следующих токенов? Я думаю, что это было бы необходимо, по крайней мере, в ситуации, когда я хочу вставить поддельный токен между двумя токенами, например. между двумя токенами примера вы ссылались на LexToken(NUMBER,3,2,1) и LexToken(PLUS,'+',2,2) с LexToken(.., .., .., tok.lexpos). - person thinwybk; 05.12.2015
comment
@fkromer: атрибуты lineno и lexpos предоставляются фреймворком, но не используются им иным образом. Обычно они используются действиями приложения для комментирования сообщений об ошибках или отладочной информации. Так что это будет зависеть от того, как вы используете информацию, но обычно простое копирование информации из предыдущего токена не должно вызывать проблем. - person rici; 05.12.2015
comment
Еще один совет: токены обычно передаются внутри приложения как генераторы. Поскольку генератор не подлежит подписке, его необходимо преобразовать в список со списком (генератором) перед добавлением элементов списка, например. список[:idx] + [fake_token_object] + список[idx:] - person thinwybk; 11.12.2015