Permalink
Browse files

Merge branch 'development'

  • Loading branch information...
2 parents c7aa8d9 + f3e3d83 commit 6fad6f2d7a3e69bdbbee4bf3526dfd337febfcf8 @vandersonmota committed Sep 3, 2016
View
84 .travis.yml
@@ -1,50 +1,52 @@
sudo: true
language: python
python:
+ - "2.6"
- "2.7"
+ - "3.2"
+ - "3.4"
+ - "3.5"
env:
- - DJANGO_VERSION=1.4.10
- - DJANGO_VERSION=1.5.5
- - DJANGO_VERSION=1.6
- - DJANGO_VERSION=1.7
- - DJANGO_VERSION=1.8.5
- - DJANGO_VERSION=1.9
+ - DJANGO=django14
+ - DJANGO=django15
+ - DJANGO=django16
+ - DJANGO=django17
+ - DJANGO=django18
+ - DJANGO=django19
matrix:
- include:
- - python: 2.6
- env: DJANGO_VERSION=1.4.10
- - python: 2.6
- env: DJANGO_VERSION=1.5.5
- - python: 2.6
- env: DJANGO_VERSION=1.6
- - python: 3.2
- env: DJANGO_VERSION=1.5.5
- - python: 3.2
- env: DJANGO_VERSION=1.6
- - python: 3.2
- env: DJANGO_VERSION=1.7
- - python: 3.2
- env: DJANGO_VERSION=1.8.5
- - python: 3.4
- env: DJANGO_VERSION=1.5.5
- - python: 3.4
- env: DJANGO_VERSION=1.6
- - python: 3.4
- env: DJANGO_VERSION=1.7
- - python: 3.4
- env: DJANGO_VERSION=1.8.5
- - python: 3.4
- env: DJANGO_VERSION=1.9
- - python: 3.5
- env: DJANGO_VERSION=1.8.5
- - python: 3.5
- env: DJANGO_VERSION=1.9
+ exclude:
+ - python: "2.6"
+ env: DJANGO=django17
+ - python: "2.6"
+ env: DJANGO=django18
+ - python: "2.6"
+ env: DJANGO=django19
+ - python: "3.2"
+ env: DJANGO=django14
+ - python: "3.2"
+ env: DJANGO=django19
+ - python: "3.4"
+ env: DJANGO=django14
+ - python: "3.5"
+ env: DJANGO=django14
+ - python: "3.5"
+ env: DJANGO=django15
+ - python: "3.5"
+ env: DJANGO=django16
+ - python: "3.5"
+ env: DJANGO=django17
before_install:
- sudo apt-get update && sudo apt-get build-dep python-imaging
install:
- # Install whatever version of Django that's listed above
- # Travis is currently working on
- - pip install -q Django==$DJANGO_VERSION
- - pip install -q Pillow
- - pip install -r requirements.txt
-script: python runtests.py
+ - pip install tox
+addons:
+ postgresql: "9.4"
+services:
+ - postgresql
+before_script:
+ - psql -U postgres -c "create extension postgis"
+ - psql -c 'create database model_mommy;' -U postgres
+ - psql -c 'create database model_mommy_test;' -U postgres
+script:
+ - TOX_TEST_PASSENV="TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH" tox -e py${TRAVIS_PYTHON_VERSION//[.]/}-$DJANGO-{postgresql}
+ - TOX_TEST_PASSENV="TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH" tox -e py${TRAVIS_PYTHON_VERSION//[.]/}-$DJANGO-{sqlite}
View
13 Changelog.txt
@@ -0,0 +1,13 @@
+1.3.0
+-----
+- Django 1.10 support
+- Added UUIDField, JSONField and ArrayField support
+- Python 3.2 support dropped
+- Fix nested m2m recipes
+- Removes deprecated API
+- Fix related() with nullable foreignkeys on django 1.9
+- Custom Mommy class implementation support
+
+1.2.6
+-----
+First changelog
View
2 MANIFEST.in
@@ -2,3 +2,5 @@ include model_mommy/mock_file.txt
include model_mommy/mock-img.jpeg
include README.rst
include requirements.txt
+include tox.ini
+recursive-include tests *.py
View
23 docs/source/how_mommy_behaves.rst
@@ -79,3 +79,26 @@ Examples:
MOMMY_CUSTOM_FIELDS_GEN = {
'test.generic.fields.CustomField': 'code.path.gen_func',
}
+
+Customizing Mommy
+-------------
+
+In some rare cases, you might need to customize the way Mommy behaves.
+This can be achieved by creating a new class and specifying it in your settings files. It is likely that you will want to extend Mommy, however the minimum requirement is that the custom class have `make` and `prepare` functions.
+In order for the custom class to be used, make sure to use the `model_mommy.mommy.make` and `model_mommy.mommy.prepare` functions, and not `model_mommy.mommy.Mommy` directly.
+
+Examples:
+
+.. code-block:: python
+
+ # in the module code.path:
+ class CustomMommy(mommy.Mommy)
+ def get_fields(self):
+ return [
+ field
+ for field in super(CustomMommy, self).get_fields()
+ if not field isinstance CustomField
+ ]
+
+ # in your settings.py file:
+ MOMMY_CUSTOM_CLASS = 'code.path.CustomMommy'
View
2 model_mommy/__init__.py
@@ -1,5 +1,5 @@
#coding:utf-8
-__version__ = '1.2.6'
+__version__ = '1.3.0'
__title__ = 'model_mommy'
__author__ = 'Vanderson Mota'
__license__ = 'Apache 2.0'
View
8 model_mommy/exceptions.py
@@ -19,3 +19,11 @@ class AmbiguousModelName(Exception):
class InvalidQuantityException(Exception):
pass
+
+
+class CustomMommyNotFound(Exception):
+ pass
+
+
+class InvalidCustomMommy(Exception):
+ pass
View
23 model_mommy/generators.py
@@ -11,6 +11,7 @@
"""
import string
+import warnings
from decimal import Decimal
from os.path import abspath, join, dirname
from random import randint, choice, random
@@ -84,8 +85,11 @@ def gen_float():
def gen_decimal(max_digits, decimal_places):
num_as_str = lambda x: ''.join([str(randint(0, 9)) for i in range(x)])
- return Decimal("%s.%s" % (num_as_str(max_digits - decimal_places - 1),
+ if decimal_places:
+ return Decimal("%s.%s" % (num_as_str(max_digits - decimal_places - 1),
num_as_str(decimal_places)))
+ return Decimal(num_as_str(max_digits))
+
gen_decimal.required = ['max_digits', 'decimal_places']
@@ -163,5 +167,20 @@ def gen_content_type():
except ImportError:
# Deprecated
from django.db.models import get_models
+ try:
+ return ContentType.objects.get_for_model(choice(get_models()))
+ except AssertionError:
+ warnings.warn('Database access disabled, returning ContentType raw instance')
+ return ContentType()
+
+def gen_uuid():
+ import uuid
+ return uuid.uuid4()
+
+
+def gen_array():
+ return []
+
- return ContentType.objects.get_for_model(choice(get_models()))
+def gen_json():
+ return {}
View
86 model_mommy/mommy.py
@@ -46,6 +46,21 @@
except ImportError:
DurationField = None
+try:
+ from django.db.models import UUIDField
+except ImportError:
+ UUIDField = None
+
+try:
+ from django.contrib.postgres.fields import ArrayField
+except ImportError:
+ ArrayField = None
+
+try:
+ from django.contrib.postgres.fields import JSONField
+except ImportError:
+ JSONField = None
+
from django.core.exceptions import ValidationError
from django.core.validators import validate_ipv4_address
try:
@@ -56,7 +71,8 @@ def validate_ipv6_address(v):
validate_ipv46_address = validate_ipv6_address
from . import generators
-from .exceptions import ModelNotFound, AmbiguousModelName, InvalidQuantityException, RecipeIteratorEmpty
+from .exceptions import (ModelNotFound, AmbiguousModelName, InvalidQuantityException, RecipeIteratorEmpty,
+ CustomMommyNotFound, InvalidCustomMommy)
from .utils import import_from_str, import_if_str
from six import string_types, advance_iterator, PY3
@@ -88,7 +104,7 @@ def make(model, _quantity=None, make_m2m=False, **attrs):
It fill the fields with random values or you can specify
which fields you want to define its values by yourself.
"""
- mommy = Mommy(model, make_m2m=make_m2m)
+ mommy = Mommy.create(model, make_m2m=make_m2m)
if _valid_quantity(_quantity):
raise InvalidQuantityException
@@ -105,7 +121,7 @@ def prepare(model, _quantity=None, **attrs):
It fill the fields with random values or you can specify
which fields you want to define its values by yourself.
"""
- mommy = Mommy(model)
+ mommy = Mommy.create(model)
if _valid_quantity(_quantity):
raise InvalidQuantityException
@@ -171,7 +187,12 @@ def __m2m_generator(model, **attrs):
default_mapping[BinaryField] = generators.gen_byte_string
if DurationField:
default_mapping[DurationField] = generators.gen_interval
-
+if UUIDField:
+ default_mapping[UUIDField] = generators.gen_uuid
+if ArrayField:
+ default_mapping[ArrayField] = generators.gen_array
+if JSONField:
+ default_mapping[JSONField] = generators.gen_json
class ModelFinder(object):
'''
@@ -255,6 +276,25 @@ def is_iterator(value):
else:
return hasattr(value, 'next')
+def _custom_mommy_class():
+ """
+ Returns custom mommy class specified by MOMMY_CUSTOM_CLASS in the django
+ settings, or None if no custom class is defined
+ """
+ custom_class_string = getattr(settings, 'MOMMY_CUSTOM_CLASS', None)
+ if custom_class_string is None:
+ return None
+
+ try:
+ mommy_class = import_from_str(custom_class_string)
+
+ for required_function_name in ['make', 'prepare']:
+ if not hasattr(mommy_class, required_function_name):
+ raise InvalidCustomMommy('Custom Mommy classes must have a "%s" function' % required_function_name)
+
+ return mommy_class
+ except ImportError:
+ raise CustomMommyNotFound("Could not find custom mommy class '%s'" % custom_class_string)
class Mommy(object):
attr_mapping = {}
@@ -264,6 +304,14 @@ class Mommy(object):
# rebuilding the model cache for every make_* or prepare_* call.
finder = ModelFinder()
+ @classmethod
+ def create(cls, model, make_m2m=False):
+ """
+ Factory which creates the mommy class defined by the MOMMY_CUSTOM_CLASS setting
+ """
+ mommy_class = _custom_mommy_class() or cls
+ return mommy_class(model, make_m2m)
+
def __init__(self, model, make_m2m=False):
self.make_m2m = make_m2m
self.m2m_dict = {}
@@ -497,33 +545,3 @@ def filter_rel_attrs(field_name, **rel_attrs):
clean_dict[k] = v
return clean_dict
-
-
-### DEPRECATED METHODS (should be removed in the future)
-def make_many(model, quantity=None, **attrs):
- msg = "make_many is deprecated. You should use make with _quantity parameter."
- warnings.warn(msg, DeprecationWarning)
- quantity = quantity or MAX_MANY_QUANTITY
- mommy = Mommy(model)
- return [mommy.make(**attrs) for i in range(quantity)]
-
-
-def make_one(model, make_m2m=False, **attrs):
- msg = "make_one is deprecated. You should use the method make instead."
- warnings.warn(msg, DeprecationWarning)
- mommy = Mommy(model, make_m2m=make_m2m)
- return mommy.make(**attrs)
-
-
-def prepare_one(model, **attrs):
- msg = "prepare_one is deprecated. You should use the method prepare instead."
- warnings.warn(msg, DeprecationWarning)
- mommy = Mommy(model)
- return mommy.prepare(**attrs)
-
-
-def make_many_from_recipe(mommy_recipe_name, quantity=None, **new_attrs):
- msg = "make_many_from_recipe is deprecated. You should use the method make_recipe with the _quantity parameter instead."
- warnings.warn(msg, DeprecationWarning)
- quantity = quantity or MAX_MANY_QUANTITY
- return [make_recipe(mommy_recipe_name, **new_attrs) for x in range(quantity)]
View
9 model_mommy/recipe.py
@@ -55,7 +55,7 @@ def _mapping(self, new_attrs):
recipe_attrs = mommy.filter_rel_attrs(k, **a)
mapping[k] = v.recipe.make(**recipe_attrs)
elif isinstance(v, related):
- mapping[k] = v.prepare()
+ mapping[k] = v.make()
mapping.update(new_attrs)
mapping.update(rel_fields_attrs)
return mapping
@@ -151,10 +151,9 @@ def __init__(self, *args):
else:
raise TypeError('Not a recipe')
- def prepare(self):
+ def make(self):
"""
- Django related manager saves related set.
- No need to persist at first
+ Persists objects to m2m relation
"""
- return [m.prepare() for m in self.related]
+ return [m.make() for m in self.related]
View
17 runtests.py
@@ -10,6 +10,7 @@
def parse_args():
parser = OptionParser()
parser.add_option('--use-tz', dest='USE_TZ', action='store_true')
+ parser.add_option('--postgresql', dest='USE_POSTGRESQL', action='store_true')
return parser.parse_args()
@@ -27,15 +28,25 @@ def configure_settings(options):
}
},
INSTALLED_APPS = (
- 'django.contrib.contenttypes',
'test.generic',
+ 'django.contrib.contenttypes',
+ 'test_without_migrations',
'test.ambiguous',
'test.ambiguous2',
),
SITE_ID=1,
TEST_RUNNER='django.test.simple.DjangoTestSuiteRunner',
TEST_ROOT=join(dirname(__file__), 'test', 'generic', 'tests'),
)
+ if getattr(options, 'USE_POSTGRESQL', False):
+ params['DATABASES'] = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.postgresql_psycopg2',
+ 'NAME': 'model_mommy',
+ 'TEST_NAME': 'test_model_mommy',
+ 'USER': 'postgres',
+ }
+ }
if django.VERSION >= (1, 7):
params.update(
@@ -60,13 +71,15 @@ def get_runner(settings):
Asks Django for the TestRunner defined in settings or the default one.
'''
from django.test.utils import get_runner
- TestRunner = get_runner(settings)
if django.VERSION >= (1, 7):
# I suspect this will not be necessary in next release after 1.7.0a1:
# See https://code.djangoproject.com/ticket/21831
setattr(settings, 'INSTALLED_APPS',
['django.contrib.auth']
+ list(getattr(settings, 'INSTALLED_APPS')))
+ from test_without_migrations.management.commands.test import DisableMigrations
+ setattr(settings, 'MIGRATION_MODULES', DisableMigrations())
+ TestRunner = get_runner(settings)
return TestRunner(verbosity=1, interactive=True, failfast=False)
View
20 test/generic/models.py
@@ -72,11 +72,29 @@ class Person(models.Model):
blog = models.URLField()
occupation = models.CharField(max_length=10, choices=OCCUPATION_CHOCIES)
try:
+ uuid = models.UUIDField(primary_key=False)
+ except AttributeError:
+ # New at Django 1.9
+ pass
+ try:
name_hash = models.BinaryField(max_length=16)
except AttributeError:
# We can't test the binary field if it is not supported
# (django < 1,6)
pass
+ try:
+ from django.contrib.postgres.fields import ArrayField
+ acquaintances = ArrayField(models.IntegerField())
+ except ImportError:
+ # New at Django 1.9
+ pass
+
+ try:
+ from django.contrib.postgres.fields import JSONField
+ data = JSONField()
+ except ImportError:
+ # New at Django 1.9
+ pass
#backward compatibilty with Django 1.1
try:
@@ -138,7 +156,7 @@ class DummyNumbersModel(models.Model):
class DummyDecimalModel(models.Model):
- decimal_field = models.DecimalField(max_digits=5, decimal_places=2)
+ decimal_field = models.DecimalField(max_digits=1, decimal_places=0)
class UnsupportedField(models.Field):
View
4 test/generic/mommy_recipes.py
@@ -59,6 +59,10 @@
friends_with=related(dog, dog),
)
+dog_with_more_friends = dog.extend(
+ friends_with=related(dog_with_friends),
+)
+
extended_dog = dog.extend(
breed = 'Super basset',
)
View
47 test/generic/tests/test_extending_mommy.py
@@ -3,9 +3,10 @@
from model_mommy import mommy
from model_mommy.generators import gen_from_list
+from model_mommy.exceptions import CustomMommyNotFound, InvalidCustomMommy
from test.generic.models import Person
-__all__ = ['SimpleExtendMommy', 'LessSimpleExtendMommy']
+__all__ = ['SimpleExtendMommy', 'LessSimpleExtendMommy', 'CustomizeMommyClassViaSettings']
class SimpleExtendMommy(TestCase):
@@ -79,3 +80,47 @@ class MyMommy(mommy.Mommy):
# for boolean
gen_age.required = [True]
self.assertRaises(ValueError, mom.make)
+
+class ClassWithoutMake(object):
+ def prepare(self):
+ pass
+
+class ClassWithoutPrepare(object):
+ def make(self):
+ pass
+
+class MommySubclass(mommy.Mommy):
+ pass
+
+class MommyDuck(object):
+ def __init__(*args, **kwargs):
+ pass
+
+ def make(self):
+ pass
+
+ def prepare(self):
+ pass
+
+class CustomizeMommyClassViaSettings(TestCase):
+ def class_to_import_string(self, class_to_convert):
+ return '%s.%s' % (self.__module__, class_to_convert.__name__)
+
+ def test_create_vanilla_mommy_used_by_default(self):
+ mommy_instance = mommy.Mommy.create(Person)
+ self.assertIs(mommy_instance.__class__, mommy.Mommy)
+
+ def test_create_fail_on_custom_mommy_load_error(self):
+ with self.settings(MOMMY_CUSTOM_CLASS='invalid_module.invalid_class'):
+ self.assertRaises(CustomMommyNotFound, mommy.Mommy.create, Person)
+
+ def test_create_fail_on_missing_required_functions(self):
+ for invalid_mommy_class in [ClassWithoutMake, ClassWithoutPrepare]:
+ with self.settings(MOMMY_CUSTOM_CLASS=self.class_to_import_string(invalid_mommy_class)):
+ self.assertRaises(InvalidCustomMommy, mommy.Mommy.create, Person)
+
+ def test_create_succeeds_with_valid_custom_mommy(self):
+ for valid_mommy_class in [MommySubclass, MommyDuck]:
+ with self.settings(MOMMY_CUSTOM_CLASS=self.class_to_import_string(valid_mommy_class)):
+ custom_mommy_instance = mommy.Mommy.create(Person)
+ self.assertIs(custom_mommy_instance.__class__, valid_mommy_class)
View
40 test/generic/tests/test_filling_fields.py
@@ -53,6 +53,21 @@
except ImportError:
DurationField = None
+try:
+ from django.db.models.fields import UUIDField
+except ImportError:
+ UUIDField = None
+
+try:
+ from django.contrib.postgres.fields import ArrayField
+except ImportError:
+ ArrayField = None
+
+try:
+ from django.contrib.postgres.fields import JSONField
+except ImportError:
+ JSONField = None
+
from django.core.validators import validate_ipv4_address
try:
from django.core.validators import validate_ipv6_address, validate_ipv46_address
@@ -189,6 +204,31 @@ def test_fill_TimeField_with_a_time(self):
self.assertIsInstance(self.person.birth_time, time)
+class UUIDFieldsFilling(FieldFillingTestCase):
+
+ if UUIDField:
+ def test_fill_UUIDField_with_uuid_object(self):
+ import uuid
+
+ uuid_field = Person._meta.get_field('uuid')
+ self.assertIsInstance(uuid_field, UUIDField)
+
+ self.assertIsInstance(self.person.uuid, uuid.UUID)
+
+
+class ArrayFieldsFilling(FieldFillingTestCase):
+
+ if ArrayField:
+ def test_fill_ArrayField_with_uuid_object(self):
+ self.assertEqual(self.person.acquaintances, [])
+
+
+class JSONFieldsFilling(FieldFillingTestCase):
+
+ if JSONField:
+ def test_fill_ArrayField_with_uuid_object(self):
+ self.assertEqual(self.person.data, {})
+
class FillingIntFields(TestCase):
def setUp(self):
View
50 test/generic/tests/test_mommy.py
@@ -81,25 +81,6 @@ def test_prepare_should_not_persist_one_object(self):
self.assertEqual(person.id, None)
- def test_make_one_should_create_one_object(self):
- """
- make_one method is deprecated, so this test must be removed when the
- method is removed
- """
- person = mommy.make_one(Person)
- self.assertIsInstance(person, Person)
- self.assertTrue(Person.objects.filter(id=person.id))
-
- def test_prepare_one_should_not_persist_one_object(self):
- """
- prepare_one method is deprecated, so this test must be removed when the
- method is removed
- """
- person = mommy.prepare_one(Person)
- self.assertIsInstance(person, Person)
- self.assertEqual(Person.objects.all().count(), 0)
- self.assertEqual(person.id, None)
-
def test_non_abstract_model_creation(self):
person = mommy.make(NonAbstractPerson, name='bob', happy=False)
self.assertIsInstance(person, NonAbstractPerson)
@@ -109,8 +90,8 @@ def test_non_abstract_model_creation(self):
def test_multiple_inheritance_creation(self):
multiple = mommy.make(DummyMultipleInheritanceModel)
self.assertIsInstance(multiple, DummyMultipleInheritanceModel)
- self.assertTrue(Person.objects.filter(id=multiple.my_id))
- self.assertTrue(DummyDefaultFieldsModel.objects.filter(default_id=multiple.id))
+ self.assertTrue(Person.objects.filter(id=multiple.id))
+ self.assertTrue(DummyDefaultFieldsModel.objects.filter(default_id=multiple.default_id))
class MommyRepeatedCreatesSimpleModel(TestCase):
@@ -152,17 +133,6 @@ def test_prepare_raises_correct_exception_if_invalid_quantity(self):
InvalidQuantityException, mommy.prepare, model=Person, _quantity=0
)
- def test_make_many_method(self):
- """
- make_many method is deprecated, so this test must be removed when the
- method is removed
- """
- people = mommy.make_many(Person, quantity=5)
- self.assertEqual(Person.objects.count(), 5)
-
- people = mommy.make_many(Person, name="George Washington")
- self.assertTrue(all(p.name == "George Washington" for p in people))
-
class MommyCreatesAssociatedModels(TestCase):
@@ -205,13 +175,6 @@ def test_prepare_fk(self):
self.assertEqual(Person.objects.all().count(), 0)
self.assertEqual(Dog.objects.all().count(), 0)
- def test_prepare_one_to_one(self):
- lonely_person = mommy.prepare(LonelyPerson)
-
- self.assertEqual(LonelyPerson.objects.all().count(), 0)
- self.assertTrue(isinstance(lonely_person.only_friend, Person))
- self.assertEqual(Person.objects.all().count(), 0)
-
def test_create_one_to_one(self):
lonely_person = mommy.make(LonelyPerson)
@@ -351,7 +314,14 @@ class HandlingContentTypeField(TestCase):
def test_create_model_with_contenttype_field(self):
dummy = mommy.make(DummyGenericForeignKeyModel)
self.assertIsInstance(dummy, DummyGenericForeignKeyModel)
-
+try:
+ from django.test import SimpleTestCase
+ class HandlingContentTypeFieldNoQueries(SimpleTestCase):
+ def test_create_model_with_contenttype_field(self):
+ dummy = mommy.prepare(DummyGenericForeignKeyModel)
+ self.assertIsInstance(dummy, DummyGenericForeignKeyModel)
+except ImportError:
+ pass
class SkipNullsTestCase(TestCase):
def test_skip_null(self):
View
37 test/generic/tests/test_recipes.py
@@ -279,37 +279,6 @@ def test_import_recipe_inside_deeper_modules(self):
person = mommy.prepare_recipe(recipe_name)
self.assertEqual(person.name, 'John Deeper')
- def test_make_many_from_recipe(self):
- """
- make_many_from_recipe is deprecated, so this test must be deleted when
- the method is
- """
- persons = mommy.make_many_from_recipe('test.generic.person')
- self.assertIsInstance(persons, list)
- self.assertEqual(len(persons), mommy.MAX_MANY_QUANTITY)
- for person in persons:
- self.assertIsInstance(person, Person)
- self.assertNotEqual(person.id, None)
-
- def test_make_many_from_recipe_with_specified_quantity(self):
- """
- make_many_from_recipe is deprecated, so this test must be deleted when
- the method is
- """
- quantity = 2
- persons = mommy.make_many_from_recipe('test.generic.person', quantity=quantity)
- self.assertIsInstance(persons, list)
- self.assertEqual(len(persons), quantity)
-
- def test_make_many_with_model_args(self):
- """
- make_many_from_recipe is deprecated, so this test must be deleted when
- the method is
- """
- persons = mommy.make_many_from_recipe('test.generic.person', name='Dennis Ritchie', age=70)
- for person in persons:
- self.assertEqual(person.name, 'Dennis Ritchie')
- self.assertEqual(person.age, 70)
class ForeignKeyTestCase(TestCase):
def test_foreign_key_method_returns_a_recipe_foreign_key_object(self):
@@ -392,6 +361,12 @@ def test_create_many_to_many(self):
self.assertEqual(friend.breed, 'Pug')
self.assertEqual(friend.owner.name, 'John Doe')
+ def test_create_nested(self):
+ dog = mommy.make_recipe('test.generic.dog_with_more_friends')
+ self.assertEqual(len(dog.friends_with.all()), 1)
+ friend = dog.friends_with.all()[0]
+ self.assertEqual(len(friend.friends_with.all()), 2)
+
class TestSequences(TestCase):
def test_increment_for_strings(self):
View
16 tox.ini
@@ -1,23 +1,27 @@
[tox]
-envlist = {py27}-django{14,15,16,17,18,19}, {py26}-django{14,15,16}, {py34,py32}-django{15,16,17,18,19}, {py35}-django{18,19}
+envlist = {py27}-django{15,16,17,18,19,110}-{postgresql,sqlite}, {py26}-django{15,16}, py34-django{15,16,17}-{postgresql,sqlite}, {py35,py34}-django{18,19,110}-{postgresql,sqlite}
[testenv]
+setenv=
+ PYTHONPATH = {toxinidir}
basepython =
py26: python2.6
py27: python2.7
py35: python3.5
py34: python3.4
- py32: python3.2
deps =
Pillow>=2.3.1
mock==1.0.1
six>=1.3.0
- django14: Django>=1.4,<1.5
+ django-test-without-migrations
django15: Django>=1.5,<1.6
django16: Django>=1.6,<1.7
django17: Django>=1.7,<1.8
django18: Django>=1.8,<1.9
- django19: Django==1.9
+ django19: Django>=1.9,>1.10
+ django110: Django==1.10
+ postgresql: psycopg2
+
commands=
- ./runtests.py
- ./runtests.py --use-tz
+ postgresql: {toxinidir}/runtests.py --postgresql
+ sqlite: {toxinidir}/runtests.py --use-tz

0 comments on commit 6fad6f2

Please sign in to comment.