InternalJob._run_validate()   F
last analyzed

Complexity

Conditions 12

Size

Total Lines 93

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 93
rs 2
c 0
b 0
f 0
cc 12

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like InternalJob._run_validate() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import os.path
2
import sys
3
import importlib
4
5
from .config import read_config
6
from .exceptions import *
7
from .server import send_post
8
from .filesystem import remove_working_directory
9
10
import logging
11
logger = logging.getLogger('opensubmitexec')
12
13
UNSPECIFIC_ERROR = -9999
14
15
16
class InternalJob():
17
    """Internal base class for jobs,
18
       with additional private functions."""
19
20
    # The current executor configuration.
21
    _config = None
22
    # Talk to the configured OpenSubmit server?
23
    _online = None
24
    # Action requested by the server (legacy)
25
    action = None
26
27
    submission_url = None
28
    validator_url = None
29
    result_sent = False
30
31
    # The base name of the validation / full test script
32
    # on disk, for importing.
33
    _validator_import_name = 'validator'
34
35
    def __init__(self, config=None, online=True):
36
        if config:
37
            self._config = config
38
        else:
39
            self._config = read_config()
40
        self._online = online
41
42
    def __str__(self):
43
        '''
44
        Nicer logging of job objects.
45
        '''
46
        return str(vars(self))
47
48
    def _run_validate(self):
49
        '''
50
        Execute the validate() method in the test script belonging to this job.
51
        '''
52
        assert(os.path.exists(self.validator_script_name))
53
        old_path = sys.path
54
        sys.path = [self.working_dir] + old_path
55
        # logger.debug('Python search path is now {0}.'.format(sys.path))
56
57
        try:
58
            module = importlib.import_module(self._validator_import_name)
59
        except Exception as e:
60
            text_student = "Internal validation problem, please contact your course responsible."
61
            text_tutor = "Exception while loading the validator: " + str(e)
62
            self._send_result(text_student, text_tutor, UNSPECIFIC_ERROR)
63
            return
64
65
        # Looped validator loading in the test suite demands this
66
        importlib.reload(module)
67
68
        # make the call
69
        try:
70
            module.validate(self)
71
        except Exception as e:
72
            # get more info
73
            text_student = None
74
            text_tutor = None
75
            if type(e) is TerminationException:
76
                text_student = "The execution of '{0}' terminated unexpectely.".format(
77
                    e.instance.name)
78
                text_tutor = "The execution of '{0}' terminated unexpectely.".format(
79
                    e.instance.name)
80
                text_student += "\n\nOutput so far:\n" + e.output
81
                text_tutor += "\n\nOutput so far:\n" + e.output
82
            elif type(e) is TimeoutException:
83
                text_student = "The execution of '{0}' was cancelled, since it took too long.".format(
84
                    e.instance.name)
85
                text_tutor = "The execution of '{0}' was cancelled due to timeout.".format(
86
                    e.instance.name)
87
                text_student += "\n\nOutput so far:\n" + e.output
88
                text_tutor += "\n\nOutput so far:\n" + e.output
89
            elif type(e) is NestedException:
90
                text_student = "Unexpected problem during the execution of '{0}'. {1}".format(
91
                    e.instance.name,
92
                    str(e.real_exception))
93
                text_tutor = "Unkown exception during the execution of '{0}'. {1}".format(
94
                    e.instance.name,
95
                    str(e.real_exception))
96
                text_student += "\n\nOutput so far:\n" + e.output
97
                text_tutor += "\n\nOutput so far:\n" + e.output
98
            elif type(e) is WrongExitStatusException:
99
                text_student = "The execution of '{0}' resulted in the unexpected exit status {1}.".format(
100
                    e.instance.name,
101
                    e.got)
102
                text_tutor = "The execution of '{0}' resulted in the unexpected exit status {1}.".format(
103
                    e.instance.name,
104
                    e.got)
105
                text_student += "\n\nOutput so far:\n" + e.output
106
                text_tutor += "\n\nOutput so far:\n" + e.output
107
            elif type(e) is JobException:
108
                # Some problem with our own code
109
                text_student = e.info_student
110
                text_tutor = e.info_tutor
111
            elif type(e) is FileNotFoundError:
112
                text_student = "A file is missing: {0}".format(
113
                    str(e))
114
                text_tutor = "Missing file: {0}".format(
115
                    str(e))
116
            elif type(e) is AssertionError:
117
                # Need this harsh approach to kill the
118
                # test suite execution at this point
119
                # Otherwise, the problem gets lost in
120
                # the log storm
121
                logger.error(
122
                    "Failed assertion in validation script. Should not happen in production.")
123
                exit(-1)
124
            else:
125
                # Something really unexpected
126
                text_student = "Internal problem while validating your submission. Please contact the course responsible."
127
                text_tutor = "Unknown exception while running the validator: {0}".format(
128
                    str(e))
129
            # We got the text. Report the problem.
130
            self._send_result(text_student, text_tutor, UNSPECIFIC_ERROR)
131
            return
132
        # no unhandled exception during the execution of the validator
133
        if not self.result_sent:
134
            logger.debug("Validation script forgot result sending, assuming success.")
135
            self.send_pass_result()
136
        # roll back
137
        sys.path = old_path
138
        # Test script was executed, result was somehow sent
139
        # Clean the file system, since we can't do anything else
140
        remove_working_directory(self.working_dir, self._config)
141
142
    def _send_result(self, info_student, info_tutor, error_code):
143
        post_data = [("SubmissionFileId", self.file_id),
144
                     ("Message", info_student),
145
                     ("Action", self.action),
146
                     ("MessageTutor", info_tutor),
147
                     ("ExecutorDir", self.working_dir),
148
                     ("ErrorCode", error_code),
149
                     ("Secret", self._config.get("Server", "secret")),
150
                     ("UUID", self._config.get("Server", "uuid"))
151
                     ]
152
        logger.info(
153
            'Sending result to OpenSubmit Server: ' + str(post_data))
154
        if self._online:
155
            send_post(self._config, "/jobs/", post_data)
156
        self.result_sent = True
157