Add pronoun parsing for msg_contents inlinefuncs

This commit is contained in:
Griatch 2021-10-30 22:36:40 +02:00
parent 9cb807a73c
commit 9d6cb98349
15 changed files with 1063 additions and 24 deletions

View file

@ -38,13 +38,8 @@ _COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
# the sessid_max is based on the length of the db_sessid csv field (excluding commas)
_SESSID_MAX = 16 if _MULTISESSION_MODE in (1, 3) else 1
_MSG_CONTENTS_PARSER = funcparser.FuncParser(
{
"you": funcparser.funcparser_callable_you,
"You": funcparser.funcparser_callable_You,
"conj": funcparser.funcparser_callable_conjugate
}
)
# init the actor-stance funcparser for msg_contents
_MSG_CONTENTS_PARSER = funcparser.FuncParser(funcparser.ACTOR_STANCE_CALLABLES)
class ObjectSessionHandler:
@ -729,8 +724,9 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
on the valid OOB outmessage form `(message, {kwargs})`,
where kwargs are optional data passed to the `text`
outputfunc. The message will be parsed for `{key}` formatting and
`$You/$you()/$You(key)` and `$conj(verb)` inline function callables.
The `key` is taken from the `mapping` kwarg {"key": object, ...}`.
`$You/$you()/$You()`, `$obj(name)`, `$conj(verb)` and `$pron(pronoun, option)`
inline function callables.
The `name` is taken from the `mapping` kwarg {"name": object, ...}`.
The `mapping[key].get_display_name(looker=recipient)` will be called
for that key for every recipient of the string.
exclude (list, optional): A list of objects not to send to.

View file

@ -53,6 +53,7 @@ from evennia.utils.utils import (
safe_convert_to_types)
from evennia.utils import search
from evennia.utils.verb_conjugation.conjugate import verb_actor_stance_components
from evennia.utils.verb_conjugation.pronouns import pronoun_to_viewpoints
# setup
@ -1082,8 +1083,8 @@ def funcparser_callable_you(*args, caller=None, receiver=None, mapping=None, cap
if hasattr(caller, "get_display_name") else str(caller))
def funcparser_callable_You(*args, you=None, receiver=None, mapping=None, capitalize=True,
**kwargs):
def funcparser_callable_you_capitalize(
*args, you=None, receiver=None, mapping=None, capitalize=True, **kwargs):
"""
Usage: $You() - capitalizes the 'you' output.
@ -1094,6 +1095,8 @@ def funcparser_callable_You(*args, you=None, receiver=None, mapping=None, capita
def funcparser_callable_conjugate(*args, caller=None, receiver=None, **kwargs):
"""
Usage: $conj(word, [options])
Conjugate a verb according to if it should be 2nd or third person.
Keyword Args:
@ -1130,6 +1133,146 @@ def funcparser_callable_conjugate(*args, caller=None, receiver=None, **kwargs):
return second_person_str if caller == receiver else third_person_str
def funcparser_callable_pronoun(*args, caller=None, receiver=None, capitalize=False, **kwargs):
"""
Usage: $prop(word, [options])
Adjust pronouns to the expected form. Pronouns are words you use instead of a
proper name, such as 'him', 'herself', 'theirs' etc. These look different
depending on who sees the outgoing string.
The parser maps between this table ...
==================== ======= ======= ========== ========== ===========
1st/2nd person Subject Object Possessive Possessive Reflexive
Pronoun Pronoun Adjective Pronoun Pronoun
==================== ======= ======= ========== ========== ===========
1st person I me my mine myself
1st person plural we us our ours ourselves
2nd person you you your yours yourself
2nd person plural you you your yours yourselves
==================== ======= ======= ========== ========== ===========
... and this table (and vice versa).
==================== ======= ======= ========== ========== ===========
3rd person Subject Object Possessive Possessive Reflexive
Pronoun Pronoun Adjective Pronoun Pronoun
==================== ======= ======= ========== ========== ===========
3rd person male he him his his himself
3rd person female she her her hers herself
3rd person neutral it it its itself
3rd person plural they them their theirs themselves
==================== ======= ======= ========== ========== ===========
This system will examine `caller` for either a property or a callable `.gender` to
get a default gender fallback (if not specified in the call). If a callable,
`.gender` will be called without arguments and should return a string
`male`/`female`/`neutral`/`plural` (plural is considered a gender for this purpose).
If no `gender` property/callable is found, `neutral` is used as a fallback.
The pronoun-type default (if not spefified in call) is `subject pronoun`.
Args:
pronoun (str): Input argument to parsed call. This can be any of the pronouns
in the table above. If given in 1st/second form, they will be mappped to
3rd-person form for others viewing the message (but will need extra input
via the `gender`, see below). If given on 3rd person form, this will be
mapped to 2nd person form for `caller` unless `viewpoint` is specified
in options.
options (str, optional): A space- or comma-separated string detailing `pronoun_type`,
`gender`/`plural` and/or `viewpoint` to help the mapper differentiate between
non-unique cases (such as if `you` should become `him` or `they`).
Allowed values are:
- `subject pronoun`/`subject`/`sp` (I, you, he, they)
- `object pronoun`/`object/`/`op` (me, you, him, them)
- `possessive adjective`/`adjective`/`pa` (my, your, his, their)
- `possessive pronoun`/`pronoun`/`pp` (mine, yours, his, theirs)
- `male`/`m`
- `female`/`f`
- `neutral`/`n`
- `plural`/`p`
- `1st person`/`1st`/`1`
- `2nd person`/`2nd`/`2`
- `3rd person`/`3rd`/`3`
Keyword Args:
caller (Object): The object creating the string. If this has a property 'gender',
it will be checked for a string 'male/female/neutral' to determine
the 3rd person gender (but if `pronoun_type` contains a gender
component, that takes precedence). Provided automatically to the
funcparser.
receiver (Object): The recipient of the string. This being the same as
`caller` or not helps determine 2nd vs 3rd-person forms. This is
provided automatically by the funcparser.
capitalize (bool): The input retains its capitalization. If this is set the output is
always capitalized.
Examples:
====================== ============= ===========
Input caller sees others see
====================== ============= ===========
$pron(I, m) I he
$pron(you,fo) you her
$pron(yourself) yourself itself
$pron(its) your its
$pron(you,op,p) you them
====================== ============= ===========
Notes:
There is no option to specify reflexive pronouns since they are all unique
and the mapping can always be auto-detected.
"""
if not args:
return ''
pronoun, *options = args
# options is either multiple args or a space-separated string
if len(options) == 1:
options = options[0]
# default differentiators
default_pronoun_type = "subject pronoun"
default_gender = "neutral"
default_viewpoint = "2nd person"
if hasattr(caller, "gender"):
if callable(caller, gender):
default_gender = caller.gender()
else:
default_gender = caller.gender
if "viewpoint" in kwargs:
# passed into FuncParser initialization
default_viewpoint = kwargs["viewpoint"]
pronoun_1st_or_2nd_person, pronoun_3rd_person = pronoun_to_viewpoints(
pronoun, options,
pronoun_type=default_pronoun_type, gender=default_gender, viewpoint=default_viewpoint)
if capitalize:
pronoun_1st_or_2nd_person = pronoun_1st_or_2nd_person.capitalize()
pronoun_3rd_person = pronoun_3rd_person.capitalize()
return pronoun_1st_or_2nd_person if caller == receiver else pronoun_3rd_person
def funcparser_callable_pronoun_capitalize(
*args, caller=None, receiver=None, capitalize=True, **kwargs):
"""
Usage: $Pron(word) - always maps to a capitalized word.
"""
return funcparser_callable_pronoun(
*args, caller=caller, receiver=receiver, capitalize=capitalize, **kwargs)
# these are made available as callables by adding 'evennia.utils.funcparser' as
# a callable-path when initializing the FuncParser.
@ -1176,6 +1319,10 @@ SEARCHING_CALLABLES = {
ACTOR_STANCE_CALLABLES = {
# requires `you`, `receiver` and `mapping` to be passed into parser
"you": funcparser_callable_you,
"You": funcparser_callable_You,
"You": funcparser_callable_you_capitalize,
"obj": funcparser_callable_you,
"Obj": funcparser_callable_you_capitalize,
"conj": funcparser_callable_conjugate,
"pron": funcparser_callable_pronoun,
"Pron": funcparser_callable_pronoun_capitalize,
}

View file

@ -4,6 +4,7 @@ The gametime module handles the global passage of time in the mud.
It also supplies some useful methods to convert between
in-mud time and real-world time as well allows to get the
total runtime of the server and the current uptime.
"""
import time
@ -244,8 +245,11 @@ def schedule(
script (Script): The created Script handling the sceduling.
Examples:
schedule(func, min=5, sec=0) # Will call 5 minutes past the next (in-game) hour.
schedule(func, hour=2, min=30, sec=0) # Will call the next (in-game) day at 02:30.
::
schedule(func, min=5, sec=0) # Will call 5 minutes past the next (in-game) hour.
schedule(func, hour=2, min=30, sec=0) # Will call the next (in-game) day at 02:30.
"""
seconds = real_seconds_until(sec=sec, min=min, hour=hour, day=day, month=month, year=year)
script = create_script(

View file

@ -5,6 +5,7 @@ Test the funcparser module.
"""
import time
from unittest.mock import MagicMock, patch
from ast import literal_eval
from simpleeval import simple_eval
from parameterized import parameterized
@ -306,6 +307,10 @@ class TestDefaultCallables(TestCase):
("$You() $conj(smile) at $You(char1).", "You smile at You.", "Char1 smiles at Char1."),
("$You() $conj(smile) at $You(char2).", "You smile at Char2.", "Char1 smiles at You."),
("$You(char2) $conj(smile) at $you(char1).", "Char2 smile at you.", "You smiles at Char1."),
("$You() $conj(smile) to $pron(yourself,m).", "You smile to yourself.",
"Char1 smiles to himself."),
("$You() $conj(smile) to $pron(herself).", "You smile to yourself.",
"Char1 smiles to herself.") # reverse reference
])
def test_conjugate(self, string, expected_you, expected_them):
"""
@ -464,3 +469,5 @@ class TestCallableSearch(test_resources.EvenniaTest):
ret = self.parser.parse(string, caller=self.char1, return_str=False, raise_errors=True)
self.assertEqual(expected, ret)

View file

@ -2628,3 +2628,40 @@ def strip_unsafe_input(txt, session=None, bypass_perms=None):
txt = strip_tags(txt)
txt = _STRIP_UNSAFE_TOKENS(txt)
return txt
def copy_word_case(base_word, new_word):
"""
Converts a word to use the same capitalization as a first word.
Args:
base_word (str): A word to get the capitalization from.
new_word (str): A new word to capitalize in the same way as `base_word`.
Returns:
str: The `new_word` with capitalization matching the first word.
Notes:
This is meant for words. Longer sentences may get unexpected results.
If the two words have a mix of capital/lower letters _and_ `new_word`
is longer than `base_word`, the excess will retain its original case.
"""
# Word
if base_word.istitle():
return new_word.title()
# word
elif base_word.islower():
return new_word.lower()
# WORD
elif base_word.isupper():
return new_word.upper()
else:
# WorD - a mix. Handle each character
maxlen = len(base_word)
shared, excess = new_word[:maxlen], new_word[maxlen - 1:]
return "".join(char.upper() if base_word[ic].isupper() else char.lower()
for ic, char in enumerate(new_word)) + excess

View file

@ -0,0 +1,560 @@
"""
English pronoun mapping between 1st/2nd person and 3rd person perspective (and vice-versa).
This file is released under the Evennia regular BSD License.
(Griatch 2021)
Pronouns are words you use instead of a proper name, such as 'him', 'herself', 'theirs' etc. These
look different depending on who sees the outgoing string. This mapping maps between 1st/2nd case and
the 3rd person case and back. In some cases, the mapping is not unique; it is assumed the system can
differentiate between the options in some other way.
==================== ======= ======== ========== ========== ===========
viewpoint/pronouns Subject Object Possessive Possessive Reflexive
Pronoun Pronoun Adjective Pronoun Pronoun
==================== ======= ======== ========== ========== ===========
1st person I me my mine myself
1st person plural we us our ours ourselves
2nd person you you your yours yourself
2nd person plural you you your yours yourselves
3rd person male he him his his himself
3rd person female she her her hers herself
3rd person neutral it it its theirs* itself
3rd person plural they them their theirs themselves
==================== ======= ======== ========== ========== ===========
> `*`) Not formally used, we use `theirs` here as a filler.
"""
from evennia.utils.utils import copy_word_case
DEFAULT_PRONOUN_TYPE = "object_pronoun"
DEFAULT_VIEWPOINT = "2nd person"
DEFAULT_GENDER = "neutral"
PRONOUN_MAPPING = {
# 1st/2nd person -> 3rd person mappings
"I": {
"subject pronoun": {
"3rd person": {
"male": "he",
"female": "she",
"neutral": "it"
}
}
},
"me": {
"object pronoun": {
"3rd person": {
"male": "him",
"female": "her",
"neutral": "it"
}
}
},
"my": {
"possessive adjective": {
"3rd person": {
"male": "his",
"female": "her",
"neutral": "its"
}
}
},
"mine": {
"possessive pronoun": {
"3rd person": {
"male": "his",
"female": "hers",
"neutral": "theirs", # colloqial,
}
}
},
"myself": {
"reflexive_pronoun": {
"3rd person": {
"male": "himself",
"female": "herself",
"neutral": "itself",
"plural": "themselves",
}
}
},
"you": {
"subject pronoun": {
"3rd person": {
"male": "he",
"female": "she",
"neutral": "it",
"plural": "they",
}
},
"object pronoun": {
"3rd person": {
"male": "him",
"female": "her",
"neutral": "it",
"plural": "them",
}
}
},
"your": {
"possessive adjective": {
"3rd person": {
"male": "his",
"female": "her",
"neutral": "its",
"plural": "their",
}
}
},
"yours": {
"possessive pronoun": {
"3rd person": {
"male": "his",
"female": "hers",
"neutral": "theirs", # colloqial
"plural": "theirs"
}
}
},
"yourself": {
"reflexive_pronoun": {
"3rd person": {
"male": "himself",
"female": "herself",
"neutral": "itself",
}
}
},
"we": {
"subject pronoun": {
"3rd person": {
"plural": "they"
}
}
},
"us": {
"object pronoun": {
"3rd person": {
"plural": "them"
}
}
},
"our": {
"possessive adjective": {
"3rd person": {
"plural": "their"
}
}
},
"ours": {
"possessive pronoun": {
"3rd person": {
"plural": "theirs"
}
}
},
"ourselves": {
"reflexive pronoun": {
"3rd person": {
"plural": "themselves"
}
}
},
"ours": {
"possessive pronoun": {
"3rd person": {
"plural": "theirs"
}
}
},
"ourselves": {
"reflexive pronoun": {
"3rd person": {
"plural": "themselves"
}
}
},
"yourselves": {
"reflexive_pronoun": {
"3rd person": {
"plural": "themselves"
}
}
},
# 3rd person to 1st/second person mappings
"he": {
"subject pronoun": {
"1st person": {
"neutral": "I",
"plural": "we" # pluralis majestatis
},
"2nd person": {
"neutral": "you",
"plural": "you" # pluralis majestatis
}
}
},
"him": {
"object pronoun": {
"1st person": {
"neutral": "me",
"plural": "us" # pluralis majestatis
},
"2nd person": {
"neutral": "you",
"plural": "you" # pluralis majestatis
},
}
},
"his": {
"possessive adjective": {
"1st person": {
"neutral": "my",
"plural": "our" # pluralis majestatis
},
"2nd person": {
"neutral": "your",
"plural": "your" # pluralis majestatis
}
},
"possessive pronoun": {
"1st person": {
"neutral": "mine",
"plural": "ours" # pluralis majestatis
},
"2nd person": {
"neutral": "yours",
"plural": "yours" # pluralis majestatis
}
}
},
"himself": {
"reflexive pronoun": {
"1st person": {
"neutral": "myself",
"plural": "ourselves" # pluralis majestatis
},
"2nd person": {
"neutral": "yours",
"plural": "yours" # pluralis majestatis
}
},
},
"she": {
"subject pronoun": {
"1st person": {
"neutral": "I",
"plural": "you" # pluralis majestatis
},
"2nd person": {
"neutral": "you",
"plural": "we" # pluralis majestatis
}
}
},
"her": {
"object pronoun": {
"1st person": {
"neutral": "me",
"plural": "us" # pluralis majestatis
},
"2nd person": {
"neutral": "you",
"plural": "you" # pluralis majestatis
}
},
"possessive adjective": {
"1st person": {
"neutral": "my",
"plural": "our" # pluralis majestatis
},
"2nd person": {
"neutral": "your",
"plural": "your" # pluralis majestatis
}
},
},
"hers": {
"possessive pronoun": {
"1st person": {
"neutral": "mine",
"plural": "ours" # pluralis majestatis
},
"2nd person": {
"neutral": "yours",
"plural": "yours" # pluralis majestatis
}
}
},
"herself": {
"reflexive pronoun": {
"1st person": {
"neutral": "myself",
"plural": "ourselves" # pluralis majestatis
},
"2nd person": {
"neutral": "yourself",
"plural": "yourselves" # pluralis majestatis
}
},
},
"it": {
"subject pronoun": {
"1st person": {
"neutral": "I",
"plural": "we" # pluralis majestatis
},
"2nd person": {
"neutral": "you",
"plural": "you" # pluralis majestatis
}
},
"object pronoun": {
"1st person": {
"neutral": "me",
"plural": "us" # pluralis majestatis
},
"2nd person": {
"neutral": "you",
"plural": "you" # pluralis majestatis
}
}
},
"its": {
"possessive adjective": {
"1st person": {
"neutral": "my",
"plural": "our" # pluralis majestatis
},
"2nd person": {
"neutral": "your",
"plural": "your" # pluralis majestatis
}
}
},
"theirs": {
"possessive pronoun": {
"1st person": {
"neutral": "mine",
"plural": "ours" # pluralis majestatis
},
"2nd person": {
"neutral": "yours",
"plural": "yours" # pluralis majestatis
}
}
},
"itself": {
"reflexive pronoun": {
"1st person": {
"neutral": "myself",
"plural": "ourselves" # pluralis majestatis
},
"2nd person": {
"neutral": "yourself",
"plural": "yourselves" # pluralis majestatis
}
},
},
"they": {
"subject pronoun": {
"1st person": {
"plural": "we",
},
"2nd person": {
"plural": "you",
}
}
},
"them": {
"object pronoun": {
"1st person": {
"plural": "us",
},
"2nd person": {
"plural": "you",
}
}
},
"their": {
"possessive adjective": {
"1st person": {
"plural": "our",
},
"2nd person": {
"plural": "your",
}
}
},
"themselves": {
"reflexive pronoun": {
"1st person": {
"plural": "ourselves",
},
"2nd person": {
"plural": "yourselves",
}
}
}
}
ALIASES = {
"m": "male",
"f": "female",
"n": "neutral",
"p": "plural",
"1st": "1st person",
"2nd": "2nd person",
"3rd": "3rd person",
"1": "1st person",
"2": "2nd person",
"3": "3rd person",
"s": "subject pronoun",
"sp": "subject pronoun",
"subject": "subject pronoun",
"op": "object pronoun",
"object": "object pronoun",
"pa": "possessive adjective",
"pp": "possessive pronoun",
}
PRONOUN_TYPES = ["subject pronoun", "object pronoun", "possessive adjective",
"possessive pronoun", "reflexive pronoun"]
VIEWPOINTS = ["1st person", "2nd person", "3rd person"]
GENDERS = ["male", "female", "neutral", "plural"] # including plural as a gender for simplicity
def pronoun_to_viewpoints(pronoun,
options=None, pronoun_type="object_pronoun",
gender="neutral", viewpoint="2nd person"):
"""
Access function for determining the forms of a pronount from different viewpoints.
Args:
pronoun (str): A valid English pronoun, such as 'you', 'his', 'themselves' etc.
options (str or list, optional): A list or space-separated string of options to help
the engine when there is no unique mapping to use. This could for example
be "2nd female" (alias 'f') or "possessive adjective" (alias 'pa' or 'a').
pronoun_type (str, optional): An explicit object pronoun to separate cases where
there is no unique mapping. Pronoun types defined in `options` take precedence.
Values are
- `subject pronoun`/`subject`/`sp` (I, you, he, they)
- `object pronoun`/`object/`/`op` (me, you, him, them)
- `possessive adjective`/`adjective`/`pa` (my, your, his, their)
- `possessive pronoun`/`pronoun`/`pp` (mine, yours, his, theirs)
gender (str, optional): Specific gender to use (plural counts a gender for this purpose).
A gender specified in `options` takes precedence. Values and aliases are:
- `male`/`m`
- `female`/`f`
- `neutral`/`n`
- `plural`/`p`
viewpoint (str, optional): A specified viewpoint of the one talking, to use
when there is no unique mapping. A viewpoint given in `options` take
precedence. Values and aliases are:
- `1st person`/`1st`/`1`
- `2nd person`/`2nd`/`2`
- `3rd person`/`3rd`/`3`
Returns:
tuple: A tuple `(1st/2nd_person_pronoun, 3rd_person_pronoun)` to show to the one sending the
string and others respectively. If pronoun is invalid, the word is returned verbatim.
Note:
The capitalization of the original word will be retained.
"""
if not pronoun:
return pronoun
pronoun_lower = "I" if pronoun == "I" else pronoun.lower()
if pronoun_lower not in PRONOUN_MAPPING:
return pronoun
# differentiators
if pronoun_type not in PRONOUN_TYPES:
pronoun_type = DEFAULT_PRONOUN_TYPE
if viewpoint not in VIEWPOINTS:
viewpoint = DEFAULT_VIEWPOINT
if gender not in GENDERS:
gender = DEFAULT_GENDER
if options:
# option string/list will override the kwargs differentiators given
if isinstance(options, str):
options = options.split()
options = [str(part).strip().lower() for part in options]
options = [ALIASES.get(opt, opt) for opt in options]
for opt in options:
if opt in PRONOUN_TYPES:
pronoun_type = opt
elif opt in VIEWPOINTS:
viewpoint = opt
elif opt in GENDERS:
gender = opt
# step down into the mapping, using differentiators as needed
pronoun_types = PRONOUN_MAPPING[pronoun_lower]
# this has one or more pronoun-types
if len(pronoun_types) == 1:
pronoun_type, viewpoints = next(iter(pronoun_types.items()))
elif pronoun_type in pronoun_types:
viewpoints = pronoun_types[pronoun_type]
elif DEFAULT_PRONOUN_TYPE in pronoun_types:
pronoun_type = DEFAULT_PRONOUN_TYPE
viewpoints = pronoun_types[pronoun_type]
else:
# not enough info - grab the first of the mappings
pronoun_type, viewpoints = next(iter(pronoun_types.items()))
# we have one or more viewpoints at this point
if len(viewpoints) == 1:
viewpoint, genders = next(iter(viewpoints.items()))
elif viewpoint in viewpoints:
genders = viewpoints[viewpoint]
elif DEFAULT_VIEWPOINT in viewpoints:
viewpoint = DEFAULT_VIEWPOINT
genders = viewpoints[viewpoint]
else:
# not enough info - grab first of mappings
viewpoint, genders = next(iter(viewpoints.items()))
# we have one or more possible genders (including plural forms)
if len(genders) == 1:
gender, mapped_pronoun = next(iter(genders.items()))
elif gender in genders:
mapped_pronoun = genders[gender]
elif DEFAULT_GENDER in genders:
gender = DEFAULT_GENDER
mapped_pronoun = genders[gender]
else:
# not enough info - grab first mapping
gender, mapped_pronoun = next(iter(genders.items()))
# keep the same capitalization as the original
if pronoun != "I":
# don't remap I, since this is always capitalized.
mapped_pronoun = copy_word_case(pronoun, mapped_pronoun)
if mapped_pronoun == "i":
mapped_pronoun = mapped_pronoun.upper()
if viewpoint == "3rd person":
# the remapped viewpoing is in 3rd person, meaning the ingoing viewpoing
# must have been 1st or 2nd person.
return pronoun, mapped_pronoun
else:
# the remapped viewpoint is 1st or 2nd person, so ingoing must have been
# in 3rd person form.
return mapped_pronoun, pronoun

View file

@ -5,7 +5,7 @@ Unit tests for verb conjugation.
from parameterized import parameterized
from django.test import TestCase
from . import conjugate
from . import conjugate, pronouns
class TestVerbConjugate(TestCase):
@ -239,3 +239,49 @@ class TestVerbConjugate(TestCase):
"""
self.assertEqual(expected, conjugate.verb_actor_stance_components(verb))
class TestPronounMapping(TestCase):
"""
Test pronoun viewpoint mapping
"""
@parameterized.expand([
("you", "m", "you", "he"),
("you", "f op", "you", "her"),
("I", "", "I", "it"),
("I", "p", "I", "it"), # plural is invalid
("I", "m", "I", "he"),
("Me", "n", "Me", "It"),
("your", "p", "your", "their"),
("ours", "", "ours", "theirs"),
("yourself", "", "yourself", "itself"),
("yourself", "m", "yourself", "himself"),
("yourself", "f", "yourself", "herself"),
("yourself", "p", "yourself", "itself"), # plural is invalid
("yourselves", "", "yourselves", "themselves"),
("he", "", "you", "he"), # assume 2nd person
("he", "1", "I", "he"),
("he", "1 p", "we", "he"),
("her", "p", "you", "her"),
("her", "pa", "your", "her"),
("their", "pa", "your", "their"),
("their", "pa", "your", "their"),
("itself", "", "yourself", "itself"),
("themselves", "", "yourselves", "themselves"),
("herself", "", "yourself", "herself"),
])
def test_mapping_with_options(self, pronoun, options,
expected_1st_or_2nd_person,
expected_3rd_person):
"""
Test the pronoun mapper.
"""
received_1st_or_2nd_person, received_3rd_person = (
pronouns.pronoun_to_viewpoints(pronoun, options)
)
self.assertEqual(expected_1st_or_2nd_person, received_1st_or_2nd_person)
self.assertEqual(expected_3rd_person, received_3rd_person)