Skip to content

Commit

Permalink
Add support for conditional attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
bohare authored and oliverroick committed Jul 6, 2016
1 parent b8bb384 commit d58e825
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 31 deletions.
3 changes: 2 additions & 1 deletion cadasta/config/settings/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@
),
'party.party': (
'project.organization.pk', 'project.pk',
'project.current_questionnaire'
'project.current_questionnaire',
'type'
),
'party.partyrelationship': (
'project.organization.pk', 'project.pk',
Expand Down
41 changes: 27 additions & 14 deletions cadasta/questionnaires/managers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import itertools
import re

from django.apps import apps
from django.contrib.contenttypes.models import ContentType
Expand Down Expand Up @@ -42,9 +43,16 @@ def create_children(children, errors=[], project=None, kwargs={}):

# parse attribute group
attribute_group = c.get('name')
if attribute_group in ATTRIBUTE_GROUPS:
create_attrs_schema(
project=project, dict=c, errors=errors)
for attr_group in ATTRIBUTE_GROUPS.keys():
if attribute_group.startswith(attr_group):
app_label = ATTRIBUTE_GROUPS[attr_group]['app_label']
model = ATTRIBUTE_GROUPS[attr_group]['model']
content_type = ContentType.objects.get(
app_label=app_label, model=model)
create_attrs_schema(
project=project, dict=c,
content_type=content_type, errors=errors
)
else:
model_name = 'Question'

Expand All @@ -62,19 +70,24 @@ def create_options(options, question, errors=[]):
" '{field_name}'".format(field_name=question.name)))


def create_attrs_schema(project=None, dict=None, errors=[]):
name = dict.get('name')
app_label = ATTRIBUTE_GROUPS[name]['app_label']
model = ATTRIBUTE_GROUPS[name]['model']
content_type = ContentType.objects.get(
app_label=app_label, model=model)
def create_attrs_schema(project=None, dict=None, content_type=None, errors=[]):
fields = []
proj = project.pk
org = project.organization.pk
quest = project.current_questionnaire
selectors = (project.organization.pk, project.pk,
project.current_questionnaire)

# check if the attribute group has a relevant bind statement,
# eg ${party_type}='IN'
# this enables conditional attribute schema creation
bind = dict.get('bind', None)
if bind:
relevant = bind.get('relevant', None)
if relevant:
clauses = relevant.split('=')
selector = re.sub("'", '', clauses[1])
selectors += (selector,)

schema_obj = Schema.objects.create(content_type=content_type,
selectors=(org, proj, quest))
selectors=selectors)

for c in dict.get('children'):
field = {}
Expand All @@ -83,7 +96,7 @@ def create_attrs_schema(project=None, dict=None, errors=[]):
# HACK: pyxform strips underscores from xform field names
field['attr_type'] = c.get('type').replace(' ', '_')
if c.get('default'):
field['default'] = c.get('default')
field['default'] = c.get('default', '')
if c.get('omit'):
field['omit'] = c.get('omit')
bind = c.get('bind')
Expand Down
Binary file modified cadasta/questionnaires/tests/files/xls-form-attrs.xlsx
Binary file not shown.
176 changes: 160 additions & 16 deletions cadasta/questionnaires/tests/test_attr_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,17 @@ def test_create_attribute_schemas(self):
project=project
)
# test for expected schema and attribute creation
assert 5 == Schema.objects.all().count()
assert 8 == Attribute.objects.all().count()
assert 6 == Schema.objects.all().count()
assert 10 == Attribute.objects.all().count()

def test_party_attribute_schema(self):
project = ProjectFactory.create(name='TestProject')
QuestionnaireFactory.create(project=project)
content_type = ContentType.objects.get(
app_label='party', model='party')
create_attrs_schema(
project=project, dict=party_xform_group, errors=[])
project=project, dict=party_xform_group,
content_type=content_type, errors=[])
party = PartyFactory.create(
name='TestParty', project=project,
attributes={
Expand All @@ -73,8 +74,11 @@ def test_party_attribute_schema(self):
def test_party_invalid_attribute(self):
project = ProjectFactory.create(name='TestProject')
QuestionnaireFactory.create(project=project)
content_type = ContentType.objects.get(
app_label='party', model='party')
create_attrs_schema(
project=project, dict=party_xform_group, errors=[])
project=project, dict=party_xform_group,
content_type=content_type, errors=[])
assert 1 == Schema.objects.all().count()
with pytest.raises(KeyError):
PartyFactory.create(
Expand All @@ -91,7 +95,8 @@ def test_spatial_unit_attribute_schema(self):
content_type = ContentType.objects.get(
app_label='spatial', model='spatialunit')
create_attrs_schema(
project=project, dict=location_xform_group, errors=[])
project=project, dict=location_xform_group,
content_type=content_type, errors=[])
spatial_unit = SpatialUnitFactory.create(
name='Test', project=project,
attributes={
Expand All @@ -111,8 +116,11 @@ def test_spatial_unit_attribute_schema(self):
def test_spatial_unit_invalid_attribute(self):
project = ProjectFactory.create(name='TestProject')
QuestionnaireFactory.create(project=project)
content_type = ContentType.objects.get(
app_label='spatial', model='spatialunit')
create_attrs_schema(
project=project, dict=location_xform_group, errors=[])
project=project, dict=location_xform_group,
content_type=content_type, errors=[])
assert 1 == Schema.objects.all().count()
with pytest.raises(KeyError):
SpatialUnitFactory.create(
Expand All @@ -128,7 +136,8 @@ def test_spatial_relationship_schema(self):
content_type = ContentType.objects.get(
app_label='spatial', model='spatialrelationship')
create_attrs_schema(
project=project, dict=location_relationship_xform_group, errors=[])
project=project, dict=location_relationship_xform_group,
content_type=content_type, errors=[])
sur = SpatialRelationshipFactory.create(
project=project, attributes={
'notes': 'Some additional textual info'}
Expand All @@ -143,8 +152,11 @@ def test_spatial_relationship_schema(self):
def test_spatial_relationship_invalid_attribute(self):
project = ProjectFactory.create(name='TestProject')
QuestionnaireFactory.create(project=project)
content_type = ContentType.objects.get(
app_label='spatial', model='spatialrelationship')
create_attrs_schema(
project=project, dict=location_relationship_xform_group, errors=[])
project=project, dict=location_relationship_xform_group,
content_type=content_type, errors=[])
assert 1 == Schema.objects.all().count()
with pytest.raises(KeyError):
SpatialRelationshipFactory.create(
Expand All @@ -160,7 +172,8 @@ def test_party_relationship_schema(self):
content_type = ContentType.objects.get(
app_label='party', model='partyrelationship')
create_attrs_schema(
project=project, dict=party_relationship_xform_group, errors=[])
project=project, dict=party_relationship_xform_group,
content_type=content_type, errors=[])
pr = PartyRelationshipFactory.create(
project=project, attributes={
'notes': 'Some additional textual info'}
Expand All @@ -175,8 +188,11 @@ def test_party_relationship_schema(self):
def test_party_relationship_invalid_attribute(self):
project = ProjectFactory.create(name='TestProject')
QuestionnaireFactory.create(project=project)
content_type = ContentType.objects.get(
app_label='party', model='partyrelationship')
create_attrs_schema(
project=project, dict=party_relationship_xform_group, errors=[])
project=project, dict=party_relationship_xform_group,
content_type=content_type, errors=[])
assert 1 == Schema.objects.all().count()
with pytest.raises(KeyError):
PartyRelationshipFactory.create(
Expand All @@ -192,7 +208,8 @@ def test_tenure_relationship_schema(self):
content_type = ContentType.objects.get(
app_label='party', model='tenurerelationship')
create_attrs_schema(
project=project, dict=tenure_relationship_xform_group, errors=[])
project=project, dict=tenure_relationship_xform_group,
content_type=content_type, errors=[])
tr = TenureRelationshipFactory.create(
project=project, attributes={
'notes': 'Some additional textual info'}
Expand All @@ -207,8 +224,11 @@ def test_tenure_relationship_schema(self):
def test_tenure_relationship_invalid_attribute(self):
project = ProjectFactory.create(name='TestProject')
QuestionnaireFactory.create(project=project)
content_type = ContentType.objects.get(
app_label='party', model='tenurerelationship')
create_attrs_schema(
project=project, dict=tenure_relationship_xform_group, errors=[])
project=project, dict=tenure_relationship_xform_group,
content_type=content_type, errors=[])
assert 1 == Schema.objects.all().count()
with pytest.raises(KeyError):
TenureRelationshipFactory.create(
Expand All @@ -221,8 +241,11 @@ def test_tenure_relationship_invalid_attribute(self):
def test_omit_attribute(self):
project = ProjectFactory.create(name='TestProject')
QuestionnaireFactory.create(project=project)
content_type = ContentType.objects.get(
app_label='spatial', model='spatialunit')
create_attrs_schema(
project=project, dict=location_xform_group, errors=[])
project=project, dict=location_xform_group,
content_type=content_type, errors=[])
with pytest.raises(KeyError):
SpatialUnitFactory.create(
project=project,
Expand All @@ -237,7 +260,8 @@ def test_required_attribute(self):
content_type = ContentType.objects.get(
app_label='party', model='party')
create_attrs_schema(
project=project, dict=party_xform_group, errors=[])
project=project, dict=party_xform_group,
content_type=content_type, errors=[])
# with pytest.raises(ValidationError):
# PartyFactory.create(
# project=project,
Expand All @@ -256,8 +280,11 @@ def test_required_attribute(self):
def test_invalid_choice_attribute(self):
project = ProjectFactory.create(name='TestProject')
QuestionnaireFactory.create(project=project)
content_type = ContentType.objects.get(
app_label='party', model='party')
create_attrs_schema(
project=project, dict=party_xform_group, errors=[])
project=project, dict=party_xform_group,
content_type=content_type, errors=[])
assert 1 == Schema.objects.all().count()
with pytest.raises(ValidationError):
PartyFactory.create(
Expand Down Expand Up @@ -286,7 +313,7 @@ def test_update_questionnaire_attribute_schema(self):
project=project
)

assert 10 == Schema.objects.all().count()
assert 12 == Schema.objects.all().count()

content_type = ContentType.objects.get(
app_label='party', model='party')
Expand All @@ -304,3 +331,120 @@ def test_update_questionnaire_attribute_schema(self):
)
assert s2 is not None
assert s1 != s2


class ConditionalAttributeSchemaTest(TestCase):

def setUp(self):
ensure_dirs()
storage = FakeS3Storage()
file = open(
path + '/questionnaires/tests/files/xls-form-attrs.xlsx', 'rb')
form = storage.save('xls-form-attrs.xlsx', file)
self.content_type = ContentType.objects.get(
app_label='party', model='party')
self.project = ProjectFactory.create(name='TestProject')
models.Questionnaire.objects.create_from_form(
xls_form=form,
project=self.project
)

def test_create_party_attribute_schemas(self):
# should create 3 attribute schemas,
# one for each of default, individual and group respectively
schemas = Schema.objects.filter(content_type=self.content_type)
assert 3 == schemas.count()
# default schema
schemas = Schema.objects.filter(
content_type=self.content_type,
selectors=(
self.project.organization.pk, self.project.pk,
self.project.current_questionnaire
)
)
assert 1 == schemas.count()
assert 1 == schemas[0].attributes.count()
# individual schema
schemas = Schema.objects.filter(
content_type=self.content_type,
selectors=(
self.project.organization.pk, self.project.pk,
self.project.current_questionnaire, 'IN'
)
)
assert 1 == schemas.count()
assert 3 == schemas[0].attributes.count()
# group schema
schemas = Schema.objects.filter(
content_type=self.content_type,
selectors=(
self.project.organization.pk, self.project.pk,
self.project.current_questionnaire, 'GR'
)
)
assert 1 == schemas.count()
assert 2 == schemas[0].attributes.count()

def test_default_party_attribute_schema(self):
schema = Schema.objects.get(
content_type=self.content_type,
selectors=(self.project.organization.pk, self.project.pk,
self.project.current_questionnaire)
)
assert schema is not None
assert 1 == schema.attributes.count()
party = PartyFactory.create(
name='TestParty', project=self.project,
attributes={
'notes': 'Some textual stuff'
}
)
assert 'notes' in party.attributes.attributes
assert 'Some textual stuff' == party.attributes['notes']

def test_individual_party_attribute_schema(self):
schema = Schema.objects.get(
content_type=self.content_type,
selectors=(self.project.organization.pk, self.project.pk,
self.project.current_questionnaire, 'IN')
)
assert schema is not None
assert 3 == schema.attributes.count()
party = PartyFactory.create(
name='TestParty', project=self.project,
type="IN",
attributes={
"notes": "Some notes",
"gender": "m",
"dob": "1908-01-01",
"homeowner": "yes"
}
)
# attribute schema composed from
# default and individual attribute schemas
assert 'gender' in party.attributes.attributes
assert 'homeowner'in party.attributes.attributes
assert 'notes' in party.attributes.attributes
assert 'dob' in party.attributes.attributes

def test_group_party_attribute_schema(self):
schema = Schema.objects.get(
content_type=self.content_type,
selectors=(self.project.organization.pk, self.project.pk,
self.project.current_questionnaire, 'GR')
)
assert schema is not None
assert 2 == schema.attributes.count()
party = PartyFactory.create(
name='TestParty', project=self.project,
type="GR",
attributes={
"number_of_members": "100",
"date_formed": "2000-01-01"
}
)
# attribute schema composed from
# default and group attribute schemas
assert 'notes' in party.attributes.attributes
assert 'number_of_members' in party.attributes.attributes
assert 'date_formed' in party.attributes.attributes

0 comments on commit d58e825

Please sign in to comment.