Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
E
edx-platform-release
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
1
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Package Registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Hsin-Yu Chien
edx-platform-release
Commits
0725e776
Unverified
Commit
0725e776
authored
7 years ago
by
Ned Batchelder
Committed by
GitHub
7 years ago
Browse files
Options
Downloads
Plain Diff
Merge pull request #17372 from mitodl/pdpinch/catch-mismated-parens
Add mismatched parenthesis detection to formula parsing
parents
312f5a44
ed90c80c
Loading
Loading
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
common/lib/calc/calc/calc.py
+32
-0
32 additions, 0 deletions
common/lib/calc/calc/calc.py
common/lib/calc/calc/tests/test_calc.py
+9
-0
9 additions, 0 deletions
common/lib/calc/calc/tests/test_calc.py
common/lib/capa/capa/responsetypes.py
+14
-2
14 additions, 2 deletions
common/lib/capa/capa/responsetypes.py
with
55 additions
and
2 deletions
common/lib/calc/calc/calc.py
+
32
−
0
View file @
0725e776
...
...
@@ -100,6 +100,13 @@ class UndefinedVariable(Exception):
pass
class
UnmatchedParenthesis
(
Exception
):
"""
Indicate when a student inputs a formula with mismatched parentheses.
"""
pass
def
lower_dict
(
input_dict
):
"""
Convert all keys in a dictionary to lowercase; keep their original values.
...
...
@@ -249,6 +256,7 @@ def evaluator(variables, functions, math_expr, case_sensitive=False):
return
float
(
'
nan
'
)
# Parse the tree.
check_parens
(
math_expr
)
math_interpreter
=
ParseAugmenter
(
math_expr
,
case_sensitive
)
math_interpreter
.
parse_algebra
()
...
...
@@ -278,6 +286,30 @@ def evaluator(variables, functions, math_expr, case_sensitive=False):
return
math_interpreter
.
reduce_tree
(
evaluate_actions
)
def
check_parens
(
formula
):
"""
Check that any open parentheses are closed
Otherwise, raise an UnmatchedParenthesis exception
"""
count
=
0
delta
=
{
'
(
'
:
+
1
,
'
)
'
:
-
1
}
for
index
,
char
in
enumerate
(
formula
):
if
char
in
delta
:
count
+=
delta
[
char
]
if
count
<
0
:
msg
=
"
Invalid Input: A closing parenthesis was found after segment
"
+
\
"
{}, but there is no matching opening parenthesis before it.
"
raise
UnmatchedParenthesis
(
msg
.
format
(
formula
[
0
:
index
]))
if
count
>
0
:
msg
=
"
Invalid Input: Parentheses are unmatched.
"
+
\
"
{} parentheses were opened but never closed.
"
raise
UnmatchedParenthesis
(
msg
.
format
(
count
))
class
ParseAugmenter
(
object
):
"""
Holds the data for a particular parse.
...
...
This diff is collapsed.
Click to expand it.
common/lib/calc/calc/tests/test_calc.py
+
9
−
0
View file @
0725e776
...
...
@@ -554,3 +554,12 @@ class EvaluatorTest(unittest.TestCase):
calc
.
evaluator
({
'
r1
'
:
5
},
{},
"
r1+r2
"
)
with
self
.
assertRaisesRegexp
(
calc
.
UndefinedVariable
,
'
r1 r3
'
):
calc
.
evaluator
(
variables
,
{},
"
r1*r3
"
,
case_sensitive
=
True
)
def
test_mismatched_parens
(
self
):
"""
Check to see if the evaluator catches mismatched parens
"""
with
self
.
assertRaisesRegexp
(
calc
.
UnmatchedParenthesis
,
'
opened but never closed
'
):
calc
.
evaluator
({},
{},
"
(1+2
"
)
with
self
.
assertRaisesRegexp
(
calc
.
UnmatchedParenthesis
,
'
no matching opening parenthesis
'
):
calc
.
evaluator
({},
{},
"
(1+2))
"
)
This diff is collapsed.
Click to expand it.
common/lib/capa/capa/responsetypes.py
+
14
−
2
View file @
0725e776
...
...
@@ -40,7 +40,7 @@ import capa.safe_exec as safe_exec
import
capa.xqueue_interface
as
xqueue_interface
import
dogstats_wrapper
as
dog_stats_api
# specific library imports
from
calc
import
UndefinedVariable
,
evaluator
from
calc
import
UndefinedVariable
,
UnmatchedParenthesis
,
evaluator
from
cmath
import
isnan
from
openedx.core.djangolib.markup
import
HTML
,
Text
...
...
@@ -1604,6 +1604,10 @@ class NumericalResponse(LoncapaResponse):
bad_variables
=
text_type
(
undef_var
),
)
)
except
UnmatchedParenthesis
as
err
:
raise
StudentInputError
(
err
.
args
[
0
]
)
except
ValueError
as
val_err
:
if
'
factorial
'
in
text_type
(
val_err
):
# This is thrown when fact() or factorial() is used in an answer
...
...
@@ -1770,7 +1774,7 @@ class NumericalResponse(LoncapaResponse):
try
:
evaluator
(
dict
(),
dict
(),
answer
)
return
True
except
(
StudentInputError
,
UndefinedVariable
):
except
(
StudentInputError
,
UndefinedVariable
,
UnmatchedParenthesis
):
return
False
def
get_answers
(
self
):
...
...
@@ -3108,6 +3112,14 @@ class FormulaResponse(LoncapaResponse):
raise
StudentInputError
(
_
(
"
Invalid input: {bad_input} not permitted in answer.
"
).
format
(
bad_input
=
text_type
(
err
))
)
except
UnmatchedParenthesis
as
err
:
log
.
debug
(
'
formularesponse: unmatched parenthesis in formula=%s
'
,
cgi
.
escape
(
answer
)
)
raise
StudentInputError
(
err
.
args
[
0
]
)
except
ValueError
as
err
:
if
'
factorial
'
in
text_type
(
err
):
# This is thrown when fact() or factorial() is used in a formularesponse answer
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment