Correctly generate plurals, ordinals, indefinite articles; convert numbers to words

Overview
Automated Tests Code style: Black https://coveralls.io/repos/github/jaraco/inflect/badge.svg?branch=master https://tidelift.com/badges/package/pypi/inflect

NAME

inflect.py - Correctly generate plurals, singular nouns, ordinals, indefinite articles; convert numbers to words.

SYNOPSIS

import inflect

p = inflect.engine()

# METHODS:

# plural plural_noun plural_verb plural_adj singular_noun no num
# compare compare_nouns compare_nouns compare_adjs
# a an
# present_participle
# ordinal number_to_words
# join
# inflect classical gender
# defnoun defverb defadj defa defan


# UNCONDITIONALLY FORM THE PLURAL

print("The plural of ", word, " is ", p.plural(word))


# CONDITIONALLY FORM THE PLURAL

print("I saw", cat_count, p.plural("cat", cat_count))


# FORM PLURALS FOR SPECIFIC PARTS OF SPEECH

print(
    p.plural_noun("I", N1),
    p.plural_verb("saw", N1),
    p.plural_adj("my", N2),
    p.plural_noun("saw", N2),
)


# FORM THE SINGULAR OF PLURAL NOUNS

print("The singular of ", word, " is ", p.singular_noun(word))

# SELECT THE GENDER OF SINGULAR PRONOUNS

print(p.singular_noun("they"))  # 'it'
p.gender("f")
print(p.singular_noun("they"))  # 'she'


# DEAL WITH "0/1/N" -> "no/1/N" TRANSLATION:

print("There ", p.plural_verb("was", errors), p.no(" error", errors))


# USE DEFAULT COUNTS:

print(
    p.num(N1, ""),
    p.plural("I"),
    p.plural_verb(" saw"),
    p.num(N2),
    p.plural_noun(" saw"),
)
print("There ", p.num(errors, ""), p.plural_verb("was"), p.no(" error"))


# COMPARE TWO WORDS "NUMBER-INSENSITIVELY":

if p.compare(word1, word2):
    print("same")
if p.compare_nouns(word1, word2):
    print("same noun")
if p.compare_verbs(word1, word2):
    print("same verb")
if p.compare_adjs(word1, word2):
    print("same adj.")


# ADD CORRECT "a" OR "an" FOR A GIVEN WORD:

print("Did you want ", p.a(thing), " or ", p.an(idea))


# CONVERT NUMERALS INTO ORDINALS (i.e. 1->1st, 2->2nd, 3->3rd, etc.)

print("It was", p.ordinal(position), " from the left\n")

# CONVERT NUMERALS TO WORDS (i.e. 1->"one", 101->"one hundred and one", etc.)
# RETURNS A SINGLE STRING...

words = p.number_to_words(1234)
# "one thousand, two hundred and thirty-four"
words = p.number_to_words(p.ordinal(1234))
# "one thousand, two hundred and thirty-fourth"


# GET BACK A LIST OF STRINGS, ONE FOR EACH "CHUNK"...

words = p.number_to_words(1234, wantlist=True)
# ("one thousand","two hundred and thirty-four")


# OPTIONAL PARAMETERS CHANGE TRANSLATION:

words = p.number_to_words(12345, group=1)
# "one, two, three, four, five"

words = p.number_to_words(12345, group=2)
# "twelve, thirty-four, five"

words = p.number_to_words(12345, group=3)
# "one twenty-three, forty-five"

words = p.number_to_words(1234, andword="")
# "one thousand, two hundred thirty-four"

words = p.number_to_words(1234, andword=", plus")
# "one thousand, two hundred, plus thirty-four"
# TODO: I get no comma before plus: check perl

words = p.number_to_words(555_1202, group=1, zero="oh")
# "five, five, five, one, two, oh, two"

words = p.number_to_words(555_1202, group=1, one="unity")
# "five, five, five, unity, two, oh, two"

words = p.number_to_words(123.456, group=1, decimal="mark")
# "one two three mark four five six"
# TODO: DOCBUG: perl gives commas here as do I

# LITERAL STYLE ONLY NAMES NUMBERS LESS THAN A CERTAIN THRESHOLD...

words = p.number_to_words(9, threshold=10)  # "nine"
words = p.number_to_words(10, threshold=10)  # "ten"
words = p.number_to_words(11, threshold=10)  # "11"
words = p.number_to_words(1000, threshold=10)  # "1,000"

# JOIN WORDS INTO A LIST:

mylist = join(("apple", "banana", "carrot"))
# "apple, banana, and carrot"

mylist = join(("apple", "banana"))
# "apple and banana"

mylist = join(("apple", "banana", "carrot"), final_sep="")
# "apple, banana and carrot"


# REQUIRE "CLASSICAL" PLURALS (EG: "focus"->"foci", "cherub"->"cherubim")

p.classical()  # USE ALL CLASSICAL PLURALS

p.classical(all=True)  # USE ALL CLASSICAL PLURALS
p.classical(all=False)  # SWITCH OFF CLASSICAL MODE

p.classical(zero=True)  #  "no error" INSTEAD OF "no errors"
p.classical(zero=False)  #  "no errors" INSTEAD OF "no error"

p.classical(herd=True)  #  "2 buffalo" INSTEAD OF "2 buffalos"
p.classical(herd=False)  #  "2 buffalos" INSTEAD OF "2 buffalo"

p.classical(persons=True)  # "2 chairpersons" INSTEAD OF "2 chairpeople"
p.classical(persons=False)  # "2 chairpeople" INSTEAD OF "2 chairpersons"

p.classical(ancient=True)  # "2 formulae" INSTEAD OF "2 formulas"
p.classical(ancient=False)  # "2 formulas" INSTEAD OF "2 formulae"


# INTERPOLATE "plural()", "plural_noun()", "plural_verb()", "plural_adj()", "singular_noun()",
# a()", "an()", "num()" AND "ordinal()" WITHIN STRINGS:

print(p.inflect("The plural of {0} is plural('{0}')".format(word)))
print(p.inflect("The singular of {0} is singular_noun('{0}')".format(word)))
print(p.inflect("I saw {0} plural('cat',{0})".format(cat_count)))
print(
    p.inflect(
        "plural('I',{0}) "
        "plural_verb('saw',{0}) "
        "plural('a',{1}) "
        "plural_noun('saw',{1})".format(N1, N2)
    )
)
print(
    p.inflect(
        "num({0}, False)plural('I') "
        "plural_verb('saw') "
        "num({1}, False)plural('a') "
        "plural_noun('saw')".format(N1, N2)
    )
)
print(p.inflect("I saw num({0}) plural('cat')\nnum()".format(cat_count)))
print(p.inflect("There plural_verb('was',{0}) no('error',{0})".format(errors)))
print(p.inflect("There num({0}, False)plural_verb('was') no('error')".format(errors)))
print(p.inflect("Did you want a('{0}') or an('{1}')".format(thing, idea)))
print(p.inflect("It was ordinal('{0}') from the left".format(position)))


# ADD USER-DEFINED INFLECTIONS (OVERRIDING INBUILT RULES):

p.defnoun("VAX", "VAXen")  # SINGULAR => PLURAL

p.defverb(
    "will",  # 1ST PERSON SINGULAR
    "shall",  # 1ST PERSON PLURAL
    "will",  # 2ND PERSON SINGULAR
    "will",  # 2ND PERSON PLURAL
    "will",  # 3RD PERSON SINGULAR
    "will",  # 3RD PERSON PLURAL
)

p.defadj("hir", "their")  # SINGULAR => PLURAL

p.defa("h")  # "AY HALWAYS SEZ 'HAITCH'!"

p.defan("horrendous.*")  # "AN HORRENDOUS AFFECTATION"

DESCRIPTION

The methods of the class engine in module inflect.py provide plural inflections, singular noun inflections, "a"/"an" selection for English words, and manipulation of numbers as words.

Plural forms of all nouns, most verbs, and some adjectives are provided. Where appropriate, "classical" variants (for example: "brother" -> "brethren", "dogma" -> "dogmata", etc.) are also provided.

Single forms of nouns are also provided. The gender of singular pronouns can be chosen (for example "they" -> "it" or "she" or "he" or "they").

Pronunciation-based "a"/"an" selection is provided for all English words, and most initialisms.

It is also possible to inflect numerals (1,2,3) to ordinals (1st, 2nd, 3rd) and to English words ("one", "two", "three").

In generating these inflections, inflect.py follows the Oxford English Dictionary and the guidelines in Fowler's Modern English Usage, preferring the former where the two disagree.

The module is built around standard British spelling, but is designed to cope with common American variants as well. Slang, jargon, and other English dialects are not explicitly catered for.

Where two or more inflected forms exist for a single word (typically a "classical" form and a "modern" form), inflect.py prefers the more common form (typically the "modern" one), unless "classical" processing has been specified (see MODERN VS CLASSICAL INFLECTIONS).

FORMING PLURALS AND SINGULARS

Inflecting Plurals and Singulars

All of the plural... plural inflection methods take the word to be inflected as their first argument and return the corresponding inflection. Note that all such methods expect the singular form of the word. The results of passing a plural form are undefined (and unlikely to be correct). Similarly, the si... singular inflection method expects the plural form of the word.

The plural... methods also take an optional second argument, which indicates the grammatical "number" of the word (or of another word with which the word being inflected must agree). If the "number" argument is supplied and is not 1 (or "one" or "a", or some other adjective that implies the singular), the plural form of the word is returned. If the "number" argument does indicate singularity, the (uninflected) word itself is returned. If the number argument is omitted, the plural form is returned unconditionally.

The si... method takes a second argument in a similar fashion. If it is some form of the number 1, or is omitted, the singular form is returned. Otherwise the plural is returned unaltered.

The various methods of inflect.engine are:

plural_noun(word, count=None)

The method plural_noun() takes a singular English noun or pronoun and returns its plural. Pronouns in the nominative ("I" -> "we") and accusative ("me" -> "us") cases are handled, as are possessive pronouns ("mine" -> "ours").

plural_verb(word, count=None)

The method plural_verb() takes the singular form of a conjugated verb (that is, one which is already in the correct "person" and "mood") and returns the corresponding plural conjugation.

plural_adj(word, count=None)

The method plural_adj() takes the singular form of certain types of adjectives and returns the corresponding plural form. Adjectives that are correctly handled include: "numerical" adjectives ("a" -> "some"), demonstrative adjectives ("this" -> "these", "that" -> "those"), and possessives ("my" -> "our", "cat's" -> "cats'", "child's" -> "childrens'", etc.)

plural(word, count=None)

The method plural() takes a singular English noun, pronoun, verb, or adjective and returns its plural form. Where a word has more than one inflection depending on its part of speech (for example, the noun "thought" inflects to "thoughts", the verb "thought" to "thought"), the (singular) noun sense is preferred to the (singular) verb sense.

Hence plural("knife") will return "knives" ("knife" having been treated as a singular noun), whereas plural("knifes") will return "knife" ("knifes" having been treated as a 3rd person singular verb).

The inherent ambiguity of such cases suggests that, where the part of speech is known, plural_noun, plural_verb, and plural_adj should be used in preference to plural.

singular_noun(word, count=None)

The method singular_noun() takes a plural English noun or pronoun and returns its singular. Pronouns in the nominative ("we" -> "I") and accusative ("us" -> "me") cases are handled, as are possessive pronouns ("ours" -> "mine"). When third person singular pronouns are returned they take the neuter gender by default ("they" -> "it"), not ("they"-> "she") nor ("they" -> "he"). This can be changed with gender().

Note that all these methods ignore any whitespace surrounding the word being inflected, but preserve that whitespace when the result is returned. For example, plural(" cat ") returns " cats ".

gender(genderletter)

The third person plural pronoun takes the same form for the female, male and neuter (e.g. "they"). The singular however, depends upon gender (e.g. "she", "he", "it" and "they" -- "they" being the gender neutral form.) By default singular_noun returns the neuter form, however, the gender can be selected with the gender method. Pass the first letter of the gender to gender to return the f(eminine), m(asculine), n(euter) or t(hey) form of the singular. e.g. gender('f') followed by singular_noun('themselves') returns 'herself'.

Numbered plurals

The plural... methods return only the inflected word, not the count that was used to inflect it. Thus, in order to produce "I saw 3 ducks", it is necessary to use:

print("I saw", N, p.plural_noun(animal, N))

Since the usual purpose of producing a plural is to make it agree with a preceding count, inflect.py provides a method (no(word, count)) which, given a word and a(n optional) count, returns the count followed by the correctly inflected word. Hence the previous example can be rewritten:

print("I saw ", p.no(animal, N))

In addition, if the count is zero (or some other term which implies zero, such as "zero", "nil", etc.) the count is replaced by the word "no". Hence, if N had the value zero, the previous example would print (the somewhat more elegant):

I saw no animals

rather than:

I saw 0 animals

Note that the name of the method is a pun: the method returns either a number (a No.) or a "no", in front of the inflected word.

Reducing the number of counts required

In some contexts, the need to supply an explicit count to the various plural... methods makes for tiresome repetition. For example:

print(
    plural_adj("This", errors),
    plural_noun(" error", errors),
    plural_verb(" was", errors),
    " fatal.",
)

inflect.py therefore provides a method (num(count=None, show=None)) which may be used to set a persistent "default number" value. If such a value is set, it is subsequently used whenever an optional second "number" argument is omitted. The default value thus set can subsequently be removed by calling num() with no arguments. Hence we could rewrite the previous example:

p.num(errors)
print(p.plural_adj("This"), p.plural_noun(" error"), p.plural_verb(" was"), "fatal.")
p.num()

Normally, num() returns its first argument, so that it may also be "inlined" in contexts like:

print(p.num(errors), p.plural_noun(" error"), p.plural_verb(" was"), " detected.")
if severity > 1:
    print(
        p.plural_adj("This"), p.plural_noun(" error"), p.plural_verb(" was"), "fatal."
    )

However, in certain contexts (see INTERPOLATING INFLECTIONS IN STRINGS) it is preferable that num() return an empty string. Hence num() provides an optional second argument. If that argument is supplied (that is, if it is defined) and evaluates to false, num returns an empty string instead of its first argument. For example:

print(p.num(errors, 0), p.no("error"), p.plural_verb(" was"), " detected.")
if severity > 1:
    print(
        p.plural_adj("This"), p.plural_noun(" error"), p.plural_verb(" was"), "fatal."
    )

Number-insensitive equality

inflect.py also provides a solution to the problem of comparing words of differing plurality through the methods compare(word1, word2), compare_nouns(word1, word2), compare_verbs(word1, word2), and compare_adjs(word1, word2). Each of these methods takes two strings, and compares them using the corresponding plural-inflection method (plural(), plural_noun(), plural_verb(), and plural_adj() respectively).

The comparison returns true if:

  • the strings are equal, or
  • one string is equal to a plural form of the other, or
  • the strings are two different plural forms of the one word.

Hence all of the following return true:

p.compare("index", "index")  # RETURNS "eq"
p.compare("index", "indexes")  # RETURNS "s:p"
p.compare("index", "indices")  # RETURNS "s:p"
p.compare("indexes", "index")  # RETURNS "p:s"
p.compare("indices", "index")  # RETURNS "p:s"
p.compare("indices", "indexes")  # RETURNS "p:p"
p.compare("indexes", "indices")  # RETURNS "p:p"
p.compare("indices", "indices")  # RETURNS "eq"

As indicated by the comments in the previous example, the actual value returned by the various compare methods encodes which of the three equality rules succeeded: "eq" is returned if the strings were identical, "s:p" if the strings were singular and plural respectively, "p:s" for plural and singular, and "p:p" for two distinct plurals. Inequality is indicated by returning an empty string.

It should be noted that two distinct singular words which happen to take the same plural form are not considered equal, nor are cases where one (singular) word's plural is the other (plural) word's singular. Hence all of the following return false:

p.compare("base", "basis")  # ALTHOUGH BOTH -> "bases"
p.compare("syrinx", "syringe")  # ALTHOUGH BOTH -> "syringes"
p.compare("she", "he")  # ALTHOUGH BOTH -> "they"

p.compare("opus", "operas")  # ALTHOUGH "opus" -> "opera" -> "operas"
p.compare("taxi", "taxes")  # ALTHOUGH "taxi" -> "taxis" -> "taxes"

Note too that, although the comparison is "number-insensitive" it is not case-insensitive (that is, plural("time","Times") returns false. To obtain both number and case insensitivity, use the lower() method on both strings (that is, plural("time".lower(), "Times".lower()) returns true).

Related Functionality

Shout out to these libraries that provide related functionality:

  • WordSet parses identifiers like variable names into sets of words suitable for re-assembling in another form.
  • word2number converts words to a number.

For Enterprise

Available as part of the Tidelift Subscription.

This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.

Learn more.

Security Contact

To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure.

Comments
  • Add Travis CI and Coveralls

    Add Travis CI and Coveralls

    I've added a configuration file so Travis CI will build each commit and pull request. It runs against each Python version supported by Travis CI: 2.6, 2.7, 3.2, 3.3, 3.4, PyPy and PyPy3, and all of them pass with no changes needed. This will help maintain the codebase by automatically running the tests against all Python versions for each PR -- it's very handy for picking up those Py2/Py3 inconsistencies..

    It also runs the tests with coverage enabled, and sends the coverage reports to Coveralls, so you can see how coverage changes, or if a PR doesn't include tests to cover its new code. Right now, inflect.py has an amazing 98% coverage!

    You get reports like this:

    • https://travis-ci.org/hugovk/inflect.py
    • https://coveralls.io/r/hugovk/inflect.py

    I've added badges to the README to show off how good stats this project has. Both Travis CI and Coveralls are free for open source project, you just need to enable them for the repo. Please can you do so at:

    • https://travis-ci.org/profile
    • https://coveralls.io/repos/new

    Thanks!

    opened by hugovk 18
  • Allow special case dictionaries to match on lowercase final word

    Allow special case dictionaries to match on lowercase final word

    While inflecting some ingredient-related content, I'd noticed that although the word olives is currently handled correctly by singular_noun, black olives is not:

    >>> import inflect
    >>> inflect.__version__
    '4.0.0'
    >>> e = inflect.engine()
    >>> e.singular_noun('olives')
    'olive'
    >>> e.singular_noun('black olives')
    'black olife'
    

    In the inflect code, the handling of single-word olives is performed by a special case which overrides the default logic for items ending ...ves.

    This is one of a number of special cases gated by boolean conditions of the form if lowerword in <map>:, which fail if lowerword doesn't exactly match with a key in the <map>.

    Switching these conditions to use lowerwordlast instead of lowerword results in additional matches for multi-word phrases without negatively impacting any existing test cases.

    It's arguably not 'perfect' since multi-word phrases may have challenging plurality rules (like the situations handled by the compound logic, but hopefully it's a reasonably safe improvement.

    This also resolves https://github.com/jazzband/inflect/issues/30 which falls into a similar special case relating to ...ies tokens.

    opened by jayaddison 14
  • Implement Jazzband guidelines for project inflect.py

    Implement Jazzband guidelines for project inflect.py

    This issue tracks the implementation of the Jazzband guidelines for the project inflect.py

    It was initiated by @jaraco who was automatically assigned in addition to the Jazzband roadies.

    See the TODO list below for the generally required tasks, but feel free to update it in case the project requires it.

    Feel free to ping a Jazzband roadie if you have any question.

    TODOs

    • [x] Fix all links in the docs (and README file etc) from old to new repo
    • [x] Add the Jazzband badge to the README file
    • [x] Add the Jazzband contributing guideline to the CONTRIBUTING.md file
    • [x] Check if continuous testing works (e.g. Travis-CI, CircleCI, AppVeyor, etc)
    • [x] Check if test coverage services work (e.g. Coveralls, Codecov, etc)
    • [x] Add jazzband account to PyPI project as maintainer role (URL: https://pypi.python.org/pypi?:action=role_form&package_name=<PROJECTNAME>)
    • [x] Add jazzband-bot as maintainer to the Read the Docs project (URL: https://readthedocs.org/dashboard/<PROJECTNAME>/users/)
    • [x] Fix project URL in GitHub project description
    • [x] Review project if other services are used and port them to Jazzband

    Project details

    Description Correctly generate plurals, ordinals, indefinite articles; convert numbers to words
    Homepage http://pypi.python.org/pypi/inflect
    Stargazers 0
    Open issues 0
    Forks 0
    Default branch master
    Is a fork True
    Has Wiki True
    Has Pages False
    opened by jazzband-bot 13
  • Transfer project to jaraco

    Transfer project to jaraco

    Given the ~~lack of support for Azure pipelines (#101)~~, the ~~less streamlined process for releases (#80)~~, and the exclusion of sponsorship for these projects (#102), the inclusion of this project in Jazzband is now more of a hindrance than a benefit.

    @jezdez Would you please transfer the project back to /jaraco?

    opened by jaraco 11
  • Plural issues?

    Plural issues?

    Some are wrong, I think:

    >>> p.plural('corpus')  # corpora
    'corpuses'
    >>> p.plural('means')  # means
    'mean'
    >>> p.plural('vita')   # vitae
    'vitas'
    >>> p.plural('backhoe')
    'backhoes'
    >>> p.plural('hoe')  # hoes
    'ho'
    >>> p.plural('ho')   # hos
    'h'
    

    These are technically correct, but unusual (and not a mistake like the octupus-plural):

    >>> p.plural('radius')  # radii, radiuses
    'radiuses'
    >>> p.plural('curriculum')  # curricula, curriculums
    'curriculums'
    >>> p.plural('medium')  # mediums, media
    'mediums'
    >>> p.plural('appendix')  # appendixes, appendices
    'appendixes'
    # also index
    

    Not sure how it should work for uncountables:

    >>> p.plural('cattle')  # cattle        
    'cattles'
    
    help wanted 
    opened by mbr 11
  • query of death

    query of death

    On version 2.1.0 This string: "lens with a lens ()." yields an exception.

    > /lib/python3.6/site-packages/inflect.py in plural(self, text, count)
    >    2239             self._pl_special_adjective(word, count)
    >    2240             or self._pl_special_verb(word, count)
    > -> 2241             or self._plnoun(word, count),
    >    2242         )
    >    2243         return "{}{}{}".format(pre, plural, post)
    > 
    > /lib/python3.6/site-packages/inflect.py in postprocess(self, orig, inflected)
    >    2209                 continue
    >    2210             if word.capitalize() == word:
    > -> 2211                 result[index] = result[index].capitalize()
    >    2212             if word == word.upper():
    >    2213                 result[index] = result[index].upper()
    

    IndexError: list index out of range

    stale invalid 
    opened by uriva 9
  • Cannot install with old setuptools

    Cannot install with old setuptools

    Windows 7 Python 2.7.8

    C:\stufftodelete>pip install -e git+https://github.com/pwdyson/inflect.py#egg=inflect
    Obtaining inflect from git+https://github.com/pwdyson/inflect.py#egg=inflect
      Cloning https://github.com/pwdyson/inflect.py to c:\stufftodelete\src\inflect
      Running setup.py (path:C:\stufftodelete\src\inflect\setup.py) egg_info for package inflect
        usage: -c [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
           or: -c --help [cmd1 cmd2 ...]
           or: -c --help-commands
           or: -c cmd --help
    
        error: invalid command 'egg_info'
        Complete output from command python setup.py egg_info:
        usage: -c [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
    
       or: -c --help [cmd1 cmd2 ...]
    
       or: -c --help-commands
    
       or: -c cmd --help
    
    
    
    error: invalid command 'egg_info'
    
    ----------------------------------------
    Cleaning up...
    Command python setup.py egg_info failed with error code 1 in C:\stufftodelete\src\inflect
    

    But then:

    C:\stufftodelete>pip install --upgrade setuptools
    Downloading/unpacking setuptools from https://pypi.python.org/packages/3.4/s/setuptools/setuptools-7.0-py2.py3-none-any.
    whl#md5=918e7e5ea108507e1ffbbdfccc3496b1
    Installing collected packages: setuptools
      Found existing installation: setuptools 0.6c11
        Uninstalling setuptools:
          Successfully uninstalled setuptools
    Successfully installed setuptools
    Cleaning up...
    

    And so:

    C:\stufftodelete>pip install -e git+https://github.com/pwdyson/inflect.py#egg=inflect
    Obtaining inflect from git+https://github.com/pwdyson/inflect.py#egg=inflect
      Updating c:\stufftodelete\src\inflect clone
      Running setup.py (path:C:\stufftodelete\src\inflect\setup.py) egg_info for package inflect
    
      Installing extra requirements: 'egg'
    Installing collected packages: inflect
      Running setup.py develop for inflect
    
        Creating c:\python27\lib\site-packages\inflect.egg-link (link to .)
        Adding inflect 0.2.5pre1 to easy-install.pth file
    
        Installed c:\stufftodelete\src\inflect
    Successfully installed inflect
    Cleaning up...
    

    Can the dependency to certain setuptools version be included in the setup, or must it already be in place? If not, can it be mentioned in the README installation instructions?

    opened by hugovk 9
  • Failed to import: `Field` default cannot be set in `Annotated` for 'num_Annotated[str, FieldInfo(min_length=1, extra={})]'

    Failed to import: `Field` default cannot be set in `Annotated` for 'num_Annotated[str, FieldInfo(min_length=1, extra={})]'

    Error message:

    Traceback (most recent call last):
      File "/data/cuih7/[REDACTED]", line 7, in <module>
        import inflect
      File "/data/cuih7/miniconda3/envs/nlp20220817/lib/python3.10/site-packages/inflect/__init__.py", line 2046, in <module>
        class engine:
      File "/data/cuih7/miniconda3/envs/nlp20220817/lib/python3.10/site-packages/inflect/__init__.py", line 3781, in engine
        def number_to_words(  # noqa: C901
      File "pydantic/decorator.py", line 36, in pydantic.decorator.validate_arguments.validate
        import sys
      File "pydantic/decorator.py", line 126, in pydantic.decorator.ValidatedFunction.__init__
        try:
      File "pydantic/decorator.py", line 259, in pydantic.decorator.ValidatedFunction.create_model
        return fun
      File "pydantic/main.py", line 972, in pydantic.main.create_model
      File "pydantic/main.py", line 204, in pydantic.main.ModelMetaclass.__new__
      File "pydantic/fields.py", line 488, in pydantic.fields.ModelField.infer
      File "pydantic/fields.py", line 419, in pydantic.fields.ModelField.__init__
      File "pydantic/fields.py", line 534, in pydantic.fields.ModelField.prepare
      File "pydantic/fields.py", line 633, in pydantic.fields.ModelField._type_analysis
      File "pydantic/fields.py", line 776, in pydantic.fields.ModelField._create_sub_type
      File "pydantic/fields.py", line 451, in pydantic.fields.ModelField._get_field_info
    ValueError: `Field` default cannot be set in `Annotated` for 'num_Annotated[str, FieldInfo(min_length=1, extra={})]'
    

    I'm using the library from conda-forge. Downgrading from 6.0.0-pyhd8ed1ab_0 to 5.6.2-pyhd8ed1ab_0 fixes the issue.

    bug 
    opened by cuihaoleo 7
  • dash and lowered_split fix for inflect.py _plnoun()

    dash and lowered_split fix for inflect.py _plnoun()

    In function _plnoun(), the variable lowered_split is split on dashes, but when reusing this variable, code required whitespace split lowerd words, not dash split.

    opened by picobyte 7
  • Import unicode_literals from __futures__ for unicode handling in 2.7

    Import unicode_literals from __futures__ for unicode handling in 2.7

    Unicode strings would cause errors in python 2.7 when using inflect. With this one additional line, no error is thrown.

    Fixes #52

    Includes test file, testing for words containing unicode characters.

    opened by nielstron 7
  • Drop unsupported Python 3.3

    Drop unsupported Python 3.3

    EOL since 2017-09-29: https://en.wikipedia.org/wiki/CPython#Version_history

    See also https://github.com/pwdyson/inflect.py/pull/44 which fixes the flake8 error for Python 3.5 on the CI.

    opened by hugovk 7
  • "Entity" gets pluralized to "Entitys"

    docker run -it python:3.11 bash
    [email protected]:/# pip install inflect==6.0.2
    Collecting inflect==6.0.2
      Downloading inflect-6.0.2-py3-none-any.whl (34 kB)
    Collecting pydantic>=1.9.1
      Downloading pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (14.1 MB)
         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.1/14.1 MB 9.7 MB/s eta 0:00:00
    Collecting typing-extensions>=4.1.0
      Downloading typing_extensions-4.4.0-py3-none-any.whl (26 kB)
    Installing collected packages: typing-extensions, pydantic, inflect
    Successfully installed inflect-6.0.2 pydantic-1.10.2 typing-extensions-4.4.0
    WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
    [email protected]:/# python
    Python 3.11.1 (main, Dec 21 2022, 18:32:57) [GCC 10.2.1 20210110] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import inflect
    >>> word="Entity"
    >>> print(f'The plural of "{word}" is "{inflect.engine().plural(word)}".')
    The plural of "Entity" is "Entitys".
    >>> print(f'The plural of "{word}" is "{inflect.engine().plural_noun(word)}".')
    The plural of "Entity" is "Entitys".
    
    opened by fezzik1620 2
  • 'defnoun' doesn't seem to work when the word is a part of a string passed

    'defnoun' doesn't seem to work when the word is a part of a string passed

    Originally reported by @aMiss-aWry in #161:

    I can fix the specific words with defnoun('jeans', 'jeans'), which corrects the result for an isolated string 'jeans' -> 'jeans'.

    However, if I try to run plural_noun on 'blue jeans' instead of 'jeans' it then breaks again, returning 'blue jeanss'. I understand this is because 'blue jeans' appears to be a different string from 'jeans', but perhaps it should check the rules for the part of the string it is altering?

    feature help wanted 
    opened by jaraco 1
  • Words ending in 's' should never be pluralized by adding another 's'

    Words ending in 's' should never be pluralized by adding another 's'

    stockings -> stockingss jeans -> jeanss sandals -> sandalss

    How do I avoid this? I can fix the specific words with defnoun('jeans', 'jeans'), which corrects the result for an isolated string 'jeans' -> 'jeans'.

    However, if I try to run plural_noun on 'blue jeans' instead of 'jeans' it then breaks again, returning 'blue jeanss'. I understand this is because 'blue jeans' appears to be a different string from 'jeans', but perhaps it should check the rules for the part of the string it is altering?

    I've gotten around this so far by this incredibly hacky 'solution', so any improvement would obviously be immensely appreciated:

                plural = _INFLECT.plural_noun(key, count)
                if plural.endswith('ss'):
                    plural = plural[0:-1]
    
    feature help wanted 
    opened by aMiss-aWry 4
  • singular_noun on word ending in

    singular_noun on word ending in "s" removes s.

    
    import inflect as Inflect
    inflect = Inflect.engine()
    inflect.singular_noun("car")           # get False, as expected
    inflect.singular_noun("mass")          # get "mas", expected False
    
    

    Is this behavior a bug? singular_noun() is supposed to return False when the word is already singular, and I can find no reference to suggest "mass" is the plural of "mas", which is itself the plural of "ma".

    help wanted 
    opened by eykamp 3
Releases(v6.0.2)
Smart discord chatbot integrated with Dialogflow

academic-NLP-chatbot Smart discord chatbot integrated with Dialogflow to interact with students naturally and manage different classes in a school. De

Tom Huynh 5 Oct 24, 2022
Precision Medicine Knowledge Graph (PrimeKG)

PrimeKG Website | bioRxiv Paper | Harvard Dataverse Precision Medicine Knowledge Graph (PrimeKG) presents a holistic view of diseases. PrimeKG integra

Machine Learning for Medicine and Science @ Harvard 103 Dec 10, 2022
AIDynamicTextReader - A simple dynamic text reader based on Artificial intelligence

AI Dynamic Text Reader: This is a simple dynamic text reader based on Artificial

Md. Rakibul Islam 1 Jan 18, 2022
A number of methods in order to perform Natural Language Processing on live data derived from Twitter

A number of methods in order to perform Natural Language Processing on live data derived from Twitter

1 Nov 24, 2021
Super Tickets in Pre-Trained Language Models: From Model Compression to Improving Generalization (ACL 2021)

Structured Super Lottery Tickets in BERT This repo contains our codes for the paper "Super Tickets in Pre-Trained Language Models: From Model Compress

Chen Liang 16 Dec 11, 2022
💬 Open source machine learning framework to automate text- and voice-based conversations: NLU, dialogue management, connect to Slack, Facebook, and more - Create chatbots and voice assistants

Rasa Open Source Rasa is an open source machine learning framework to automate text-and voice-based conversations. With Rasa, you can build contextual

Rasa 15.3k Jan 03, 2023
Research code for "What to Pre-Train on? Efficient Intermediate Task Selection", EMNLP 2021

efficient-task-transfer This repository contains code for the experiments in our paper "What to Pre-Train on? Efficient Intermediate Task Selection".

AdapterHub 26 Dec 24, 2022
A Python wrapper for simple offline real-time dictation (speech-to-text) and speaker-recognition using Vosk.

Simple-Vosk A Python wrapper for simple offline real-time dictation (speech-to-text) and speaker-recognition using Vosk. Check out the official Vosk G

2 Jun 19, 2022
Fast topic modeling platform

The state-of-the-art platform for topic modeling. Full Documentation User Mailing List Download Releases User survey What is BigARTM? BigARTM is a pow

BigARTM 633 Dec 21, 2022
Unsupervised Language Modeling at scale for robust sentiment classification

** DEPRECATED ** This repo has been deprecated. Please visit Megatron-LM for our up to date Large-scale unsupervised pretraining and finetuning code.

NVIDIA Corporation 1k Nov 17, 2022
Mirco Ravanelli 2.3k Dec 27, 2022
Deeply Supervised, Layer-wise Prediction-aware (DSLP) Transformer for Non-autoregressive Neural Machine Translation

Non-Autoregressive Translation with Layer-Wise Prediction and Deep Supervision Training Efficiency We show the training efficiency of our DSLP model b

Chenyang Huang 37 Jan 04, 2023
Lingtrain Aligner — ML powered library for the accurate texts alignment.

Lingtrain Aligner ML powered library for the accurate texts alignment in different languages. Purpose Main purpose of this alignment tool is to build

Sergei Averkiev 76 Dec 14, 2022
Generate product descriptions, blogs, ads and more using GPT architecture with a single request to TextCortex API a.k.a Hemingwai

TextCortex - HemingwAI Generate product descriptions, blogs, ads and more using GPT architecture with a single request to TextCortex API a.k.a Hemingw

TextCortex AI 27 Nov 28, 2022
Signature remover is a NLP based solution which removes email signatures from the rest of the text.

Signature Remover Signature remover is a NLP based solution which removes email signatures from the rest of the text. It helps to enchance data conten

Forges Alterway 8 Jan 06, 2023
translate using your voice

speech-to-text-translator Usage translate using your voice description this project makes translating a word easy, all you have to do is speak and...

1 Oct 18, 2021
A modular Karton Framework service that unpacks common packers like UPX and others using the Qiling Framework.

Unpacker Karton Service A modular Karton Framework service that unpacks common packers like UPX and others using the Qiling Framework. This project is

c3rb3ru5 45 Jan 05, 2023
Py65 65816 - Add support for the 65C816 to py65

Add support for the 65C816 to py65 Py65 (https://github.com/mnaberez/py65) is a

4 Jan 04, 2023
Text to speech for Vietnamese, ez to use, ez to update

Chào mọi người, đây là dự án mở nhằm giúp việc đọc được trở nên dễ dàng hơn. Rất cảm ơn đội ngũ Zalo đã cung cấp hạ tầng để mình có thể tạo ra app này

Trần Cao Minh Bách 32 Jul 29, 2022
A Non-Autoregressive Transformer based TTS, supporting a family of SOTA transformers with supervised and unsupervised duration modelings. This project grows with the research community, aiming to achieve the ultimate TTS.

A Non-Autoregressive Transformer based TTS, supporting a family of SOTA transformers with supervised and unsupervised duration modelings. This project grows with the research community, aiming to ach

Keon Lee 237 Jan 02, 2023