CAT-SOOP is a flexible, programmable learning management system based on the Python programming language. https://catsoop.mit.edu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

136 lines
4.1 KiB

  1. # This file is part of CAT-SOOP
  2. # Copyright (c) 2011-2017 Adam Hartz <hartz@mit.edu>
  3. #
  4. # This program is free software: you can redistribute it and/or modify it under
  5. # the terms of the GNU Affero General Public License as published by the Free
  6. # Software Foundation, either version 3 of the License, or (at your option) any
  7. # later version.
  8. #
  9. # This program is distributed in the hope that it will be useful, but WITHOUT
  10. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  12. # details.
  13. #
  14. # You should have received a copy of the GNU Affero General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. import ast
  17. import collections.abc
  18. import traceback
  19. tutor.qtype_inherit('smallbox')
  20. base1, _ = tutor.question('pythoncode')
  21. defaults.update({
  22. 'csq_soln': '',
  23. 'csq_check_function': lambda sub, soln: ((type(sub) == type(soln)) and
  24. (sub == soln)),
  25. 'csq_input_check': lambda sub: None,
  26. 'csq_npoints': 1,
  27. 'csq_msg_function': lambda sub, soln: '',
  28. 'csq_show_check': False,
  29. 'csq_code_pre': '',
  30. 'csq_mode': 'raw',
  31. 'csq_size': 50
  32. })
  33. def gensym(code=''):
  34. pre = n = '___'
  35. count = 0
  36. while n in code:
  37. n = '%s%s' % (pre, count)
  38. count += 1
  39. return n
  40. def handle_submission(submissions, **info):
  41. py3k = info.get('csq_python3', True)
  42. sub = submissions[info['csq_name']]
  43. inp = info['csq_input_check'](sub)
  44. if inp is not None:
  45. return {'score': 0.0, 'msg': '<font color="red">%s</font>' % inp}
  46. base1['get_sandbox'](info)
  47. if info['csq_mode'] == 'raw':
  48. soln = info['csq_soln']
  49. else:
  50. code = info['csq_code_pre']
  51. s = info['csq_soln']
  52. varname = gensym(code + s)
  53. code += '\n%s = %s' % (varname, s)
  54. if py3k:
  55. code += '\nprint(repr(%s))' % varname
  56. else:
  57. code += '\nprint repr(%s)' % varname
  58. opts = info.get('csq_options', {})
  59. soln = eval(info['sandbox_run_code'](info, code, opts)[1], info)
  60. try:
  61. code = info['csq_code_pre']
  62. if sub == '':
  63. return {'score': 0.0, 'msg': ''}
  64. varname = gensym(code + sub)
  65. code += '\n%s = %s' % (varname, sub)
  66. if py3k:
  67. code += '\nprint(repr(%s))' % varname
  68. else:
  69. code += '\nprint repr(%s)' % varname
  70. opts = info.get('csq_options', {})
  71. fname, out, err = info['sandbox_run_code'](info, code, opts)
  72. sub = eval(out, info)
  73. except:
  74. msg = ''
  75. mfunc = info['csq_msg_function']
  76. try:
  77. msg += mfunc(sub, soln)
  78. except:
  79. try:
  80. msg += mfunc(sub)
  81. except:
  82. pass
  83. return {'score': 0.0,
  84. 'msg': msg}
  85. check = info['csq_check_function']
  86. try:
  87. check_result = check(sub, soln)
  88. except:
  89. err = info['csm_errors']
  90. e = err.html_format(err.clear_info(info, traceback.format_exc()))
  91. check_result = (0.0, '<font color="red">An error occurred in the checker: <pre>%s</pre></font>' % e)
  92. if isinstance(check_result, collections.abc.Mapping):
  93. score = check_result['score']
  94. msg = check_result['msg']
  95. elif isinstance(check_result, collections.abc.Sequence):
  96. score, msg = check_result
  97. else:
  98. score = check_result
  99. mfunc = info['csq_msg_function']
  100. try:
  101. msg = mfunc(sub, soln)
  102. except:
  103. try:
  104. msg = mfunc(sub)
  105. except:
  106. msg = ''
  107. percent = float(score)
  108. response = ''
  109. if info['csq_show_check']:
  110. if percent == 1.0:
  111. response = '<img src="BASE/images/check.png" />'
  112. elif percent == 0.0:
  113. response = '<img src="BASE/images/cross.png" />'
  114. response += msg
  115. return {'score': percent, 'msg': response}
  116. def answer_display(**info):
  117. if info['csq_mode'] == 'raw':
  118. out = "<p>Solution: <tt>%r</tt><p>" % (info['csq_soln'], )
  119. else:
  120. out = "<p>Solution: <tt>%s</tt><p>" % (info['csq_soln'], )
  121. return out