def handle_scpi_file(self, filepath=SCPI_FILEPATH): """Checks file location for scpi script Description: Checks for a scpi file at the filepath parameter. This method is a wrapper for the read_scpi_file method, which gets called as long as a file exists at the filepath. This will build the G1Script that can be run later by calling the run_script method. Exceptions raised by the read_scpi_file method are logged here. Parameters: filepath: the location to check with os.path.exists to see if a scpi file exists. Returns: None. This command does not return a value """ if not os.path.exists(filepath): logger.error("No SCPI file at {}".format(filepath)) return self.script = None try: self.script = self.read_scpi_file(filepath) except IOError as e: logger.warning(e) except OSError as e: logger.warning(e) except Exception as e: logger.error("Unexpected error: {}".format(e), exc_info=True)
def get_default_headers(self, refresh=False): """Gets the headers for a request Summary: Assigns the auth token to the Auth-Token header. If a refresh is needed, a request is made with the refresh token and the auth token is updated. Paramters: refresh: a boolean to trigger refreshes Returns: a dictionary with the Auth-Token header """ if refresh and 'REFRESH_TOKEN' in COMMON_SETTINGS: url = BASE_URL + '/profile/auth_token/refresh' headers = {'Refresh-Token': COMMON_SETTINGS['REFRESH_TOKEN']} try: response = requests.get(url, headers=headers) assert response.status_code == 200 except Exception: logger.warning("Unable to get refresh token", exc_info=True) data = json.loads(response.text) try: self.auth_token = data['new auth token'] except KeyError: logger.warning("No new auth token in response") headers = { 'Auth-Token': self.auth_token, 'Content-Type': 'application/json', 'Accept': 'text/plain', } return headers
def _set_divisions(self, h_divs=0, v_divs=0): """Checks the instrument for divisions If the instrument does not have them then default values are used. If vertical and horizontal divisions are passed in as parameters then those will take priority in setting the class attributes. """ DEFAULT_HORIZONTAL_DIVS = 10 DEFAULT_VERTICAL_DIVS = 8 if self.instr and self.instr._horizontal_divisions: self._horizontal_divisions = self.instr._horizontal_divisions else: self._horizontal_divisions = DEFAULT_HORIZONTAL_DIVS if self.instr and self.instr._vertical_divisions: self._vertical_divisions = self.instr._vertical_divisions else: self._vertical_divisions = DEFAULT_VERTICAL_DIVS if h_divs: self._horizontal_divisions = h_divs if v_divs: self._vertical_divisions = v_divs if not isinstance(self.trace_dict, dict): print(self.trace_dict) logger.warning("trace data not properly initialized") self.trace_dict = {} self.trace_dict['h_divs'] = self._horizontal_divisions self.trace_dict['v_divs'] = self._vertical_divisions
def write(self, file='', mode='r', content=''): try: with open(file, mode) as f: f.write(content) except IOError as e: # not able to read the file logger.warning("IOError write(): {}".format(e)) except TypeError as e: # bad data in the file logger.warning("TypeError write(): {}".format(e)) except Exception as e: logger.error("Unexpected error in write(): {}".format(e))
def run(self): for command in self.commands: try: response = command.run() except TimeoutError: logger.warning("Command '{}' timed out!".format(command)) except Exception as e: logger.warning("Command '{}' encountered an unexpected " "exception: {};".format(command, e)) else: if isinstance(response, list): self.responses.extend(response) else: self.responses.append(response)
def run(self): """Runs the Fetch Screenshot Command Summary: Fetches the screenshot and writes it to file """ scn = None try: scn = self.instrument.fetch_screenshot() except NotInitializedException as e: logger.warning("instrument not initialized for screenshot") except IOError as e: logger.warning(e) except OSError as e: logger.warning(e) except Exception as e: logger.error("Unexpected error: {}".format(e), exc_info=True) if scn: response = self.save_to_file(scn) else: response = "Unable to fetch screenshot!" logger.warning(response) self.response = response logger.info("FetchScreenshotCommand response: {}".format(response)) return self.response
def _read_trace_data(self, filepath=''): if not filepath: filepath = settings.WAVEFORM_FILE data = None with open(filepath, 'rb') as f: try: data = json.loads(f.read()) except IOError as e: logger.warning(e) except OSError as e: logger.warning(e) except Exception as e: logger.error("Unexpected error: {}".format(e), exc_info=True) if not data: data = {} return data
def save_to_file(self, data, filepath=''): """saves data to filepath designated in settings.py""" if not filepath: filepath = settings.WAVEFORM_FILE response = 'No waveform saved' # default msg until success try: with open(filepath, 'wb') as f: f.write(json.dumps(data)) except IOError as e: logger.warning(e) except OSError as e: logger.warning(e) except Exception as e: logger.error("Unexpected error: {}".format(e), exc_info=True) else: # success! response = "Waveform saved to: {}".format(filepath) return response
def save_to_file(self, data, filepath=''): """saves data to filepath designated in settings.py""" if not filepath: filepath = SCREENSHOT_FILE response = 'No screenshot saved' # default msg until success try: with open(SCREENSHOT_FILE, 'wb') as f: f.write((data)) except IOError as e: logger.warning(e) except OSError as e: logger.warning(e) except Exception as e: logger.error("Unexpected error: {}".format(e), exc_info=True) else: # success! response = "Screenshot saved to: {}".format(filepath) return response
def run(self): for i in range(self.maxcount): for command in self.commands: try: response = command.run() except TimeoutError: response = "G1Loop: '{}' timed out!".format(command) logger.warning(response) except Exception as e: response = ("G1Loop: '{}' encountered an unexpected " "exception: {};".format(command, e)) logger.warning(response) self.responses.append(response) if self.break_on is not None and response == self.break_on: # Note: will break from the outer range() loop also logger.info( "Received response {}; Breaking from loop".format( response)) return
def _retry_request(self, url, kind, data={}, params={}, headers={}): """Retries the https request with a fresh session""" self.session = requests.session() self.session.headers.update(self.get_default_headers()) response = None if headers: # include any headers from method arg self.session.headers.update(headers) try: if data: response = self.request_dict[kind](url, data=data) else: response = self.request_dict[kind](url, params=params) except ssl.SSLError: logger.warning("SSLError on retry. Aborting request.") except Exception as e: logger.warning("The retry request encountered an unexpected " "exception: {}".format(e)) logger.debug("The retry request exception info:", exc_info=True) return response
def transmit(self, filepath, file_key='', mode='rb'): """transmits file to server""" with open(filepath, mode) as f: filename = os.path.basename(f.name) if not file_key: file_key = filename fields = { 'file': (filename, open(filepath, mode)), 'file_key': file_key, 'category': self.category, } multipartblob = MultipartEncoder(fields=fields) # get the temporary upload url to post the file to resp = self.requester.https_get(BASE_URL + "/upload/geturl") if not resp: logger.warning("No response from {}. Aborting upload.".format( BASE_URL + "/upload/geturl")) return headers = {'Content-Type': multipartblob.content_type} response = None try: response = requests.post(resp.text, data=multipartblob, headers=headers) except TypeError: logger.warning("TypeError during transmit_file call", exc_info=True) except ssl.SSLError: logger.warning("SSLError! during transmit_file", exc_info=True) self._log_upload_response(response) return response
def run(self): """Posts the screenshot file to the server Summary: Transmits the screenshot file with a file_key to look up the file at a later date. The file_key is set with date and time to the second, e.g. "screenshot-2019-08-14T15:50:43" If this was successful a result_id is generated and will be logged. """ transmitter = FileTransmitter(category='fetch_screenshot') dt_str = datetime.datetime.now().isoformat() file_key = 'screenshot-' + dt_str.split(',')[0] logger.info("Using file_key: " + file_key) response = transmitter.transmit(SCREENSHOT_FILE, file_key=file_key) result_id = self._handle_response(response) if result_id: logger.info("Result ID for screenshot: {}".format(result_id)) rid_url = BASE_URL + '/results/{}'.format(result_id) logger.info("You can view the result at: {}".format(rid_url)) else: logger.warning("No Result ID from waveform upload")
def _parse_command_string(self, cmdstr): """Parses the commands string and adds it to the G1Script Summary: Either initializes the instrument or handles a scpi command. Handling a scpi command will instantiate a SCPICommand object to use for controlling the instrument. Returns: None """ cmdcaps = cmdstr.upper() if cmdcaps.startswith('G1:OPEN') or cmdcaps.startswith('TCPIP'): try: self.instrument = self._open_instrument(cmdstr) except InstrumentConnectionError: logger.warning("Encountered InstrumentConnectionError when " "attempting to open with '{}'".format(cmdstr)) logger.warning("Exiting...") sys.exit() elif cmdcaps.startswith('G1:STARTLOOP') or cmdcaps == 'G1:ENDLOOP': self._parse_loop_cmd(cmdstr) else: self._parse_basic_cmd(cmdstr)
def _log_http_err_response(self, response, data={}, params={}): logger.warning("response.text %s" % response.text) logger.warning("request headers %s" % self.session.headers) logger.warning("more request details in debug level") if data: msg = "request data %s" % data elif params: msg = "request params %s" % params if len(msg) > 500: msg = msg[0:500] + "..." logger.debug(msg)
def _log_upload_response(self, response): if response and response.status_code == 200: logger.info("File upload succeeded!") else: logger.warning("File upload failed") response_text = None if hasattr(response, 'text'): response_text = response.text if not response_text: logger.warning("No response text to log") else: logger.warning("Non 200 response {}".format(response_text))
def https_request(self, url, data={}, params={}, headers={}, kind='get'): """Makes https requests Summary: Tries to make a https request and logs exceptions. Will retry the Parameters: url: the target url data: a dictionary payload for POST or PUT requests params: a dictionary of params for GET or DEL requests headers: request headers, these will update the base headers that are already assigned by get_default_headers kind: the flavor of the request (GET, POST, etc.) Returs: a requests module response object """ hdrs = self.get_default_headers() hdrs.update(headers) response = None try: if data: response = self.request_dict[kind](url, data=data, headers=hdrs) else: response = self.request_dict[kind](url, params=params, headers=hdrs) except ssl.SSLError: logger.warning("SSLError!", exc_info=True) logger.info("Retrying request to {}".format(url)) response = self._retry_request(url, kind, data, params, headers) except Exception as e: logger.warning("Unexpected request exc: {}".format(e)) logger.debug("The request exception info:", exc_info=True) if not response: logger.warning("No response from {}".format(url)) elif response.status_code in [401, 403]: # refresh headers and try again hdrs = self.get_default_headers(refresh=True) self.session.headers.update(hdrs) response = self._retry_request(url, kind, data, params, headers) elif response.status_code != 200: self._log_http_err_response(response, data, params) # reset the headers to default self.session.headers = self.get_default_headers() return response
def _create_waveform_result(self): """Creates a waveform result on the server""" dt_str = datetime.datetime.now().isoformat() waveform_id = 'waveform-' + dt_str.split(',')[0] if 'instrument_type' in self.trace_dict: instrument_type = self.trace_dict.pop('instrument_type') else: instrument_type = 'sample_instrument_type' data = { 'command_id': waveform_id, 'config_name': waveform_id, 'instrument_type': instrument_type, 'kind': 'Result_Summary', 'upload_kind': 'Waveform', 'info': {}, 'waveform': self.trace_dict, } # assuming these are set in settings them # data['instrument_type'] = settings.INSTRUMENT_TYPE, # data['device_under_test'] = settings.DUT r_url = BASE_URL + '/results' json_data = json.dumps(data, ensure_ascii=True) response = self.requester.https_post(r_url, data=json_data) result_id = '' if not response: return logger.info("Request to {} response.status_code: {}".format( r_url, response.status_code)) try: result_id = json.loads(response.text)['result']['id'] except ValueError: logger.warning("ValueError in _create_waveform_results") logger.info("response text: {}".format(response.text)) except KeyError: logger.warning("KeyError in _create_waveform_results") except Exception as e: logger.warning("Unexpected error: {}".format(e), exc_info=True) else: logger.info( "Result created successfully with result_id: {}".format( result_id)) rid_url = r_url + '/{}'.format(result_id) logger.info("You can view the result at: {}".format(rid_url)) self.trace_dict['result_id'] = result_id return result_id
def _handle_socket_err(self, err): logger.warning("Socket Error: {}".format(err))