Skip to content
This repository was archived by the owner on Feb 27, 2020. It is now read-only.
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
28 changes: 13 additions & 15 deletions djeneralize/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ def __new__(cls, name, bases, attrs):
# This must be a direct descendant from the BaseGeneralizationModel.
# Prepare the look-up mapping of specializations which the sub-
# classes will update:
new_model._meta.specializations = {}
new_model._meta.specialization = PATH_SEPERATOR
new_model._meta.specializations = {new_model._meta.specialization: new_model}

if specialization is not None:
# We need to ensure this is actually None and not just evaluates
Expand All @@ -103,7 +103,6 @@ def __new__(cls, name, bases, attrs):

parent_class = new_model.__base__

new_model._meta.specializations = {}
new_model._generalized_parent = parent_class

path_specialization = '%s%s%s' % (
Expand All @@ -114,7 +113,8 @@ def __new__(cls, name, bases, attrs):
# Calculate the specialization as a path taking into account the
# specialization of any ancestors:
new_model._meta.specialization = path_specialization

new_model._meta.specializations = {new_model._meta.specialization: new_model}

# Update the specializations mapping on the General model so that it
# knows to use this class for that specialization:
ancestor = getattr(new_model, '_generalized_parent', None)
Expand Down Expand Up @@ -187,14 +187,12 @@ def __init__(self, *args, **kwargs):
declared in Meta

"""

super(BaseGeneralizationModel, self).__init__(*args, **kwargs)

# If we have a final specialization, and a specialization_type is not
# specified in kwargs, set it to the default for this model:
if ('specialization_type' not in kwargs and
not self._meta.specializations):
self.specialization_type = self.__class__.model_specialization
if ('specialization_type' not in kwargs):
kwargs['specialization_type'] = self.__class__.model_specialization

super(BaseGeneralizationModel, self).__init__(*args, **kwargs)

class Meta:
abstract = True
Expand All @@ -212,13 +210,13 @@ def get_as_specialization(self, final_specialization=True):

"""

path = self.specialization_type

if not final_specialization:
current_path = self.__class__.model_specialization
path = self.specialization_type

if not final_specialization and not path is current_path:
# We need to find the path which is only one-step down from the
# current level of specialization.
path = find_next_path_down(self.__class__.model_specialization,
path, PATH_SEPERATOR)
path = find_next_path_down(current_path, path, PATH_SEPERATOR)

return self._meta.specializations[path].objects.get(pk=self.pk)

Expand Down Expand Up @@ -280,4 +278,4 @@ def ensure_specialization_manager(sender, **kwargs):
)

specialized_model_prepared.connect(ensure_specialization_manager)
#}
#}
15 changes: 0 additions & 15 deletions tests/__init__.py

This file was deleted.

6 changes: 3 additions & 3 deletions tests/fixtures.py → tests/test_djeneralize/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
# INFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
#
##############################################################################
from tests.test_djeneralize.producers.models import EcoProducer
from tests.test_djeneralize.fruit.models import Banana
from test_djeneralize.producers.models import EcoProducer
from test_djeneralize.fruit.models import Banana

"""Fixtures for djeneralize tests"""

Expand Down Expand Up @@ -129,4 +129,4 @@ class Meta:
class EcoMart:
name = 'EcoMart'
producer = EcoProducerData.BananaProducer


12 changes: 9 additions & 3 deletions tests/test_djeneralize/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
##############################################################################

from os import path
# add djeneralize to the path
import sys
sys.path.append('../..')

def get_and_ensure_exists_path_to_db_file():
"""
Expand All @@ -31,6 +34,8 @@ def get_and_ensure_exists_path_to_db_file():
return db_path


TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

# Django settings for test_djeneralize project.

DEBUG = True
Expand Down Expand Up @@ -122,7 +127,8 @@ def get_and_ensure_exists_path_to_db_file():
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'tests.test_djeneralize.writing',
'tests.test_djeneralize.fruit',
'tests.test_djeneralize.producers',
'test_djeneralize.writing',
'test_djeneralize.fruit',
'test_djeneralize.producers',
'django_nose',
)
Empty file.
64 changes: 41 additions & 23 deletions tests/test_base.py → tests/test_djeneralize/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
##############################################################################

from itertools import chain
import os
# Ensure that Django knows where the project is:
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.test_djeneralize.settings'

from django.http import Http404
from fixture.django_testcase import FixtureTestCase
Expand All @@ -26,8 +23,8 @@
)

from djeneralize.utils import *
from .fixtures import *
from .test_djeneralize.writing.models import *
from test_djeneralize.fixtures import *
from test_djeneralize.writing.models import *


class TestMetaclass(object):
Expand All @@ -37,19 +34,21 @@ class TestMetaclass(object):
def test_specializations_general(self):
"""
The specializations dictionary on the most general case is populated
with all the descdencts direct or otherwise.
with all the descdencts direct or otherwise or the model itself.

"""

specializations = WritingImplement._meta.specializations
specializations_classes = set(specializations.values())
specializations_keys = set(specializations.keys())

ok_(WritingImplement in specializations_classes)
ok_(Pen in specializations_classes)
ok_(Pencil in specializations_classes)
ok_(FountainPen in specializations_classes)
ok_(BallPointPen in specializations_classes)

ok_(WritingImplement.model_specialization in specializations_keys)
ok_(Pen.model_specialization in specializations_keys)
ok_(Pencil.model_specialization in specializations_keys)
ok_(FountainPen.model_specialization in specializations_keys)
Expand All @@ -58,26 +57,26 @@ def test_specializations_general(self):

def test_sub_specialization(self):
"""
Only the child specializations are stored in a specialization of the
general case.
Only the child specializations and the model iself are stored in a specialization of the
most general case.

"""

specializations = Pen._meta.specializations
specializations_classes = set(specializations.values())
specializations_keys = set(specializations.keys())

assert_false(Pen in specializations_classes)
assert_false(Pencil in specializations_classes)
ok_(Pen in specializations_classes)
ok_(FountainPen in specializations_classes)
ok_(BallPointPen in specializations_classes)

assert_false(Pen.model_specialization in specializations_keys)
assert_false(Pencil.model_specialization in specializations_keys)
ok_(Pen.model_specialization in specializations_keys)
ok_(FountainPen.model_specialization in specializations_keys)
ok_(BallPointPen.model_specialization in specializations_keys)

eq_(BallPointPen._meta.specializations, {})
eq_(BallPointPen._meta.specializations, {BallPointPen.model_specialization: BallPointPen})

def test_path_specialization(self):
"""
Expand Down Expand Up @@ -162,17 +161,6 @@ class TestModelInstance(FixtureTestCase):
"""Tests for model instances"""

datasets = [PenData, PencilData, FountainPenData, BallPointPenData]

def test_no_matching_specialization_raises_key_error(self):
"""
If get_as_specialization is called on the most specialized instance a
key error will be raised.

"""

pencil = Pencil.objects.all()[0]

assert_raises(KeyError, pencil.get_as_specialization)

def test_final_specialization(self):
"""
Expand All @@ -186,8 +174,8 @@ def test_final_specialization(self):
montblanc_special = FountainPen.objects.get(name='Mont Blanc')

eq_(montblanc_general.get_as_specialization(), montblanc_special)

eq_(montblanc_intermediate.get_as_specialization(), montblanc_special)
eq_(montblanc_special.get_as_specialization(), montblanc_special)

def test_direct_specialization(self):
"""
Expand Down Expand Up @@ -275,6 +263,36 @@ def test_all_final(self):
model_value = getattr(wi, field_name)
eq_(model_value, value)


def test_all_final_on_model_with_instances(self):
"""
The all() method on the manager and queryset returns final
specializations, on a model that has instances of itself AND specialized instances.

"""
all_pens = Pen.specializations.all()

models = set(m.__class__ for m in all_pens)

assert_false(WritingImplement in models)
ok_(Pen in models)
ok_(FountainPen in models)
ok_(BallPointPen in models)


# Ensure that all the objects have the correct fields and values
# specified in their original definition, i.e. they've been
# reconstituted correctly:
for p in all_pens:
dataset = self.datasets[p.name]

for field_name, value in dataset.__dict__.items():
if field_name.startswith('_') or field_name == 'ref':
continue

model_value = getattr(p, field_name)
eq_(model_value, value)

def test_all_direct(self):
"""
The all() method on the manager and queryset returns direct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,14 @@
# INFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
#
##############################################################################
import os
# Ensure that Django knows where the project is:
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.test_djeneralize.settings'

from fixture.django_testcase import FixtureTestCase
from nose.tools import eq_

from tests.fixtures import BananaData, EcoProducerData, PenData, ShopData
from tests.test_djeneralize.fruit.models import Banana
from tests.test_djeneralize.producers.models import EcoProducer, Shop
from tests.test_djeneralize.writing.models import WritingImplement
from test_djeneralize.fixtures import BananaData, EcoProducerData, PenData, ShopData
from test_djeneralize.fruit.models import Banana
from test_djeneralize.producers.models import EcoProducer, Shop
from test_djeneralize.writing.models import WritingImplement


class TestForeignKey(FixtureTestCase):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@

"""Integration tests to confirm nothing Django-related is broken"""

import os
# Ensure that Django knows where the project is:
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.test_djeneralize.settings'

from django.db.models import Avg, F, Q
from django.db.models.query import ValuesListQuerySet, ValuesQuerySet
from fixture.django_testcase import FixtureTestCase
Expand All @@ -29,8 +25,8 @@

from djeneralize.models import BaseGeneralizationModel
from djeneralize.utils import *
from .fixtures import *
from .test_djeneralize.writing.models import *
from test_djeneralize.fixtures import *
from test_djeneralize.writing.models import *


class TestManager(FixtureTestCase):
Expand Down Expand Up @@ -276,4 +272,4 @@ def test_complex_query(self):
q_small | q_large
)

self._check_attributes(normal_objects, specialized_objects)
self._check_attributes(normal_objects, specialized_objects)
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
"""Test suite to ensure that correct copying of managers"""

import os
# Ensure that Django knows where the project is:
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.test_djeneralize.settings'

from django.db.models.manager import Manager
from fixture.django_testcase import FixtureTestCase
from nose.tools import (
eq_, ok_, assert_false, raises, assert_raises, assert_not_equal
)

from djeneralize.manager import SpecializationManager
from .test_djeneralize.fruit.models import *
from test_djeneralize.fruit.models import *


class TestManager(object):
Expand Down Expand Up @@ -73,4 +69,4 @@ def test_specialized_not_inherit_specialized_managers(self):

eq_(Apple.specializations.__class__, SpecializationManager)
eq_(Banana.specializations.__class__, SpecializationManager)