Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance singular_noun #228

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

BBC-Esq
Copy link

@BBC-Esq BBC-Esq commented Feb 4, 2025

This fixes the issue with #222 and is an improvement. However, it is not a perfect solution for all other possible phrases.

Summary of Changes:

  1. Added Handling for Irregular Plurals:

    • Introduced a new helper function, handle_irregular_plural(), which checks if a word is an irregular plural and replaces it with its singular form when necessary.
    • Uses pl_sb_irregular.values() to determine if the word is irregular and maps it back to its singular form.
  2. Improved Inflection Handling:

    • The inflection process now includes logic to avoid unnecessary pluralization when count != 1 but the word already ends in 's'.
    • Ensures irregular plural forms are properly converted using handle_irregular_plural().
  3. Refactored Inflection Logic:

    • The original inflection(cand, count) call is now stored in a for loop to ensure that it is only computed once and can be used in multiple checks.
    • Used a conditional expression to determine whether the candidate word (cand) should be replaced with the inflected version or left unchanged.
  4. Removed Docstring Examples:

    • The revised version omits the docstring examples (doctests), which were present in the original method.

Possible Future Improvements

Here is a script that illustrates other scenarios that are related conceptually but that this PR decided to not address at this time, for your future improvements:

TEST SCRIPT
import inflect
from typing import Union, Dict, Tuple

GREEN = "\033[92m"
RED = "\033[91m"
RESET = "\033[0m"

p = inflect.engine()

expected_results = {
    # Your existing test cases
    "pair of scissors": ("pair of scissors", "pairs of scissors"),
    "pairs of scissors": ("pair of scissors", "pairs of scissors"),
    "mother in law": ("mother in law", "mothers in law"),
    "mothers in law": ("mother in law", "mothers in law"),
    "student of physics": ("student of physics", "students of physics"),
    "students of physics": ("student of physics", "students of physics"),
    "piece of cake": ("piece of cake", "pieces of cake"),
    "pieces of cake": ("piece of cake", "pieces of cake"),
    "man at arms": ("man at arms", "men at arms"),
    "men at arms": ("man at arms", "men at arms"),
    "right of way": ("right of way", "rights of way"),
    "rights of way": ("right of way", "rights of way"),
    "editor in chief": ("editor in chief", "editors in chief"),
    "editors in chief": ("editor in chief", "editors in chief"),
    "secretary of state": ("secretary of state", "secretaries of state"),
    "secretaries of state": ("secretary of state", "secretaries of state"),
    "court of law": ("court of law", "courts of law"),
    "courts of law": ("court of law", "courts of law"),
    "brother in arms": ("brother in arms", "brothers in arms"),
    "brothers in arms": ("brother in arms", "brothers in arms"),
    "head of household": ("head of household", "heads of household"),
    "heads of household": ("head of household", "heads of household"),
    
    # 1. Compound words with different plural forms
    "attorney general": ("attorney general", "attorneys general"),
    "attorney at law": ("attorney at law", "attorneys at law"),
    "commander in chief": ("commander in chief", "commanders in chief"),
    "passer by": ("passer by", "passers by"),
    "runner up": ("runner up", "runners up"),
    
    # 2. Words with irregular plurals
    "criterion": ("criterion", "criteria"),
    "phenomenon": ("phenomenon", "phenomena"),
    "thesis": ("thesis", "theses"),
    "analysis": ("analysis", "analyses"),
    "datum": ("datum", "data"),
    
    # 3. Compound phrases with possessives
    "child's play": ("child's play", "children's play"),
    "wolf's bane": ("wolf's bane", "wolves' bane"),
    
    # 4. Hyphenated compounds
    "father-in-law": ("father-in-law", "fathers-in-law"),
    "merry-go-round": ("merry-go-round", "merry-go-rounds"),
    
    # 5. Words that maintain the same form
    "species": ("species", "species"),
    "series": ("series", "series"),
    "means": ("means", "means"),
    
    # 6. Words with multiple accepted plurals
    "octopus": ("octopus", "octopi"),
    "formula": ("formula", "formulae"),
    "cactus": ("cactus", "cacti")
}

error_expected_results = {
    "": ("", ""),
    "of": (False, "ofs"),
    "pair scissors of": (False, "pair scissors ofs"),
    "student physics of": (False, "student physics ofs"),
    "pair_of_scissors": (False, "pair_of_scissorses"),
    "of of of": (False, "of of ofs"),
    "pair-of-scissors": ("pair-of-scissors", "pairs-of-scissors"),
    "   pair of scissors   ": ("   pair of scissors   ", "   pairs of scissors   "),
    "PaIr Of ScIsSoRs": ("PaIr Of ScIsSoRs", "PaIrS Of ScIsSoRs")
}

def check_result(actual: Union[str, bool], expected: Union[str, bool]) -> bool:
    if expected is False:
        return actual is False
    return actual == expected

def print_result(passed: bool, message: str = ""):
    if passed:
        print(f"{GREEN}✓ Correct{RESET} {message}")
    else:
        print(f"{RED}✗ Failed{RESET} {message}")

print("Testing Regular Cases")
print("-" * 75)

for phrase in expected_results:
    print(f"\nTesting: '{phrase}'")
    expected_sing, expected_plur = expected_results[phrase]
    
    singular_result = p.singular_noun(phrase)
    singular_display = singular_result if singular_result is not False else "[already singular]"
    print(f"Singular:  {singular_display}")
    print_result(check_result(singular_result, expected_sing), 
                f"(Expected: {expected_sing})")
    
    plural_result = p.plural_noun(phrase)
    print(f"Plural:    {plural_result}")
    print_result(plural_result == expected_plur, 
                f"(Expected: {expected_plur})")
    
    final_singular = p.singular_noun(plural_result)
    final_display = final_singular if final_singular is not False else "[already singular]"
    print(f"Back to singular: {final_display}")
    print_result(check_result(final_singular, expected_sing), 
                f"(Expected: {expected_sing})")

print("\nTesting Error Cases")
print("-" * 75)

for phrase in error_expected_results:
    print(f"\nTesting: '{phrase}'")
    expected_sing, expected_plur = error_expected_results[phrase]
    
    try:
        singular = p.singular_noun(phrase)
        print(f"Singular attempt: {singular}")
        print_result(check_result(singular, expected_sing), 
                    f"(Expected: {expected_sing})")
    except Exception as e:
        if isinstance(expected_sing, type) and isinstance(e, expected_sing):
            print_result(True, f"Got expected exception: {type(e).__name__}")
        else:
            print_result(False, f"Got unexpected exception: {type(e).__name__}")
    
    try:
        plural = p.plural_noun(phrase)
        print(f"Plural attempt: {plural}")
        print_result(plural == expected_plur, 
                    f"(Expected: {expected_plur})")
    except Exception as e:
        if isinstance(expected_plur, type) and isinstance(e, expected_plur):
            print_result(True, f"Got expected exception: {type(e).__name__}")
        else:
            print_result(False, f"Got unexpected exception: {type(e).__name__}")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant