From 7fcf04eaf5aab47bb8d3030ab5e2aec5b4c5aabf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Fri, 2 Nov 2012 14:14:13 +0200 Subject: [PATCH 01/13] add shapely --- requirements.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 28b12404a1..ac50bd1691 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,11 +8,11 @@ lxml boto mako python-memcached -python-openid +python-openid path.py django_debug_toolbar fs -beautifulsoup +beautifulsoup beautifulsoup4 feedparser requests @@ -37,7 +37,7 @@ django-jasmine django-keyedcache django-mako django-masquerade -django-openid-auth +django-openid-auth django-robots django-ses django-storages @@ -54,3 +54,4 @@ dogstatsd-python # Taking out MySQL-python for now because it requires mysql to be installed, so breaks updates on content folks' envs. # MySQL-python sphinx +Shapely From 88c98b9a56b42b0541e8ab1dc7be6ad05ce6a5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Fri, 2 Nov 2012 14:16:37 +0200 Subject: [PATCH 02/13] added multiple regions support --- common/lib/capa/capa/responsetypes.py | 63 +++++++++++++++++---------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index b990c489b3..85efd70cee 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -23,6 +23,7 @@ import abc import os import subprocess import xml.sax.saxutils as saxutils +from shapely.geometry import Polygon, Point # specific library imports from calc import evaluator, UndefinedVariable @@ -1720,12 +1721,20 @@ class ImageResponse(LoncapaResponse): Lon-CAPA requires that each has a inside it. That doesn't make sense to me (Ike). Instead, let's have it such that should contain one or more stanzas. Each should specify - a rectangle, given as an attribute, defining the correct answer. + a rectangle(s) or region(s), given as an attribute, defining the correct answer. + + Rectangle(s) are more prioritized over regions due to simplicity and backward compatibility. + In this example regions will be ignored: + + + Regions is list of lists [region1, region2, region3, ...] where regionN is ordered list of points: [[1,1], [100,100], [50,50], [20, 70]]. """ snippets = [{'snippet': ''' - + + + '''}] response_tag = 'imageresponse' @@ -1733,7 +1742,7 @@ class ImageResponse(LoncapaResponse): def setup_response(self): self.ielements = self.inputfields - self.answer_ids = [ie.get('id') for ie in self.ielements] + self.answer_ids = [ie.get('id') for ie in self.ielements] def get_score(self, student_answers): correct_map = CorrectMap() @@ -1743,7 +1752,7 @@ class ImageResponse(LoncapaResponse): given = student_answers[aid] # this should be a string of the form '[x,y]' correct_map.set(aid, 'incorrect') - if not given: # No answer to parse. Mark as incorrect and move on + if not given: # No answer to parse. Mark as incorrect and move on continue # parse given answer @@ -1753,29 +1762,37 @@ class ImageResponse(LoncapaResponse): 'error grading %s (input=%s)' % (aid, given)) (gx, gy) = [int(x) for x in m.groups()] - # Check whether given point lies in any of the solution rectangles - solution_rectangles = expectedset[aid].split(';') - for solution_rectangle in solution_rectangles: - # parse expected answer - # TODO: Compile regexp on file load - m = re.match('[\(\[]([0-9]+),([0-9]+)[\)\]]-[\(\[]([0-9]+),([0-9]+)[\)\]]', - solution_rectangle.strip().replace(' ', '')) - if not m: - msg = 'Error in problem specification! cannot parse rectangle in %s' % ( - etree.tostring(self.ielements[aid], pretty_print=True)) - raise Exception('[capamodule.capa.responsetypes.imageinput] ' + msg) - (llx, lly, urx, ury) = [int(x) for x in m.groups()] - - # answer is correct if (x,y) is within the specified rectangle - if (llx <= gx <= urx) and (lly <= gy <= ury): - correct_map.set(aid, 'correct') - break + rectangles, regions = expectedset + if rectangles[aid]: # rectangles part - for backward compatibility + # Check whether given point lies in any of the solution rectangles + solution_rectangles = rectangles[aid].split(';') + for solution_rectangle in solution_rectangles: + # parse expected answer + # TODO: Compile regexp on file load + m = re.match('[\(\[]([0-9]+),([0-9]+)[\)\]]-[\(\[]([0-9]+),([0-9]+)[\)\]]', + solution_rectangle.strip().replace(' ', '')) + if not m: + msg = 'Error in problem specification! cannot parse rectangle in %s' % ( + etree.tostring(self.ielements[aid], pretty_print=True)) + raise Exception('[capamodule.capa.responsetypes.imageinput] ' + msg) + (llx, lly, urx, ury) = [int(x) for x in m.groups()] + # answer is correct if (x,y) is within the specified rectangle + if (llx <= gx <= urx) and (lly <= gy <= ury): + correct_map.set(aid, 'correct') + break + else: # rectangles are more prioretized for same id + if regions[aid]: + parsed_region = json.loads(regions[aid]) + for region in parsed_region: + if Polygon(region).contains(Point(gx, gy)): + correct_map.set(aid, 'correct') + break return correct_map def get_answers(self): - return dict([(ie.get('id'), ie.get('rectangle')) for ie in self.ielements]) - + return (dict([(ie.get('id'), ie.get('rectangle')) for ie in self.ielements]), + dict([(ie.get('id'), ie.get('regions')) for ie in self.ielements])) #----------------------------------------------------------------------------- # TEMPORARY: List of all response subclasses # FIXME: To be replaced by auto-registration From 406e7e29c04bcbe829752a802f675f22c1a8629b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Fri, 2 Nov 2012 17:25:18 +0200 Subject: [PATCH 03/13] added geos to requirements --- brew-formulas.txt | 15 ++++++++------- create-dev-env.sh | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/brew-formulas.txt b/brew-formulas.txt index b5b555e2a0..e06829a43a 100644 --- a/brew-formulas.txt +++ b/brew-formulas.txt @@ -1,10 +1,11 @@ -readline -sqlite -gdbm -pkg-config -gfortran -python -yuicompressor +readline +sqlite +gdbm +pkg-config +gfortran +python +yuicompressor node graphviz mysql +geos diff --git a/create-dev-env.sh b/create-dev-env.sh index e481d3fd5e..2a7f68d3b0 100755 --- a/create-dev-env.sh +++ b/create-dev-env.sh @@ -99,7 +99,7 @@ NUMPY_VER="1.6.2" SCIPY_VER="0.10.1" BREW_FILE="$BASE/mitx/brew-formulas.txt" LOG="/var/tmp/install-$(date +%Y%m%d-%H%M%S).log" -APT_PKGS="pkg-config curl git python-virtualenv build-essential python-dev gfortran liblapack-dev libfreetype6-dev libpng12-dev libxml2-dev libxslt-dev yui-compressor nodejs npm graphviz graphviz-dev mysql-server libmysqlclient-dev" +APT_PKGS="pkg-config curl git python-virtualenv build-essential python-dev gfortran liblapack-dev libfreetype6-dev libpng12-dev libxml2-dev libxslt-dev yui-compressor nodejs npm graphviz graphviz-dev mysql-server libmysqlclient-dev geos" if [[ $EUID -eq 0 ]]; then error "This script should not be run using sudo or as the root user" From 03c338d6e3a64235fbc8f7f32da060b5922d704d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Mon, 26 Nov 2012 18:26:16 +0200 Subject: [PATCH 04/13] added geos library for linux --- create-dev-env.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create-dev-env.sh b/create-dev-env.sh index 2a7f68d3b0..5edc765e4f 100755 --- a/create-dev-env.sh +++ b/create-dev-env.sh @@ -99,7 +99,7 @@ NUMPY_VER="1.6.2" SCIPY_VER="0.10.1" BREW_FILE="$BASE/mitx/brew-formulas.txt" LOG="/var/tmp/install-$(date +%Y%m%d-%H%M%S).log" -APT_PKGS="pkg-config curl git python-virtualenv build-essential python-dev gfortran liblapack-dev libfreetype6-dev libpng12-dev libxml2-dev libxslt-dev yui-compressor nodejs npm graphviz graphviz-dev mysql-server libmysqlclient-dev geos" +APT_PKGS="pkg-config curl git python-virtualenv build-essential python-dev gfortran liblapack-dev libfreetype6-dev libpng12-dev libxml2-dev libxslt-dev yui-compressor nodejs npm graphviz graphviz-dev mysql-server libmysqlclient-dev libgeos-dev" if [[ $EUID -eq 0 ]]; then error "This script should not be run using sudo or as the root user" From b4fb0cc463fa58ba4a8bc2f0bbef5da1a7c9e0cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Mon, 26 Nov 2012 18:34:38 +0200 Subject: [PATCH 05/13] fixed line length --- common/lib/capa/capa/responsetypes.py | 41 +++++++++++++++++---------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 85efd70cee..730cdb12cf 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1718,23 +1718,33 @@ class ImageResponse(LoncapaResponse): which produces an [x,y] coordinate pair. The click is correct if it falls within a region specified. This region is a union of rectangles. - Lon-CAPA requires that each has a inside it. That - doesn't make sense to me (Ike). Instead, let's have it such that - should contain one or more stanzas. Each should specify - a rectangle(s) or region(s), given as an attribute, defining the correct answer. + Lon-CAPA requires that each has a inside it. + That doesn't make sense to me (Ike). Instead, let's have it such that + should contain one or more stanzas. + Each should specify a rectangle(s) or region(s), given as an + attribute, defining the correct answer. - Rectangle(s) are more prioritized over regions due to simplicity and backward compatibility. - In this example regions will be ignored: - + Rectangle(s) are more prioritized over regions due to simplicity and + backward compatibility. In this example regions will be ignored: + - Regions is list of lists [region1, region2, region3, ...] where regionN is ordered list of points: [[1,1], [100,100], [50,50], [20, 70]]. + Regions is list of lists [region1, region2, region3, ...] where regionN + is ordered list of points: [[1,1], [100,100], [50,50], [20, 70]]. """ snippets = [{'snippet': ''' - - - - - + + + + + '''}] response_tag = 'imageresponse' @@ -1748,8 +1758,9 @@ class ImageResponse(LoncapaResponse): correct_map = CorrectMap() expectedset = self.get_answers() - for aid in self.answer_ids: # loop through IDs of fields in our stanza - given = student_answers[aid] # this should be a string of the form '[x,y]' + for aid in self.answer_ids: # loop through IDs of + # fields in our stanza + given = student_answers[aid] # this should be a string of the form '[x,y]' correct_map.set(aid, 'incorrect') if not given: # No answer to parse. Mark as incorrect and move on From 647d1514aa7d4433595943727ecec57ddd4a71f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80?= Date: Mon, 26 Nov 2012 18:38:46 +0200 Subject: [PATCH 06/13] support both regions and rectangles --- common/lib/capa/capa/responsetypes.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 730cdb12cf..74c801b450 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1724,14 +1724,15 @@ class ImageResponse(LoncapaResponse): Each should specify a rectangle(s) or region(s), given as an attribute, defining the correct answer. - Rectangle(s) are more prioritized over regions due to simplicity and - backward compatibility. In this example regions will be ignored: Regions is list of lists [region1, region2, region3, ...] where regionN is ordered list of points: [[1,1], [100,100], [50,50], [20, 70]]. + + Returns: + True, if click is inside any region or rectangle. Otherwise False. """ snippets = [{'snippet': ''' Date: Tue, 27 Nov 2012 13:09:58 +0200 Subject: [PATCH 07/13] support for single list syntax in regions --- common/lib/capa/capa/responsetypes.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 74c801b450..000d77d655 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1758,9 +1758,10 @@ class ImageResponse(LoncapaResponse): def get_score(self, student_answers): correct_map = CorrectMap() expectedset = self.get_answers() - + # import ipdb; ipdb.set_trace() for aid in self.answer_ids: # loop through IDs of # fields in our stanza + # import ipdb; ipdb.set_trace() given = student_answers[aid] # this should be a string of the form '[x,y]' correct_map.set(aid, 'incorrect') @@ -1795,10 +1796,16 @@ class ImageResponse(LoncapaResponse): break if regions[aid]: parsed_region = json.loads(regions[aid]) - for region in parsed_region: - if Polygon(region).contains(Point(gx, gy)): - correct_map.set(aid, 'correct') - break + if parsed_region: + if type(parsed_region[0][0]) != list: + # we have [[1,2],[3,4],[5,6] - single region + # instead of [[[1,2],[3,4],[5,6], [[1,2],[3,4],[5,6]] + # or [[[1,2],[3,4],[5,6]] - multiple regions syntax + parsed_region = [parsed_region] + for region in parsed_region: + if Polygon(region).contains(Point(gx, gy)): + correct_map.set(aid, 'correct') + break return correct_map def get_answers(self): From 5723672e490c4d19ddedbcb6e6ea40cce2e6f822 Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Tue, 27 Nov 2012 13:16:47 +0200 Subject: [PATCH 08/13] speed improvements --- common/lib/capa/capa/responsetypes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 000d77d655..aeabacef59 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1794,7 +1794,9 @@ class ImageResponse(LoncapaResponse): if (llx <= gx <= urx) and (lly <= gy <= ury): correct_map.set(aid, 'correct') break - if regions[aid]: + # import ipdb; ipdb.set_trace() + if correct_map[aid]['correctness'] != 'correct' and regions[aid]: + import ipdb; ipdb.set_trace() parsed_region = json.loads(regions[aid]) if parsed_region: if type(parsed_region[0][0]) != list: From 72f9358f64d055d46466e1adf836f368aaf4182d Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Tue, 27 Nov 2012 13:18:37 +0200 Subject: [PATCH 09/13] tests for imageresponse regions --- .../capa/tests/test_files/imageresponse.xml | 19 ++++++++++++ .../lib/capa/capa/tests/test_responsetypes.py | 30 ++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/common/lib/capa/capa/tests/test_files/imageresponse.xml b/common/lib/capa/capa/tests/test_files/imageresponse.xml index 34dba37e3b..c4590b211f 100644 --- a/common/lib/capa/capa/tests/test_files/imageresponse.xml +++ b/common/lib/capa/capa/tests/test_files/imageresponse.xml @@ -18,4 +18,23 @@ Hello

Use conservation of energy.

+ + + + + + + +Click on either of the two positions as discussed previously. + +Click on either of the two positions as discussed previously. + + +Click on either of the two positions as discussed previously. + +

Use conservation of energy.

+
+
+ + diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index bcac555b5e..3564ad3fe8 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -52,24 +52,52 @@ class ImageResponseTest(unittest.TestCase): def test_ir_grade(self): imageresponse_file = os.path.dirname(__file__) + "/test_files/imageresponse.xml" test_lcp = lcp.LoncapaProblem(open(imageresponse_file).read(), '1', system=test_system) - correct_answers = {'1_2_1': '(490,11)-(556,98)', + # testing regions only + correct_answers = { + #regions + '1_2_1': '(490,11)-(556,98)', '1_2_2': '(242,202)-(296,276)', '1_2_3': '(490,11)-(556,98);(242,202)-(296,276)', '1_2_4': '(490,11)-(556,98);(242,202)-(296,276)', '1_2_5': '(490,11)-(556,98);(242,202)-(296,276)', + #testing regions and rectanges + '1_3_1': '(490,11)-(556,98)', + '1_3_2': '(242,202)-(296,276)', + '1_3_3': '(490,11)-(556,98);(242,202)-(296,276)', + '1_3_4': '(490,11)-(556,98);(242,202)-(296,276)', + '1_3_5': '(490,11)-(556,98);(242,202)-(296,276)', } test_answers = {'1_2_1': '[500,20]', '1_2_2': '[250,300]', '1_2_3': '[500,20]', '1_2_4': '[250,250]', '1_2_5': '[10,10]', + + '1_3_1': '[500,20]', + '1_3_2': '[15,15]', + '1_3_3': '[500,20]', + '1_3_4': '[115,115]', + '1_3_5': '[15,15]', + '1_3_6': '[20,20]', + '1_3_7': '[20,20]', } + + # regions self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_1'), 'correct') self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_2'), 'incorrect') self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_3'), 'correct') self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_4'), 'correct') self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_2_5'), 'incorrect') + # regions and rectangles + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_3_1'), 'correct') + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_3_2'), 'correct') + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_3_3'), 'incorrect') + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_3_4'), 'correct') + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_3_5'), 'correct') + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_3_6'), 'incorrect') + self.assertEquals(test_lcp.grade_answers(test_answers).get_correctness('1_3_7'), 'correct') + class SymbolicResponseTest(unittest.TestCase): def test_sr_grade(self): From adef5d6f7eb1af0f12fdfc543d3822ad91253cad Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Tue, 27 Nov 2012 14:11:11 +0200 Subject: [PATCH 10/13] polygon is created from points via convex_hull --- common/lib/capa/capa/responsetypes.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index aeabacef59..ae5d764568 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -23,7 +23,7 @@ import abc import os import subprocess import xml.sax.saxutils as saxutils -from shapely.geometry import Polygon, Point +from shapely.geometry import Point, MultiPoint # specific library imports from calc import evaluator, UndefinedVariable @@ -1796,16 +1796,20 @@ class ImageResponse(LoncapaResponse): break # import ipdb; ipdb.set_trace() if correct_map[aid]['correctness'] != 'correct' and regions[aid]: - import ipdb; ipdb.set_trace() + # import ipdb; ipdb.set_trace() parsed_region = json.loads(regions[aid]) if parsed_region: if type(parsed_region[0][0]) != list: - # we have [[1,2],[3,4],[5,6] - single region - # instead of [[[1,2],[3,4],[5,6], [[1,2],[3,4],[5,6]] - # or [[[1,2],[3,4],[5,6]] - multiple regions syntax + # we have [[1,2],[3,4],[5,6]] - single region + # instead of [[[1,2],[3,4],[5,6], [[1,2],[3,4],[5,6]]] + # or [[[1,2],[3,4],[5,6]]] - multiple regions syntax parsed_region = [parsed_region] + # if aid =='1_3_6': + # import ipdb; ipdb.set_trace() for region in parsed_region: - if Polygon(region).contains(Point(gx, gy)): + polygon = MultiPoint(region).convex_hull + if (polygon.type == 'Polygon' and + polygon.contains(Point(gx, gy))): correct_map.set(aid, 'correct') break return correct_map From 896e922858adfbda5e3117186d154292c1865103 Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Tue, 27 Nov 2012 14:27:19 +0200 Subject: [PATCH 11/13] cleaning and documeting --- common/lib/capa/capa/responsetypes.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index ae5d764568..20e7c43577 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1726,10 +1726,14 @@ class ImageResponse(LoncapaResponse): + regions="[[[10,10], [20,30], [40, 10]], [[100,100], [120,130], [110,150]]]"/> Regions is list of lists [region1, region2, region3, ...] where regionN - is ordered list of points: [[1,1], [100,100], [50,50], [20, 70]]. + is disordered list of points: [[1,1], [100,100], [50,50], [20, 70]]. + + If there is only one region in the list, simpler notation can be used: + regions="[[10,10], [30,30], [10, 30], [30, 10]]" (without explicitly + setting outer list) Returns: True, if click is inside any region or rectangle. Otherwise False. @@ -1743,9 +1747,9 @@ class ImageResponse(LoncapaResponse): rectangle="(10,10)-(20,30);(12,12)-(40,60)" /> + regions="[[[10,10], [20,30], [40, 10]], [[100,100], [120,130], [110,150]]]"/> + regions="[[[10,10], [20,30], [40, 10]], [[100,100], [120,130], [110,150]]]"/>
'''}] response_tag = 'imageresponse' @@ -1758,16 +1762,12 @@ class ImageResponse(LoncapaResponse): def get_score(self, student_answers): correct_map = CorrectMap() expectedset = self.get_answers() - # import ipdb; ipdb.set_trace() for aid in self.answer_ids: # loop through IDs of # fields in our stanza - # import ipdb; ipdb.set_trace() given = student_answers[aid] # this should be a string of the form '[x,y]' - correct_map.set(aid, 'incorrect') if not given: # No answer to parse. Mark as incorrect and move on continue - # parse given answer m = re.match('\[([0-9]+),([0-9]+)]', given.strip().replace(' ', '')) if not m: @@ -1794,9 +1794,7 @@ class ImageResponse(LoncapaResponse): if (llx <= gx <= urx) and (lly <= gy <= ury): correct_map.set(aid, 'correct') break - # import ipdb; ipdb.set_trace() if correct_map[aid]['correctness'] != 'correct' and regions[aid]: - # import ipdb; ipdb.set_trace() parsed_region = json.loads(regions[aid]) if parsed_region: if type(parsed_region[0][0]) != list: @@ -1804,8 +1802,6 @@ class ImageResponse(LoncapaResponse): # instead of [[[1,2],[3,4],[5,6], [[1,2],[3,4],[5,6]]] # or [[[1,2],[3,4],[5,6]]] - multiple regions syntax parsed_region = [parsed_region] - # if aid =='1_3_6': - # import ipdb; ipdb.set_trace() for region in parsed_region: polygon = MultiPoint(region).convex_hull if (polygon.type == 'Polygon' and From 95151ad33a6deabba01c9b1cfab7acd789a2537c Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Tue, 27 Nov 2012 14:27:44 +0200 Subject: [PATCH 12/13] tests updates for imageresponse --- .../capa/tests/test_files/imageresponse.xml | 4 ++-- .../lib/capa/capa/tests/test_responsetypes.py | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/common/lib/capa/capa/tests/test_files/imageresponse.xml b/common/lib/capa/capa/tests/test_files/imageresponse.xml index c4590b211f..41c9f01218 100644 --- a/common/lib/capa/capa/tests/test_files/imageresponse.xml +++ b/common/lib/capa/capa/tests/test_files/imageresponse.xml @@ -22,14 +22,14 @@ Hello

- + Click on either of the two positions as discussed previously. Click on either of the two positions as discussed previously. - + Click on either of the two positions as discussed previously.

Use conservation of energy.

diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index 3564ad3fe8..be734bdb88 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -54,18 +54,20 @@ class ImageResponseTest(unittest.TestCase): test_lcp = lcp.LoncapaProblem(open(imageresponse_file).read(), '1', system=test_system) # testing regions only correct_answers = { - #regions - '1_2_1': '(490,11)-(556,98)', + #regions + '1_2_1': '(490,11)-(556,98)', '1_2_2': '(242,202)-(296,276)', '1_2_3': '(490,11)-(556,98);(242,202)-(296,276)', '1_2_4': '(490,11)-(556,98);(242,202)-(296,276)', '1_2_5': '(490,11)-(556,98);(242,202)-(296,276)', #testing regions and rectanges - '1_3_1': '(490,11)-(556,98)', - '1_3_2': '(242,202)-(296,276)', - '1_3_3': '(490,11)-(556,98);(242,202)-(296,276)', - '1_3_4': '(490,11)-(556,98);(242,202)-(296,276)', - '1_3_5': '(490,11)-(556,98);(242,202)-(296,276)', + '1_3_1': 'rectangle="(490,11)-(556,98)" regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', + '1_3_2': 'rectangle="(490,11)-(556,98)" regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', + '1_3_3': 'regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', + '1_3_4': 'regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', + '1_3_5': 'regions="[[[10,10], [20,10], [20, 30]]]"', + '1_3_6': 'regions="[[10,10], [30,30], [15, 15]]"', + '1_3_7': 'regions="[[10,10], [30,30], [10, 30], [30, 10]]"', } test_answers = {'1_2_1': '[500,20]', '1_2_2': '[250,300]', @@ -79,7 +81,7 @@ class ImageResponseTest(unittest.TestCase): '1_3_4': '[115,115]', '1_3_5': '[15,15]', '1_3_6': '[20,20]', - '1_3_7': '[20,20]', + '1_3_7': '[20,15]', } # regions From b0a85fde540941be127f317cd4f131ecbbdc4ddb Mon Sep 17 00:00:00 2001 From: Alexander Kryklia Date: Tue, 27 Nov 2012 14:29:04 +0200 Subject: [PATCH 13/13] fix line widths --- .../lib/capa/capa/tests/test_responsetypes.py | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index be734bdb88..9eecef3986 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -54,34 +54,37 @@ class ImageResponseTest(unittest.TestCase): test_lcp = lcp.LoncapaProblem(open(imageresponse_file).read(), '1', system=test_system) # testing regions only correct_answers = { - #regions - '1_2_1': '(490,11)-(556,98)', - '1_2_2': '(242,202)-(296,276)', - '1_2_3': '(490,11)-(556,98);(242,202)-(296,276)', - '1_2_4': '(490,11)-(556,98);(242,202)-(296,276)', - '1_2_5': '(490,11)-(556,98);(242,202)-(296,276)', - #testing regions and rectanges - '1_3_1': 'rectangle="(490,11)-(556,98)" regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', - '1_3_2': 'rectangle="(490,11)-(556,98)" regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', - '1_3_3': 'regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', - '1_3_4': 'regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', - '1_3_5': 'regions="[[[10,10], [20,10], [20, 30]]]"', - '1_3_6': 'regions="[[10,10], [30,30], [15, 15]]"', - '1_3_7': 'regions="[[10,10], [30,30], [10, 30], [30, 10]]"', + #regions + '1_2_1': '(490,11)-(556,98)', + '1_2_2': '(242,202)-(296,276)', + '1_2_3': '(490,11)-(556,98);(242,202)-(296,276)', + '1_2_4': '(490,11)-(556,98);(242,202)-(296,276)', + '1_2_5': '(490,11)-(556,98);(242,202)-(296,276)', + #testing regions and rectanges + '1_3_1': 'rectangle="(490,11)-(556,98)" \ + regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', + '1_3_2': 'rectangle="(490,11)-(556,98)" \ + regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', + '1_3_3': 'regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', + '1_3_4': 'regions="[[[10,10], [20,10], [20, 30]], [[100,100], [120,100], [120,150]]]"', + '1_3_5': 'regions="[[[10,10], [20,10], [20, 30]]]"', + '1_3_6': 'regions="[[10,10], [30,30], [15, 15]]"', + '1_3_7': 'regions="[[10,10], [30,30], [10, 30], [30, 10]]"', } - test_answers = {'1_2_1': '[500,20]', - '1_2_2': '[250,300]', - '1_2_3': '[500,20]', - '1_2_4': '[250,250]', - '1_2_5': '[10,10]', + test_answers = { + '1_2_1': '[500,20]', + '1_2_2': '[250,300]', + '1_2_3': '[500,20]', + '1_2_4': '[250,250]', + '1_2_5': '[10,10]', - '1_3_1': '[500,20]', - '1_3_2': '[15,15]', - '1_3_3': '[500,20]', - '1_3_4': '[115,115]', - '1_3_5': '[15,15]', - '1_3_6': '[20,20]', - '1_3_7': '[20,15]', + '1_3_1': '[500,20]', + '1_3_2': '[15,15]', + '1_3_3': '[500,20]', + '1_3_4': '[115,115]', + '1_3_5': '[15,15]', + '1_3_6': '[20,20]', + '1_3_7': '[20,15]', } # regions