3454a55636
cffconvert / validate (push) Has been cancelled
ci-workflow / pre-commit (push) Has been cancelled
ci-workflow / Minimal NLTK Download Test (macos-latest) (push) Has been cancelled
ci-workflow / Minimal NLTK Download Test (ubuntu-latest) (push) Has been cancelled
ci-workflow / Minimal NLTK Download Test (windows-latest) (push) Has been cancelled
ci-workflow / Python 3.10 on macos-latest (push) Has been cancelled
ci-workflow / Python 3.11 on macos-latest (push) Has been cancelled
ci-workflow / Python 3.12 on macos-latest (push) Has been cancelled
ci-workflow / Python 3.13 on macos-latest (push) Has been cancelled
ci-workflow / Python 3.14 on macos-latest (push) Has been cancelled
ci-workflow / Python 3.14t on macos-latest (push) Has been cancelled
ci-workflow / Python 3.10 on ubuntu-latest (push) Has been cancelled
ci-workflow / Python 3.11 on ubuntu-latest (push) Has been cancelled
ci-workflow / Python 3.12 on ubuntu-latest (push) Has been cancelled
ci-workflow / Python 3.13 on ubuntu-latest (push) Has been cancelled
ci-workflow / Python 3.14 on ubuntu-latest (push) Has been cancelled
ci-workflow / Python 3.14t on ubuntu-latest (push) Has been cancelled
ci-workflow / Python 3.10 on windows-latest (push) Has been cancelled
ci-workflow / Python 3.11 on windows-latest (push) Has been cancelled
ci-workflow / Python 3.12 on windows-latest (push) Has been cancelled
ci-workflow / Python 3.13 on windows-latest (push) Has been cancelled
ci-workflow / Python 3.14 on windows-latest (push) Has been cancelled
129 lines
4.1 KiB
Python
129 lines
4.1 KiB
Python
import unittest
|
|
|
|
from nltk.ccg import lexicon
|
|
from nltk.ccg.api import Direction, FunctionalCategory, PrimitiveCategory
|
|
|
|
|
|
class TestCCGDirection(unittest.TestCase):
|
|
|
|
# --- Parser and Unification Tests (PR #3556) ---
|
|
|
|
def test_parse_variable_direction(self):
|
|
"""
|
|
Ensures the string parser can successfully instantiate a Direction object
|
|
that correctly identifies as a variable.
|
|
"""
|
|
lex_str = r"""
|
|
:- S, NP
|
|
quickly => (S\_NP)/(S\_NP)
|
|
"""
|
|
lex = lexicon.fromstring(lex_str)
|
|
|
|
quickly_token = lex.categories("quickly")[0]
|
|
quickly_cat = quickly_token.categ()
|
|
var_direction = quickly_cat.res().dir()
|
|
|
|
self.assertTrue(
|
|
var_direction.is_variable(),
|
|
"Lexer failed to properly parse the direction as a variable.",
|
|
)
|
|
self.assertEqual(
|
|
var_direction.restrs(),
|
|
"_",
|
|
f"Expected restriction '_', got {var_direction.restrs()!r}",
|
|
)
|
|
|
|
def test_variable_direction_can_unify(self):
|
|
"""
|
|
Ensures that when a variable direction unifies with a concrete direction,
|
|
the substitution mapping is correctly extracted and returned to the caller.
|
|
"""
|
|
lex_str = r"""
|
|
:- S, NP
|
|
walked => S\NP
|
|
quickly => (S\_NP)/(S\_NP)
|
|
"""
|
|
lex = lexicon.fromstring(lex_str)
|
|
|
|
walked_cat = lex.categories("walked")[0].categ()
|
|
quickly_cat = lex.categories("quickly")[0].categ()
|
|
|
|
subs = quickly_cat.res().can_unify(walked_cat)
|
|
|
|
self.assertIsNotNone(subs, "Unification failed entirely.")
|
|
substituted_vars = [var for var, val in subs]
|
|
self.assertIn(
|
|
"_", substituted_vars, "can_unify dropped the direction variable mapping!"
|
|
)
|
|
|
|
def test_strict_regex_rejects_double_variable(self):
|
|
r"""
|
|
Ensures that the stricter APP_RE regex rejects invalid consecutive
|
|
variable modalities (e.g., `\__`).
|
|
"""
|
|
lex_str = r"""
|
|
:- S, NP
|
|
bad_word => (S\__NP)/(S\_NP)
|
|
"""
|
|
with self.assertRaises(AttributeError):
|
|
lex = lexicon.fromstring(lex_str)
|
|
|
|
def test_direction_equality_and_hashing(self):
|
|
"""
|
|
Ensures that a parsed variable direction (instantiated with a regex tuple)
|
|
and a hand-constructed variable direction (instantiated with a string)
|
|
evaluate as equal and share the same hash.
|
|
"""
|
|
manual_dir = Direction("\\", "_")
|
|
parsed_dir = Direction("\\", ("_", ""))
|
|
|
|
self.assertEqual(
|
|
manual_dir,
|
|
parsed_dir,
|
|
"Directions with coerced tuples do not evaluate as equal!",
|
|
)
|
|
self.assertEqual(
|
|
hash(manual_dir),
|
|
hash(parsed_dir),
|
|
"Directions with coerced tuples do not hash equally!",
|
|
)
|
|
|
|
# --- Substitution Tests (PR #3547 & Legacy) ---
|
|
|
|
def test_substitute_applies_to_direction(self):
|
|
"""
|
|
Direction substitutions must propagate through substitute().
|
|
Regression test updated to expect string restrictions instead of lists.
|
|
"""
|
|
res = PrimitiveCategory("S")
|
|
arg = PrimitiveCategory("NP")
|
|
variable_dir = Direction("/", "_")
|
|
category = FunctionalCategory(res, arg, variable_dir)
|
|
|
|
# Replaced list ["."] with string "."
|
|
new_restrictions = "."
|
|
subs = [("_", new_restrictions)]
|
|
result = category.substitute(subs)
|
|
|
|
self.assertFalse(result.dir().is_variable())
|
|
self.assertEqual(result.dir().restrs(), new_restrictions)
|
|
|
|
def test_substitute_no_op_on_concrete_direction(self):
|
|
"""
|
|
Substitution on a non-variable direction should be a no-op.
|
|
Regression test updated to pass and expect string restrictions.
|
|
"""
|
|
res = PrimitiveCategory("S")
|
|
arg = PrimitiveCategory("NP")
|
|
# Replaced list ["."] with string "."
|
|
concrete_dir = Direction("\\", ".")
|
|
category = FunctionalCategory(res, arg, concrete_dir)
|
|
|
|
result = category.substitute([("_", ",")])
|
|
|
|
self.assertEqual(result.dir().restrs(), ".")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|