Skip to content

Commit

Permalink
Fix #357: improve TDL list values iteration (#359)
Browse files Browse the repository at this point in the history
* Fix #357; recognize implicit AVMs created by lists

This required a new (non-public) type: _ImplicitAVM. This is the AVM
constructed by list syntax (< ... > or <! ... !>).

* Add CHANGELOG entry

* Fix flake8 errors

* Temporarily allow implicit optional for mypy
  • Loading branch information
goodmami authored Jan 4, 2023
1 parent b5c7094 commit 172a4c8
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ jobs:
pytest .
- name: Type-check with mypy
run: |
mypy delphin --namespace-packages --explicit-package-bases --ignore-missing-imports
mypy delphin --namespace-packages --explicit-package-bases --ignore-missing-imports --implicit-optional
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Change Log

## Unreleased

### Fixed

* `delphin.tdl.ConsList.values()` and `delphin.tdl.DiffList.values()`
now treat explicit sublists as regular items instead of descending
into their structures ([#357])


## [v1.7.0]

**Release date: 2022-10-13**
Expand Down Expand Up @@ -1556,3 +1565,4 @@ information about changes, except for
[#343]: https://github.com/delph-in/pydelphin/issues/343
[#344]: https://github.com/delph-in/pydelphin/issues/344
[#352]: https://github.com/delph-in/pydelphin/issues/352
[#357]: https://github.com/delph-in/pydelphin/issues/357
2 changes: 0 additions & 2 deletions delphin/cli/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@

import sys
import argparse
import warnings

from delphin.exceptions import PyDelphinWarning
from delphin.commands import convert
from delphin import util

Expand Down
2 changes: 0 additions & 2 deletions delphin/cli/repp.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@

import sys
import argparse
import warnings

from delphin.exceptions import PyDelphinWarning
from delphin.commands import repp


Expand Down
34 changes: 21 additions & 13 deletions delphin/tdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ def features(self, expand=False):
return fs


class _ImplicitAVM(AVM):
"""AVM implicitly constructed by list syntax."""


class ConsList(AVM):
"""
AVM subclass for cons-lists (``< ... >``)
Expand Down Expand Up @@ -308,12 +312,7 @@ def values(self):
if self._avm is None:
return []
else:
vals = [val for _, val in _collect_list_items(self)]
# the < a . b > notation puts b on the last REST path,
# which is not returned by _collect_list_items()
if self.terminated and self[self._last_path] is not None:
vals.append(self[self._last_path])
return vals
return [val for _, val in _collect_list_items(self)]

def append(self, value):
"""
Expand All @@ -330,7 +329,7 @@ def append(self, value):
path += '.'
self[path + LIST_HEAD] = value
self._last_path = path + LIST_TAIL
self[self._last_path] = AVM()
self[self._last_path] = _ImplicitAVM()
else:
raise TDLError('Cannot append to a closed list.')

Expand Down Expand Up @@ -395,7 +394,7 @@ def __init__(self, values=None, docstring=None):
if values:
# use ConsList to construct the list, but discard the class
tmplist = ConsList(values, end=cr)
dl_list = AVM()
dl_list = _ImplicitAVM()
dl_list._avm.update(tmplist._avm)
dl_list._feats = tmplist._feats
self.last = 'LIST.' + tmplist._last_path
Expand All @@ -416,16 +415,25 @@ def values(self):
"""
Return the list of values in the DiffList feature structure.
"""
return [val for _, val
in _collect_list_items(self.get(DIFF_LIST_LIST))]
if isinstance(self[DIFF_LIST_LIST], Coreference):
vals = []
else:
vals = [val for _, val
in _collect_list_items(self.get(DIFF_LIST_LIST))]
vals.pop() # last item of diff list is coreference
return vals


def _collect_list_items(d):
if d is None or not isinstance(d, AVM) or d.get(LIST_HEAD) is None:
if not isinstance(d, AVM) or d.get(LIST_HEAD) is None:
return []
vals = [(LIST_HEAD, d[LIST_HEAD])]
vals.extend((LIST_TAIL + '.' + path, val)
for path, val in _collect_list_items(d.get(LIST_TAIL)))
rest = d[LIST_TAIL]
if isinstance(rest, _ImplicitAVM):
vals.extend((LIST_TAIL + '.' + path, val)
for path, val in _collect_list_items(rest))
elif rest is not None:
vals.append((LIST_TAIL, rest))
return vals


Expand Down
15 changes: 15 additions & 0 deletions tests/tdl_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -960,3 +960,18 @@ def test_format_environments():
' :end :instance.\n'
' :include "another.tdl".\n'
':end :type.')


def test_issue_357():
# https://github.com/delph-in/pydelphin/issues/357
t = TypeDefinition(
'id',
ConsList(
[TypeIdentifier('a')],
end=ConsList([TypeIdentifier('b')], end=TypeIdentifier('c'))
)
)
c = t.conjunction.terms[0]
assert isinstance(c, ConsList)
assert len(c.values()) == 2
assert tdl.format(t) == 'id := < a . < b . c > >.'

0 comments on commit 172a4c8

Please sign in to comment.