from typing import List
from pytest import fixture, mark
from edsnlp.pipes.qualifiers.negation import Negation
from edsnlp.utils.examples import parse_example
negation_examples: List[str] = [
"<ent polarity_=NEG>métas,tases</ent> : non",
(
"Pas de <ent negated=true>lésion pulmonaire avec "
"l'absence de lésion secondaire</ent>."
),
"Cancer non <ent negation=true>métastasé</ent>.",
"Absence d'<ent negated=true>image osseuse d'allure évolutive</ent>.",
"il n'y a pas de <ent polarity_=NEG>métas,tases</ent>",
"Le patient n'est pas <ent polarity_=NEG>malade</ent>.",
"Aucun <ent polarity_=NEG>traitement</ent>.",
"Le <ent polarity_=AFF>scan</ent> révèle une grosseur.",
"il y a des <ent polarity_=AFF>métastases</ent>",
"aucun doute sur les <ent polarity_=AFF>métastases</ent>",
"il n'y a pas de <ent polarity_=NEG>métastases</ent>",
"il n'y a pas d' <ent polarity_=NEG>métastases</ent>",
"il n'y a pas d'<ent polarity_=NEG>métastases</ent>",
"il n'y a pas d'amélioration de la <ent negated=false>maladie</ent>",
"<ent negated=true>maladie écartée",
"Le patient ne <ent negated=true>fume</ent> pas.",
"Le patient ne <ent negated=true>fume vraiment vraiment</ent> pas.",
"Le patient ne <ent negated=false>fume</ent> que des cigares.",
"Le résultat exclut un <ent negated=true>SMD</ent>",
"Le résultat ne permet pas d'exclure un <ent negated=false>SMD</ent>",
"Situation aggravée par une <ent negated=false>neutropénie fébrile</ent>."
"Patient est traité d'une cure d'<ent negated=false>ALECTINIB</ent> depuis le ...",
]
@fixture
def negation_factory(blank_nlp):
default_config = dict(
pseudo=None,
preceding=None,
following=None,
termination=None,
verbs=None,
attr="NORM",
within_ents=False,
explain=True,
span_getter="ents",
)
def factory(on_ents_only, **kwargs) -> Negation:
config = dict(**default_config)
config.update(kwargs)
return Negation(
nlp=blank_nlp,
on_ents_only=on_ents_only,
**config,
)
return factory
@mark.parametrize("on_ents_only", [True, False])
def test_negation(blank_nlp, negation_factory, on_ents_only):
negation = negation_factory(on_ents_only=on_ents_only)
for example in negation_examples:
text, entities = parse_example(example=example)
doc = blank_nlp(text)
doc.ents = [
doc.char_span(ent.start_char, ent.end_char, label="ent") for ent in entities
]
doc = negation(doc)
for entity, ent in zip(entities, doc.ents):
for modifier in entity.modifiers:
assert bool(ent._.negation_cues) == (modifier.value in {True, "NEG"})
assert (
getattr(ent._, modifier.key) == modifier.value
), f"{modifier.key} labels don't match."
if not on_ents_only:
for token in ent:
assert (
getattr(token._, modifier.key) == modifier.value
), f"{modifier.key} labels don't match."
def test_negation_within_ents(blank_nlp, negation_factory):
negation = negation_factory(on_ents_only=True, within_ents=True)
examples = [
"<ent negated=true>Lésion pulmonaire avec absence de lésion secondaire</ent>.",
]
for example in examples:
text, entities = parse_example(example=example)
doc = blank_nlp(text)
doc.ents = [
doc.char_span(ent.start_char, ent.end_char, label="ent") for ent in entities
]
doc = negation(doc)
for entity, ent in zip(entities, doc.ents):
for modifier in entity.modifiers:
assert bool(ent._.negation_cues) == (modifier.value in {True, "NEG"})
assert (
getattr(ent._, modifier.key) == modifier.value
), f"{modifier.key} labels don't match."