Doctests for the List class

List and ListRef element classes

Basic usage

Setup test tooling:

>>> from dragonfly import *
>>> from dragonfly.test import ElementTester
>>> list_fruit = List("list_fruit")
>>> element = Sequence([Literal("item"), ListRef("list_fruit_ref", list_fruit)])
>>> tester_fruit = ElementTester(element)
>>> # Explicitly load tester grammar because lists can only be updated
>>> # for loaded grammars.
>>> tester_fruit.load()

Empty lists cannot be recognized:

>>> tester_fruit.recognize("item")
RecognitionFailure
>>> tester_fruit.recognize("item apple")
RecognitionFailure

A list update is automatically available for recognition without reloading the grammar:

>>> tester_fruit.recognize("item apple")
RecognitionFailure

>>> list_fruit.append("apple")
>>> list_fruit
['apple']
>>> tester_fruit.recognize("item apple")
[u'item', u'apple']
>>> tester_fruit.recognize("item banana")
RecognitionFailure

>>> list_fruit.append("banana")
>>> list_fruit
['apple', 'banana']
>>> tester_fruit.recognize("item apple")
[u'item', u'apple']
>>> tester_fruit.recognize("item banana")
[u'item', u'banana']
>>> tester_fruit.recognize("item apple banana")
RecognitionFailure

>>> list_fruit.remove("apple")
>>> list_fruit
['banana']
>>> tester_fruit.recognize("item apple")
RecognitionFailure
>>> tester_fruit.recognize("item banana")
[u'item', u'banana']

Lists can contain the same value multiple times, although that does not affect recognition:

>>> list_fruit.append("banana")
>>> list_fruit
['banana', 'banana']
>>> tester_fruit.recognize("item banana")
[u'item', u'banana']
>>> tester_fruit.recognize("item banana banana")
RecognitionFailure

Tear down test tooling:

>>> # Explicitly unload tester grammar.
>>> tester_fruit.unload()

Multiple lists

Setup test tooling:

>>> list_meat = List("list_meat")
>>> list_veg = List("list_veg")
>>> element = Sequence([Literal("food"),
...                     ListRef("list_meat_ref", list_meat),
...                     ListRef("list_veg_ref", list_veg)])
>>> tester_meat_veg = ElementTester(element)
>>> # Explicitly load tester grammar because lists can only be updated
>>> # for loaded grammars.
>>> tester_meat_veg.load()

Multiple lists can be combined within a single rule:

>>> list_meat.append("steak")
>>> tester_meat_veg.recognize("food steak")
RecognitionFailure
>>> list_veg.append("carrot")
>>> tester_meat_veg.recognize("food steak carrot")
[u'food', u'steak', u'carrot']
>>> list_meat.append("hamburger")
>>> tester_meat_veg.recognize("food hamburger carrot")
[u'food', u'hamburger', u'carrot']

Tear down test tooling:

>>> # Explicitly unload tester grammar.
>>> tester_meat_veg.unload()

A single list can be present multiple times within a rule:

>>> element = Sequence([Literal("carnivore"),
...                     ListRef("list_meat_ref1", list_meat),
...                     ListRef("list_meat_ref2", list_meat)])
>>> tester_carnivore = ElementTester(element)
>>> # Explicitly load tester grammar because lists can only be updated
>>> # for loaded grammars.
>>> tester_carnivore.load()

>>> tester_carnivore.recognize("carnivore steak")
RecognitionFailure
>>> tester_carnivore.recognize("carnivore hamburger steak")
[u'carnivore', u'hamburger', u'steak']
>>> tester_carnivore.recognize("carnivore steak hamburger")
[u'carnivore', u'steak', u'hamburger']
>>> tester_carnivore.recognize("carnivore steak steak")
[u'carnivore', u'steak', u'steak']

>>> list_meat.remove("steak")
>>> tester_carnivore.recognize("carnivore steak hamburger")
RecognitionFailure
>>> tester_carnivore.recognize("carnivore hamburger hamburger")
[u'carnivore', u'hamburger', u'hamburger']

Tear down test tooling:

>>> # Explicitly unload tester grammar.
>>> tester_carnivore.unload()

Unique list names

The names of lists must be unique within a grammar:

>>> list_fruit1 = List("list_fruit")
>>> list_fruit2 = List("list_fruit")
>>> element = Sequence([Literal("fruit"),
...                     ListRef("list_fruit1_ref", list_fruit1),
...                     ListRef("list_fruit2_ref", list_fruit2)])
>>> tester_fruit = ElementTester(element)
>>> # Explicitly load tester grammar because lists can only be updated
>>> # for loaded grammars.
>>> tester_fruit.load()
Traceback (most recent call last):
    ...
GrammarError: Two lists with the same name 'list_fruit' not allowed.

List add/remove restrictions

Setup test tooling:

>>> list_fruit = List("list_fruit", ["apple", "banana"])
>>> element = Sequence([Literal("item"), ListRef("list_fruit_ref", list_fruit)])
>>> tester_fruit = ElementTester(element)
>>> # Explicitly load tester grammar because lists can only be updated
>>> # for loaded grammars.
>>> tester_fruit.load()

Lists cannot be added while the grammar is loaded:

>>> list_other = List("list_other", ["other"])
>>> tester_fruit.add_list(list_other)  # Fails.
Traceback (most recent call last):
    ...
GrammarError: Cannot add list while loaded.

Lists cannot be removed while the grammar is loaded:

>>> tester_fruit.remove_list(list_fruit)  # Fails.
Traceback (most recent call last):
    ...
GrammarError: Cannot remove list while loaded.

Tear down test tooling:

>>> # Explicitly unload tester grammar.
>>> tester_fruit.unload()

ListRef construction

ListRef objects must be created referencing the correct type of list object:

>>> print(ListRef("list_fruit_ref", []))  # Fails.
Traceback (most recent call last):
    ...
TypeError: List argument to ListRef constructor must be a Dragonfly list.
>>> print(ListRef("list_fruit_ref", List("list_fruit")))  # Succeeds.
ListRef('list_fruit')

List context manager

List operations can be performed optimally via Python’s with statement:

>>> list_fruit = List("list_fruit")
>>> element = Sequence([Literal("item"), ListRef("list_fruit_ref", list_fruit)])
>>> tester_fruit = ElementTester(element)
>>> tester_fruit.load()
>>> with list_fruit:
...     list_fruit.append("apple")
...     list_fruit.append("banana")
...
>>> list_fruit
['apple', 'banana']
>>> tester_fruit.recognize("item apple")
[u'item', u'apple']
>>> tester_fruit.recognize("item banana")
[u'item', u'banana']

Tear down test tooling:

>>> # Explicitly unload tester grammar.
>>> tester_fruit.unload()