initial implementaton with some tests

This commit is contained in:
Tiendil 2012-01-17 00:31:56 +03:00
parent 4cb61830cf
commit 94483a13d2
7 changed files with 250 additions and 0 deletions

1
pynames/__init__.py Normal file
View file

@ -0,0 +1 @@
# coding: utf-8

View file

@ -0,0 +1,32 @@
{
"names": [ {"native_language": "ru",
"genders": {"m": {"ru": "ru_m_name_1",
"en": "en_m_name_1"}}},
{"native_language": "ru",
"genders": {"f": {"ru": "ru_f_name_2",
"en": "en_f_name_2"}}},
{"native_language": "ru",
"genders": {"f": {"ru": "ru_f_name_3",
"en": "en_f_name_3"}}},
{"native_language": "ru",
"genders": {"m": {"ru": "ru_m_name_4",
"en": "en_m_name_4"},
"f": {"ru": "ru_f_name_4",
"en": "en_f_name_4"}}},
{"native_language": "ru",
"genders": {"m": {"ru": "ru_m_name_5",
"en": "en_m_name_5"},
"f": {"ru": "ru_f_name_5",
"en": "en_f_name_5"}}},
{"native_language": "ru",
"genders": {"m": {"ru": "ru_m_name_5",
"en": "en_m_name_5"},
"f": {"ru": "ru_f_name_5",
"en": "en_f_name_5"}}}
]
}

98
pynames/generators.py Normal file
View file

@ -0,0 +1,98 @@
# coding: utf-8
import json
import random
class PynamesException(Exception):
pass
class GENDER:
MALE = 'm'
FEMALE = 'f'
MF = ['m', 'f']
ALL = ['m', 'f']
class LANGUAGE:
RU = 'ru'
EN = 'en'
NATIVE = 'native'
ALL = ['ru', 'en', 'native']
class BaseGenerator(object):
pass
class Name(object):
__slots__ = ('genders', 'native_language', 'translations')
def __init__(self, data):
self.native_language = data['native_language']
self.genders = frozenset(data['genders'].keys())
self.translations = data['genders']
def get_for(self, gender, language=LANGUAGE.NATIVE):
if language == LANGUAGE.NATIVE:
language = self.native_language
return self.translations[gender][language]
def exists_for(self, genders):
return genders & self.genders
def __unicode__(self):
for gender in GENDER.ALL:
if gender in self.genders:
return self.translations[gender][self.native_language]
error_msg = 'Name: can not get default value for name with data: %r' % self.genders
raise PynamesException(error_msg)
def __str__(self): return self.__unicode__()
class FromListGenerator(BaseGenerator):
SOURCE = None
def __init__(self):
self.names_list = []
self.choices = {}
if self.SOURCE is None:
error_msg = 'FromListGenerator: you must make subclass of FromListGenerator and defined attribute SOURCE in it.'
raise NotImplementedError(error_msg)
with open(self.SOURCE) as f:
names_data = json.load(f)
for name_data in names_data['names']:
self.names_list.append(Name(name_data))
if not self.names_list:
raise PynamesException('FromListGenerator: no names loaded from "%s"' % self.SOURCE)
def _get_cache_key(self, genders):
return '_'.join(genders)
def _get_slice(self, genders):
key = self._get_cache_key(genders)
genders = frozenset(genders)
if key not in self.choices:
self.choices[key] = [name_record
for name_record in self.names_list
if name_record.exists_for(genders)]
return self.choices[key]
def get_names_number(self, genders=GENDER.ALL):
return len(self._get_slice(genders))
def get_name(self, genders=GENDER.ALL):
return random.choice(self._get_slice(genders))
def get_name_simple(self, gender=GENDER.MALE, language=LANGUAGE.NATIVE):
name = self.get_name(genders=[gender])
return name.get_for(gender, language)

View file

@ -0,0 +1,5 @@
# coding: utf-8
import os

87
pynames/tests.py Normal file
View file

@ -0,0 +1,87 @@
# coding: utf-8
import os
import unittest
from .generators import Name, GENDER, LANGUAGE, FromListGenerator, PynamesException
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixtures')
class TestName(unittest.TestCase):
def test_base(self):
name = Name({'native_language': 'ru',
'genders': {'m': {'ru': 'ru_name'}}})
self.assertEqual(unicode(name), 'ru_name')
self.assertEqual(name.get_for(GENDER.MALE, LANGUAGE.RU), 'ru_name')
self.assertEqual(name.get_for(GENDER.MALE), 'ru_name')
def test_genders(self):
name = Name({'native_language': 'ru',
'genders': {'m': {'ru': 'ru_m_name'},
'f': {'ru': 'ru_f_name'}}})
self.assertEqual(unicode(name), 'ru_m_name')
self.assertEqual(name.get_for(GENDER.MALE, LANGUAGE.RU), 'ru_m_name')
self.assertEqual(name.get_for(GENDER.FEMALE, LANGUAGE.RU), 'ru_f_name')
def test_languages(self):
name = Name({'native_language': 'ru',
'genders': {'m': {'ru': 'ru_m_name',
'en': 'en_m_name'},
'f': {'ru': 'ru_f_name',
'en': 'en_f_name'}}})
self.assertEqual(unicode(name), 'ru_m_name')
self.assertEqual(name.get_for(GENDER.MALE, LANGUAGE.RU), 'ru_m_name')
self.assertEqual(name.get_for(GENDER.FEMALE, LANGUAGE.RU), 'ru_f_name')
self.assertEqual(name.get_for(GENDER.MALE, LANGUAGE.EN), 'en_m_name')
self.assertEqual(name.get_for(GENDER.FEMALE, LANGUAGE.EN), 'en_f_name')
self.assertEqual(name.get_for(GENDER.MALE), 'ru_m_name')
self.assertEqual(name.get_for(GENDER.FEMALE), 'ru_f_name')
class TestFromListGenerator(unittest.TestCase):
class TestGenerator(FromListGenerator):
SOURCE = os.path.join(FIXTURES_DIR, 'test_from_list_generator.json')
NAMES_RU_MALE = ['ru_m_name_1', 'ru_m_name_4', 'ru_m_name_5', 'ru_m_name_6']
NAMES_EN_MALE = ['en_m_name_1', 'en_m_name_4', 'en_m_name_5', 'en_m_name_6']
NAMES_RU_FEMALE = ['ru_f_name_2', 'ru_f_name_3', 'ru_f_name_4', 'ru_f_name_5', 'ru_f_name_6']
NAMES_EN_FEMALE = ['en_f_name_2', 'en_f_name_3', 'en_f_name_4', 'en_f_name_5', 'en_f_name_6']
def test_not_derived(self):
self.assertRaises(NotImplementedError, FromListGenerator)
def test_wrong_path(self):
class WrongGenerator(FromListGenerator):
SOURCE = ''
self.assertRaises(IOError, WrongGenerator)
def test_base(self):
generator = self.TestGenerator()
self.assertEqual(generator.get_names_number(), 6)
self.assertTrue(generator.get_name_simple() in self.NAMES_RU_MALE)
def test_male_female_selection(self):
generator = self.TestGenerator()
self.assertEqual(generator.get_names_number(genders=[GENDER.MALE]), 4)
self.assertEqual(generator.get_names_number(genders=[GENDER.FEMALE]), 5)
def test_get_name(self):
generator = self.TestGenerator()
for i in xrange(100):
name = generator.get_name_simple(gender=GENDER.MALE, language=LANGUAGE.RU)
self.assertTrue(name in self.NAMES_RU_MALE)
for i in xrange(100):
name = generator.get_name_simple(gender=GENDER.FEMALE, language=LANGUAGE.RU)
self.assertTrue(name in self.NAMES_RU_FEMALE)
for i in xrange(100):
name = generator.get_name_simple(gender=GENDER.MALE, language=LANGUAGE.EN)
self.assertTrue(name in self.NAMES_EN_MALE)
for i in xrange(100):
name = generator.get_name_simple(gender=GENDER.FEMALE, language=LANGUAGE.EN)
self.assertTrue(name in self.NAMES_EN_FEMALE)