Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions app/inflector/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .src.inflector import Inflector, English
from .src.rules.spanish import Spanish
File renamed without changes.
14 changes: 3 additions & 11 deletions inflector.py → app/inflector/src/inflector.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
#!/usr/bin/env python

# Copyright (c) 2006 Bermi Ferrer Martinez
#
# bermi a-t bermilabs - com
# See the end of this file for the free software, open source license
# (BSD-style).

from rules.english import English
from .rules.english import English


class Inflector:
Expand All @@ -19,7 +11,7 @@ class Inflector:

def __init__(self, Inflector=English):
assert callable(Inflector), "Inflector should be a callable obj"
self.Inflector = apply(Inflector)
self.Inflector = Inflector()

def pluralize(self, word):
'''Pluralizes nouns.'''
Expand Down Expand Up @@ -124,4 +116,4 @@ def foreignKey(self, class_name, separate_class_name_and_id_with_underscore=1):
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THIS SOFTWARE.
# THIS SOFTWARE.
Empty file.
9 changes: 1 addition & 8 deletions rules/base.py → app/inflector/src/rules/base.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
#!/usr/bin/env python

# Copyright (c) 2006 Bermi Ferrer Martinez
# bermi a-t bermilabs - com
# See the end of this file for the free software, open source license
# (BSD-style).

import re


Expand Down Expand Up @@ -147,4 +140,4 @@ def foreignKey(self, class_name, separate_class_name_and_id_with_underscore=1):
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THIS SOFTWARE.
# THIS SOFTWARE.
12 changes: 2 additions & 10 deletions rules/english.py → app/inflector/src/rules/english.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
#!/usr/bin/env python

# Copyright (c) 2006 Bermi Ferrer Martinez
# bermi a-t bermilabs - com
#
# See the end of this file for the free software, open source license
# (BSD-style).

import re
from base import Base
from .base import Base


class English (Base):
Expand Down Expand Up @@ -158,4 +150,4 @@ def singularize(self, word):
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THIS SOFTWARE.
# THIS SOFTWARE.
55 changes: 20 additions & 35 deletions rules/spanish.py → app/inflector/src/rules/spanish.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# coding=utf-8
# Copyright (c) 2006 Bermi Ferrer Martinez
# Copyright (c) 2006 Carles Sadurní Anguita
#
# bermi a-t bermilabs - com
#
# See the end of this file for the free software, open source license
# (BSD-style).

import re
from base import Base
import utils

from .base import Base
from .. import utils

class Spanish (Base):
'''
Expand Down Expand Up @@ -77,7 +65,7 @@ def pluralize(self, word):
if lower_cased_word[-1 * len(uncountable_word):] == uncountable_word:
return utils.deunicodify(word, origType)

for irregular_singular, irregular_plural in self.irregular_words.iteritems():
for irregular_singular, irregular_plural in self.irregular_words.items():
match = re.search(u'(?i)(^' + irregular_singular + u')$', word, re.IGNORECASE)
if match:
result = re.sub(u'(?i)' + irregular_singular + u'$', match.expand(u'\\1')[0] + irregular_plural[1:], word)
Expand All @@ -90,7 +78,7 @@ def pluralize(self, word):
replacement = rule[1]
if re.match(u'\|', replacement):
for k in range(1, len(groups)):
replacement = replacement.replace(u'|' + unicode(
replacement = replacement.replace(u'|' + str(
k), self.string_replace(groups[k - 1], u'ÁÉÍÓÚáéíóú', u'AEIOUaeiou'))

result = re.sub(rule[0], replacement, word)
Expand All @@ -117,19 +105,19 @@ def singularize(self, word):
word, origType = utils.unicodify(word) # all internal calculations are done in Unicode

rules = [
[ur'(?i)^([bcdfghjklmnñpqrstvwxyz]*)([aeiou])([ns])es$', u'\\1\\2\\3'],
[ur'(?i)([aeiou])([ns])es$', u'~1\\2'],
[ur'(?i)shes$', u'sh'], # flashes->flash
[ur'(?i)oides$', u'oide'], # androides->androide
[ur'(?i)(sis|tis|xis)$', u'\\1'], # crisis, apendicitis, praxis
[ur'(?i)(é)s$', u'\\1'], # bebés->bebé
[ur'(?i)(ces)$', u'z'], # luces->luz
[ur'(?i)([^e])s$', u'\\1'], # casas->casa
[ur'(?i)([bcdfghjklmnñprstvwxyz]{2,}e)s$', u'\\1'], # cofres->cofre
[ur'(?i)([ghñptv]e)s$', u'\\1'], # llaves->llave, radiocasetes->radiocasete
[ur'(?i)jes$', u'je'], # ejes->eje
[ur'(?i)ques$', u'que'], # tanques->tanque
[ur'(?i)es$', u''] # ELSE remove _es_ monitores->monitor
[r'(?i)^([bcdfghjklmnñpqrstvwxyz]*)([aeiou])([ns])es$', u'\\1\\2\\3'],
[r'(?i)([aeiou])([ns])es$', r'~1\2'],
[r'(?i)shes$', u'sh'], # flashes->flash
[r'(?i)oides$', u'oide'], # androides->androide
[r'(?i)(sis|tis|xis)$', u'\\1'], # crisis, apendicitis, praxis
[r'(?i)(é)s$', u'\\1'], # bebés->bebé
[r'(?i)(ces)$', u'z'], # luces->luz
[r'(?i)([^e])s$', u'\\1'], # casas->casa
[r'(?i)([bcdfghjklmnñprstvwxyz]{2,}e)s$', u'\\1'], # cofres->cofre
[r'(?i)([ghñptv]e)s$', u'\\1'], # llaves->llave, radiocasetes->radiocasete
[r'(?i)jes$', u'je'], # ejes->eje
[r'(?i)ques$', u'que'], # tanques->tanque
[r'(?i)es$', u''] # ELSE remove _es_ monitores->monitor
]

lower_cased_word = word.lower()
Expand All @@ -138,7 +126,7 @@ def singularize(self, word):
if lower_cased_word[-1 * len(uncountable_word):] == uncountable_word:
return utils.deunicodify(word, origType)

for irregular_singular, irregular_plural in self.irregular_words.iteritems():
for irregular_singular, irregular_plural in self.irregular_words.items():
match = re.search(u'(^' + irregular_plural + u')$', word, re.IGNORECASE)
if match:
result = re.sub(u'(?i)' + irregular_plural + u'$', match.expand(u'\\1')[0] + irregular_singular[1:], word)
Expand All @@ -151,7 +139,7 @@ def singularize(self, word):
replacement = rule[1]
if re.match(u'~', replacement):
for k in range(1, len(groups)):
replacement = replacement.replace(u'~' + unicode(
replacement = replacement.replace(u'~' + str(
k), self.string_replace(groups[k - 1], u'AEIOUaeiou', u'ÁÉÍÓÚáéíóú'))

result = re.sub(rule[0], replacement, word)
Expand All @@ -166,8 +154,6 @@ def singularize(self, word):
return utils.deunicodify(result, origType)

return utils.deunicodify(word, origType)


# Copyright (c) 2006 Bermi Ferrer Martinez
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software to deal in this software without restriction, including
Expand All @@ -182,5 +168,4 @@ def singularize(self, word):
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THIS SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THIS SOFTWARE.

# THIS SOFTWARE.
25 changes: 17 additions & 8 deletions utils.py → app/inflector/src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,28 @@ def unicodify(st):
@return a tuple with the unicodified string and the original string encoding.
'''

# Convert 'st' to Unicode
if isinstance(st, unicode):
origType = 'unicode'
elif isinstance(st, str):
import unicodedata

def unicodify(st):
# Verificar si la cadena es de tipo str (Unicode en Python 3)
if isinstance(st, str):
origType = 'str'
elif isinstance(st, bytes):
try:
st = st.decode('utf8')
origType = 'utf8'
# Decodificar la cadena de bytes a Unicode utilizando utf-8
st = st.decode('utf-8')
origType = 'utf-8'
except UnicodeDecodeError:
try:
# Si falla la decodificación utf-8, intentar decodificarla utilizando latin-1
st = st.decode('latin1')
origType = 'latin1'
except:
raise UnicodeEncodeError('Given string %s must be either Unicode, UTF-8 or Latin-1' % repr(st))
else:
origType = 'noConversion'

# Normalize the Unicode (to combine any combining characters, e.g. accents, into the previous letter)
# Normalizar el Unicode (para combinar cualquier caracter que se combine, por ejemplo, acentos, en la letra anterior)
if origType != 'noConversion':
st = unicodedata.normalize('NFKC', st)

Expand All @@ -40,5 +45,9 @@ def deunicodify(unicodifiedStr, origType):

if origType == 'unicode':
return unicodifiedStr

# Si origType es 'str', simplemente devuelve la cadena sin codificarla nuevamente
if origType == 'str':
return unicodifiedStr

return unicodifiedStr.encode(origType)
return unicodifiedStr.encode(origType)
Empty file added app/inflector/tests/__init__.py
Empty file.
13 changes: 3 additions & 10 deletions tests.py → app/inflector/tests/tests.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (c) 2006 Bermi Ferrer Martinez
#
# bermi a-t bermilabs - com
#
import unittest
from inflector import Inflector, English
from ..src.inflector import Inflector, English


class EnglishInflectorTestCase(unittest.TestCase):
Expand Down Expand Up @@ -113,14 +106,14 @@ def tearDown(self):
self.inflector = None

def test_pluralize(self):
for singular, plural in self.singular_to_plural.iteritems():
for singular, plural in self.singular_to_plural.items():
inflector_pluralize = self.inflector.pluralize(singular)
assert inflector_pluralize == plural, \
'English Inflector pluralize(%s) should produce "%s" and NOT "%s"' % (
singular, plural, inflector_pluralize)

def test_singularize(self):
for singular, plural in self.singular_to_plural.iteritems():
for singular, plural in self.singular_to_plural.items():
inflector_singularize = self.inflector.singularize(plural)
assert inflector_singularize == singular, \
'English Inflector singularize(%s) should produce "%s" and NOT "%s"' % (
Expand Down
15 changes: 4 additions & 11 deletions tests_es.py → app/inflector/tests/tests_es.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (c) 2006 Bermi Ferrer Martinez
#
# bermi a-t bermilabs - com
#
import unittest
from inflector import Inflector
from rules.spanish import Spanish
from ..src.inflector import Inflector
from ..src.rules.spanish import Spanish


class SpanishInflectorTestCase(unittest.TestCase):
Expand Down Expand Up @@ -68,14 +61,14 @@ def tearDown(self):
self.inflector = None

def test_pluralize(self):
for singular, plural in self.singular_to_plural.iteritems():
for singular, plural in self.singular_to_plural.items():
inflector_pluralize = self.inflector.pluralize(singular)
assert inflector_pluralize == plural, \
'Spanish Inflector pluralize(%s) should produce "%s" and NOT "%s"' % (
singular, plural, inflector_pluralize)

def test_singularize(self):
for singular, plural in self.singular_to_plural.iteritems():
for singular, plural in self.singular_to_plural.items():
inflector_singularize = self.inflector.singularize(plural)
assert inflector_singularize == singular, \
'Spanish Inflector singularize(%s) should produce "%s" and NOT "%s"' % (
Expand Down
12 changes: 12 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from setuptools import find_packages, setup

setup(
name="python-inflector",
version="0.0.12",
description="The Inflector is used for getting the plural and singular form of nouns",
package_dir={"": "app"},
packages=find_packages(where="app"),
author="Kemok",
license="MIT",
python_requires=">=3.10",
)