Best Python code snippet using pytest
test_util_open_ended.py
Source:test_util_open_ended.py  
1import json2from textwrap import dedent3from xmodule.modulestore.xml import XMLModuleStore4from xmodule.tests import DATA_DIR, get_test_system5from StringIO import StringIO6OPEN_ENDED_GRADING_INTERFACE = {7    'url': 'blah/',8    'username': 'incorrect',9    'password': 'incorrect',10    'staff_grading': 'staff_grading',11    'peer_grading': 'peer_grading',12    'grading_controller': 'grading_controller'13}14S3_INTERFACE = {15    'access_key': "",16    'secret_access_key': "",17    "storage_bucket_name": "",18}19class MockS3Key(object):20    """21    Mock an S3 Key object from boto.  Used for file upload testing.22    """23    def __init__(self, bucket):24        pass25    def set_metadata(self, key, value):26        setattr(self, key, value)27    def set_contents_from_file(self, fileobject):28        self.data = fileobject.read()29    def set_acl(self, acl):30        self.set_metadata("acl", acl)31    def generate_url(self, timeout):32        return "http://www.edx.org/sample_url"33class MockS3Connection(object):34    """35    Mock boto S3Connection for testing image uploads.36    """37    def __init__(self, access_key, secret_key, **kwargs):38        """39        Mock the init call.  S3Connection has a lot of arguments, but we don't need them.40        """41        pass42    def create_bucket(self, bucket_name, **kwargs):43        return "edX Bucket"44    def lookup(self, bucket_name):45        return None46class MockUploadedFile(object):47    """48    Create a mock uploaded file for image submission tests.49    value - String data to place into the mock file.50    return - A StringIO object that behaves like a file.51    """52    def __init__(self, name, value):53        self.mock_file = StringIO()54        self.mock_file.write(value)55        self.name = name56    def seek(self, index):57        return self.mock_file.seek(index)58    def read(self):59        return self.mock_file.read()60class DummyModulestore(object):61    """62    A mixin that allows test classes to have convenience functions to get a module given a location63    """64    def get_module_system(self, descriptor):65        raise NotImplementedError("Sub-tests must specify how to generate a module-system")66    def setup_modulestore(self, name):67        self.modulestore = XMLModuleStore(DATA_DIR, course_dirs=[name])68    def get_course(self, _):69        """Get a test course by directory name.  If there's more than one, error."""70        courses = self.modulestore.get_courses()71        return courses[0]72    def get_module_from_location(self, usage_key):73        descriptor = self.modulestore.get_item(usage_key, depth=None)74        descriptor.xmodule_runtime = self.get_module_system(descriptor)75        return descriptor76def serialize_child_history(task_state):77    """78    To json serialize feedback and post_assessment in child_history of task state.79    """80    child_history = task_state.get("child_history", [])81    for i, attempt in enumerate(child_history):82        if "post_assessment" in attempt:83            if "feedback" in attempt["post_assessment"]:84                attempt["post_assessment"]["feedback"] = json.dumps(attempt["post_assessment"].get("feedback"))85            task_state["child_history"][i]["post_assessment"] = json.dumps(attempt["post_assessment"])86def serialize_open_ended_instance_state(json_str):87    """88    To json serialize task_states and old_task_states in instance state.89    """90    json_data = json.loads(json_str)91    task_states = json_data.get('task_states', [])92    for i, task_state in enumerate(task_states):93        serialize_child_history(task_state)94        json_data['task_states'][i] = json.dumps(task_state)95    old_task_states = json_data.get('old_task_states', [])96    for i, old_task in enumerate(old_task_states):97        for j, task_state in enumerate(old_task):98            old_task[j] = json.dumps(task_state)99        json_data['old_task_states'][i] = old_task100    return json.dumps(json_data)101# Task state for a module with self assessment then instructor assessment.102TEST_STATE_SA_IN = ["{\"child_created\": false, \"child_attempts\": 2, \"version\": 1, \"child_history\": [{\"answer\": \"However venture pursuit he am mr cordial. Forming musical am hearing studied be luckily. Ourselves for determine attending how led gentleman sincerity. Valley afford uneasy joy she thrown though bed set. In me forming general prudent on country carried. Behaved an or suppose justice. Seemed whence how son rather easily and change missed. Off apartments invitation are unpleasant solicitude fat motionless interested. Hardly suffer wisdom wishes valley as an. As friendship advantages resolution it alteration stimulated he or increasing. \\r<br><br>Now led tedious shy lasting females off. Dashwood marianne in of entrance be on wondered possible building. Wondered sociable he carriage in speedily margaret. Up devonshire of he thoroughly insensible alteration. An mr settling occasion insisted distance ladyship so. Not attention say frankness intention out dashwoods now curiosity. Stronger ecstatic as no judgment daughter speedily thoughts. Worse downs nor might she court did nay forth these. \", \"post_assessment\": \"[3, 3, 2, 2, 2]\", \"score\": 12}, {\"answer\": \"Delightful remarkably mr on announcing themselves entreaties favourable. About to in so terms voice at. Equal an would is found seems of. The particular friendship one sufficient terminated frequently themselves. It more shed went up is roof if loud case. Delay music in lived noise an. Beyond genius really enough passed is up. \\r<br><br>John draw real poor on call my from. May she mrs furnished discourse extremely. Ask doubt noisy shade guest did built her him. Ignorant repeated hastened it do. Consider bachelor he yourself expenses no. Her itself active giving for expect vulgar months. Discovery commanded fat mrs remaining son she principle middleton neglected. Be miss he in post sons held. No tried is defer do money scale rooms. \", \"post_assessment\": \"[3, 3, 2, 2, 2]\", \"score\": 12}], \"max_score\": 12, \"child_state\": \"done\"}", "{\"child_created\": false, \"child_attempts\": 0, \"version\": 1, \"child_history\": [{\"answer\": \"However venture pursuit he am mr cordial. Forming musical am hearing studied be luckily. Ourselves for determine attending how led gentleman sincerity. Valley afford uneasy joy she thrown though bed set. In me forming general prudent on country carried. Behaved an or suppose justice. Seemed whence how son rather easily and change missed. Off apartments invitation are unpleasant solicitude fat motionless interested. Hardly suffer wisdom wishes valley as an. As friendship advantages resolution it alteration stimulated he or increasing. \\r<br><br>Now led tedious shy lasting females off. Dashwood marianne in of entrance be on wondered possible building. Wondered sociable he carriage in speedily margaret. Up devonshire of he thoroughly insensible alteration. An mr settling occasion insisted distance ladyship so. Not attention say frankness intention out dashwoods now curiosity. Stronger ecstatic as no judgment daughter speedily thoughts. Worse downs nor might she court did nay forth these. \", \"post_assessment\": \"{\\\"submission_id\\\": 1460, \\\"score\\\": 12, \\\"feedback\\\": \\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 5413, \\\"grader_type\\\": \\\"IN\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"<rubric><category><description>\\\\nIdeas\\\\n</description><score>3</score><option points='0'>\\\\nDifficult for the reader to discern the main idea.  Too brief or too repetitive to establish or maintain a focus.\\\\n</option><option points='1'>\\\\nAttempts a main idea.  Sometimes loses focus or ineffectively displays focus.\\\\n</option><option points='2'>\\\\nPresents a unifying theme or main idea, but may include minor tangents.  Stays somewhat focused on topic and task.\\\\n</option><option points='3'>\\\\nPresents a unifying theme or main idea without going off on tangents.  Stays completely focused on topic and task.\\\\n</option></category><category><description>\\\\nContent\\\\n</description><score>3</score><option points='0'>\\\\nIncludes little information with few or no details or unrelated details.  Unsuccessful in attempts to explore any facets of the topic.\\\\n</option><option points='1'>\\\\nIncludes little information and few or no details.  Explores only one or two facets of the topic.\\\\n</option><option points='2'>\\\\nIncludes sufficient information and supporting details. (Details may not be fully developed; ideas may be listed.)  Explores some facets of the topic.\\\\n</option><option points='3'>\\\\nIncludes in-depth information and exceptional supporting details that are fully developed.  Explores all facets of the topic.\\\\n</option></category><category><description>\\\\nOrganization\\\\n</description><score>2</score><option points='0'>\\\\nIdeas organized illogically, transitions weak, and response difficult to follow.\\\\n</option><option points='1'>\\\\nAttempts to logically organize ideas.  Attempts to progress in an order that enhances meaning, and demonstrates use of transitions.\\\\n</option><option points='2'>\\\\nIdeas organized logically.  Progresses in an order that enhances meaning.  Includes smooth transitions.\\\\n</option></category><category><description>\\\\nStyle\\\\n</description><score>2</score><option points='0'>\\\\nContains limited vocabulary, with many words used incorrectly.  Demonstrates problems with sentence patterns.\\\\n</option><option points='1'>\\\\nContains basic vocabulary, with words that are predictable and common.  Contains mostly simple sentences (although there may be an attempt at more varied sentence patterns).\\\\n</option><option points='2'>\\\\nIncludes vocabulary to make explanations detailed and precise.  Includes varied sentence patterns, including complex sentences.\\\\n</option></category><category><description>\\\\nVoice\\\\n</description><score>2</score><option points='0'>\\\\nDemonstrates language and tone that may be inappropriate to task and reader.\\\\n</option><option points='1'>\\\\nDemonstrates an attempt to adjust language and tone to task and reader.\\\\n</option><option points='2'>\\\\nDemonstrates effective adjustment of language and tone to task and reader.\\\\n</option></category></rubric>\\\"}\", \"score\": 12}, {\"answer\": \"Delightful remarkably mr on announcing themselves entreaties favourable. About to in so terms voice at. Equal an would is found seems of. The particular friendship one sufficient terminated frequently themselves. It more shed went up is roof if loud case. Delay music in lived noise an. Beyond genius really enough passed is up. \\r<br><br>John draw real poor on call my from. May she mrs furnished discourse extremely. Ask doubt noisy shade guest did built her him. Ignorant repeated hastened it do. Consider bachelor he yourself expenses no. Her itself active giving for expect vulgar months. Discovery commanded fat mrs remaining son she principle middleton neglected. Be miss he in post sons held. No tried is defer do money scale rooms. \", \"post_assessment\": \"{\\\"submission_id\\\": 1462, \\\"score\\\": 12, \\\"feedback\\\": \\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 5418, \\\"grader_type\\\": \\\"IN\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"<rubric><category><description>\\\\nIdeas\\\\n</description><score>3</score><option points='0'>\\\\nDifficult for the reader to discern the main idea.  Too brief or too repetitive to establish or maintain a focus.\\\\n</option><option points='1'>\\\\nAttempts a main idea.  Sometimes loses focus or ineffectively displays focus.\\\\n</option><option points='2'>\\\\nPresents a unifying theme or main idea, but may include minor tangents.  Stays somewhat focused on topic and task.\\\\n</option><option points='3'>\\\\nPresents a unifying theme or main idea without going off on tangents.  Stays completely focused on topic and task.\\\\n</option></category><category><description>\\\\nContent\\\\n</description><score>3</score><option points='0'>\\\\nIncludes little information with few or no details or unrelated details.  Unsuccessful in attempts to explore any facets of the topic.\\\\n</option><option points='1'>\\\\nIncludes little information and few or no details.  Explores only one or two facets of the topic.\\\\n</option><option points='2'>\\\\nIncludes sufficient information and supporting details. (Details may not be fully developed; ideas may be listed.)  Explores some facets of the topic.\\\\n</option><option points='3'>\\\\nIncludes in-depth information and exceptional supporting details that are fully developed.  Explores all facets of the topic.\\\\n</option></category><category><description>\\\\nOrganization\\\\n</description><score>2</score><option points='0'>\\\\nIdeas organized illogically, transitions weak, and response difficult to follow.\\\\n</option><option points='1'>\\\\nAttempts to logically organize ideas.  Attempts to progress in an order that enhances meaning, and demonstrates use of transitions.\\\\n</option><option points='2'>\\\\nIdeas organized logically.  Progresses in an order that enhances meaning.  Includes smooth transitions.\\\\n</option></category><category><description>\\\\nStyle\\\\n</description><score>2</score><option points='0'>\\\\nContains limited vocabulary, with many words used incorrectly.  Demonstrates problems with sentence patterns.\\\\n</option><option points='1'>\\\\nContains basic vocabulary, with words that are predictable and common.  Contains mostly simple sentences (although there may be an attempt at more varied sentence patterns).\\\\n</option><option points='2'>\\\\nIncludes vocabulary to make explanations detailed and precise.  Includes varied sentence patterns, including complex sentences.\\\\n</option></category><category><description>\\\\nVoice\\\\n</description><score>2</score><option points='0'>\\\\nDemonstrates language and tone that may be inappropriate to task and reader.\\\\n</option><option points='1'>\\\\nDemonstrates an attempt to adjust language and tone to task and reader.\\\\n</option><option points='2'>\\\\nDemonstrates effective adjustment of language and tone to task and reader.\\\\n</option></category></rubric>\\\"}\", \"score\": 12}], \"max_score\": 12, \"child_state\": \"post_assessment\"}"]103# Mock instance state.  Should receive a score of 15.104MOCK_INSTANCE_STATE = r"""{"ready_to_reset": false, "skip_spelling_checks": true, "current_task_number": 1, "weight": 5.0, "graceperiod": "1 day 12 hours 59 minutes 59 seconds", "graded": "True", "task_states": ["{\"child_created\": false, \"child_attempts\": 4, \"version\": 1, \"child_history\": [{\"answer\": \"After 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"To replicate the experiment, the procedure would require more detail. One piece of information that is omitted is the amount of vinegar used in the experiment. It is also important to know what temperature the experiment was kept at during the 24 hours. Finally, the procedure needs to include details about the experiment, for example if the whole sample must be submerged.\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"e the mass of four different samples.\\r\\nPour vinegar in each of four separate, but identical, containers.\\r\\nPlace a sample of one material into one container and label. Repeat with remaining samples, placing a single sample into a single container.\\r\\nAfter 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\", \"post_assessment\": \"[3]\", \"score\": 3}, {\"answer\": \"\", \"post_assessment\": \"[3]\", \"score\": 3}], \"max_score\": 3, \"child_state\": \"done\"}", "{\"child_created\": false, \"child_attempts\": 0, \"version\": 1, \"child_history\": [{\"answer\": \"The students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the group\\u2019s procedure, describe what additional information you would need in order to replicate the expe\", \"post_assessment\": \"{\\\"submission_id\\\": 3097, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: More grammar errors than average.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"the students data are recorded in the <bg>table below . starting mass</bg> g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the groups <bg>procedure , describe what additional</bg> information you would need in order to replicate the <bs>expe</bs>\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3233, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"<rubric><category><description>Response Quality</description><score>0</score><option points='0'>The response is not a satisfactory answer to the question.  It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option><option points='1'>The response is a marginal answer to the question.  It may contain some elements of a proficient response, but it is inaccurate or incomplete.</option><option points='2'>The response is a proficient answer to the question.  It is generally correct, although it may contain minor inaccuracies.  There is limited evidence of higher-order thinking.</option><option points='3'>The response is correct, complete, and contains evidence of higher-order thinking.</option></category></rubric>\\\"}\", \"score\": 0}, {\"answer\": \"After 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\\r\\nStarting Mass (g)\\tEnding Mass (g)\\tDifference in Mass (g)\\r\\nMarble\\t 9.8\\t 9.4\\t\\u20130.4\\r\\nLimestone\\t10.4\\t 9.1\\t\\u20131.3\\r\\nWood\\t11.2\\t11.2\\t 0.0\\r\\nPlastic\\t 7.2\\t 7.1\\t\\u20130.1\\r\\nAfter reading the\", \"post_assessment\": \"{\\\"submission_id\\\": 3098, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"after hours , remove the samples from the containers and rinse each sample with distilled water . allow the samples to sit and dry for minutes . determine the mass of each sample . the students data are recorded in the <bg>table below . starting mass</bg> g ending mass g difference in mass g marble . . . limestone . . . wood . . . plastic . . . after reading the\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3235, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"<rubric><category><description>Response Quality</description><score>0</score><option points='0'>The response is not a satisfactory answer to the question.  It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option><option points='1'>The response is a marginal answer to the question.  It may contain some elements of a proficient response, but it is inaccurate or incomplete.</option><option points='2'>The response is a proficient answer to the question.  It is generally correct, although it may contain minor inaccuracies.  There is limited evidence of higher-order thinking.</option><option points='3'>The response is correct, complete, and contains evidence of higher-order thinking.</option></category></rubric>\\\"}\", \"score\": 0}, {\"answer\": \"To replicate the experiment, the procedure would require more detail. One piece of information that is omitted is the amount of vinegar used in the experiment. It is also important to know what temperature the experiment was kept at during the 24 hours. Finally, the procedure needs to include details about the experiment, for example if the whole sample must be submerged.\", \"post_assessment\": \"{\\\"submission_id\\\": 3099, \\\"score\\\": 3, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"to replicate the experiment , the procedure would require <bg>more detail . one</bg> piece of information <bg>that is omitted is the</bg> amount of vinegar used in the experiment . it is also important to know what temperature the experiment was kept at during the hours . finally , the procedure needs to include details about the experiment , for example if the whole sample must be submerged .\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3237, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"<rubric><category><description>Response Quality</description><score>3</score><option points='0'>The response is not a satisfactory answer to the question.  It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option><option points='1'>The response is a marginal answer to the question.  It may contain some elements of a proficient response, but it is inaccurate or incomplete.</option><option points='2'>The response is a proficient answer to the question.  It is generally correct, although it may contain minor inaccuracies.  There is limited evidence of higher-order thinking.</option><option points='3'>The response is correct, complete, and contains evidence of higher-order thinking.</option></category></rubric>\\\"}\", \"score\": 3}, {\"answer\": \"e the mass of four different samples.\\r\\nPour vinegar in each of four separate, but identical, containers.\\r\\nPlace a sample of one material into one container and label. Repeat with remaining samples, placing a single sample into a single container.\\r\\nAfter 24 hours, remove the samples from the containers and rinse each sample with distilled water.\\r\\nAllow the samples to sit and dry for 30 minutes.\\r\\nDetermine the mass of each sample.\\r\\nThe students\\u2019 data are recorded in the table below.\\r\\n\", \"post_assessment\": \"{\\\"submission_id\\\": 3100, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"e the mass of four different samples . pour vinegar in <bg>each of four separate</bg> , but identical , containers . place a sample of one material into one container and label . repeat with remaining samples , placing a single sample into a single container . after hours , remove the samples from the containers and rinse each sample with distilled water . allow the samples to sit and dry for minutes . determine the mass of each sample . the students data are recorded in the table below . \\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3239, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"<rubric><category><description>Response Quality</description><score>0</score><option points='0'>The response is not a satisfactory answer to the question.  It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option><option points='1'>The response is a marginal answer to the question.  It may contain some elements of a proficient response, but it is inaccurate or incomplete.</option><option points='2'>The response is a proficient answer to the question.  It is generally correct, although it may contain minor inaccuracies.  There is limited evidence of higher-order thinking.</option><option points='3'>The response is correct, complete, and contains evidence of higher-order thinking.</option></category></rubric>\\\"}\", \"score\": 0}, {\"answer\": \"\", \"post_assessment\": \"{\\\"submission_id\\\": 3101, \\\"score\\\": 0, \\\"feedback\\\": \\\"{\\\\\\\"spelling\\\\\\\": \\\\\\\"Spelling: Ok.\\\\\\\", \\\\\\\"grammar\\\\\\\": \\\\\\\"Grammar: Ok.\\\\\\\", \\\\\\\"markup-text\\\\\\\": \\\\\\\"invalid essay .\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 3241, \\\"grader_type\\\": \\\"ML\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"<rubric><category><description>Response Quality</description><score>0</score><option points='0'>The response is not a satisfactory answer to the question.  It either fails to address the question or does so in a limited way, with no evidence of higher-order thinking.</option><option points='1'>The response is a marginal answer to the question.  It may contain some elements of a proficient response, but it is inaccurate or incomplete.</option><option points='2'>The response is a proficient answer to the question.  It is generally correct, although it may contain minor inaccuracies.  There is limited evidence of higher-order thinking.</option><option points='3'>The response is correct, complete, and contains evidence of higher-order thinking.</option></category></rubric>\\\"}\", \"score\": 0}], \"max_score\": 3, \"child_state\": \"done\"}"], "attempts": "10000", "student_attempts": 0, "due": null, "state": "done", "accept_file_upload": false, "display_name": "Science Question -- Machine Assessed"}"""105# Instance state. To test the rubric scores are consistent. Should receive a score of 15.106INSTANCE_INCONSISTENT_STATE = serialize_open_ended_instance_state("""107{ "accept_file_upload" : false,108  "attempts" : "10000",109  "current_task_number" : 1,110  "display_name" : "Science Question -- Machine Assessed",111  "due" : null,112  "graceperiod" : "1 day 12 hours 59 minutes 59 seconds",113  "graded" : "True",114  "ready_to_reset" : false,115  "skip_spelling_checks" : true,116  "state" : "done",117  "student_attempts" : 0,118  "task_states" : [ { "child_attempts" : 4,119        "child_created" : false,120        "child_history" : [ { "answer" : "Student answer 1st attempt.",121              "post_assessment" : [ 3 ],122              "score" : 1123            },124            { "answer" : "Student answer 2nd attempt.",125              "post_assessment" : [ 3 ],126              "score" : 1127            },128            { "answer" : "Student answer 3rd attempt.",129              "post_assessment" : [ 3 ],130              "score" : 1131            },132            { "answer" : "",133              "post_assessment" : [ 3 ],134              "score" : 1135            }136          ],137        "child_state" : "done",138        "max_score" : 3,139        "version" : 1140      },141      { "child_attempts" : 0,142        "child_created" : false,143        "child_history" : [ { "answer" : "Student answer 1st attempt.",144              "post_assessment" : { "feedback" : { "grammar" : "Grammar: More grammar errors than average.",145                      "markup-text" : "valid essay",146                      "spelling" : "Spelling: Ok."147                    },148                  "grader_id" : 3233,149                  "grader_type" : "ML",150                  "rubric_scores_complete" : true,151                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",152                  "score" : 0,153                  "submission_id" : 3097,154                  "success" : true155                },156              "score" : 0157            },158            { "answer" : "Student answer 2nd attempt.",159              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",160                      "markup-text" : "valid essay",161                      "spelling" : "Spelling: Ok."162                    },163                  "grader_id" : 3235,164                  "grader_type" : "ML",165                  "rubric_scores_complete" : true,166                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",167                  "score" : 0,168                  "submission_id" : 3098,169                  "success" : true170                },171              "score" : 0172            },173            { "answer" : "Student answer 3rd attempt.",174              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",175                      "markup-text" : "valid essay",176                      "spelling" : "Spelling: Ok."177                    },178                  "grader_id" : 3237,179                  "grader_type" : "ML",180                  "rubric_scores_complete" : true,181                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>3</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",182                  "score" : 2,183                  "submission_id" : 3099,184                  "success" : true185                },186              "score" : 2187            },188            { "answer" : "Student answer 4th attempt.",189              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",190                      "markup-text" : "valid essay",191                      "spelling" : "Spelling: Ok."192                    },193                  "grader_id" : 3239,194                  "grader_type" : "ML",195                  "rubric_scores_complete" : true,196                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",197                  "score" : 0,198                  "submission_id" : 3100,199                  "success" : true200                },201              "score" : 0202            },203            { "answer" : "",204              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",205                      "markup-text" : "invalid essay .",206                      "spelling" : "Spelling: Ok."207                    },208                  "grader_id" : 3241,209                  "grader_type" : "ML",210                  "rubric_scores_complete" : true,211                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",212                  "score" : 0,213                  "submission_id" : 3101,214                  "success" : true215                },216              "score" : 0217            }218          ],219        "child_state" : "done",220        "max_score" : 3,221        "version" : 1222      }223    ],224  "weight" : 5.0225}226    """)227# Instance state. Should receive a score of 10 if grader type is PE.228INSTANCE_INCONSISTENT_STATE2 = serialize_open_ended_instance_state("""229{ "accept_file_upload" : false,230  "attempts" : "10000",231  "current_task_number" : 1,232  "display_name" : "Science Question -- Machine Assessed",233  "due" : null,234  "graceperiod" : "1 day 12 hours 59 minutes 59 seconds",235  "graded" : "True",236  "ready_to_reset" : false,237  "skip_spelling_checks" : true,238  "state" : "done",239  "student_attempts" : 0,240  "task_states" : [ { "child_attempts" : 4,241        "child_created" : false,242        "child_history" : [ { "answer" : "Student answer 1st attempt.",243              "post_assessment" : [3],244              "score" : 1245            },246            { "answer" : "Student answer 2nd attempt.",247              "post_assessment" : [3],248              "score" : 1249            },250            { "answer" : "Student answer 3rd attempt.",251              "post_assessment" : [3],252              "score" : 1253            },254            { "answer" : "",255              "post_assessment" : [3],256              "score" : 1257            }258          ],259        "child_state" : "done",260        "max_score" : 3,261        "version" : 1262      },263      { "child_attempts" : 0,264        "child_created" : false,265        "child_history" : [ { "answer" : "Student answer 1st attempt.",266              "post_assessment" : { "feedback" : { "grammar" : "Grammar: More grammar errors than average.",267                      "markup-text" : "valid essay",268                      "spelling" : "Spelling: Ok."269                    },270                  "grader_id" : 3233,271                  "grader_type" : "PE",272                  "rubric_scores_complete" : true,273                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",274                  "score" : 0,275                  "submission_id" : 3097,276                  "success" : true277                },278              "score" : 0279            },280            { "answer" : "Student answer 2nd attempt.",281              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",282                      "markup-text" : "valid essay",283                      "spelling" : "Spelling: Ok."284                    },285                  "grader_id" : 3235,286                  "grader_type" : "PE",287                  "rubric_scores_complete" : true,288                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",289                  "score" : 0,290                  "submission_id" : 3098,291                  "success" : true292                },293              "score" : 0294            },295            { "answer" : "Student answer 3rd attempt.",296              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",297                      "markup-text" : "valid essay",298                      "spelling" : "Spelling: Ok."299                    },300                  "grader_id" : 3237,301                  "grader_type" : "PE",302                  "rubric_scores_complete" : true,303                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>5</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",304                  "score" : 2,305                  "submission_id" : 3099,306                  "success" : true307                },308              "score" : 2309            },310            { "answer" : "Student answer 4th attempt.",311              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",312                      "markup-text" : "valid essay",313                      "spelling" : "Spelling: Ok."314                    },315                  "grader_id" : 3239,316                  "grader_type" : "PE",317                  "rubric_scores_complete" : true,318                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",319                  "score" : 0,320                  "submission_id" : 3100,321                  "success" : true322                },323              "score" : 0324            },325            { "answer" : "",326              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",327                      "markup-text" : "invalid essay .",328                      "spelling" : "Spelling: Ok."329                    },330                  "grader_id" : 3241,331                  "grader_type" : "PE",332                  "rubric_scores_complete" : true,333                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",334                  "score" : 0,335                  "submission_id" : 3101,336                  "success" : true337                },338              "score" : 0339            }340          ],341        "child_state" : "done",342        "max_score" : 3,343        "version" : 1344      }345    ],346  "weight" : 5.0347}348    """)349# Instance state. To test score if sum of rubric score is different from score value. Should receive score of 25.350INSTANCE_INCONSISTENT_STATE3 = serialize_open_ended_instance_state("""351{ "accept_file_upload" : false,352  "attempts" : "10000",353  "current_task_number" : 1,354  "display_name" : "Science Question -- Machine Assessed",355  "due" : null,356  "graceperiod" : "1 day 12 hours 59 minutes 59 seconds",357  "graded" : "True",358  "ready_to_reset" : false,359  "skip_spelling_checks" : true,360  "state" : "done",361  "student_attempts" : 0,362  "task_states" : [ { "child_attempts" : 4,363        "child_created" : false,364        "child_history" : [ { "answer" : "Student answer 1st attempt.",365              "post_assessment" : [3],366              "score" : 1367            },368            { "answer" : "Student answer 2nd attempt.",369              "post_assessment" : [3],370              "score" : 1371            },372            { "answer" : "Student answer 3rd attempt.",373              "post_assessment" : [3],374              "score" : 1375            },376            { "answer" : "",377              "post_assessment" : [3],378              "score" : 1379            }380          ],381        "child_state" : "done",382        "max_score" : 3,383        "version" : 1384      },385      { "child_attempts" : 0,386        "child_created" : false,387        "child_history" : [ { "answer" : "Student answer 1st attempt.",388              "post_assessment" : { "feedback" : { "grammar" : "Grammar: More grammar errors than average.",389                      "markup-text" : "valid essay",390                      "spelling" : "Spelling: Ok."391                    },392                  "grader_id" : 3233,393                  "grader_type" : "ML",394                  "rubric_scores_complete" : true,395                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>2</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",396                  "score" : 0,397                  "submission_id" : 3097,398                  "success" : true399                },400              "score" : 0401            },402            { "answer" : "Student answer 2nd attempt.",403              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",404                      "markup-text" : "valid essay",405                      "spelling" : "Spelling: Ok."406                    },407                  "grader_id" : 3235,408                  "grader_type" : "ML",409                  "rubric_scores_complete" : true,410                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",411                  "score" : 0,412                  "submission_id" : 3098,413                  "success" : true414                },415              "score" : 0416            },417            { "answer" : "Student answer 3rd attempt.",418              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",419                      "markup-text" : "valid essay",420                      "spelling" : "Spelling: Ok."421                    },422                  "grader_id" : 3237,423                  "grader_type" : "ML",424                  "rubric_scores_complete" : true,425                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>5</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",426                  "score" : 2,427                  "submission_id" : 3099,428                  "success" : true429                },430              "score" : 2431            },432            { "answer" : "Student answer 4th attempt.",433              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",434                      "markup-text" : "valid essay",435                      "spelling" : "Spelling: Ok."436                    },437                  "grader_id" : 3239,438                  "grader_type" : "ML",439                  "rubric_scores_complete" : true,440                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",441                  "score" : 0,442                  "submission_id" : 3100,443                  "success" : true444                },445              "score" : 0446            },447            { "answer" : "",448              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",449                      "markup-text" : "invalid essay .",450                      "spelling" : "Spelling: Ok."451                    },452                  "grader_id" : 3241,453                  "grader_type" : "ML",454                  "rubric_scores_complete" : true,455                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",456                  "score" : 0,457                  "submission_id" : 3101,458                  "success" : true459                },460              "score" : 0461            }462          ],463        "child_state" : "done",464        "max_score" : 3,465        "version" : 1466      }467    ],468  "weight" : 5.0469}470""")471# Instance state. To test score if old task states are available. Should receive a score of 15.472INSTANCE_INCONSISTENT_STATE4 = serialize_open_ended_instance_state("""473{ "accept_file_upload" : false,474  "attempts" : "10000",475  "current_task_number" : 0,476  "display_name" : "Science Question -- Machine Assessed",477  "due" : null,478  "graceperiod" : "1 day 12 hours 59 minutes 59 seconds",479  "graded" : "True",480  "old_task_states" : [ [ { "child_attempts" : 4,481          "child_created" : false,482          "child_history" : [ { "answer" : "Student answer 1st attempt.",483                "post_assessment" : "[3]",484                "score" : 1485              },486              { "answer" : "Student answer 2nd attempt.",487                "post_assessment" : "[3]",488                "score" : 1489              },490              { "answer" : "Student answer 3rd attempt.",491                "post_assesssment" : "[3]",492                "score" : 1493              },494              { "answer" : "",495                "post_assessment" : "[3]",496                "score" : 1497              }498            ],499          "child_state" : "done",500          "max_score" : 3,501          "version" : 1502        } ] ],503  "ready_to_reset" : false,504  "skip_spelling_checks" : true,505  "state" : "assessing",506  "student_attempts" : 0,507  "task_states" : [ { "child_attempts" : 4,508        "child_created" : false,509        "child_history" : [ { "answer" : "Student answer 1st attempt.",510              "post_assessment" : [3],511              "score" : 1512            },513            { "answer" : "Student answer 2nd attempt.",514              "post_assessment" : [3],515              "score" : 1516            },517            { "answer" : "Student answer 3rd attempt.",518              "post_assessment" : [3],519              "score" : 1520            },521            { "answer" : "",522              "post_assessment" : [3],523              "score" : 1524            }525          ],526        "child_state" : "done",527        "max_score" : 3,528        "stored_answer" : null,529        "version" : 1530      },531      { "child_attempts" : 0,532        "child_created" : false,533        "child_history" : [ { "answer" : "Student answer 1st attempt.",534              "post_assessment" : { "feedback" : { "grammar" : "Grammar: More grammar errors than average.",535                      "markup-text" : "valid essay",536                      "spelling" : "Spelling: Ok."537                    },538                  "grader_id" : 3233,539                  "grader_type" : "ML",540                  "rubric_scores_complete" : true,541                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",542                  "score" : 0,543                  "submission_id" : 3097,544                  "success" : true545                },546              "score" : 0547            },548            { "answer" : "Student answer 2nd attempt.",549              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",550                      "markup-text" : "valid essay",551                      "spelling" : "Spelling: Ok."552                    },553                  "grader_id" : 3235,554                  "grader_type" : "ML",555                  "rubric_scores_complete" : true,556                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",557                  "score" : 0,558                  "submission_id" : 3098,559                  "success" : true560                },561              "score" : 0562            },563            { "answer" : "Student answer 3rd attempt.",564              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",565                      "markup-text" : "valid essay",566                      "spelling" : "Spelling: Ok."567                    },568                  "grader_id" : 3237,569                  "grader_type" : "ML",570                  "rubric_scores_complete" : true,571                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>3</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",572                  "score" : 2,573                  "submission_id" : 3099,574                  "success" : true575                },576              "score" : 2577            },578            { "answer" : "Student answer 4th attempt.",579              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",580                      "markup-text" : "valid essay",581                      "spelling" : "Spelling: Ok."582                    },583                  "grader_id" : 3239,584                  "grader_type" : "ML",585                  "rubric_scores_complete" : true,586                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",587                  "score" : 0,588                  "submission_id" : 3100,589                  "success" : true590                },591              "score" : 0592            },593            { "answer" : "",594              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",595                      "markup-text" : "invalid essay .",596                      "spelling" : "Spelling: Ok."597                    },598                  "grader_id" : 3241,599                  "grader_type" : "ML",600                  "rubric_scores_complete" : true,601                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",602                  "score" : 0,603                  "submission_id" : 3101,604                  "success" : true605                },606              "score" : 0607            }608          ],609        "child_state" : "done",610        "max_score" : 3,611        "version" : 1612      }613    ],614  "weight" : 5.0615}616""")617# Instance state. To test score if rubric scores are available but score is missing. Should receive a score of 15.618INSTANCE_INCONSISTENT_STATE5 = serialize_open_ended_instance_state("""619{ "accept_file_upload" : false,620  "attempts" : "10000",621  "current_task_number" : 1,622  "display_name" : "Science Question -- Machine Assessed",623  "due" : null,624  "graceperiod" : "1 day 12 hours 59 minutes 59 seconds",625  "graded" : "True",626  "ready_to_reset" : false,627  "skip_spelling_checks" : true,628  "state" : "done",629  "student_attempts" : 0,630  "task_states" : [ { "child_attempts" : 4,631        "child_created" : false,632        "child_history" : [ { "answer" : "Student answer 1st attempt.",633              "post_assessment" : [3],634              "score" : 1635            },636            { "answer" : "Student answer 2nd attempt.",637              "post_assessment" : [3],638              "score" : 1639            },640            { "answer" : "Student answer 3rd attempt.",641              "post_assessment" : [3],642              "score" : 1643            },644            { "answer" : "",645              "post_assessment" : [3],646              "score" : 1647            }648          ],649        "child_state" : "done",650        "max_score" : 3,651        "version" : 1652      },653      { "child_attempts" : 0,654        "child_created" : false,655        "child_history" : [ { "answer" : "Student answer 1st attempt.",656              "post_assessment" : { "feedback" : { "grammar" : "Grammar: More grammar errors than average.",657                      "markup-text" : "valid essay",658                      "spelling" : "Spelling: Ok."659                    },660                  "grader_id" : 3233,661                  "grader_type" : "ML",662                  "rubric_scores_complete" : true,663                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",664                  "score" : 0,665                  "submission_id" : 3097,666                  "success" : true667                },668              "score" : 0669            },670            { "answer" : "Student answer 2nd attempt.",671              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",672                      "markup-text" : "valid essay",673                      "spelling" : "Spelling: Ok."674                    },675                  "grader_id" : 3235,676                  "grader_type" : "ML",677                  "rubric_scores_complete" : true,678                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",679                  "score" : 0,680                  "submission_id" : 3098,681                  "success" : true682                },683              "score" : 0684            },685            { "answer" : "Student answer 3rd attempt.",686              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",687                      "markup-text" : "valid essay",688                      "spelling" : "Spelling: Ok."689                    },690                  "grader_id" : 3237,691                  "grader_type" : "ML",692                  "rubric_scores_complete" : true,693                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>3</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",694                  "score" : 2,695                  "submission_id" : 3099,696                  "success" : true697                }698            },699            { "answer" : "Student answer 4th attempt.",700              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",701                      "markup-text" : "valid essay",702                      "spelling" : "Spelling: Ok."703                    },704                  "grader_id" : 3239,705                  "grader_type" : "ML",706                  "rubric_scores_complete" : true,707                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",708                  "score" : 0,709                  "submission_id" : 3100,710                  "success" : true711                },712              "score" : 0713            },714            { "answer" : "",715              "post_assessment" : { "feedback" : { "grammar" : "Grammar: Ok.",716                      "markup-text" : "invalid essay .",717                      "spelling" : "Spelling: Ok."718                    },719                  "grader_id" : 3241,720                  "grader_type" : "ML",721                  "rubric_scores_complete" : true,722                  "rubric_xml" : "<rubric><category><description>Response Quality</description><score>0</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",723                  "score" : 0,724                  "submission_id" : 3101,725                  "success" : true726                },727              "score" : 0728            }729          ],730        "child_state" : "done",731        "max_score" : 3,732        "version" : 1733      }734    ],735  "weight" : 5.0736}737""")738# State Initial739STATE_INITIAL = serialize_open_ended_instance_state("""740{741    "ready_to_reset": false,742    "skip_spelling_checks": false,743    "current_task_number": 0,744    "old_task_states": [],745    "weight": 1,746    "task_states": [747        {748            "child_attempts" : 1,749            "child_created" : false,750            "child_history" : [],751            "child_state" : "done",752            "max_score" : 3,753            "version" : 1754        },755        {756            "child_created": false,757            "child_attempts": 0,758            "stored_answer": "A stored answer.",759            "version": 1,760            "child_history": [],761            "max_score": 3,762            "child_state": "initial"763        }764    ],765    "graded": true,766    "student_attempts": 0,767    "required_peer_grading": 3,768    "state": "initial",769    "accept_file_upload": false,770    "min_to_calibrate": 3,771    "max_to_calibrate": 6,772    "display_name": "Open Response Assessment",773    "peer_grader_count": 3,774    "max_attempts": 1775}""")776STATE_ACCESSING = serialize_open_ended_instance_state("""777{778    "ready_to_reset": false,779    "skip_spelling_checks": false,780    "current_task_number": 0,781    "old_task_states": [],782    "weight": 1,783    "task_states": [784        {785            "child_attempts" : 1,786            "child_created" : false,787            "child_history": [788                {789                    "answer": "Here is an answer."790                }791            ],792            "child_state" : "done",793            "max_score" : 3,794            "version" : 1795        },796        {797            "child_created": false,798            "child_attempts": 0,799            "stored_answer": null,800            "version": 1,801            "child_history": [802                {803                    "answer": "Here is an answer."804                }805            ],806            "max_score": 3,807            "child_state": "assessing"808        }809    ],810    "graded": true,811    "student_attempts": 0,812    "required_peer_grading": 3,813    "state": "assessing",814    "accept_file_upload": false,815    "min_to_calibrate": 3,816    "max_to_calibrate": 6,817    "display_name": "Open Response Assessment",818    "peer_grader_count": 3,819    "max_attempts": 1820}""")821STATE_POST_ASSESSMENT = serialize_open_ended_instance_state("""822{823    "ready_to_reset": false,824    "skip_spelling_checks": false,825    "current_task_number": 0,826    "old_task_states": [],827    "weight": 1,828    "task_states": [829        {830            "child_attempts" : 1,831            "child_created" : false,832            "child_history": [833                {834                    "answer": "Here is an answer."835                }836            ],837            "child_state" : "done",838            "max_score" : 3,839            "version" : 1840        },841        {842            "child_created": false,843            "child_attempts": 0,844            "stored_answer": null,845            "version": 1,846            "child_history": [847                {848                    "answer": "Here is an answer."849                }850            ],851            "max_score": 3,852            "post_assessment": {853                "feedback" : {854                    "grammar" : "Grammar: Ok.",855                    "markup-text" : "valid essay",856                    "spelling" : "Spelling: Ok."857                },858                "grader_id" : 3237,859                "grader_type" : "ML",860                "rubric_scores_complete" : true,861                "rubric_xml" : "<rubric><category><description>Response Quality</description><score>3</score><option points='0'>Category one description.</option><option points='1'>Category two description.</option><option points='2'>Category three description.</option><option points='3'>Category four description.</option></category></rubric>",862                "score" : 2,863                "submission_id" : 3099,864                "success" : true865            },866            "child_state": "post_assessment"867        }868    ],869    "graded": true,870    "student_attempts": 0,871    "required_peer_grading": 3,872    "state": "done",873    "accept_file_upload": false,874    "min_to_calibrate": 3,875    "max_to_calibrate": 6,876    "display_name": "Open Response Assessment",877    "peer_grader_count": 3,878    "max_attempts": 1879}""")880# Task state with self assessment only.881TEST_STATE_SA = ["{\"child_created\": false, \"child_attempts\": 1, \"version\": 1, \"child_history\": [{\"answer\": \"Censorship in the Libraries\\r<br>'All of us can think of a book that we hope none of our children or any other children have taken off the shelf. But if I have the right to remove that book from the shelf -- that work I abhor -- then you also have exactly the same right and so does everyone else. And then we have no books left on the shelf for any of us.' --Katherine Paterson, Author\\r<br><br>Write a persuasive essay to a newspaper reflecting your views on censorship in libraries. Do you believe that certain materials, such as books, music, movies, magazines, etc., should be removed from the shelves if they are found offensive? Support your position with convincing arguments from your own experience, observations, and/or reading.\", \"post_assessment\": \"[3, 3, 2, 2, 2]\", \"score\": 12}], \"max_score\": 12, \"child_state\": \"done\"}", "{\"child_created\": false, \"child_attempts\": 0, \"version\": 1, \"child_history\": [{\"answer\": \"Censorship in the Libraries\\r<br>'All of us can think of a book that we hope none of our children or any other children have taken off the shelf. But if I have the right to remove that book from the shelf -- that work I abhor -- then you also have exactly the same right and so does everyone else. And then we have no books left on the shelf for any of us.' --Katherine Paterson, Author\\r<br><br>Write a persuasive essay to a newspaper reflecting your views on censorship in libraries. Do you believe that certain materials, such as books, music, movies, magazines, etc., should be removed from the shelves if they are found offensive? Support your position with convincing arguments from your own experience, observations, and/or reading.\", \"post_assessment\": \"{\\\"submission_id\\\": 1461, \\\"score\\\": 12, \\\"feedback\\\": \\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 5414, \\\"grader_type\\\": \\\"IN\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"<rubric><category><description>\\\\nIdeas\\\\n</description><score>3</score><option points='0'>\\\\nDifficult for the reader to discern the main idea.  Too brief or too repetitive to establish or maintain a focus.\\\\n</option><option points='1'>\\\\nAttempts a main idea.  Sometimes loses focus or ineffectively displays focus.\\\\n</option><option points='2'>\\\\nPresents a unifying theme or main idea, but may include minor tangents.  Stays somewhat focused on topic and task.\\\\n</option><option points='3'>\\\\nPresents a unifying theme or main idea without going off on tangents.  Stays completely focused on topic and task.\\\\n</option></category><category><description>\\\\nContent\\\\n</description><score>3</score><option points='0'>\\\\nIncludes little information with few or no details or unrelated details.  Unsuccessful in attempts to explore any facets of the topic.\\\\n</option><option points='1'>\\\\nIncludes little information and few or no details.  Explores only one or two facets of the topic.\\\\n</option><option points='2'>\\\\nIncludes sufficient information and supporting details. (Details may not be fully developed; ideas may be listed.)  Explores some facets of the topic.\\\\n</option><option points='3'>\\\\nIncludes in-depth information and exceptional supporting details that are fully developed.  Explores all facets of the topic.\\\\n</option></category><category><description>\\\\nOrganization\\\\n</description><score>2</score><option points='0'>\\\\nIdeas organized illogically, transitions weak, and response difficult to follow.\\\\n</option><option points='1'>\\\\nAttempts to logically organize ideas.  Attempts to progress in an order that enhances meaning, and demonstrates use of transitions.\\\\n</option><option points='2'>\\\\nIdeas organized logically.  Progresses in an order that enhances meaning.  Includes smooth transitions.\\\\n</option></category><category><description>\\\\nStyle\\\\n</description><score>2</score><option points='0'>\\\\nContains limited vocabulary, with many words used incorrectly.  Demonstrates problems with sentence patterns.\\\\n</option><option points='1'>\\\\nContains basic vocabulary, with words that are predictable and common.  Contains mostly simple sentences (although there may be an attempt at more varied sentence patterns).\\\\n</option><option points='2'>\\\\nIncludes vocabulary to make explanations detailed and precise.  Includes varied sentence patterns, including complex sentences.\\\\n</option></category><category><description>\\\\nVoice\\\\n</description><score>2</score><option points='0'>\\\\nDemonstrates language and tone that may be inappropriate to task and reader.\\\\n</option><option points='1'>\\\\nDemonstrates an attempt to adjust language and tone to task and reader.\\\\n</option><option points='2'>\\\\nDemonstrates effective adjustment of language and tone to task and reader.\\\\n</option></category></rubric>\\\"}\", \"score\": 12}], \"max_score\": 12, \"child_state\": \"post_assessment\"}"]882# Task state with self and then ai assessment.883TEST_STATE_AI = ["{\"child_created\": false, \"child_attempts\": 2, \"version\": 1, \"child_history\": [{\"answer\": \"In libraries, there should not be censorship on materials considering that it's an individual's decision to read what they prefer. There is no appropriate standard on what makes a book offensive to a group, so it should be undetermined as to what makes a book offensive. In a public library, many children, who the books are censored for, are with their parents. Parents should make an independent choice on what they can allow their children to read. Letting society ban a book simply for the use of inappropriate materials is ridiculous. If an author spent time creating a story, it should be appreciated, and should not put on a list of no-nos. If a certain person doesn't like a book's reputation, all they have to do is not read it. Even in school systems, librarians are there to guide kids to read good books. If a child wants to read an inappropriate book, the librarian will most likely discourage him or her not to read it. In my experience, I wanted to read a book that my mother suggested to me, but as I went to the school library it turned out to be a censored book. Some parents believe children should be ignorant about offensive things written in books, but honestly many of the same ideas are exploited to them everyday on television and internet. So trying to shield your child from the bad things may be a great thing, but the efforts are usually failed attempts. It also never occurs to the people censoring the books, that some people can't afford to buy the books they want to read. The libraries, for some, are the main means for getting books. To conclude there is very little reason to ban a book from the shelves. Many of the books banned have important lessons that can be obtained through reading it. If a person doesn't like a book, the simplest thing to do is not to pick it up.\", \"post_assessment\": \"[1, 1]\", \"score\": 2}, {\"answer\": \"This is another response\", \"post_assessment\": \"[1, 1]\", \"score\": 2}], \"max_score\": 2, \"child_state\": \"done\"}", "{\"child_created\": false, \"child_attempts\": 0, \"version\": 1, \"child_history\": [{\"answer\": \"In libraries, there should not be censorship on materials considering that it's an individual's decision to read what they prefer. There is no appropriate standard on what makes a book offensive to a group, so it should be undetermined as to what makes a book offensive. In a public library, many children, who the books are censored for, are with their parents. Parents should make an independent choice on what they can allow their children to read. Letting society ban a book simply for the use of inappropriate materials is ridiculous. If an author spent time creating a story, it should be appreciated, and should not put on a list of no-nos. If a certain person doesn't like a book's reputation, all they have to do is not read it. Even in school systems, librarians are there to guide kids to read good books. If a child wants to read an inappropriate book, the librarian will most likely discourage him or her not to read it. In my experience, I wanted to read a book that my mother suggested to me, but as I went to the school library it turned out to be a censored book. Some parents believe children should be ignorant about offensive things written in books, but honestly many of the same ideas are exploited to them everyday on television and internet. So trying to shield your child from the bad things may be a great thing, but the efforts are usually failed attempts. It also never occurs to the people censoring the books, that some people can't afford to buy the books they want to read. The libraries, for some, are the main means for getting books. To conclude there is very little reason to ban a book from the shelves. Many of the books banned have important lessons that can be obtained through reading it. If a person doesn't like a book, the simplest thing to do is not to pick it up.\", \"post_assessment\": \"{\\\"submission_id\\\": 6107, \\\"score\\\": 2, \\\"feedback\\\": \\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"\\\\\\\"}\\\", \\\"success\\\": true, \\\"grader_id\\\": 1898718, \\\"grader_type\\\": \\\"IN\\\", \\\"rubric_scores_complete\\\": true, \\\"rubric_xml\\\": \\\"<rubric><category><description>Writing Applications</description><score>1</score><option points='0'> The essay loses focus, has little information or supporting details, and the organization makes it difficult to follow.</option><option points='1'> The essay presents a mostly unified theme, includes sufficient information to convey the theme, and is generally organized well.</option></category><category><description> Language Conventions </description><score>1</score><option points='0'> The essay demonstrates a reasonable command of proper spelling and grammar. </option><option points='1'> The essay demonstrates superior command of proper spelling and grammar.</option></category></rubric>\\\"}\", \"score\": 2}, {\"answer\": \"This is another response\"}], \"max_score\": 2, \"child_state\": \"assessing\"}"]884# Task state with ai assessment only.885TEST_STATE_AI2 = ["{\"child_created\": false, \"child_attempts\": 0, \"version\": 1, \"child_history\": [{\"answer\": \"This isn't a real essay, and you should give me a zero on it. \", \"post_assessment\": \"{\\\"submission_id\\\": 18446, \\\"score\\\": [0, 1, 0], \\\"feedback\\\": [\\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"\\\\\\\"}\\\", \\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"\\\\\\\"}\\\", \\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"Zero it is! \\\\\\\"}\\\"], \\\"success\\\": true, \\\"grader_id\\\": [1944146, 1943188, 1940991], \\\"grader_type\\\": \\\"PE\\\", \\\"rubric_scores_complete\\\": [true, true, true], \\\"rubric_xml\\\": [\\\"<rubric><category><description>Writing Applications</description><score>0</score><option points='0'> The essay loses focus, has little information or supporting details, and the organization makes it difficult to follow.</option><option points='1'> The essay presents a mostly unified theme, includes sufficient information to convey the theme, and is generally organized well.</option></category><category><description> Language Conventions </description><score>0</score><option points='0'> The essay demonstrates a reasonable command of proper spelling and grammar. </option><option points='1'> The essay demonstrates superior command of proper spelling and grammar.</option></category></rubric>\\\", \\\"<rubric><category><description>Writing Applications</description><score>0</score><option points='0'> The essay loses focus, has little information or supporting details, and the organization makes it difficult to follow.</option><option points='1'> The essay presents a mostly unified theme, includes sufficient information to convey the theme, and is generally organized well.</option></category><category><description> Language Conventions </description><score>1</score><option points='0'> The essay demonstrates a reasonable command of proper spelling and grammar. </option><option points='1'> The essay demonstrates superior command of proper spelling and grammar.</option></category></rubric>\\\", \\\"<rubric><category><description>Writing Applications</description><score>0</score><option points='0'> The essay loses focus, has little information or supporting details, and the organization makes it difficult to follow.</option><option points='1'> The essay presents a mostly unified theme, includes sufficient information to convey the theme, and is generally organized well.</option></category><category><description> Language Conventions </description><score>0</score><option points='0'> The essay demonstrates a reasonable command of proper spelling and grammar. </option><option points='1'> The essay demonstrates superior command of proper spelling and grammar.</option></category></rubric>\\\"]}\", \"score\": 0}], \"max_score\": 2, \"child_state\": \"post_assessment\"}"]886# Invalid task state with ai assessment.887TEST_STATE_AI2_INVALID = ["{\"child_created\": false, \"child_attempts\": 0, \"version\": 1, \"child_history\": [{\"answer\": \"This isn't a real essay, and you should give me a zero on it. \", \"post_assessment\": \"{\\\"submission_id\\\": 18446, \\\"score\\\": [0, 1, 0], \\\"feedback\\\": [\\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"\\\\\\\"}\\\", \\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"\\\\\\\"}\\\", \\\"{\\\\\\\"feedback\\\\\\\": \\\\\\\"Zero it is! \\\\\\\"}\\\"], \\\"success\\\": true, \\\"grader_id\\\": [1943188, 1940991], \\\"grader_type\\\": \\\"PE\\\", \\\"rubric_scores_complete\\\": [true, true, true], \\\"rubric_xml\\\": [\\\"<rubric><category><description>Writing Applications</description><score>0</score><option points='0'> The essay loses focus, has little information or supporting details, and the organization makes it difficult to follow.</option><option points='1'> The essay presents a mostly unified theme, includes sufficient information to convey the theme, and is generally organized well.</option></category><category><description> Language Conventions </description><score>0</score><option points='0'> The essay demonstrates a reasonable command of proper spelling and grammar. </option><option points='1'> The essay demonstrates superior command of proper spelling and grammar.</option></category></rubric>\\\", \\\"<rubric><category><description>Writing Applications</description><score>0</score><option points='0'> The essay loses focus, has little information or supporting details, and the organization makes it difficult to follow.</option><option points='1'> The essay presents a mostly unified theme, includes sufficient information to convey the theme, and is generally organized well.</option></category><category><description> Language Conventions </description><score>1</score><option points='0'> The essay demonstrates a reasonable command of proper spelling and grammar. </option><option points='1'> The essay demonstrates superior command of proper spelling and grammar.</option></category></rubric>\\\", \\\"<rubric><category><description>Writing Applications</description><score>0</score><option points='0'> The essay loses focus, has little information or supporting details, and the organization makes it difficult to follow.</option><option points='1'> The essay presents a mostly unified theme, includes sufficient information to convey the theme, and is generally organized well.</option></category><category><description> Language Conventions </description><score>0</score><option points='0'> The essay demonstrates a reasonable command of proper spelling and grammar. </option><option points='1'> The essay demonstrates superior command of proper spelling and grammar.</option></category></rubric>\\\"]}\", \"score\": 0}], \"max_score\": 2, \"child_state\": \"post_assessment\"}"]888# Self assessment state.889TEST_STATE_SINGLE = ["{\"child_created\": false, \"child_attempts\": 1, \"version\": 1, \"child_history\": [{\"answer\": \"'All of us can think of a book that we hope none of our children or any other children have taken off the shelf. But if I have the right to remove that book from the shelf -- that work I abhor -- then you also have exactly the same right and so does everyone else. And then we have no books left on the shelf for any of us.' --Katherine Paterson, Author\\r<br><br>Write a persuasive essay to a newspaper reflecting your views on censorship in libraries. Do you believe that certain materials, such as books, music, movies, magazines, etc., should be removed from the shelves if they are found offensive? Support your position with convincing arguments from your own experience, observations, and/or reading. \", \"post_assessment\": \"[3, 3, 2, 2, 2]\", \"score\": 12}], \"max_score\": 12, \"child_state\": \"done\"}"]890# Peer grading state....test_optparse.py
Source:test_optparse.py  
...155            raise self.failureException(156                'help text failure; expected:\n"' +157                expected_help + '"; got:\n"' +158                actual_help + '"\n')159# -- Test make_option() aka Option -------------------------------------160# It's not necessary to test correct options here.  All the tests in the161# parser.parse_args() section deal with those, because they're needed162# there.163class TestOptionChecks(BaseTest):164    def setUp(self):165        self.parser = OptionParser(usage=SUPPRESS_USAGE)166    def assertOptionError(self, expected_message, args=[], kwargs={}):167        self.assertRaises(make_option, args, kwargs,168                          OptionError, expected_message)169    def test_opt_string_empty(self):170        self.assertTypeError(make_option,171                             "at least one option string must be supplied")172    def test_opt_string_too_short(self):173        self.assertOptionError(174            "invalid option string 'b': must be at least two characters long",175            ["b"])176    def test_opt_string_short_invalid(self):177        self.assertOptionError(178            "invalid short option string '--': must be "179            "of the form -x, (x any non-dash char)",180            ["--"])181    def test_opt_string_long_invalid(self):182        self.assertOptionError(183            "invalid long option string '---': "184            "must start with --, followed by non-dash",185            ["---"])186    def test_attr_invalid(self):187        self.assertOptionError(188            "option -b: invalid keyword arguments: bar, foo",189            ["-b"], {'foo': None, 'bar': None})190    def test_action_invalid(self):191        self.assertOptionError(192            "option -b: invalid action: 'foo'",193            ["-b"], {'action': 'foo'})194    def test_type_invalid(self):195        self.assertOptionError(196            "option -b: invalid option type: 'foo'",197            ["-b"], {'type': 'foo'})198        self.assertOptionError(199            "option -b: invalid option type: 'tuple'",200            ["-b"], {'type': tuple})201    def test_no_type_for_action(self):202        self.assertOptionError(203            "option -b: must not supply a type for action 'count'",204            ["-b"], {'action': 'count', 'type': 'int'})205    def test_no_choices_list(self):206        self.assertOptionError(207            "option -b/--bad: must supply a list of "208            "choices for type 'choice'",209            ["-b", "--bad"], {'type': "choice"})210    def test_bad_choices_list(self):211        typename = type('').__name__212        self.assertOptionError(213            "option -b/--bad: choices must be a list of "214            "strings ('%s' supplied)" % typename,215            ["-b", "--bad"],216            {'type': "choice", 'choices':"bad choices"})217    def test_no_choices_for_type(self):218        self.assertOptionError(219            "option -b: must not supply choices for type 'int'",220            ["-b"], {'type': 'int', 'choices':"bad"})221    def test_no_const_for_action(self):222        self.assertOptionError(223            "option -b: 'const' must not be supplied for action 'store'",224            ["-b"], {'action': 'store', 'const': 1})225    def test_no_nargs_for_action(self):226        self.assertOptionError(227            "option -b: 'nargs' must not be supplied for action 'count'",228            ["-b"], {'action': 'count', 'nargs': 2})229    def test_callback_not_callable(self):230        self.assertOptionError(231            "option -b: callback not callable: 'foo'",232            ["-b"], {'action': 'callback',233                     'callback': 'foo'})234    def dummy(self):235        pass236    def test_callback_args_no_tuple(self):237        self.assertOptionError(238            "option -b: callback_args, if supplied, "239            "must be a tuple: not 'foo'",240            ["-b"], {'action': 'callback',241                     'callback': self.dummy,242                     'callback_args': 'foo'})243    def test_callback_kwargs_no_dict(self):244        self.assertOptionError(245            "option -b: callback_kwargs, if supplied, "246            "must be a dict: not 'foo'",247            ["-b"], {'action': 'callback',248                     'callback': self.dummy,249                     'callback_kwargs': 'foo'})250    def test_no_callback_for_action(self):251        self.assertOptionError(252            "option -b: callback supplied ('foo') for non-callback option",253            ["-b"], {'action': 'store',254                     'callback': 'foo'})255    def test_no_callback_args_for_action(self):256        self.assertOptionError(257            "option -b: callback_args supplied for non-callback option",258            ["-b"], {'action': 'store',259                     'callback_args': 'foo'})260    def test_no_callback_kwargs_for_action(self):261        self.assertOptionError(262            "option -b: callback_kwargs supplied for non-callback option",263            ["-b"], {'action': 'store',264                     'callback_kwargs': 'foo'})265    def test_no_single_dash(self):266        self.assertOptionError(267            "invalid long option string '-debug': "268            "must start with --, followed by non-dash",269            ["-debug"])270        self.assertOptionError(271            "option -d: invalid long option string '-debug': must start with"272            " --, followed by non-dash",273            ["-d", "-debug"])274        self.assertOptionError(275            "invalid long option string '-debug': "276            "must start with --, followed by non-dash",277            ["-debug", "--debug"])278class TestOptionParser(BaseTest):279    def setUp(self):280        self.parser = OptionParser()281        self.parser.add_option("-v", "--verbose", "-n", "--noisy",282                          action="store_true", dest="verbose")283        self.parser.add_option("-q", "--quiet", "--silent",284                          action="store_false", dest="verbose")285    def test_add_option_no_Option(self):286        self.assertTypeError(self.parser.add_option,287                             "not an Option instance: None", None)288    def test_add_option_invalid_arguments(self):289        self.assertTypeError(self.parser.add_option,290                             "invalid arguments", None, None)291    def test_get_option(self):292        opt1 = self.parser.get_option("-v")293        self.assertIsInstance(opt1, Option)294        self.assertEqual(opt1._short_opts, ["-v", "-n"])295        self.assertEqual(opt1._long_opts, ["--verbose", "--noisy"])296        self.assertEqual(opt1.action, "store_true")297        self.assertEqual(opt1.dest, "verbose")298    def test_get_option_equals(self):299        opt1 = self.parser.get_option("-v")300        opt2 = self.parser.get_option("--verbose")301        opt3 = self.parser.get_option("-n")302        opt4 = self.parser.get_option("--noisy")303        self.assertTrue(opt1 is opt2 is opt3 is opt4)304    def test_has_option(self):305        self.assertTrue(self.parser.has_option("-v"))306        self.assertTrue(self.parser.has_option("--verbose"))307    def assertTrueremoved(self):308        self.assertTrue(self.parser.get_option("-v") is None)309        self.assertTrue(self.parser.get_option("--verbose") is None)310        self.assertTrue(self.parser.get_option("-n") is None)311        self.assertTrue(self.parser.get_option("--noisy") is None)312        self.assertFalse(self.parser.has_option("-v"))313        self.assertFalse(self.parser.has_option("--verbose"))314        self.assertFalse(self.parser.has_option("-n"))315        self.assertFalse(self.parser.has_option("--noisy"))316        self.assertTrue(self.parser.has_option("-q"))317        self.assertTrue(self.parser.has_option("--silent"))318    def test_remove_short_opt(self):319        self.parser.remove_option("-n")320        self.assertTrueremoved()321    def test_remove_long_opt(self):322        self.parser.remove_option("--verbose")323        self.assertTrueremoved()324    def test_remove_nonexistent(self):325        self.assertRaises(self.parser.remove_option, ('foo',), None,326                          ValueError, "no such option 'foo'")327    def test_refleak(self):328        # If an OptionParser is carrying around a reference to a large329        # object, various cycles can prevent it from being GC'd in330        # a timely fashion.  destroy() breaks the cycles to ensure stuff331        # can be cleaned up.332        big_thing = [42]333        refcount = sys.getrefcount(big_thing)334        parser = OptionParser()335        parser.add_option("-a", "--aaarggh")336        parser.big_thing = big_thing337        parser.destroy()338        #self.assertEqual(refcount, sys.getrefcount(big_thing))339        del parser340        self.assertEqual(refcount, sys.getrefcount(big_thing))341class TestOptionValues(BaseTest):342    def setUp(self):343        pass344    def test_basics(self):345        values = Values()346        self.assertEqual(vars(values), {})347        self.assertEqual(values, {})348        self.assertNotEqual(values, {"foo": "bar"})349        self.assertNotEqual(values, "")350        dict = {"foo": "bar", "baz": 42}351        values = Values(defaults=dict)352        self.assertEqual(vars(values), dict)353        self.assertEqual(values, dict)354        self.assertNotEqual(values, {"foo": "bar"})355        self.assertNotEqual(values, {})356        self.assertNotEqual(values, "")357        self.assertNotEqual(values, [])358class TestTypeAliases(BaseTest):359    def setUp(self):360        self.parser = OptionParser()361    def test_str_aliases_string(self):362        self.parser.add_option("-s", type="str")363        self.assertEqual(self.parser.get_option("-s").type, "string")364    def test_type_object(self):365        self.parser.add_option("-s", type=str)366        self.assertEqual(self.parser.get_option("-s").type, "string")367        self.parser.add_option("-x", type=int)368        self.assertEqual(self.parser.get_option("-x").type, "int")369# Custom type for testing processing of default values.370_time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 }371def _check_duration(option, opt, value):372    try:373        if value[-1].isdigit():374            return int(value)375        else:376            return int(value[:-1]) * _time_units[value[-1]]377    except (ValueError, IndexError):378        raise OptionValueError(379            'option %s: invalid duration: %r' % (opt, value))380class DurationOption(Option):381    TYPES = Option.TYPES + ('duration',)382    TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)383    TYPE_CHECKER['duration'] = _check_duration384class TestDefaultValues(BaseTest):385    def setUp(self):386        self.parser = OptionParser()387        self.parser.add_option("-v", "--verbose", default=True)388        self.parser.add_option("-q", "--quiet", dest='verbose')389        self.parser.add_option("-n", type="int", default=37)390        self.parser.add_option("-m", type="int")391        self.parser.add_option("-s", default="foo")392        self.parser.add_option("-t")393        self.parser.add_option("-u", default=None)394        self.expected = { 'verbose': True,395                          'n': 37,396                          'm': None,397                          's': "foo",398                          't': None,399                          'u': None }400    def test_basic_defaults(self):401        self.assertEqual(self.parser.get_default_values(), self.expected)402    def test_mixed_defaults_post(self):403        self.parser.set_defaults(n=42, m=-100)404        self.expected.update({'n': 42, 'm': -100})405        self.assertEqual(self.parser.get_default_values(), self.expected)406    def test_mixed_defaults_pre(self):407        self.parser.set_defaults(x="barf", y="blah")408        self.parser.add_option("-x", default="frob")409        self.parser.add_option("-y")410        self.expected.update({'x': "frob", 'y': "blah"})411        self.assertEqual(self.parser.get_default_values(), self.expected)412        self.parser.remove_option("-y")413        self.parser.add_option("-y", default=None)414        self.expected.update({'y': None})415        self.assertEqual(self.parser.get_default_values(), self.expected)416    def test_process_default(self):417        self.parser.option_class = DurationOption418        self.parser.add_option("-d", type="duration", default=300)419        self.parser.add_option("-e", type="duration", default="6m")420        self.parser.set_defaults(n="42")421        self.expected.update({'d': 300, 'e': 360, 'n': 42})422        self.assertEqual(self.parser.get_default_values(), self.expected)423        self.parser.set_process_default_values(False)424        self.expected.update({'d': 300, 'e': "6m", 'n': "42"})425        self.assertEqual(self.parser.get_default_values(), self.expected)426class TestProgName(BaseTest):427    """428    Test that %prog expands to the right thing in usage, version,429    and help strings.430    """431    def assertUsage(self, parser, expected_usage):432        self.assertEqual(parser.get_usage(), expected_usage)433    def assertVersion(self, parser, expected_version):434        self.assertEqual(parser.get_version(), expected_version)435    def test_default_progname(self):436        # Make sure that program name taken from sys.argv[0] by default.437        save_argv = sys.argv[:]438        try:439            sys.argv[0] = os.path.join("foo", "bar", "baz.py")440            parser = OptionParser("%prog ...", version="%prog 1.2")441            expected_usage = "Usage: baz.py ...\n"442            self.assertUsage(parser, expected_usage)443            self.assertVersion(parser, "baz.py 1.2")444            self.assertHelp(parser,445                            expected_usage + "\n" +446                            "Options:\n"447                            "  --version   show program's version number and exit\n"448                            "  -h, --help  show this help message and exit\n")449        finally:450            sys.argv[:] = save_argv451    def test_custom_progname(self):452        parser = OptionParser(prog="thingy",453                              version="%prog 0.1",454                              usage="%prog arg arg")455        parser.remove_option("-h")456        parser.remove_option("--version")457        expected_usage = "Usage: thingy arg arg\n"458        self.assertUsage(parser, expected_usage)459        self.assertVersion(parser, "thingy 0.1")460        self.assertHelp(parser, expected_usage + "\n")461class TestExpandDefaults(BaseTest):462    def setUp(self):463        self.parser = OptionParser(prog="test")464        self.help_prefix = """\465Usage: test [options]466Options:467  -h, --help            show this help message and exit468"""469        self.file_help = "read from FILE [default: %default]"470        self.expected_help_file = self.help_prefix + \471            "  -f FILE, --file=FILE  read from FILE [default: foo.txt]\n"472        self.expected_help_none = self.help_prefix + \473            "  -f FILE, --file=FILE  read from FILE [default: none]\n"474    def test_option_default(self):475        self.parser.add_option("-f", "--file",476                               default="foo.txt",477                               help=self.file_help)478        self.assertHelp(self.parser, self.expected_help_file)479    def test_parser_default_1(self):480        self.parser.add_option("-f", "--file",481                               help=self.file_help)482        self.parser.set_default('file', "foo.txt")483        self.assertHelp(self.parser, self.expected_help_file)484    def test_parser_default_2(self):485        self.parser.add_option("-f", "--file",486                               help=self.file_help)487        self.parser.set_defaults(file="foo.txt")488        self.assertHelp(self.parser, self.expected_help_file)489    def test_no_default(self):490        self.parser.add_option("-f", "--file",491                               help=self.file_help)492        self.assertHelp(self.parser, self.expected_help_none)493    def test_default_none_1(self):494        self.parser.add_option("-f", "--file",495                               default=None,496                               help=self.file_help)497        self.assertHelp(self.parser, self.expected_help_none)498    def test_default_none_2(self):499        self.parser.add_option("-f", "--file",500                               help=self.file_help)501        self.parser.set_defaults(file=None)502        self.assertHelp(self.parser, self.expected_help_none)503    def test_float_default(self):504        self.parser.add_option(505            "-p", "--prob",506            help="blow up with probability PROB [default: %default]")507        self.parser.set_defaults(prob=0.43)508        expected_help = self.help_prefix + \509            "  -p PROB, --prob=PROB  blow up with probability PROB [default: 0.43]\n"510        self.assertHelp(self.parser, expected_help)511    def test_alt_expand(self):512        self.parser.add_option("-f", "--file",513                               default="foo.txt",514                               help="read from FILE [default: *DEFAULT*]")515        self.parser.formatter.default_tag = "*DEFAULT*"516        self.assertHelp(self.parser, self.expected_help_file)517    def test_no_expand(self):518        self.parser.add_option("-f", "--file",519                               default="foo.txt",520                               help="read from %default file")521        self.parser.formatter.default_tag = None522        expected_help = self.help_prefix + \523            "  -f FILE, --file=FILE  read from %default file\n"524        self.assertHelp(self.parser, expected_help)525# -- Test parser.parse_args() ------------------------------------------526class TestStandard(BaseTest):527    def setUp(self):528        options = [make_option("-a", type="string"),529                   make_option("-b", "--boo", type="int", dest='boo'),530                   make_option("--foo", action="append")]531        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,532                                               option_list=options)533    def test_required_value(self):534        self.assertParseFail(["-a"], "-a option requires 1 argument")535    def test_invalid_integer(self):536        self.assertParseFail(["-b", "5x"],537                             "option -b: invalid integer value: '5x'")538    def test_no_such_option(self):539        self.assertParseFail(["--boo13"], "no such option: --boo13")540    def test_long_invalid_integer(self):541        self.assertParseFail(["--boo=x5"],542                             "option --boo: invalid integer value: 'x5'")543    def test_empty(self):544        self.assertParseOK([], {'a': None, 'boo': None, 'foo': None}, [])545    def test_shortopt_empty_longopt_append(self):546        self.assertParseOK(["-a", "", "--foo=blah", "--foo="],547                           {'a': "", 'boo': None, 'foo': ["blah", ""]},548                           [])549    def test_long_option_append(self):550        self.assertParseOK(["--foo", "bar", "--foo", "", "--foo=x"],551                           {'a': None,552                            'boo': None,553                            'foo': ["bar", "", "x"]},554                           [])555    def test_option_argument_joined(self):556        self.assertParseOK(["-abc"],557                           {'a': "bc", 'boo': None, 'foo': None},558                           [])559    def test_option_argument_split(self):560        self.assertParseOK(["-a", "34"],561                           {'a': "34", 'boo': None, 'foo': None},562                           [])563    def test_option_argument_joined_integer(self):564        self.assertParseOK(["-b34"],565                           {'a': None, 'boo': 34, 'foo': None},566                           [])567    def test_option_argument_split_negative_integer(self):568        self.assertParseOK(["-b", "-5"],569                           {'a': None, 'boo': -5, 'foo': None},570                           [])571    def test_long_option_argument_joined(self):572        self.assertParseOK(["--boo=13"],573                           {'a': None, 'boo': 13, 'foo': None},574                           [])575    def test_long_option_argument_split(self):576        self.assertParseOK(["--boo", "111"],577                           {'a': None, 'boo': 111, 'foo': None},578                           [])579    def test_long_option_short_option(self):580        self.assertParseOK(["--foo=bar", "-axyz"],581                           {'a': 'xyz', 'boo': None, 'foo': ["bar"]},582                           [])583    def test_abbrev_long_option(self):584        self.assertParseOK(["--f=bar", "-axyz"],585                           {'a': 'xyz', 'boo': None, 'foo': ["bar"]},586                           [])587    def test_defaults(self):588        (options, args) = self.parser.parse_args([])589        defaults = self.parser.get_default_values()590        self.assertEqual(vars(defaults), vars(options))591    def test_ambiguous_option(self):592        self.parser.add_option("--foz", action="store",593                               type="string", dest="foo")594        self.assertParseFail(["--f=bar"],595                             "ambiguous option: --f (--foo, --foz?)")596    def test_short_and_long_option_split(self):597        self.assertParseOK(["-a", "xyz", "--foo", "bar"],598                           {'a': 'xyz', 'boo': None, 'foo': ["bar"]},599                           []),600    def test_short_option_split_long_option_append(self):601        self.assertParseOK(["--foo=bar", "-b", "123", "--foo", "baz"],602                           {'a': None, 'boo': 123, 'foo': ["bar", "baz"]},603                           [])604    def test_short_option_split_one_positional_arg(self):605        self.assertParseOK(["-a", "foo", "bar"],606                           {'a': "foo", 'boo': None, 'foo': None},607                           ["bar"]),608    def test_short_option_consumes_separator(self):609        self.assertParseOK(["-a", "--", "foo", "bar"],610                           {'a': "--", 'boo': None, 'foo': None},611                           ["foo", "bar"]),612        self.assertParseOK(["-a", "--", "--foo", "bar"],613                           {'a': "--", 'boo': None, 'foo': ["bar"]},614                           []),615    def test_short_option_joined_and_separator(self):616        self.assertParseOK(["-ab", "--", "--foo", "bar"],617                           {'a': "b", 'boo': None, 'foo': None},618                           ["--foo", "bar"]),619    def test_hyphen_becomes_positional_arg(self):620        self.assertParseOK(["-ab", "-", "--foo", "bar"],621                           {'a': "b", 'boo': None, 'foo': ["bar"]},622                           ["-"])623    def test_no_append_versus_append(self):624        self.assertParseOK(["-b3", "-b", "5", "--foo=bar", "--foo", "baz"],625                           {'a': None, 'boo': 5, 'foo': ["bar", "baz"]},626                           [])627    def test_option_consumes_optionlike_string(self):628        self.assertParseOK(["-a", "-b3"],629                           {'a': "-b3", 'boo': None, 'foo': None},630                           [])631    def test_combined_single_invalid_option(self):632        self.parser.add_option("-t", action="store_true")633        self.assertParseFail(["-test"],634                             "no such option: -e")635class TestBool(BaseTest):636    def setUp(self):637        options = [make_option("-v",638                               "--verbose",639                               action="store_true",640                               dest="verbose",641                               default=''),642                   make_option("-q",643                               "--quiet",644                               action="store_false",645                               dest="verbose")]646        self.parser = OptionParser(option_list = options)647    def test_bool_default(self):648        self.assertParseOK([],649                           {'verbose': ''},650                           [])651    def test_bool_false(self):652        (options, args) = self.assertParseOK(["-q"],653                                             {'verbose': 0},654                                             [])655        self.assertTrue(options.verbose is False)656    def test_bool_true(self):657        (options, args) = self.assertParseOK(["-v"],658                                             {'verbose': 1},659                                             [])660        self.assertTrue(options.verbose is True)661    def test_bool_flicker_on_and_off(self):662        self.assertParseOK(["-qvq", "-q", "-v"],663                           {'verbose': 1},664                           [])665class TestChoice(BaseTest):666    def setUp(self):667        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)668        self.parser.add_option("-c", action="store", type="choice",669                               dest="choice", choices=["one", "two", "three"])670    def test_valid_choice(self):671        self.assertParseOK(["-c", "one", "xyz"],672                           {'choice': 'one'},673                           ["xyz"])674    def test_invalid_choice(self):675        self.assertParseFail(["-c", "four", "abc"],676                             "option -c: invalid choice: 'four' "677                             "(choose from 'one', 'two', 'three')")678    def test_add_choice_option(self):679        self.parser.add_option("-d", "--default",680                               choices=["four", "five", "six"])681        opt = self.parser.get_option("-d")682        self.assertEqual(opt.type, "choice")683        self.assertEqual(opt.action, "store")684class TestCount(BaseTest):685    def setUp(self):686        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)687        self.v_opt = make_option("-v", action="count", dest="verbose")688        self.parser.add_option(self.v_opt)689        self.parser.add_option("--verbose", type="int", dest="verbose")690        self.parser.add_option("-q", "--quiet",691                               action="store_const", dest="verbose", const=0)692    def test_empty(self):693        self.assertParseOK([], {'verbose': None}, [])694    def test_count_one(self):695        self.assertParseOK(["-v"], {'verbose': 1}, [])696    def test_count_three(self):697        self.assertParseOK(["-vvv"], {'verbose': 3}, [])698    def test_count_three_apart(self):699        self.assertParseOK(["-v", "-v", "-v"], {'verbose': 3}, [])700    def test_count_override_amount(self):701        self.assertParseOK(["-vvv", "--verbose=2"], {'verbose': 2}, [])702    def test_count_override_quiet(self):703        self.assertParseOK(["-vvv", "--verbose=2", "-q"], {'verbose': 0}, [])704    def test_count_overriding(self):705        self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],706                           {'verbose': 1}, [])707    def test_count_interspersed_args(self):708        self.assertParseOK(["--quiet", "3", "-v"],709                           {'verbose': 1},710                           ["3"])711    def test_count_no_interspersed_args(self):712        self.parser.disable_interspersed_args()713        self.assertParseOK(["--quiet", "3", "-v"],714                           {'verbose': 0},715                           ["3", "-v"])716    def test_count_no_such_option(self):717        self.assertParseFail(["-q3", "-v"], "no such option: -3")718    def test_count_option_no_value(self):719        self.assertParseFail(["--quiet=3", "-v"],720                             "--quiet option does not take a value")721    def test_count_with_default(self):722        self.parser.set_default('verbose', 0)723        self.assertParseOK([], {'verbose':0}, [])724    def test_count_overriding_default(self):725        self.parser.set_default('verbose', 0)726        self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],727                           {'verbose': 1}, [])728class TestMultipleArgs(BaseTest):729    def setUp(self):730        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)731        self.parser.add_option("-p", "--point",732                               action="store", nargs=3, type="float", dest="point")733    def test_nargs_with_positional_args(self):734        self.assertParseOK(["foo", "-p", "1", "2.5", "-4.3", "xyz"],735                           {'point': (1.0, 2.5, -4.3)},736                           ["foo", "xyz"])737    def test_nargs_long_opt(self):738        self.assertParseOK(["--point", "-1", "2.5", "-0", "xyz"],739                           {'point': (-1.0, 2.5, -0.0)},740                           ["xyz"])741    def test_nargs_invalid_float_value(self):742        self.assertParseFail(["-p", "1.0", "2x", "3.5"],743                             "option -p: "744                             "invalid floating-point value: '2x'")745    def test_nargs_required_values(self):746        self.assertParseFail(["--point", "1.0", "3.5"],747                             "--point option requires 3 arguments")748class TestMultipleArgsAppend(BaseTest):749    def setUp(self):750        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)751        self.parser.add_option("-p", "--point", action="store", nargs=3,752                               type="float", dest="point")753        self.parser.add_option("-f", "--foo", action="append", nargs=2,754                               type="int", dest="foo")755        self.parser.add_option("-z", "--zero", action="append_const",756                               dest="foo", const=(0, 0))757    def test_nargs_append(self):758        self.assertParseOK(["-f", "4", "-3", "blah", "--foo", "1", "666"],759                           {'point': None, 'foo': [(4, -3), (1, 666)]},760                           ["blah"])761    def test_nargs_append_required_values(self):762        self.assertParseFail(["-f4,3"],763                             "-f option requires 2 arguments")764    def test_nargs_append_simple(self):765        self.assertParseOK(["--foo=3", "4"],766                           {'point': None, 'foo':[(3, 4)]},767                           [])768    def test_nargs_append_const(self):769        self.assertParseOK(["--zero", "--foo", "3", "4", "-z"],770                           {'point': None, 'foo':[(0, 0), (3, 4), (0, 0)]},771                           [])772class TestVersion(BaseTest):773    def test_version(self):774        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,775                                               version="%prog 0.1")776        save_argv = sys.argv[:]777        try:778            sys.argv[0] = os.path.join(os.curdir, "foo", "bar")779            self.assertOutput(["--version"], "bar 0.1\n")780        finally:781            sys.argv[:] = save_argv782    def test_no_version(self):783        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)784        self.assertParseFail(["--version"],785                             "no such option: --version")786# -- Test conflicting default values and parser.parse_args() -----------787class TestConflictingDefaults(BaseTest):788    """Conflicting default values: the last one should win."""789    def setUp(self):790        self.parser = OptionParser(option_list=[791            make_option("-v", action="store_true", dest="verbose", default=1)])792    def test_conflict_default(self):793        self.parser.add_option("-q", action="store_false", dest="verbose",794                               default=0)795        self.assertParseOK([], {'verbose': 0}, [])796    def test_conflict_default_none(self):797        self.parser.add_option("-q", action="store_false", dest="verbose",798                               default=None)799        self.assertParseOK([], {'verbose': None}, [])800class TestOptionGroup(BaseTest):801    def setUp(self):802        self.parser = OptionParser(usage=SUPPRESS_USAGE)803    def test_option_group_create_instance(self):804        group = OptionGroup(self.parser, "Spam")805        self.parser.add_option_group(group)806        group.add_option("--spam", action="store_true",807                         help="spam spam spam spam")808        self.assertParseOK(["--spam"], {'spam': 1}, [])809    def test_add_group_no_group(self):810        self.assertTypeError(self.parser.add_option_group,811                             "not an OptionGroup instance: None", None)812    def test_add_group_invalid_arguments(self):813        self.assertTypeError(self.parser.add_option_group,814                             "invalid arguments", None, None)815    def test_add_group_wrong_parser(self):816        group = OptionGroup(self.parser, "Spam")817        group.parser = OptionParser()818        self.assertRaises(self.parser.add_option_group, (group,), None,819                          ValueError, "invalid OptionGroup (wrong parser)")820    def test_group_manipulate(self):821        group = self.parser.add_option_group("Group 2",822                                             description="Some more options")823        group.set_title("Bacon")824        group.add_option("--bacon", type="int")825        self.assertTrue(self.parser.get_option_group("--bacon"), group)826# -- Test extending and parser.parse_args() ----------------------------827class TestExtendAddTypes(BaseTest):828    def setUp(self):829        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,830                                               option_class=self.MyOption)831        self.parser.add_option("-a", None, type="string", dest="a")832        self.parser.add_option("-f", "--file", type="file", dest="file")833    def tearDown(self):834        if os.path.isdir(support.TESTFN):835            os.rmdir(support.TESTFN)836        elif os.path.isfile(support.TESTFN):837            os.unlink(support.TESTFN)838    class MyOption (Option):839        def check_file(option, opt, value):840            if not os.path.exists(value):841                raise OptionValueError("%s: file does not exist" % value)842            elif not os.path.isfile(value):843                raise OptionValueError("%s: not a regular file" % value)844            return value845        TYPES = Option.TYPES + ("file",)846        TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)847        TYPE_CHECKER["file"] = check_file848    def test_filetype_ok(self):849        support.create_empty_file(support.TESTFN)850        self.assertParseOK(["--file", support.TESTFN, "-afoo"],851                           {'file': support.TESTFN, 'a': 'foo'},852                           [])853    def test_filetype_noexist(self):854        self.assertParseFail(["--file", support.TESTFN, "-afoo"],855                             "%s: file does not exist" %856                             support.TESTFN)857    def test_filetype_notfile(self):858        os.mkdir(support.TESTFN)859        self.assertParseFail(["--file", support.TESTFN, "-afoo"],860                             "%s: not a regular file" %861                             support.TESTFN)862class TestExtendAddActions(BaseTest):863    def setUp(self):864        options = [self.MyOption("-a", "--apple", action="extend",865                                 type="string", dest="apple")]866        self.parser = OptionParser(option_list=options)867    class MyOption (Option):868        ACTIONS = Option.ACTIONS + ("extend",)869        STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)870        TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)871        def take_action(self, action, dest, opt, value, values, parser):872            if action == "extend":873                lvalue = value.split(",")874                values.ensure_value(dest, []).extend(lvalue)875            else:876                Option.take_action(self, action, dest, opt, parser, value,877                                   values)878    def test_extend_add_action(self):879        self.assertParseOK(["-afoo,bar", "--apple=blah"],880                           {'apple': ["foo", "bar", "blah"]},881                           [])882    def test_extend_add_action_normal(self):883        self.assertParseOK(["-a", "foo", "-abar", "--apple=x,y"],884                           {'apple': ["foo", "bar", "x", "y"]},885                           [])886# -- Test callbacks and parser.parse_args() ----------------------------887class TestCallback(BaseTest):888    def setUp(self):889        options = [make_option("-x",890                               None,891                               action="callback",892                               callback=self.process_opt),893                   make_option("-f",894                               "--file",895                               action="callback",896                               callback=self.process_opt,897                               type="string",898                               dest="filename")]899        self.parser = OptionParser(option_list=options)900    def process_opt(self, option, opt, value, parser_):901        if opt == "-x":902            self.assertEqual(option._short_opts, ["-x"])903            self.assertEqual(option._long_opts, [])904            self.assertTrue(parser_ is self.parser)905            self.assertTrue(value is None)906            self.assertEqual(vars(parser_.values), {'filename': None})907            parser_.values.x = 42908        elif opt == "--file":909            self.assertEqual(option._short_opts, ["-f"])910            self.assertEqual(option._long_opts, ["--file"])911            self.assertTrue(parser_ is self.parser)912            self.assertEqual(value, "foo")913            self.assertEqual(vars(parser_.values), {'filename': None, 'x': 42})914            setattr(parser_.values, option.dest, value)915        else:916            self.fail("Unknown option %r in process_opt." % opt)917    def test_callback(self):918        self.assertParseOK(["-x", "--file=foo"],919                           {'filename': "foo", 'x': 42},920                           [])921    def test_callback_help(self):922        # This test was prompted by SF bug #960515 -- the point is923        # not to inspect the help text, just to make sure that924        # format_help() doesn't crash.925        parser = OptionParser(usage=SUPPRESS_USAGE)926        parser.remove_option("-h")927        parser.add_option("-t", "--test", action="callback",928                          callback=lambda: None, type="string",929                          help="foo")930        expected_help = ("Options:\n"931                         "  -t TEST, --test=TEST  foo\n")932        self.assertHelp(parser, expected_help)933class TestCallbackExtraArgs(BaseTest):934    def setUp(self):935        options = [make_option("-p", "--point", action="callback",936                               callback=self.process_tuple,937                               callback_args=(3, int), type="string",938                               dest="points", default=[])]939        self.parser = OptionParser(option_list=options)940    def process_tuple(self, option, opt, value, parser_, len, type):941        self.assertEqual(len, 3)942        self.assertTrue(type is int)943        if opt == "-p":944            self.assertEqual(value, "1,2,3")945        elif opt == "--point":946            self.assertEqual(value, "4,5,6")947        value = tuple(map(type, value.split(",")))948        getattr(parser_.values, option.dest).append(value)949    def test_callback_extra_args(self):950        self.assertParseOK(["-p1,2,3", "--point", "4,5,6"],951                           {'points': [(1,2,3), (4,5,6)]},952                           [])953class TestCallbackMeddleArgs(BaseTest):954    def setUp(self):955        options = [make_option(str(x), action="callback",956                               callback=self.process_n, dest='things')957                   for x in range(-1, -6, -1)]958        self.parser = OptionParser(option_list=options)959    # Callback that meddles in rargs, largs960    def process_n(self, option, opt, value, parser_):961        # option is -3, -5, etc.962        nargs = int(opt[1:])963        rargs = parser_.rargs964        if len(rargs) < nargs:965            self.fail("Expected %d arguments for %s option." % (nargs, opt))966        dest = parser_.values.ensure_value(option.dest, [])967        dest.append(tuple(rargs[0:nargs]))968        parser_.largs.append(nargs)969        del rargs[0:nargs]970    def test_callback_meddle_args(self):971        self.assertParseOK(["-1", "foo", "-3", "bar", "baz", "qux"],972                           {'things': [("foo",), ("bar", "baz", "qux")]},973                           [1, 3])974    def test_callback_meddle_args_separator(self):975        self.assertParseOK(["-2", "foo", "--"],976                           {'things': [('foo', '--')]},977                           [2])978class TestCallbackManyArgs(BaseTest):979    def setUp(self):980        options = [make_option("-a", "--apple", action="callback", nargs=2,981                               callback=self.process_many, type="string"),982                   make_option("-b", "--bob", action="callback", nargs=3,983                               callback=self.process_many, type="int")]984        self.parser = OptionParser(option_list=options)985    def process_many(self, option, opt, value, parser_):986        if opt == "-a":987            self.assertEqual(value, ("foo", "bar"))988        elif opt == "--apple":989            self.assertEqual(value, ("ding", "dong"))990        elif opt == "-b":991            self.assertEqual(value, (1, 2, 3))992        elif opt == "--bob":993            self.assertEqual(value, (-666, 42, 0))994    def test_many_args(self):995        self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong",996                            "-b", "1", "2", "3", "--bob", "-666", "42",997                            "0"],998                           {"apple": None, "bob": None},999                           [])1000class TestCallbackCheckAbbrev(BaseTest):1001    def setUp(self):1002        self.parser = OptionParser()1003        self.parser.add_option("--foo-bar", action="callback",1004                               callback=self.check_abbrev)1005    def check_abbrev(self, option, opt, value, parser):1006        self.assertEqual(opt, "--foo-bar")1007    def test_abbrev_callback_expansion(self):1008        self.assertParseOK(["--foo"], {}, [])1009class TestCallbackVarArgs(BaseTest):1010    def setUp(self):1011        options = [make_option("-a", type="int", nargs=2, dest="a"),1012                   make_option("-b", action="store_true", dest="b"),1013                   make_option("-c", "--callback", action="callback",1014                               callback=self.variable_args, dest="c")]1015        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,1016                                               option_list=options)1017    def variable_args(self, option, opt, value, parser):1018        self.assertTrue(value is None)1019        value = []1020        rargs = parser.rargs1021        while rargs:1022            arg = rargs[0]1023            if ((arg[:2] == "--" and len(arg) > 2) or1024                (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):1025                break1026            else:1027                value.append(arg)1028                del rargs[0]1029        setattr(parser.values, option.dest, value)1030    def test_variable_args(self):1031        self.assertParseOK(["-a3", "-5", "--callback", "foo", "bar"],1032                           {'a': (3, -5), 'b': None, 'c': ["foo", "bar"]},1033                           [])1034    def test_consume_separator_stop_at_option(self):1035        self.assertParseOK(["-c", "37", "--", "xxx", "-b", "hello"],1036                           {'a': None,1037                            'b': True,1038                            'c': ["37", "--", "xxx"]},1039                           ["hello"])1040    def test_positional_arg_and_variable_args(self):1041        self.assertParseOK(["hello", "-c", "foo", "-", "bar"],1042                           {'a': None,1043                            'b': None,1044                            'c':["foo", "-", "bar"]},1045                           ["hello"])1046    def test_stop_at_option(self):1047        self.assertParseOK(["-c", "foo", "-b"],1048                           {'a': None, 'b': True, 'c': ["foo"]},1049                           [])1050    def test_stop_at_invalid_option(self):1051        self.assertParseFail(["-c", "3", "-5", "-a"], "no such option: -5")1052# -- Test conflict handling and parser.parse_args() --------------------1053class ConflictBase(BaseTest):1054    def setUp(self):1055        options = [make_option("-v", "--verbose", action="count",1056                               dest="verbose", help="increment verbosity")]1057        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,1058                                               option_list=options)1059    def show_version(self, option, opt, value, parser):1060        parser.values.show_version = 11061class TestConflict(ConflictBase):1062    """Use the default conflict resolution for Optik 1.2: error."""1063    def assertTrueconflict_error(self, func):1064        err = self.assertRaises(1065            func, ("-v", "--version"), {'action' : "callback",1066                                        'callback' : self.show_version,1067                                        'help' : "show version"},1068            OptionConflictError,1069            "option -v/--version: conflicting option string(s): -v")1070        self.assertEqual(err.msg, "conflicting option string(s): -v")1071        self.assertEqual(err.option_id, "-v/--version")1072    def test_conflict_error(self):1073        self.assertTrueconflict_error(self.parser.add_option)1074    def test_conflict_error_group(self):1075        group = OptionGroup(self.parser, "Group 1")1076        self.assertTrueconflict_error(group.add_option)1077    def test_no_such_conflict_handler(self):1078        self.assertRaises(1079            self.parser.set_conflict_handler, ('foo',), None,1080            ValueError, "invalid conflict_resolution value 'foo'")1081class TestConflictResolve(ConflictBase):1082    def setUp(self):1083        ConflictBase.setUp(self)1084        self.parser.set_conflict_handler("resolve")1085        self.parser.add_option("-v", "--version", action="callback",1086                               callback=self.show_version, help="show version")1087    def test_conflict_resolve(self):1088        v_opt = self.parser.get_option("-v")1089        verbose_opt = self.parser.get_option("--verbose")1090        version_opt = self.parser.get_option("--version")1091        self.assertTrue(v_opt is version_opt)1092        self.assertTrue(v_opt is not verbose_opt)1093        self.assertEqual(v_opt._long_opts, ["--version"])1094        self.assertEqual(version_opt._short_opts, ["-v"])1095        self.assertEqual(version_opt._long_opts, ["--version"])1096        self.assertEqual(verbose_opt._short_opts, [])1097        self.assertEqual(verbose_opt._long_opts, ["--verbose"])1098    def test_conflict_resolve_help(self):1099        self.assertOutput(["-h"], """\1100Options:1101  --verbose      increment verbosity1102  -h, --help     show this help message and exit1103  -v, --version  show version1104""")1105    def test_conflict_resolve_short_opt(self):1106        self.assertParseOK(["-v"],1107                           {'verbose': None, 'show_version': 1},1108                           [])1109    def test_conflict_resolve_long_opt(self):1110        self.assertParseOK(["--verbose"],1111                           {'verbose': 1},1112                           [])1113    def test_conflict_resolve_long_opts(self):1114        self.assertParseOK(["--verbose", "--version"],1115                           {'verbose': 1, 'show_version': 1},1116                           [])1117class TestConflictOverride(BaseTest):1118    def setUp(self):1119        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)1120        self.parser.set_conflict_handler("resolve")1121        self.parser.add_option("-n", "--dry-run",1122                               action="store_true", dest="dry_run",1123                               help="don't do anything")1124        self.parser.add_option("--dry-run", "-n",1125                               action="store_const", const=42, dest="dry_run",1126                               help="dry run mode")1127    def test_conflict_override_opts(self):1128        opt = self.parser.get_option("--dry-run")1129        self.assertEqual(opt._short_opts, ["-n"])1130        self.assertEqual(opt._long_opts, ["--dry-run"])1131    def test_conflict_override_help(self):1132        self.assertOutput(["-h"], """\1133Options:1134  -h, --help     show this help message and exit1135  -n, --dry-run  dry run mode1136""")1137    def test_conflict_override_args(self):1138        self.assertParseOK(["-n"],1139                           {'dry_run': 42},1140                           [])1141# -- Other testing. ----------------------------------------------------1142_expected_help_basic = """\1143Usage: bar.py [options]1144Options:1145  -a APPLE           throw APPLEs at basket1146  -b NUM, --boo=NUM  shout "boo!" NUM times (in order to frighten away all the1147                     evil spirits that cause trouble and mayhem)1148  --foo=FOO          store FOO in the foo list for later fooing1149  -h, --help         show this help message and exit1150"""1151_expected_help_long_opts_first = """\1152Usage: bar.py [options]1153Options:1154  -a APPLE           throw APPLEs at basket1155  --boo=NUM, -b NUM  shout "boo!" NUM times (in order to frighten away all the1156                     evil spirits that cause trouble and mayhem)1157  --foo=FOO          store FOO in the foo list for later fooing1158  --help, -h         show this help message and exit1159"""1160_expected_help_title_formatter = """\1161Usage1162=====1163  bar.py [options]1164Options1165=======1166-a APPLE           throw APPLEs at basket1167--boo=NUM, -b NUM  shout "boo!" NUM times (in order to frighten away all the1168                   evil spirits that cause trouble and mayhem)1169--foo=FOO          store FOO in the foo list for later fooing1170--help, -h         show this help message and exit1171"""1172_expected_help_short_lines = """\1173Usage: bar.py [options]1174Options:1175  -a APPLE           throw APPLEs at basket1176  -b NUM, --boo=NUM  shout "boo!" NUM times (in order to1177                     frighten away all the evil spirits1178                     that cause trouble and mayhem)1179  --foo=FOO          store FOO in the foo list for later1180                     fooing1181  -h, --help         show this help message and exit1182"""1183class TestHelp(BaseTest):1184    def setUp(self):1185        self.parser = self.make_parser(80)1186    def make_parser(self, columns):1187        options = [1188            make_option("-a", type="string", dest='a',1189                        metavar="APPLE", help="throw APPLEs at basket"),1190            make_option("-b", "--boo", type="int", dest='boo',1191                        metavar="NUM",1192                        help=1193                        "shout \"boo!\" NUM times (in order to frighten away "1194                        "all the evil spirits that cause trouble and mayhem)"),1195            make_option("--foo", action="append", type="string", dest='foo',1196                        help="store FOO in the foo list for later fooing"),1197            ]1198        # We need to set COLUMNS for the OptionParser constructor, but1199        # we must restore its original value -- otherwise, this test1200        # screws things up for other tests when it's part of the Python1201        # test suite.1202        with support.EnvironmentVarGuard() as env:1203            env['COLUMNS'] = str(columns)1204            return InterceptingOptionParser(option_list=options)1205    def assertHelpEquals(self, expected_output):1206        save_argv = sys.argv[:]1207        try:1208            # Make optparse believe bar.py is being executed.1209            sys.argv[0] = os.path.join("foo", "bar.py")1210            self.assertOutput(["-h"], expected_output)1211        finally:1212            sys.argv[:] = save_argv1213    def test_help(self):1214        self.assertHelpEquals(_expected_help_basic)1215    def test_help_old_usage(self):1216        self.parser.set_usage("Usage: %prog [options]")1217        self.assertHelpEquals(_expected_help_basic)1218    def test_help_long_opts_first(self):1219        self.parser.formatter.short_first = 01220        self.assertHelpEquals(_expected_help_long_opts_first)1221    def test_help_title_formatter(self):1222        with support.EnvironmentVarGuard() as env:1223            env["COLUMNS"] = "80"1224            self.parser.formatter = TitledHelpFormatter()1225            self.assertHelpEquals(_expected_help_title_formatter)1226    def test_wrap_columns(self):1227        # Ensure that wrapping respects $COLUMNS environment variable.1228        # Need to reconstruct the parser, since that's the only time1229        # we look at $COLUMNS.1230        self.parser = self.make_parser(60)1231        self.assertHelpEquals(_expected_help_short_lines)1232    def test_help_unicode(self):1233        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)1234        self.parser.add_option("-a", action="store_true", help="ol\u00E9!")1235        expect = """\1236Options:1237  -h, --help  show this help message and exit1238  -a          ol\u00E9!1239"""1240        self.assertHelpEquals(expect)1241    def test_help_unicode_description(self):1242        self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,1243                                               description="ol\u00E9!")1244        expect = """\1245ol\u00E9!1246Options:1247  -h, --help  show this help message and exit1248"""1249        self.assertHelpEquals(expect)1250    def test_help_description_groups(self):1251        self.parser.set_description(1252            "This is the program description for %prog.  %prog has "1253            "an option group as well as single options.")1254        group = OptionGroup(1255            self.parser, "Dangerous Options",1256            "Caution: use of these options is at your own risk.  "1257            "It is believed that some of them bite.")1258        group.add_option("-g", action="store_true", help="Group option.")1259        self.parser.add_option_group(group)1260        expect = """\1261Usage: bar.py [options]1262This is the program description for bar.py.  bar.py has an option group as1263well as single options.1264Options:1265  -a APPLE           throw APPLEs at basket1266  -b NUM, --boo=NUM  shout "boo!" NUM times (in order to frighten away all the1267                     evil spirits that cause trouble and mayhem)1268  --foo=FOO          store FOO in the foo list for later fooing1269  -h, --help         show this help message and exit1270  Dangerous Options:1271    Caution: use of these options is at your own risk.  It is believed1272    that some of them bite.1273    -g               Group option.1274"""1275        self.assertHelpEquals(expect)1276        self.parser.epilog = "Please report bugs to /dev/null."1277        self.assertHelpEquals(expect + "\nPlease report bugs to /dev/null.\n")1278class TestMatchAbbrev(BaseTest):1279    def test_match_abbrev(self):1280        self.assertEqual(_match_abbrev("--f",1281                                       {"--foz": None,1282                                        "--foo": None,1283                                        "--fie": None,1284                                        "--f": None}),1285                         "--f")1286    def test_match_abbrev_error(self):1287        s = "--f"1288        wordmap = {"--foz": None, "--foo": None, "--fie": None}1289        self.assertRaises(1290            _match_abbrev, (s, wordmap), None,1291            BadOptionError, "ambiguous option: --f (--fie, --foo, --foz?)")1292class TestParseNumber(BaseTest):1293    def setUp(self):1294        self.parser = InterceptingOptionParser()1295        self.parser.add_option("-n", type=int)1296        self.parser.add_option("-l", type=int)1297    def test_parse_num_fail(self):1298        self.assertRaises(1299            _parse_num, ("", int), {},1300            ValueError,1301            re.compile(r"invalid literal for int().*: '?'?"))1302        self.assertRaises(1303            _parse_num, ("0xOoops", int), {},1304            ValueError,1305            re.compile(r"invalid literal for int().*: s?'?0xOoops'?"))1306    def test_parse_num_ok(self):1307        self.assertEqual(_parse_num("0", int), 0)1308        self.assertEqual(_parse_num("0x10", int), 16)1309        self.assertEqual(_parse_num("0XA", int), 10)1310        self.assertEqual(_parse_num("010", int), 8)...optparse.py
Source:optparse.py  
...5(http://lists.sourceforge.net/lists/listinfo/optik-users).6Simple usage example:7   from optparse import OptionParser8   parser = OptionParser()9   parser.add_option("-f", "--file", dest="filename",10                     help="write report to FILE", metavar="FILE")11   parser.add_option("-q", "--quiet",12                     action="store_false", dest="verbose", default=True,13                     help="don't print status messages to stdout")14   (options, args) = parser.parse_args()15"""16__version__ = "1.5.3"17__all__ = ['Option',18           'make_option',19           'SUPPRESS_HELP',20           'SUPPRESS_USAGE',21           'Values',22           'OptionContainer',23           'OptionGroup',24           'OptionParser',25           'HelpFormatter',26           'IndentedHelpFormatter',27           'TitledHelpFormatter',28           'OptParseError',29           'OptionError',30           'OptionConflictError',31           'OptionValueError',32           'BadOptionError']33__copyright__ = """34Copyright (c) 2001-2006 Gregory P. Ward.  All rights reserved.35Copyright (c) 2002-2006 Python Software Foundation.  All rights reserved.36Redistribution and use in source and binary forms, with or without37modification, are permitted provided that the following conditions are38met:39  * Redistributions of source code must retain the above copyright40    notice, this list of conditions and the following disclaimer.41  * Redistributions in binary form must reproduce the above copyright42    notice, this list of conditions and the following disclaimer in the43    documentation and/or other materials provided with the distribution.44  * Neither the name of the author nor the names of its45    contributors may be used to endorse or promote products derived from46    this software without specific prior written permission.47THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS48IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED49TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A50PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR51CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,52EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,53PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR54PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF55LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING56NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS57SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.58"""59import sys, os60import textwrap61def _repr(self):62    return "<%s at 0x%x: %s>" % (self.__class__.__name__, id(self), self)63# This file was generated from:64#   Id: option_parser.py 527 2006-07-23 15:21:30Z greg65#   Id: option.py 522 2006-06-11 16:22:03Z gward66#   Id: help.py 527 2006-07-23 15:21:30Z greg67#   Id: errors.py 509 2006-04-20 00:58:24Z gward68try:69    from gettext import gettext, ngettext70except ImportError:71    def gettext(message):72        return message73    def ngettext(singular, plural, n):74        if n == 1:75            return singular76        return plural77_ = gettext78class OptParseError (Exception):79    def __init__(self, msg):80        self.msg = msg81    def __str__(self):82        return self.msg83class OptionError (OptParseError):84    """85    Raised if an Option instance is created with invalid or86    inconsistent arguments.87    """88    def __init__(self, msg, option):89        self.msg = msg90        self.option_id = str(option)91    def __str__(self):92        if self.option_id:93            return "option %s: %s" % (self.option_id, self.msg)94        else:95            return self.msg96class OptionConflictError (OptionError):97    """98    Raised if conflicting options are added to an OptionParser.99    """100class OptionValueError (OptParseError):101    """102    Raised if an invalid option value is encountered on the command103    line.104    """105class BadOptionError (OptParseError):106    """107    Raised if an invalid option is seen on the command line.108    """109    def __init__(self, opt_str):110        self.opt_str = opt_str111    def __str__(self):112        return _("no such option: %s") % self.opt_str113class AmbiguousOptionError (BadOptionError):114    """115    Raised if an ambiguous option is seen on the command line.116    """117    def __init__(self, opt_str, possibilities):118        BadOptionError.__init__(self, opt_str)119        self.possibilities = possibilities120    def __str__(self):121        return (_("ambiguous option: %s (%s?)")122                % (self.opt_str, ", ".join(self.possibilities)))123class HelpFormatter:124    """125    Abstract base class for formatting option help.  OptionParser126    instances should use one of the HelpFormatter subclasses for127    formatting help; by default IndentedHelpFormatter is used.128    Instance attributes:129      parser : OptionParser130        the controlling OptionParser instance131      indent_increment : int132        the number of columns to indent per nesting level133      max_help_position : int134        the maximum starting column for option help text135      help_position : int136        the calculated starting column for option help text;137        initially the same as the maximum138      width : int139        total number of columns for output (pass None to constructor for140        this value to be taken from the $COLUMNS environment variable)141      level : int142        current indentation level143      current_indent : int144        current indentation level (in columns)145      help_width : int146        number of columns available for option help text (calculated)147      default_tag : str148        text to replace with each option's default value, "%default"149        by default.  Set to false value to disable default value expansion.150      option_strings : { Option : str }151        maps Option instances to the snippet of help text explaining152        the syntax of that option, e.g. "-h, --help" or153        "-fFILE, --file=FILE"154      _short_opt_fmt : str155        format string controlling how short options with values are156        printed in help text.  Must be either "%s%s" ("-fFILE") or157        "%s %s" ("-f FILE"), because those are the two syntaxes that158        Optik supports.159      _long_opt_fmt : str160        similar but for long options; must be either "%s %s" ("--file FILE")161        or "%s=%s" ("--file=FILE").162    """163    NO_DEFAULT_VALUE = "none"164    def __init__(self,165                 indent_increment,166                 max_help_position,167                 width,168                 short_first):169        self.parser = None170        self.indent_increment = indent_increment171        self.help_position = self.max_help_position = max_help_position172        if width is None:173            try:174                width = int(os.environ['COLUMNS'])175            except (KeyError, ValueError):176                width = 80177            width -= 2178        self.width = width179        self.current_indent = 0180        self.level = 0181        self.help_width = None          # computed later182        self.short_first = short_first183        self.default_tag = "%default"184        self.option_strings = {}185        self._short_opt_fmt = "%s %s"186        self._long_opt_fmt = "%s=%s"187    def set_parser(self, parser):188        self.parser = parser189    def set_short_opt_delimiter(self, delim):190        if delim not in ("", " "):191            raise ValueError(192                "invalid metavar delimiter for short options: %r" % delim)193        self._short_opt_fmt = "%s" + delim + "%s"194    def set_long_opt_delimiter(self, delim):195        if delim not in ("=", " "):196            raise ValueError(197                "invalid metavar delimiter for long options: %r" % delim)198        self._long_opt_fmt = "%s" + delim + "%s"199    def indent(self):200        self.current_indent += self.indent_increment201        self.level += 1202    def dedent(self):203        self.current_indent -= self.indent_increment204        assert self.current_indent >= 0, "Indent decreased below 0."205        self.level -= 1206    def format_usage(self, usage):207        raise NotImplementedError("subclasses must implement")208    def format_heading(self, heading):209        raise NotImplementedError("subclasses must implement")210    def _format_text(self, text):211        """212        Format a paragraph of free-form text for inclusion in the213        help output at the current indentation level.214        """215        text_width = self.width - self.current_indent216        indent = " "*self.current_indent217        return textwrap.fill(text,218                             text_width,219                             initial_indent=indent,220                             subsequent_indent=indent)221    def format_description(self, description):222        if description:223            return self._format_text(description) + "\n"224        else:225            return ""226    def format_epilog(self, epilog):227        if epilog:228            return "\n" + self._format_text(epilog) + "\n"229        else:230            return ""231    def expand_default(self, option):232        if self.parser is None or not self.default_tag:233            return option.help234        default_value = self.parser.defaults.get(option.dest)235        if default_value is NO_DEFAULT or default_value is None:236            default_value = self.NO_DEFAULT_VALUE237        return option.help.replace(self.default_tag, str(default_value))238    def format_option(self, option):239        # The help for each option consists of two parts:240        #   * the opt strings and metavars241        #     eg. ("-x", or "-fFILENAME, --file=FILENAME")242        #   * the user-supplied help string243        #     eg. ("turn on expert mode", "read data from FILENAME")244        #245        # If possible, we write both of these on the same line:246        #   -x      turn on expert mode247        #248        # But if the opt string list is too long, we put the help249        # string on a second line, indented to the same column it would250        # start in if it fit on the first line.251        #   -fFILENAME, --file=FILENAME252        #           read data from FILENAME253        result = []254        opts = self.option_strings[option]255        opt_width = self.help_position - self.current_indent - 2256        if len(opts) > opt_width:257            opts = "%*s%s\n" % (self.current_indent, "", opts)258            indent_first = self.help_position259        else:                       # start help on same line as opts260            opts = "%*s%-*s  " % (self.current_indent, "", opt_width, opts)261            indent_first = 0262        result.append(opts)263        if option.help:264            help_text = self.expand_default(option)265            help_lines = textwrap.wrap(help_text, self.help_width)266            result.append("%*s%s\n" % (indent_first, "", help_lines[0]))267            result.extend(["%*s%s\n" % (self.help_position, "", line)268                           for line in help_lines[1:]])269        elif opts[-1] != "\n":270            result.append("\n")271        return "".join(result)272    def store_option_strings(self, parser):273        self.indent()274        max_len = 0275        for opt in parser.option_list:276            strings = self.format_option_strings(opt)277            self.option_strings[opt] = strings278            max_len = max(max_len, len(strings) + self.current_indent)279        self.indent()280        for group in parser.option_groups:281            for opt in group.option_list:282                strings = self.format_option_strings(opt)283                self.option_strings[opt] = strings284                max_len = max(max_len, len(strings) + self.current_indent)285        self.dedent()286        self.dedent()287        self.help_position = min(max_len + 2, self.max_help_position)288        self.help_width = self.width - self.help_position289    def format_option_strings(self, option):290        """Return a comma-separated list of option strings & metavariables."""291        if option.takes_value():292            metavar = option.metavar or option.dest.upper()293            short_opts = [self._short_opt_fmt % (sopt, metavar)294                          for sopt in option._short_opts]295            long_opts = [self._long_opt_fmt % (lopt, metavar)296                         for lopt in option._long_opts]297        else:298            short_opts = option._short_opts299            long_opts = option._long_opts300        if self.short_first:301            opts = short_opts + long_opts302        else:303            opts = long_opts + short_opts304        return ", ".join(opts)305class IndentedHelpFormatter (HelpFormatter):306    """Format help with indented section bodies.307    """308    def __init__(self,309                 indent_increment=2,310                 max_help_position=24,311                 width=None,312                 short_first=1):313        HelpFormatter.__init__(314            self, indent_increment, max_help_position, width, short_first)315    def format_usage(self, usage):316        return _("Usage: %s\n") % usage317    def format_heading(self, heading):318        return "%*s%s:\n" % (self.current_indent, "", heading)319class TitledHelpFormatter (HelpFormatter):320    """Format help with underlined section headers.321    """322    def __init__(self,323                 indent_increment=0,324                 max_help_position=24,325                 width=None,326                 short_first=0):327        HelpFormatter.__init__ (328            self, indent_increment, max_help_position, width, short_first)329    def format_usage(self, usage):330        return "%s  %s\n" % (self.format_heading(_("Usage")), usage)331    def format_heading(self, heading):332        return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading))333def _parse_num(val, type):334    if val[:2].lower() == "0x":         # hexadecimal335        radix = 16336    elif val[:2].lower() == "0b":       # binary337        radix = 2338        val = val[2:] or "0"            # have to remove "0b" prefix339    elif val[:1] == "0":                # octal340        radix = 8341    else:                               # decimal342        radix = 10343    return type(val, radix)344def _parse_int(val):345    return _parse_num(val, int)346_builtin_cvt = { "int" : (_parse_int, _("integer")),347                 "long" : (_parse_int, _("integer")),348                 "float" : (float, _("floating-point")),349                 "complex" : (complex, _("complex")) }350def check_builtin(option, opt, value):351    (cvt, what) = _builtin_cvt[option.type]352    try:353        return cvt(value)354    except ValueError:355        raise OptionValueError(356            _("option %s: invalid %s value: %r") % (opt, what, value))357def check_choice(option, opt, value):358    if value in option.choices:359        return value360    else:361        choices = ", ".join(map(repr, option.choices))362        raise OptionValueError(363            _("option %s: invalid choice: %r (choose from %s)")364            % (opt, value, choices))365# Not supplying a default is different from a default of None,366# so we need an explicit "not supplied" value.367NO_DEFAULT = ("NO", "DEFAULT")368class Option:369    """370    Instance attributes:371      _short_opts : [string]372      _long_opts : [string]373      action : string374      type : string375      dest : string376      default : any377      nargs : int378      const : any379      choices : [string]380      callback : function381      callback_args : (any*)382      callback_kwargs : { string : any }383      help : string384      metavar : string385    """386    # The list of instance attributes that may be set through387    # keyword args to the constructor.388    ATTRS = ['action',389             'type',390             'dest',391             'default',392             'nargs',393             'const',394             'choices',395             'callback',396             'callback_args',397             'callback_kwargs',398             'help',399             'metavar']400    # The set of actions allowed by option parsers.  Explicitly listed401    # here so the constructor can validate its arguments.402    ACTIONS = ("store",403               "store_const",404               "store_true",405               "store_false",406               "append",407               "append_const",408               "count",409               "callback",410               "help",411               "version")412    # The set of actions that involve storing a value somewhere;413    # also listed just for constructor argument validation.  (If414    # the action is one of these, there must be a destination.)415    STORE_ACTIONS = ("store",416                     "store_const",417                     "store_true",418                     "store_false",419                     "append",420                     "append_const",421                     "count")422    # The set of actions for which it makes sense to supply a value423    # type, ie. which may consume an argument from the command line.424    TYPED_ACTIONS = ("store",425                     "append",426                     "callback")427    # The set of actions which *require* a value type, ie. that428    # always consume an argument from the command line.429    ALWAYS_TYPED_ACTIONS = ("store",430                            "append")431    # The set of actions which take a 'const' attribute.432    CONST_ACTIONS = ("store_const",433                     "append_const")434    # The set of known types for option parsers.  Again, listed here for435    # constructor argument validation.436    TYPES = ("string", "int", "long", "float", "complex", "choice")437    # Dictionary of argument checking functions, which convert and438    # validate option arguments according to the option type.439    #440    # Signature of checking functions is:441    #   check(option : Option, opt : string, value : string) -> any442    # where443    #   option is the Option instance calling the checker444    #   opt is the actual option seen on the command-line445    #     (eg. "-a", "--file")446    #   value is the option argument seen on the command-line447    #448    # The return value should be in the appropriate Python type449    # for option.type -- eg. an integer if option.type == "int".450    #451    # If no checker is defined for a type, arguments will be452    # unchecked and remain strings.453    TYPE_CHECKER = { "int"    : check_builtin,454                     "long"   : check_builtin,455                     "float"  : check_builtin,456                     "complex": check_builtin,457                     "choice" : check_choice,458                   }459    # CHECK_METHODS is a list of unbound method objects; they are called460    # by the constructor, in order, after all attributes are461    # initialized.  The list is created and filled in later, after all462    # the methods are actually defined.  (I just put it here because I463    # like to define and document all class attributes in the same464    # place.)  Subclasses that add another _check_*() method should465    # define their own CHECK_METHODS list that adds their check method466    # to those from this class.467    CHECK_METHODS = None468    # -- Constructor/initialization methods ----------------------------469    def __init__(self, *opts, **attrs):470        # Set _short_opts, _long_opts attrs from 'opts' tuple.471        # Have to be set now, in case no option strings are supplied.472        self._short_opts = []473        self._long_opts = []474        opts = self._check_opt_strings(opts)475        self._set_opt_strings(opts)476        # Set all other attrs (action, type, etc.) from 'attrs' dict477        self._set_attrs(attrs)478        # Check all the attributes we just set.  There are lots of479        # complicated interdependencies, but luckily they can be farmed480        # out to the _check_*() methods listed in CHECK_METHODS -- which481        # could be handy for subclasses!  The one thing these all share482        # is that they raise OptionError if they discover a problem.483        for checker in self.CHECK_METHODS:484            checker(self)485    def _check_opt_strings(self, opts):486        # Filter out None because early versions of Optik had exactly487        # one short option and one long option, either of which488        # could be None.489        opts = [opt for opt in opts if opt]490        if not opts:491            raise TypeError("at least one option string must be supplied")492        return opts493    def _set_opt_strings(self, opts):494        for opt in opts:495            if len(opt) < 2:496                raise OptionError(497                    "invalid option string %r: "498                    "must be at least two characters long" % opt, self)499            elif len(opt) == 2:500                if not (opt[0] == "-" and opt[1] != "-"):501                    raise OptionError(502                        "invalid short option string %r: "503                        "must be of the form -x, (x any non-dash char)" % opt,504                        self)505                self._short_opts.append(opt)506            else:507                if not (opt[0:2] == "--" and opt[2] != "-"):508                    raise OptionError(509                        "invalid long option string %r: "510                        "must start with --, followed by non-dash" % opt,511                        self)512                self._long_opts.append(opt)513    def _set_attrs(self, attrs):514        for attr in self.ATTRS:515            if attr in attrs:516                setattr(self, attr, attrs[attr])517                del attrs[attr]518            else:519                if attr == 'default':520                    setattr(self, attr, NO_DEFAULT)521                else:522                    setattr(self, attr, None)523        if attrs:524            attrs = sorted(attrs.keys())525            raise OptionError(526                "invalid keyword arguments: %s" % ", ".join(attrs),527                self)528    # -- Constructor validation methods --------------------------------529    def _check_action(self):530        if self.action is None:531            self.action = "store"532        elif self.action not in self.ACTIONS:533            raise OptionError("invalid action: %r" % self.action, self)534    def _check_type(self):535        if self.type is None:536            if self.action in self.ALWAYS_TYPED_ACTIONS:537                if self.choices is not None:538                    # The "choices" attribute implies "choice" type.539                    self.type = "choice"540                else:541                    # No type given?  "string" is the most sensible default.542                    self.type = "string"543        else:544            # Allow type objects or builtin type conversion functions545            # (int, str, etc.) as an alternative to their names.  (The546            # complicated check of builtins is only necessary for547            # Python 2.1 and earlier, and is short-circuited by the548            # first check on modern Pythons.)549            import builtins550            if ( isinstance(self.type, type) or551                 (hasattr(self.type, "__name__") and552                  getattr(builtins, self.type.__name__, None) is self.type) ):553                self.type = self.type.__name__554            if self.type == "str":555                self.type = "string"556            if self.type not in self.TYPES:557                raise OptionError("invalid option type: %r" % self.type, self)558            if self.action not in self.TYPED_ACTIONS:559                raise OptionError(560                    "must not supply a type for action %r" % self.action, self)561    def _check_choice(self):562        if self.type == "choice":563            if self.choices is None:564                raise OptionError(565                    "must supply a list of choices for type 'choice'", self)566            elif not isinstance(self.choices, (tuple, list)):567                raise OptionError(568                    "choices must be a list of strings ('%s' supplied)"569                    % str(type(self.choices)).split("'")[1], self)570        elif self.choices is not None:571            raise OptionError(572                "must not supply choices for type %r" % self.type, self)573    def _check_dest(self):574        # No destination given, and we need one for this action.  The575        # self.type check is for callbacks that take a value.576        takes_value = (self.action in self.STORE_ACTIONS or577                       self.type is not None)578        if self.dest is None and takes_value:579            # Glean a destination from the first long option string,580            # or from the first short option string if no long options.581            if self._long_opts:582                # eg. "--foo-bar" -> "foo_bar"583                self.dest = self._long_opts[0][2:].replace('-', '_')584            else:585                self.dest = self._short_opts[0][1]586    def _check_const(self):587        if self.action not in self.CONST_ACTIONS and self.const is not None:588            raise OptionError(589                "'const' must not be supplied for action %r" % self.action,590                self)591    def _check_nargs(self):592        if self.action in self.TYPED_ACTIONS:593            if self.nargs is None:594                self.nargs = 1595        elif self.nargs is not None:596            raise OptionError(597                "'nargs' must not be supplied for action %r" % self.action,598                self)599    def _check_callback(self):600        if self.action == "callback":601            if not callable(self.callback):602                raise OptionError(603                    "callback not callable: %r" % self.callback, self)604            if (self.callback_args is not None and605                not isinstance(self.callback_args, tuple)):606                raise OptionError(607                    "callback_args, if supplied, must be a tuple: not %r"608                    % self.callback_args, self)609            if (self.callback_kwargs is not None and610                not isinstance(self.callback_kwargs, dict)):611                raise OptionError(612                    "callback_kwargs, if supplied, must be a dict: not %r"613                    % self.callback_kwargs, self)614        else:615            if self.callback is not None:616                raise OptionError(617                    "callback supplied (%r) for non-callback option"618                    % self.callback, self)619            if self.callback_args is not None:620                raise OptionError(621                    "callback_args supplied for non-callback option", self)622            if self.callback_kwargs is not None:623                raise OptionError(624                    "callback_kwargs supplied for non-callback option", self)625    CHECK_METHODS = [_check_action,626                     _check_type,627                     _check_choice,628                     _check_dest,629                     _check_const,630                     _check_nargs,631                     _check_callback]632    # -- Miscellaneous methods -----------------------------------------633    def __str__(self):634        return "/".join(self._short_opts + self._long_opts)635    __repr__ = _repr636    def takes_value(self):637        return self.type is not None638    def get_opt_string(self):639        if self._long_opts:640            return self._long_opts[0]641        else:642            return self._short_opts[0]643    # -- Processing methods --------------------------------------------644    def check_value(self, opt, value):645        checker = self.TYPE_CHECKER.get(self.type)646        if checker is None:647            return value648        else:649            return checker(self, opt, value)650    def convert_value(self, opt, value):651        if value is not None:652            if self.nargs == 1:653                return self.check_value(opt, value)654            else:655                return tuple([self.check_value(opt, v) for v in value])656    def process(self, opt, value, values, parser):657        # First, convert the value(s) to the right type.  Howl if any658        # value(s) are bogus.659        value = self.convert_value(opt, value)660        # And then take whatever action is expected of us.661        # This is a separate method to make life easier for662        # subclasses to add new actions.663        return self.take_action(664            self.action, self.dest, opt, value, values, parser)665    def take_action(self, action, dest, opt, value, values, parser):666        if action == "store":667            setattr(values, dest, value)668        elif action == "store_const":669            setattr(values, dest, self.const)670        elif action == "store_true":671            setattr(values, dest, True)672        elif action == "store_false":673            setattr(values, dest, False)674        elif action == "append":675            values.ensure_value(dest, []).append(value)676        elif action == "append_const":677            values.ensure_value(dest, []).append(self.const)678        elif action == "count":679            setattr(values, dest, values.ensure_value(dest, 0) + 1)680        elif action == "callback":681            args = self.callback_args or ()682            kwargs = self.callback_kwargs or {}683            self.callback(self, opt, value, parser, *args, **kwargs)684        elif action == "help":685            parser.print_help()686            parser.exit()687        elif action == "version":688            parser.print_version()689            parser.exit()690        else:691            raise ValueError("unknown action %r" % self.action)692        return 1693# class Option694SUPPRESS_HELP = "SUPPRESS"+"HELP"695SUPPRESS_USAGE = "SUPPRESS"+"USAGE"696class Values:697    def __init__(self, defaults=None):698        if defaults:699            for (attr, val) in defaults.items():700                setattr(self, attr, val)701    def __str__(self):702        return str(self.__dict__)703    __repr__ = _repr704    def __eq__(self, other):705        if isinstance(other, Values):706            return self.__dict__ == other.__dict__707        elif isinstance(other, dict):708            return self.__dict__ == other709        else:710            return NotImplemented711    def _update_careful(self, dict):712        """713        Update the option values from an arbitrary dictionary, but only714        use keys from dict that already have a corresponding attribute715        in self.  Any keys in dict without a corresponding attribute716        are silently ignored.717        """718        for attr in dir(self):719            if attr in dict:720                dval = dict[attr]721                if dval is not None:722                    setattr(self, attr, dval)723    def _update_loose(self, dict):724        """725        Update the option values from an arbitrary dictionary,726        using all keys from the dictionary regardless of whether727        they have a corresponding attribute in self or not.728        """729        self.__dict__.update(dict)730    def _update(self, dict, mode):731        if mode == "careful":732            self._update_careful(dict)733        elif mode == "loose":734            self._update_loose(dict)735        else:736            raise ValueError("invalid update mode: %r" % mode)737    def read_module(self, modname, mode="careful"):738        __import__(modname)739        mod = sys.modules[modname]740        self._update(vars(mod), mode)741    def read_file(self, filename, mode="careful"):742        vars = {}743        exec(open(filename).read(), vars)744        self._update(vars, mode)745    def ensure_value(self, attr, value):746        if not hasattr(self, attr) or getattr(self, attr) is None:747            setattr(self, attr, value)748        return getattr(self, attr)749class OptionContainer:750    """751    Abstract base class.752    Class attributes:753      standard_option_list : [Option]754        list of standard options that will be accepted by all instances755        of this parser class (intended to be overridden by subclasses).756    Instance attributes:757      option_list : [Option]758        the list of Option objects contained by this OptionContainer759      _short_opt : { string : Option }760        dictionary mapping short option strings, eg. "-f" or "-X",761        to the Option instances that implement them.  If an Option762        has multiple short option strings, it will appears in this763        dictionary multiple times. [1]764      _long_opt : { string : Option }765        dictionary mapping long option strings, eg. "--file" or766        "--exclude", to the Option instances that implement them.767        Again, a given Option can occur multiple times in this768        dictionary. [1]769      defaults : { string : any }770        dictionary mapping option destination names to default771        values for each destination [1]772    [1] These mappings are common to (shared by) all components of the773        controlling OptionParser, where they are initially created.774    """775    def __init__(self, option_class, conflict_handler, description):776        # Initialize the option list and related data structures.777        # This method must be provided by subclasses, and it must778        # initialize at least the following instance attributes:779        # option_list, _short_opt, _long_opt, defaults.780        self._create_option_list()781        self.option_class = option_class782        self.set_conflict_handler(conflict_handler)783        self.set_description(description)784    def _create_option_mappings(self):785        # For use by OptionParser constructor -- create the master786        # option mappings used by this OptionParser and all787        # OptionGroups that it owns.788        self._short_opt = {}            # single letter -> Option instance789        self._long_opt = {}             # long option -> Option instance790        self.defaults = {}              # maps option dest -> default value791    def _share_option_mappings(self, parser):792        # For use by OptionGroup constructor -- use shared option793        # mappings from the OptionParser that owns this OptionGroup.794        self._short_opt = parser._short_opt795        self._long_opt = parser._long_opt796        self.defaults = parser.defaults797    def set_conflict_handler(self, handler):798        if handler not in ("error", "resolve"):799            raise ValueError("invalid conflict_resolution value %r" % handler)800        self.conflict_handler = handler801    def set_description(self, description):802        self.description = description803    def get_description(self):804        return self.description805    def destroy(self):806        """see OptionParser.destroy()."""807        del self._short_opt808        del self._long_opt809        del self.defaults810    # -- Option-adding methods -----------------------------------------811    def _check_conflict(self, option):812        conflict_opts = []813        for opt in option._short_opts:814            if opt in self._short_opt:815                conflict_opts.append((opt, self._short_opt[opt]))816        for opt in option._long_opts:817            if opt in self._long_opt:818                conflict_opts.append((opt, self._long_opt[opt]))819        if conflict_opts:820            handler = self.conflict_handler821            if handler == "error":822                raise OptionConflictError(823                    "conflicting option string(s): %s"824                    % ", ".join([co[0] for co in conflict_opts]),825                    option)826            elif handler == "resolve":827                for (opt, c_option) in conflict_opts:828                    if opt.startswith("--"):829                        c_option._long_opts.remove(opt)830                        del self._long_opt[opt]831                    else:832                        c_option._short_opts.remove(opt)833                        del self._short_opt[opt]834                    if not (c_option._short_opts or c_option._long_opts):835                        c_option.container.option_list.remove(c_option)836    def add_option(self, *args, **kwargs):837        """add_option(Option)838           add_option(opt_str, ..., kwarg=val, ...)839        """840        if isinstance(args[0], str):841            option = self.option_class(*args, **kwargs)842        elif len(args) == 1 and not kwargs:843            option = args[0]844            if not isinstance(option, Option):845                raise TypeError("not an Option instance: %r" % option)846        else:847            raise TypeError("invalid arguments")848        self._check_conflict(option)849        self.option_list.append(option)850        option.container = self851        for opt in option._short_opts:852            self._short_opt[opt] = option853        for opt in option._long_opts:854            self._long_opt[opt] = option855        if option.dest is not None:     # option has a dest, we need a default856            if option.default is not NO_DEFAULT:857                self.defaults[option.dest] = option.default858            elif option.dest not in self.defaults:859                self.defaults[option.dest] = None860        return option861    def add_options(self, option_list):862        for option in option_list:863            self.add_option(option)864    # -- Option query/removal methods ----------------------------------865    def get_option(self, opt_str):866        return (self._short_opt.get(opt_str) or867                self._long_opt.get(opt_str))868    def has_option(self, opt_str):869        return (opt_str in self._short_opt or870                opt_str in self._long_opt)871    def remove_option(self, opt_str):872        option = self._short_opt.get(opt_str)873        if option is None:874            option = self._long_opt.get(opt_str)875        if option is None:876            raise ValueError("no such option %r" % opt_str)877        for opt in option._short_opts:878            del self._short_opt[opt]879        for opt in option._long_opts:880            del self._long_opt[opt]881        option.container.option_list.remove(option)882    # -- Help-formatting methods ---------------------------------------883    def format_option_help(self, formatter):884        if not self.option_list:885            return ""886        result = []887        for option in self.option_list:888            if not option.help is SUPPRESS_HELP:889                result.append(formatter.format_option(option))890        return "".join(result)891    def format_description(self, formatter):892        return formatter.format_description(self.get_description())893    def format_help(self, formatter):894        result = []895        if self.description:896            result.append(self.format_description(formatter))897        if self.option_list:898            result.append(self.format_option_help(formatter))899        return "\n".join(result)900class OptionGroup (OptionContainer):901    def __init__(self, parser, title, description=None):902        self.parser = parser903        OptionContainer.__init__(904            self, parser.option_class, parser.conflict_handler, description)905        self.title = title906    def _create_option_list(self):907        self.option_list = []908        self._share_option_mappings(self.parser)909    def set_title(self, title):910        self.title = title911    def destroy(self):912        """see OptionParser.destroy()."""913        OptionContainer.destroy(self)914        del self.option_list915    # -- Help-formatting methods ---------------------------------------916    def format_help(self, formatter):917        result = formatter.format_heading(self.title)918        formatter.indent()919        result += OptionContainer.format_help(self, formatter)920        formatter.dedent()921        return result922class OptionParser (OptionContainer):923    """924    Class attributes:925      standard_option_list : [Option]926        list of standard options that will be accepted by all instances927        of this parser class (intended to be overridden by subclasses).928    Instance attributes:929      usage : string930        a usage string for your program.  Before it is displayed931        to the user, "%prog" will be expanded to the name of932        your program (self.prog or os.path.basename(sys.argv[0])).933      prog : string934        the name of the current program (to override935        os.path.basename(sys.argv[0])).936      description : string937        A paragraph of text giving a brief overview of your program.938        optparse reformats this paragraph to fit the current terminal939        width and prints it when the user requests help (after usage,940        but before the list of options).941      epilog : string942        paragraph of help text to print after option help943      option_groups : [OptionGroup]944        list of option groups in this parser (option groups are945        irrelevant for parsing the command-line, but very useful946        for generating help)947      allow_interspersed_args : bool = true948        if true, positional arguments may be interspersed with options.949        Assuming -a and -b each take a single argument, the command-line950          -ablah foo bar -bboo baz951        will be interpreted the same as952          -ablah -bboo -- foo bar baz953        If this flag were false, that command line would be interpreted as954          -ablah -- foo bar -bboo baz955        -- ie. we stop processing options as soon as we see the first956        non-option argument.  (This is the tradition followed by957        Python's getopt module, Perl's Getopt::Std, and other argument-958        parsing libraries, but it is generally annoying to users.)959      process_default_values : bool = true960        if true, option default values are processed similarly to option961        values from the command line: that is, they are passed to the962        type-checking function for the option's type (as long as the963        default value is a string).  (This really only matters if you964        have defined custom types; see SF bug #955889.)  Set it to false965        to restore the behaviour of Optik 1.4.1 and earlier.966      rargs : [string]967        the argument list currently being parsed.  Only set when968        parse_args() is active, and continually trimmed down as969        we consume arguments.  Mainly there for the benefit of970        callback options.971      largs : [string]972        the list of leftover arguments that we have skipped while973        parsing options.  If allow_interspersed_args is false, this974        list is always empty.975      values : Values976        the set of option values currently being accumulated.  Only977        set when parse_args() is active.  Also mainly for callbacks.978    Because of the 'rargs', 'largs', and 'values' attributes,979    OptionParser is not thread-safe.  If, for some perverse reason, you980    need to parse command-line arguments simultaneously in different981    threads, use different OptionParser instances.982    """983    standard_option_list = []984    def __init__(self,985                 usage=None,986                 option_list=None,987                 option_class=Option,988                 version=None,989                 conflict_handler="error",990                 description=None,991                 formatter=None,992                 add_help_option=True,993                 prog=None,994                 epilog=None):995        OptionContainer.__init__(996            self, option_class, conflict_handler, description)997        self.set_usage(usage)998        self.prog = prog999        self.version = version1000        self.allow_interspersed_args = True1001        self.process_default_values = True1002        if formatter is None:1003            formatter = IndentedHelpFormatter()1004        self.formatter = formatter1005        self.formatter.set_parser(self)1006        self.epilog = epilog1007        # Populate the option list; initial sources are the1008        # standard_option_list class attribute, the 'option_list'1009        # argument, and (if applicable) the _add_version_option() and1010        # _add_help_option() methods.1011        self._populate_option_list(option_list,1012                                   add_help=add_help_option)1013        self._init_parsing_state()1014    def destroy(self):1015        """1016        Declare that you are done with this OptionParser.  This cleans up1017        reference cycles so the OptionParser (and all objects referenced by1018        it) can be garbage-collected promptly.  After calling destroy(), the1019        OptionParser is unusable.1020        """1021        OptionContainer.destroy(self)1022        for group in self.option_groups:1023            group.destroy()1024        del self.option_list1025        del self.option_groups1026        del self.formatter1027    # -- Private methods -----------------------------------------------1028    # (used by our or OptionContainer's constructor)1029    def _create_option_list(self):1030        self.option_list = []1031        self.option_groups = []1032        self._create_option_mappings()1033    def _add_help_option(self):1034        self.add_option("-h", "--help",1035                        action="help",1036                        help=_("show this help message and exit"))1037    def _add_version_option(self):1038        self.add_option("--version",1039                        action="version",1040                        help=_("show program's version number and exit"))1041    def _populate_option_list(self, option_list, add_help=True):1042        if self.standard_option_list:1043            self.add_options(self.standard_option_list)1044        if option_list:1045            self.add_options(option_list)1046        if self.version:1047            self._add_version_option()1048        if add_help:1049            self._add_help_option()1050    def _init_parsing_state(self):1051        # These are set in parse_args() for the convenience of callbacks.1052        self.rargs = None1053        self.largs = None1054        self.values = None1055    # -- Simple modifier methods ---------------------------------------1056    def set_usage(self, usage):1057        if usage is None:1058            self.usage = _("%prog [options]")1059        elif usage is SUPPRESS_USAGE:1060            self.usage = None1061        # For backwards compatibility with Optik 1.3 and earlier.1062        elif usage.lower().startswith("usage: "):1063            self.usage = usage[7:]1064        else:1065            self.usage = usage1066    def enable_interspersed_args(self):1067        """Set parsing to not stop on the first non-option, allowing1068        interspersing switches with command arguments. This is the1069        default behavior. See also disable_interspersed_args() and the1070        class documentation description of the attribute1071        allow_interspersed_args."""1072        self.allow_interspersed_args = True1073    def disable_interspersed_args(self):1074        """Set parsing to stop on the first non-option. Use this if1075        you have a command processor which runs another command that1076        has options of its own and you want to make sure these options1077        don't get confused.1078        """1079        self.allow_interspersed_args = False1080    def set_process_default_values(self, process):1081        self.process_default_values = process1082    def set_default(self, dest, value):1083        self.defaults[dest] = value1084    def set_defaults(self, **kwargs):1085        self.defaults.update(kwargs)1086    def _get_all_options(self):1087        options = self.option_list[:]1088        for group in self.option_groups:1089            options.extend(group.option_list)1090        return options1091    def get_default_values(self):1092        if not self.process_default_values:1093            # Old, pre-Optik 1.5 behaviour.1094            return Values(self.defaults)1095        defaults = self.defaults.copy()1096        for option in self._get_all_options():1097            default = defaults.get(option.dest)1098            if isinstance(default, str):1099                opt_str = option.get_opt_string()1100                defaults[option.dest] = option.check_value(opt_str, default)1101        return Values(defaults)1102    # -- OptionGroup methods -------------------------------------------1103    def add_option_group(self, *args, **kwargs):1104        # XXX lots of overlap with OptionContainer.add_option()1105        if isinstance(args[0], str):1106            group = OptionGroup(self, *args, **kwargs)1107        elif len(args) == 1 and not kwargs:1108            group = args[0]1109            if not isinstance(group, OptionGroup):1110                raise TypeError("not an OptionGroup instance: %r" % group)1111            if group.parser is not self:1112                raise ValueError("invalid OptionGroup (wrong parser)")1113        else:1114            raise TypeError("invalid arguments")1115        self.option_groups.append(group)1116        return group1117    def get_option_group(self, opt_str):1118        option = (self._short_opt.get(opt_str) or1119                  self._long_opt.get(opt_str))1120        if option and option.container is not self:1121            return option.container1122        return None1123    # -- Option-parsing methods ----------------------------------------1124    def _get_args(self, args):1125        if args is None:1126            return sys.argv[1:]1127        else:1128            return args[:]              # don't modify caller's list1129    def parse_args(self, args=None, values=None):1130        """1131        parse_args(args : [string] = sys.argv[1:],1132                   values : Values = None)1133        -> (values : Values, args : [string])1134        Parse the command-line options found in 'args' (default:1135        sys.argv[1:]).  Any errors result in a call to 'error()', which1136        by default prints the usage message to stderr and calls1137        sys.exit() with an error message.  On success returns a pair1138        (values, args) where 'values' is an Values instance (with all1139        your option values) and 'args' is the list of arguments left1140        over after parsing options.1141        """1142        rargs = self._get_args(args)1143        if values is None:1144            values = self.get_default_values()1145        # Store the halves of the argument list as attributes for the1146        # convenience of callbacks:1147        #   rargs1148        #     the rest of the command-line (the "r" stands for1149        #     "remaining" or "right-hand")1150        #   largs1151        #     the leftover arguments -- ie. what's left after removing1152        #     options and their arguments (the "l" stands for "leftover"1153        #     or "left-hand")1154        self.rargs = rargs1155        self.largs = largs = []1156        self.values = values1157        try:1158            stop = self._process_args(largs, rargs, values)1159        except (BadOptionError, OptionValueError) as err:1160            self.error(str(err))1161        args = largs + rargs1162        return self.check_values(values, args)1163    def check_values(self, values, args):1164        """1165        check_values(values : Values, args : [string])1166        -> (values : Values, args : [string])1167        Check that the supplied option values and leftover arguments are1168        valid.  Returns the option values and leftover arguments1169        (possibly adjusted, possibly completely new -- whatever you1170        like).  Default implementation just returns the passed-in1171        values; subclasses may override as desired.1172        """1173        return (values, args)1174    def _process_args(self, largs, rargs, values):1175        """_process_args(largs : [string],1176                         rargs : [string],1177                         values : Values)1178        Process command-line arguments and populate 'values', consuming1179        options and arguments from 'rargs'.  If 'allow_interspersed_args' is1180        false, stop at the first non-option argument.  If true, accumulate any1181        interspersed non-option arguments in 'largs'.1182        """1183        while rargs:1184            arg = rargs[0]1185            # We handle bare "--" explicitly, and bare "-" is handled by the1186            # standard arg handler since the short arg case ensures that the1187            # len of the opt string is greater than 1.1188            if arg == "--":1189                del rargs[0]1190                return1191            elif arg[0:2] == "--":1192                # process a single long option (possibly with value(s))1193                self._process_long_opt(rargs, values)1194            elif arg[:1] == "-" and len(arg) > 1:1195                # process a cluster of short options (possibly with1196                # value(s) for the last one only)1197                self._process_short_opts(rargs, values)1198            elif self.allow_interspersed_args:1199                largs.append(arg)1200                del rargs[0]1201            else:1202                return                  # stop now, leave this arg in rargs1203        # Say this is the original argument list:1204        # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]1205        #                            ^1206        # (we are about to process arg(i)).1207        #1208        # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of1209        # [arg0, ..., arg(i-1)] (any options and their arguments will have1210        # been removed from largs).1211        #1212        # The while loop will usually consume 1 or more arguments per pass.1213        # If it consumes 1 (eg. arg is an option that takes no arguments),1214        # then after _process_arg() is done the situation is:1215        #1216        #   largs = subset of [arg0, ..., arg(i)]1217        #   rargs = [arg(i+1), ..., arg(N-1)]1218        #1219        # If allow_interspersed_args is false, largs will always be1220        # *empty* -- still a subset of [arg0, ..., arg(i-1)], but1221        # not a very interesting subset!1222    def _match_long_opt(self, opt):1223        """_match_long_opt(opt : string) -> string1224        Determine which long option string 'opt' matches, ie. which one1225        it is an unambiguous abbreviation for.  Raises BadOptionError if1226        'opt' doesn't unambiguously match any long option string.1227        """1228        return _match_abbrev(opt, self._long_opt)1229    def _process_long_opt(self, rargs, values):1230        arg = rargs.pop(0)1231        # Value explicitly attached to arg?  Pretend it's the next1232        # argument.1233        if "=" in arg:1234            (opt, next_arg) = arg.split("=", 1)1235            rargs.insert(0, next_arg)1236            had_explicit_value = True1237        else:1238            opt = arg1239            had_explicit_value = False1240        opt = self._match_long_opt(opt)1241        option = self._long_opt[opt]1242        if option.takes_value():1243            nargs = option.nargs1244            if len(rargs) < nargs:1245                self.error(ngettext(1246                    "%(option)s option requires %(number)d argument",1247                    "%(option)s option requires %(number)d arguments",1248                    nargs) % {"option": opt, "number": nargs})1249            elif nargs == 1:1250                value = rargs.pop(0)1251            else:1252                value = tuple(rargs[0:nargs])1253                del rargs[0:nargs]1254        elif had_explicit_value:1255            self.error(_("%s option does not take a value") % opt)1256        else:1257            value = None1258        option.process(opt, value, values, self)1259    def _process_short_opts(self, rargs, values):1260        arg = rargs.pop(0)1261        stop = False1262        i = 11263        for ch in arg[1:]:1264            opt = "-" + ch1265            option = self._short_opt.get(opt)1266            i += 1                      # we have consumed a character1267            if not option:1268                raise BadOptionError(opt)1269            if option.takes_value():1270                # Any characters left in arg?  Pretend they're the1271                # next arg, and stop consuming characters of arg.1272                if i < len(arg):1273                    rargs.insert(0, arg[i:])1274                    stop = True1275                nargs = option.nargs1276                if len(rargs) < nargs:1277                    self.error(ngettext(1278                        "%(option)s option requires %(number)d argument",1279                        "%(option)s option requires %(number)d arguments",1280                        nargs) % {"option": opt, "number": nargs})1281                elif nargs == 1:1282                    value = rargs.pop(0)1283                else:1284                    value = tuple(rargs[0:nargs])1285                    del rargs[0:nargs]1286            else:                       # option doesn't take a value1287                value = None1288            option.process(opt, value, values, self)1289            if stop:1290                break1291    # -- Feedback methods ----------------------------------------------1292    def get_prog_name(self):1293        if self.prog is None:1294            return os.path.basename(sys.argv[0])1295        else:1296            return self.prog1297    def expand_prog_name(self, s):1298        return s.replace("%prog", self.get_prog_name())1299    def get_description(self):1300        return self.expand_prog_name(self.description)1301    def exit(self, status=0, msg=None):1302        if msg:1303            sys.stderr.write(msg)1304        sys.exit(status)1305    def error(self, msg):1306        """error(msg : string)1307        Print a usage message incorporating 'msg' to stderr and exit.1308        If you override this in a subclass, it should not return -- it1309        should either exit or raise an exception.1310        """1311        self.print_usage(sys.stderr)1312        self.exit(2, "%s: error: %s\n" % (self.get_prog_name(), msg))1313    def get_usage(self):1314        if self.usage:1315            return self.formatter.format_usage(1316                self.expand_prog_name(self.usage))1317        else:1318            return ""1319    def print_usage(self, file=None):1320        """print_usage(file : file = stdout)1321        Print the usage message for the current program (self.usage) to1322        'file' (default stdout).  Any occurrence of the string "%prog" in1323        self.usage is replaced with the name of the current program1324        (basename of sys.argv[0]).  Does nothing if self.usage is empty1325        or not defined.1326        """1327        if self.usage:1328            print(self.get_usage(), file=file)1329    def get_version(self):1330        if self.version:1331            return self.expand_prog_name(self.version)1332        else:1333            return ""1334    def print_version(self, file=None):1335        """print_version(file : file = stdout)1336        Print the version message for this program (self.version) to1337        'file' (default stdout).  As with print_usage(), any occurrence1338        of "%prog" in self.version is replaced by the current program's1339        name.  Does nothing if self.version is empty or undefined.1340        """1341        if self.version:1342            print(self.get_version(), file=file)1343    def format_option_help(self, formatter=None):1344        if formatter is None:1345            formatter = self.formatter1346        formatter.store_option_strings(self)1347        result = []1348        result.append(formatter.format_heading(_("Options")))1349        formatter.indent()1350        if self.option_list:1351            result.append(OptionContainer.format_option_help(self, formatter))1352            result.append("\n")1353        for group in self.option_groups:1354            result.append(group.format_help(formatter))1355            result.append("\n")1356        formatter.dedent()1357        # Drop the last "\n", or the header if no options or option groups:1358        return "".join(result[:-1])1359    def format_epilog(self, formatter):1360        return formatter.format_epilog(self.epilog)1361    def format_help(self, formatter=None):1362        if formatter is None:1363            formatter = self.formatter1364        result = []1365        if self.usage:1366            result.append(self.get_usage() + "\n")1367        if self.description:1368            result.append(self.format_description(formatter) + "\n")1369        result.append(self.format_option_help(formatter))1370        result.append(self.format_epilog(formatter))1371        return "".join(result)1372    def print_help(self, file=None):1373        """print_help(file : file = stdout)1374        Print an extended help message, listing all options and any1375        help text provided with them, to 'file' (default stdout).1376        """1377        if file is None:1378            file = sys.stdout1379        file.write(self.format_help())1380# class OptionParser1381def _match_abbrev(s, wordmap):1382    """_match_abbrev(s : string, wordmap : {string : Option}) -> string1383    Return the string key in 'wordmap' for which 's' is an unambiguous1384    abbreviation.  If 's' is found to be ambiguous or doesn't match any of1385    'words', raise BadOptionError.1386    """1387    # Is there an exact match?1388    if s in wordmap:1389        return s1390    else:1391        # Isolate all words with s as a prefix.1392        possibilities = [word for word in wordmap.keys()1393                         if word.startswith(s)]1394        # No exact match, so there had better be just one possibility.1395        if len(possibilities) == 1:1396            return possibilities[0]1397        elif not possibilities:1398            raise BadOptionError(s)1399        else:1400            # More than one possible completion: ambiguous prefix.1401            possibilities.sort()1402            raise AmbiguousOptionError(s, possibilities)1403# Some day, there might be many Option classes.  As of Optik 1.3, the1404# preferred way to instantiate Options is indirectly, via make_option(),1405# which will become a factory function when there are many Option1406# classes....cmdline.py
Source:cmdline.py  
...44    usage = "%s%s [options]" % ("python " if not IS_WIN else "", \45            "\"%s\"" % _ if " " in _ else _)46    parser = OptionParser(usage=usage)47    try:48        parser.add_option("--hh", dest="advancedHelp",49                          action="store_true",50                          help="Show advanced help message and exit")51        parser.add_option("--version", dest="showVersion",52                          action="store_true",53                          help="Show program's version number and exit")54        parser.add_option("-v", dest="verbose", type="int",55                          help="Verbosity level: 0-6 (default %d)" % defaults.verbose)56        # Target options57        target = OptionGroup(parser, "Target", "At least one of these "58                             "options has to be provided to define the target(s)")59        target.add_option("-d", dest="direct", help="Connection string "60                          "for direct database connection")61        target.add_option("-u", "--url", dest="url", help="Target URL (e.g. \"http://www.site.com/vuln.php?id=1\")")62        target.add_option("-l", dest="logFile", help="Parse target(s) from Burp "63                          "or WebScarab proxy log file")64        target.add_option("-x", dest="sitemapUrl", help="Parse target(s) from remote sitemap(.xml) file")65        target.add_option("-m", dest="bulkFile", help="Scan multiple targets given "66                          "in a textual file ")67        target.add_option("-r", dest="requestFile",68                          help="Load HTTP request from a file")69        target.add_option("-g", dest="googleDork",70                          help="Process Google dork results as target URLs")71        target.add_option("-c", dest="configFile",72                          help="Load options from a configuration INI file")73        # Request options74        request = OptionGroup(parser, "Request", "These options can be used "75                              "to specify how to connect to the target URL")76        request.add_option("--method", dest="method",77                           help="Force usage of given HTTP method (e.g. PUT)")78        request.add_option("--data", dest="data",79                           help="Data string to be sent through POST")80        request.add_option("--param-del", dest="paramDel",81                           help="Character used for splitting parameter values")82        request.add_option("--cookie", dest="cookie",83                           help="HTTP Cookie header value")84        request.add_option("--cookie-del", dest="cookieDel",85                           help="Character used for splitting cookie values")86        request.add_option("--load-cookies", dest="loadCookies",87                           help="File containing cookies in Netscape/wget format")88        request.add_option("--drop-set-cookie", dest="dropSetCookie",89                           action="store_true",90                           help="Ignore Set-Cookie header from response")91        request.add_option("--user-agent", dest="agent",92                           help="HTTP User-Agent header value")93        request.add_option("--random-agent", dest="randomAgent",94                           action="store_true",95                           help="Use randomly selected HTTP User-Agent header value")96        request.add_option("--host", dest="host",97                           help="HTTP Host header value")98        request.add_option("--referer", dest="referer",99                           help="HTTP Referer header value")100        request.add_option("-H", "--header", dest="header",101                           help="Extra header (e.g. \"X-Forwarded-For: 127.0.0.1\")")102        request.add_option("--headers", dest="headers",103                           help="Extra headers (e.g. \"Accept-Language: fr\\nETag: 123\")")104        request.add_option("--auth-type", dest="authType",105                           help="HTTP authentication type "106                                "(Basic, Digest, NTLM or PKI)")107        request.add_option("--auth-cred", dest="authCred",108                           help="HTTP authentication credentials "109                                "(name:password)")110        request.add_option("--auth-file", dest="authFile",111                           help="HTTP authentication PEM cert/private key file")112        request.add_option("--ignore-401", dest="ignore401", action="store_true",113                          help="Ignore HTTP Error 401 (Unauthorized)")114        request.add_option("--ignore-proxy", dest="ignoreProxy", action="store_true",115                           help="Ignore system default proxy settings")116        request.add_option("--ignore-redirects", dest="ignoreRedirects", action="store_true",117                          help="Ignore redirection attempts")118        request.add_option("--ignore-timeouts", dest="ignoreTimeouts", action="store_true",119                          help="Ignore connection timeouts")120        request.add_option("--proxy", dest="proxy",121                           help="Use a proxy to connect to the target URL")122        request.add_option("--proxy-cred", dest="proxyCred",123                           help="Proxy authentication credentials "124                                "(name:password)")125        request.add_option("--proxy-file", dest="proxyFile",126                           help="Load proxy list from a file")127        request.add_option("--tor", dest="tor",128                                  action="store_true",129                                  help="Use Tor anonymity network")130        request.add_option("--tor-port", dest="torPort",131                                  help="Set Tor proxy port other than default")132        request.add_option("--tor-type", dest="torType",133                                  help="Set Tor proxy type (HTTP, SOCKS4 or SOCKS5 (default))")134        request.add_option("--check-tor", dest="checkTor",135                                  action="store_true",136                                  help="Check to see if Tor is used properly")137        request.add_option("--delay", dest="delay", type="float",138                           help="Delay in seconds between each HTTP request")139        request.add_option("--timeout", dest="timeout", type="float",140                           help="Seconds to wait before timeout connection "141                                "(default %d)" % defaults.timeout)142        request.add_option("--retries", dest="retries", type="int",143                           help="Retries when the connection timeouts "144                                "(default %d)" % defaults.retries)145        request.add_option("--randomize", dest="rParam",146                           help="Randomly change value for given parameter(s)")147        request.add_option("--safe-url", dest="safeUrl",148                           help="URL address to visit frequently during testing")149        request.add_option("--safe-post", dest="safePost",150                           help="POST data to send to a safe URL")151        request.add_option("--safe-req", dest="safeReqFile",152                           help="Load safe HTTP request from a file")153        request.add_option("--safe-freq", dest="safeFreq", type="int",154                           help="Test requests between two visits to a given safe URL")155        request.add_option("--skip-urlencode", dest="skipUrlEncode",156                           action="store_true",157                           help="Skip URL encoding of payload data")158        request.add_option("--csrf-token", dest="csrfToken",159                           help="Parameter used to hold anti-CSRF token")160        request.add_option("--csrf-url", dest="csrfUrl",161                           help="URL address to visit to extract anti-CSRF token")162        request.add_option("--force-ssl", dest="forceSSL",163                           action="store_true",164                           help="Force usage of SSL/HTTPS")165        request.add_option("--hpp", dest="hpp",166                                  action="store_true",167                                  help="Use HTTP parameter pollution method")168        request.add_option("--eval", dest="evalCode",169                           help="Evaluate provided Python code before the request (e.g. \"import hashlib;id2=hashlib.md5(id).hexdigest()\")")170        # Optimization options171        optimization = OptionGroup(parser, "Optimization", "These "172                               "options can be used to optimize the "173                               "performance of sqlmap")174        optimization.add_option("-o", dest="optimize",175                                 action="store_true",176                                 help="Turn on all optimization switches")177        optimization.add_option("--predict-output", dest="predictOutput", action="store_true",178                          help="Predict common queries output")179        optimization.add_option("--keep-alive", dest="keepAlive", action="store_true",180                           help="Use persistent HTTP(s) connections")181        optimization.add_option("--null-connection", dest="nullConnection", action="store_true",182                          help="Retrieve page length without actual HTTP response body")183        optimization.add_option("--threads", dest="threads", type="int",184                           help="Max number of concurrent HTTP(s) "185                                "requests (default %d)" % defaults.threads)186        # Injection options187        injection = OptionGroup(parser, "Injection", "These options can be "188                                "used to specify which parameters to test "189                                "for, provide custom injection payloads and "190                                "optional tampering scripts")191        injection.add_option("-p", dest="testParameter",192                             help="Testable parameter(s)")193        injection.add_option("--skip", dest="skip",194                             help="Skip testing for given parameter(s)")195        injection.add_option("--skip-static", dest="skipStatic", action="store_true",196                             help="Skip testing parameters that not appear to be dynamic")197        injection.add_option("--param-exclude", dest="paramExclude",198                           help="Regexp to exclude parameters from testing (e.g. \"ses\")")199        injection.add_option("--dbms", dest="dbms",200                             help="Force back-end DBMS to this value")201        injection.add_option("--dbms-cred", dest="dbmsCred",202                            help="DBMS authentication credentials (user:password)")203        injection.add_option("--os", dest="os",204                             help="Force back-end DBMS operating system "205                                  "to this value")206        injection.add_option("--invalid-bignum", dest="invalidBignum",207                             action="store_true",208                             help="Use big numbers for invalidating values")209        injection.add_option("--invalid-logical", dest="invalidLogical",210                             action="store_true",211                             help="Use logical operations for invalidating values")212        injection.add_option("--invalid-string", dest="invalidString",213                             action="store_true",214                             help="Use random strings for invalidating values")215        injection.add_option("--no-cast", dest="noCast",216                             action="store_true",217                             help="Turn off payload casting mechanism")218        injection.add_option("--no-escape", dest="noEscape",219                             action="store_true",220                             help="Turn off string escaping mechanism")221        injection.add_option("--prefix", dest="prefix",222                             help="Injection payload prefix string")223        injection.add_option("--suffix", dest="suffix",224                             help="Injection payload suffix string")225        injection.add_option("--tamper", dest="tamper",226                             help="Use given script(s) for tampering injection data")227        # Detection options228        detection = OptionGroup(parser, "Detection", "These options can be "229                                "used to customize the detection phase")230        detection.add_option("--level", dest="level", type="int",231                             help="Level of tests to perform (1-5, "232                                  "default %d)" % defaults.level)233        detection.add_option("--risk", dest="risk", type="int",234                             help="Risk of tests to perform (1-3, "235                                  "default %d)" % defaults.level)236        detection.add_option("--string", dest="string",237                             help="String to match when "238                                  "query is evaluated to True")239        detection.add_option("--not-string", dest="notString",240                             help="String to match when "241                                  "query is evaluated to False")242        detection.add_option("--regexp", dest="regexp",243                             help="Regexp to match when "244                                  "query is evaluated to True")245        detection.add_option("--code", dest="code", type="int",246                             help="HTTP code to match when "247                                  "query is evaluated to True")248        detection.add_option("--text-only", dest="textOnly",249                             action="store_true",250                             help="Compare pages based only on the textual content")251        detection.add_option("--titles", dest="titles",252                             action="store_true",253                             help="Compare pages based only on their titles")254        # Techniques options255        techniques = OptionGroup(parser, "Techniques", "These options can be "256                                 "used to tweak testing of specific SQL "257                                 "injection techniques")258        techniques.add_option("--technique", dest="tech",259                              help="SQL injection techniques to use "260                                   "(default \"%s\")" % defaults.tech)261        techniques.add_option("--time-sec", dest="timeSec",262                              type="int",263                              help="Seconds to delay the DBMS response "264                                   "(default %d)" % defaults.timeSec)265        techniques.add_option("--union-cols", dest="uCols",266                              help="Range of columns to test for UNION query SQL injection")267        techniques.add_option("--union-char", dest="uChar",268                              help="Character to use for bruteforcing number of columns")269        techniques.add_option("--union-from", dest="uFrom",270                              help="Table to use in FROM part of UNION query SQL injection")271        techniques.add_option("--dns-domain", dest="dnsDomain",272                              help="Domain name used for DNS exfiltration attack")273        techniques.add_option("--second-order", dest="secondOrder",274                             help="Resulting page URL searched for second-order "275                                  "response")276        # Fingerprint options277        fingerprint = OptionGroup(parser, "Fingerprint")278        fingerprint.add_option("-f", "--fingerprint", dest="extensiveFp",279                               action="store_true",280                               help="Perform an extensive DBMS version fingerprint")281        # Enumeration options282        enumeration = OptionGroup(parser, "Enumeration", "These options can "283                                  "be used to enumerate the back-end database "284                                  "management system information, structure "285                                  "and data contained in the tables. Moreover "286                                  "you can run your own SQL statements")287        enumeration.add_option("-a", "--all", dest="getAll",288                               action="store_true", help="Retrieve everything")289        enumeration.add_option("-b", "--banner", dest="getBanner",290                               action="store_true", help="Retrieve DBMS banner")291        enumeration.add_option("--current-user", dest="getCurrentUser",292                               action="store_true",293                               help="Retrieve DBMS current user")294        enumeration.add_option("--current-db", dest="getCurrentDb",295                               action="store_true",296                               help="Retrieve DBMS current database")297        enumeration.add_option("--hostname", dest="getHostname",298                               action="store_true",299                               help="Retrieve DBMS server hostname")300        enumeration.add_option("--is-dba", dest="isDba",301                               action="store_true",302                               help="Detect if the DBMS current user is DBA")303        enumeration.add_option("--users", dest="getUsers", action="store_true",304                               help="Enumerate DBMS users")305        enumeration.add_option("--passwords", dest="getPasswordHashes",306                               action="store_true",307                               help="Enumerate DBMS users password hashes")308        enumeration.add_option("--privileges", dest="getPrivileges",309                               action="store_true",310                               help="Enumerate DBMS users privileges")311        enumeration.add_option("--roles", dest="getRoles",312                               action="store_true",313                               help="Enumerate DBMS users roles")314        enumeration.add_option("--dbs", dest="getDbs", action="store_true",315                               help="Enumerate DBMS databases")316        enumeration.add_option("--tables", dest="getTables", action="store_true",317                               help="Enumerate DBMS database tables")318        enumeration.add_option("--columns", dest="getColumns", action="store_true",319                               help="Enumerate DBMS database table columns")320        enumeration.add_option("--schema", dest="getSchema", action="store_true",321                               help="Enumerate DBMS schema")322        enumeration.add_option("--count", dest="getCount", action="store_true",323                               help="Retrieve number of entries for table(s)")324        enumeration.add_option("--dump", dest="dumpTable", action="store_true",325                               help="Dump DBMS database table entries")326        enumeration.add_option("--dump-all", dest="dumpAll", action="store_true",327                               help="Dump all DBMS databases tables entries")328        enumeration.add_option("--search", dest="search", action="store_true",329                               help="Search column(s), table(s) and/or database name(s)")330        enumeration.add_option("--comments", dest="getComments", action="store_true",331                               help="Retrieve DBMS comments")332        enumeration.add_option("-D", dest="db",333                               help="DBMS database to enumerate")334        enumeration.add_option("-T", dest="tbl",335                               help="DBMS database table(s) to enumerate")336        enumeration.add_option("-C", dest="col",337                               help="DBMS database table column(s) to enumerate")338        enumeration.add_option("-X", dest="excludeCol",339                               help="DBMS database table column(s) to not enumerate")340        enumeration.add_option("-U", dest="user",341                               help="DBMS user to enumerate")342        enumeration.add_option("--exclude-sysdbs", dest="excludeSysDbs",343                               action="store_true",344                               help="Exclude DBMS system databases when "345                                    "enumerating tables")346        enumeration.add_option("--pivot-column", dest="pivotColumn",347                               help="Pivot column name")348        enumeration.add_option("--where", dest="dumpWhere",349                               help="Use WHERE condition while table dumping")350        enumeration.add_option("--start", dest="limitStart", type="int",351                               help="First query output entry to retrieve")352        enumeration.add_option("--stop", dest="limitStop", type="int",353                               help="Last query output entry to retrieve")354        enumeration.add_option("--first", dest="firstChar", type="int",355                               help="First query output word character to retrieve")356        enumeration.add_option("--last", dest="lastChar", type="int",357                               help="Last query output word character to retrieve")358        enumeration.add_option("--sql-query", dest="query",359                               help="SQL statement to be executed")360        enumeration.add_option("--sql-shell", dest="sqlShell",361                               action="store_true",362                               help="Prompt for an interactive SQL shell")363        enumeration.add_option("--sql-file", dest="sqlFile",364                               help="Execute SQL statements from given file(s)")365        # Brute force options366        brute = OptionGroup(parser, "Brute force", "These "367                          "options can be used to run brute force "368                          "checks")369        brute.add_option("--common-tables", dest="commonTables", action="store_true",370                               help="Check existence of common tables")371        brute.add_option("--common-columns", dest="commonColumns", action="store_true",372                               help="Check existence of common columns")373        # User-defined function options374        udf = OptionGroup(parser, "User-defined function injection", "These "375                          "options can be used to create custom user-defined "376                          "functions")377        udf.add_option("--udf-inject", dest="udfInject", action="store_true",378                       help="Inject custom user-defined functions")379        udf.add_option("--shared-lib", dest="shLib",380                       help="Local path of the shared library")381        # File system options382        filesystem = OptionGroup(parser, "File system access", "These options "383                                 "can be used to access the back-end database "384                                 "management system underlying file system")385        filesystem.add_option("--file-read", dest="rFile",386                              help="Read a file from the back-end DBMS "387                                   "file system")388        filesystem.add_option("--file-write", dest="wFile",389                              help="Write a local file on the back-end "390                                   "DBMS file system")391        filesystem.add_option("--file-dest", dest="dFile",392                              help="Back-end DBMS absolute filepath to "393                                   "write to")394        # Takeover options395        takeover = OptionGroup(parser, "Operating system access", "These "396                               "options can be used to access the back-end "397                               "database management system underlying "398                               "operating system")399        takeover.add_option("--os-cmd", dest="osCmd",400                            help="Execute an operating system command")401        takeover.add_option("--os-shell", dest="osShell",402                            action="store_true",403                            help="Prompt for an interactive operating "404                                 "system shell")405        takeover.add_option("--os-pwn", dest="osPwn",406                            action="store_true",407                            help="Prompt for an OOB shell, "408                                 "Meterpreter or VNC")409        takeover.add_option("--os-smbrelay", dest="osSmb",410                            action="store_true",411                            help="One click prompt for an OOB shell, "412                                 "Meterpreter or VNC")413        takeover.add_option("--os-bof", dest="osBof",414                            action="store_true",415                            help="Stored procedure buffer overflow "416                                 "exploitation")417        takeover.add_option("--priv-esc", dest="privEsc",418                            action="store_true",419                            help="Database process user privilege escalation")420        takeover.add_option("--msf-path", dest="msfPath",421                            help="Local path where Metasploit Framework "422                                 "is installed")423        takeover.add_option("--tmp-path", dest="tmpPath",424                            help="Remote absolute path of temporary files "425                                 "directory")426        # Windows registry options427        windows = OptionGroup(parser, "Windows registry access", "These "428                               "options can be used to access the back-end "429                               "database management system Windows "430                               "registry")431        windows.add_option("--reg-read", dest="regRead",432                            action="store_true",433                            help="Read a Windows registry key value")434        windows.add_option("--reg-add", dest="regAdd",435                            action="store_true",436                            help="Write a Windows registry key value data")437        windows.add_option("--reg-del", dest="regDel",438                            action="store_true",439                            help="Delete a Windows registry key value")440        windows.add_option("--reg-key", dest="regKey",441                            help="Windows registry key")442        windows.add_option("--reg-value", dest="regVal",443                            help="Windows registry key value")444        windows.add_option("--reg-data", dest="regData",445                            help="Windows registry key value data")446        windows.add_option("--reg-type", dest="regType",447                            help="Windows registry key value type")448        # General options449        general = OptionGroup(parser, "General", "These options can be used "450                             "to set some general working parameters")451        #general.add_option("-x", dest="xmlFile",452        #                    help="Dump the data into an XML file")453        general.add_option("-s", dest="sessionFile",454                            help="Load session from a stored (.sqlite) file")455        general.add_option("-t", dest="trafficFile",456                            help="Log all HTTP traffic into a "457                            "textual file")458        general.add_option("--batch", dest="batch",459                            action="store_true",460                            help="Never ask for user input, use the default behaviour")461        general.add_option("--binary-fields", dest="binaryFields",462                          help="Result fields having binary values (e.g. \"digest\")")463        general.add_option("--charset", dest="charset",464                            help="Force character encoding used for data retrieval")465        general.add_option("--crawl", dest="crawlDepth", type="int",466                            help="Crawl the website starting from the target URL")467        general.add_option("--crawl-exclude", dest="crawlExclude",468                           help="Regexp to exclude pages from crawling (e.g. \"logout\")")469        general.add_option("--csv-del", dest="csvDel",470                                  help="Delimiting character used in CSV output "471                                  "(default \"%s\")" % defaults.csvDel)472        general.add_option("--dump-format", dest="dumpFormat",473                                  help="Format of dumped data (CSV (default), HTML or SQLITE)")474        general.add_option("--eta", dest="eta",475                            action="store_true",476                            help="Display for each output the "477                                 "estimated time of arrival")478        general.add_option("--flush-session", dest="flushSession",479                            action="store_true",480                            help="Flush session files for current target")481        general.add_option("--forms", dest="forms",482                                  action="store_true",483                                  help="Parse and test forms on target URL")484        general.add_option("--fresh-queries", dest="freshQueries",485                            action="store_true",486                            help="Ignore query results stored in session file")487        general.add_option("--hex", dest="hexConvert",488                            action="store_true",489                            help="Use DBMS hex function(s) for data retrieval")490        general.add_option("--output-dir", dest="outputDir",491                            action="store",492                            help="Custom output directory path")493        general.add_option("--parse-errors", dest="parseErrors",494                                  action="store_true",495                                  help="Parse and display DBMS error messages from responses")496        general.add_option("--save", dest="saveConfig",497                            help="Save options to a configuration INI file")498        general.add_option("--scope", dest="scope",499                           help="Regexp to filter targets from provided proxy log")500        general.add_option("--test-filter", dest="testFilter",501                           help="Select tests by payloads and/or titles (e.g. ROW)")502        general.add_option("--test-skip", dest="testSkip",503                           help="Skip tests by payloads and/or titles (e.g. BENCHMARK)")504        general.add_option("--update", dest="updateAll",505                            action="store_true",506                            help="Update sqlmap")507        # Miscellaneous options508        miscellaneous = OptionGroup(parser, "Miscellaneous")509        miscellaneous.add_option("-z", dest="mnemonics",510                               help="Use short mnemonics (e.g. \"flu,bat,ban,tec=EU\")")511        miscellaneous.add_option("--alert", dest="alert",512                                  help="Run host OS command(s) when SQL injection is found")513        miscellaneous.add_option("--answers", dest="answers",514                                  help="Set question answers (e.g. \"quit=N,follow=N\")")515        miscellaneous.add_option("--beep", dest="beep", action="store_true",516                                  help="Beep on question and/or when SQL injection is found")517        miscellaneous.add_option("--cleanup", dest="cleanup",518                                  action="store_true",519                                  help="Clean up the DBMS from sqlmap specific "520                                  "UDF and tables")521        miscellaneous.add_option("--dependencies", dest="dependencies",522                                  action="store_true",523                                  help="Check for missing (non-core) sqlmap dependencies")524        miscellaneous.add_option("--disable-coloring", dest="disableColoring",525                                  action="store_true",526                                  help="Disable console output coloring")527        miscellaneous.add_option("--gpage", dest="googlePage", type="int",528                                  help="Use Google dork results from specified page number")529        miscellaneous.add_option("--identify-waf", dest="identifyWaf",530                                  action="store_true",531                                  help="Make a thorough testing for a WAF/IPS/IDS protection")532        miscellaneous.add_option("--mobile", dest="mobile",533                                  action="store_true",534                                  help="Imitate smartphone through HTTP User-Agent header")535        miscellaneous.add_option("--offline", dest="offline",536                                  action="store_true",537                                  help="Work in offline mode (only use session data)")538        miscellaneous.add_option("--page-rank", dest="pageRank",539                                  action="store_true",540                                  help="Display page rank (PR) for Google dork results")541        miscellaneous.add_option("--purge-output", dest="purgeOutput",542                                  action="store_true",543                                  help="Safely remove all content from output directory")544        miscellaneous.add_option("--skip-waf", dest="skipWaf",545                                  action="store_true",546                                  help="Skip heuristic detection of WAF/IPS/IDS protection")547        miscellaneous.add_option("--smart", dest="smart",548                                  action="store_true",549                                  help="Conduct thorough tests only if positive heuristic(s)")550        miscellaneous.add_option("--sqlmap-shell", dest="sqlmapShell", action="store_true",551                                  help="Prompt for an interactive sqlmap shell")552        miscellaneous.add_option("--tmp-dir", dest="tmpDir",553                                  help="Local directory for storing temporary files")554        miscellaneous.add_option("--wizard", dest="wizard",555                                  action="store_true",556                                  help="Simple wizard interface for beginner users")557        # Hidden and/or experimental options558        parser.add_option("--dummy", dest="dummy", action="store_true",559                          help=SUPPRESS_HELP)560        parser.add_option("--murphy-rate", dest="murphyRate", type="int",561                          help=SUPPRESS_HELP)562        parser.add_option("--pickled-options", dest="pickledOptions",563                          help=SUPPRESS_HELP)564        parser.add_option("--disable-precon", dest="disablePrecon", action="store_true",565                          help=SUPPRESS_HELP)566        parser.add_option("--profile", dest="profile", action="store_true",567                          help=SUPPRESS_HELP)568        parser.add_option("--force-dns", dest="forceDns", action="store_true",569                          help=SUPPRESS_HELP)570        parser.add_option("--force-threads", dest="forceThreads", action="store_true",571                          help=SUPPRESS_HELP)572        parser.add_option("--smoke-test", dest="smokeTest", action="store_true",573                          help=SUPPRESS_HELP)574        parser.add_option("--live-test", dest="liveTest", action="store_true",575                          help=SUPPRESS_HELP)576        parser.add_option("--stop-fail", dest="stopFail", action="store_true",577                          help=SUPPRESS_HELP)578        parser.add_option("--run-case", dest="runCase", help=SUPPRESS_HELP)579        parser.add_option_group(target)580        parser.add_option_group(request)581        parser.add_option_group(optimization)582        parser.add_option_group(injection)583        parser.add_option_group(detection)584        parser.add_option_group(techniques)585        parser.add_option_group(fingerprint)586        parser.add_option_group(enumeration)587        parser.add_option_group(brute)588        parser.add_option_group(udf)589        parser.add_option_group(filesystem)590        parser.add_option_group(takeover)591        parser.add_option_group(windows)592        parser.add_option_group(general)593        parser.add_option_group(miscellaneous)594        # Dirty hack to display longer options without breaking into two lines595        def _(self, *args):596            retVal = parser.formatter._format_option_strings(*args)597            if len(retVal) > MAX_HELP_OPTION_LENGTH:598                retVal = ("%%.%ds.." % (MAX_HELP_OPTION_LENGTH - parser.formatter.indent_increment)) % retVal599            return retVal600        parser.formatter._format_option_strings = parser.formatter.format_option_strings601        parser.formatter.format_option_strings = type(parser.formatter.format_option_strings)(_, parser, type(parser))602        # Dirty hack for making a short option '-hh'603        option = parser.get_option("--hh")604        option._short_opts = ["-hh"]605        option._long_opts = []606        # Dirty hack for inherent help message of switch '-h'607        option = parser.get_option("-h")608        option.help = option.help.capitalize().replace("this help", "basic help")609        _ = []610        prompt = False611        advancedHelp = True612        extraHeaders = []613        for arg in argv:614            _.append(getUnicode(arg, encoding=sys.getfilesystemencoding() or UNICODE_ENCODING))615        argv = _616        checkDeprecatedOptions(argv)617        prompt = "--sqlmap-shell" in argv618        if prompt:619            parser.usage = ""620            cmdLineOptions.sqlmapShell = True621            _ = ["x", "q", "exit", "quit", "clear"]622            for option in parser.option_list:623                _.extend(option._long_opts)624                _.extend(option._short_opts)625            for group in parser.option_groups:626                for option in group.option_list:627                    _.extend(option._long_opts)628                    _.extend(option._short_opts)629            autoCompletion(AUTOCOMPLETE_TYPE.SQLMAP, commands=_)630            while True:631                command = None632                try:633                    command = raw_input("sqlmap-shell> ").strip()634                    command = getUnicode(command, encoding=sys.stdin.encoding)635                except (KeyboardInterrupt, EOFError):636                    print637                    raise SqlmapShellQuitException638                if not command:639                    continue640                elif command.lower() == "clear":641                    clearHistory()642                    dataToStdout("[i] history cleared\n")643                    saveHistory(AUTOCOMPLETE_TYPE.SQLMAP)644                elif command.lower() in ("x", "q", "exit", "quit"):645                    raise SqlmapShellQuitException646                elif command[0] != '-':647                    dataToStdout("[!] invalid option(s) provided\n")648                    dataToStdout("[i] proper example: '-u http://www.site.com/vuln.php?id=1 --banner'\n")649                else:650                    saveHistory(AUTOCOMPLETE_TYPE.SQLMAP)651                    loadHistory(AUTOCOMPLETE_TYPE.SQLMAP)652                    break653            try:654                for arg in shlex.split(command):655                    argv.append(getUnicode(arg, encoding=sys.stdin.encoding))656            except ValueError, ex:657                raise SqlmapSyntaxException, "something went wrong during command line parsing ('%s')" % ex.message658        for i in xrange(len(argv)):659            if argv[i] == "-hh":660                argv[i] = "-h"661            elif len(argv[i]) > 1 and all(ord(_) in xrange(0x2018, 0x2020) for _ in ((argv[i].split('=', 1)[-1].strip() or ' ')[0], argv[i][-1])):...Looking for an in-depth tutorial around pytest? LambdaTest covers the detailed pytest tutorial that has everything related to the pytest, from setting up the pytest framework to automation testing. Delve deeper into pytest testing by exploring advanced use cases like parallel testing, pytest fixtures, parameterization, executing multiple test cases from a single file, and more.
Skim our below pytest tutorial playlist to get started with automation testing using the pytest framework.
https://www.youtube.com/playlist?list=PLZMWkkQEwOPlcGgDmHl8KkXKeLF83XlrP
Get 100 minutes of automation test minutes FREE!!
