def download_file( filename: str, save_path: str, remote_connection: 'environ.RemoteConnection' = None ) -> 'environ.Response': """ """ url = assemble_url('/download/{}'.format(filename), remote_connection=remote_connection) try: http_response = requests.get(url, stream=True) except Exception as error: return environ.Response().fail( code='CONNECTION_ERROR', error=error, message='Unable to communicate with the remote download connection' ).console(whitespace=1).response try: with open(save_path, 'wb') as f: for chunk in http_response.iter_content(2048): if chunk: f.write(chunk) except Exception as error: return environ.Response().fail( code='WRITE_ERROR', error=error, message='Unable to write data to "{}"'.format(save_path)).console( whitespace=1).response return environ.Response()
def test_run_in_parts(self): """ """ support.open_project(self, '@examples:hello_cauldron') r = environ.Response() commander.execute('run', 'S01-create-data.py', r) r.thread.join() self.assertFalse(r.failed) r = environ.Response() commander.execute('run', 'S02-plot-data.py', r) r.thread.join() self.assertFalse(r.failed)
def open_project(tester: scaffolds.ResultsTest, path: str) -> 'environ.Response': """...""" r = environ.Response() commander.execute('open', '{} --forget'.format(path), r) r.thread.join() return r
def open_project(self) -> 'exposed.ExposedProject': """ Returns the Response object populated by the open project command """ project_path = self.make_project_path() res = environ.Response() commander.execute('open', '{} --forget'.format(project_path), res) res.thread.join() # Prevent threading race conditions check_count = 0 while res.success and not cd.project.internal_project: if check_count > 100: break check_count += 1 time.sleep(0.25) if res.failed or not cd.project.internal_project: self.fail( 'Unable to open project at path "{}"'.format(project_path)) os.chdir(cd.project.internal_project.source_directory) return cd.project
def parse_http_response(http_response: HttpResponse) -> 'environ.Response': """ Returns a Cauldron response object parsed from the serialized JSON data specified in the http_response argument. If the response doesn't contain valid Cauldron response data, an error Cauldron response object is returned instead. :param http_response: The response object from an http request that contains a JSON serialized Cauldron response object as its body :return: The Cauldron response object for the given http response """ try: response = environ.Response.deserialize(http_response.json()) except Exception as error: response = environ.Response().fail( code='INVALID_REMOTE_RESPONSE', error=error, message='Invalid HTTP response from remote connection').console( whitespace=1).response response.http_response = http_response return response
def default(self, line: str): """ :param line: :return: """ line = line.strip() if len(line) < 1: return self.history.append(line) name, raw_args = parse.split_line(line) if name == 'help': return commander.show_help().ended result = commander.execute(name, raw_args) result = (result.response if hasattr(result, 'response') else environ.Response(failed=result)) if result.thread: result.thread.join() p = cauldron.project if not p or not p.internal_project or not p.internal_project.id: name = '' else: name = cauldron.project.internal_project.id[:20] self.prompt = '<{}>: '.format(name) self.last_response = result return result.ended
def open_project(project_path: str) -> 'exposed.ExposedProject': """ Opens the project located at the specified path and returns the public (exposed) project after it has been loaded. If the project cannot be opened a `RuntimeError` will be raised instead. :param project_path: The path to the Cauldron project to open. It should be either a directory that contains a `cauldron.json` file or a file path to the `cauldron.json` file for the project to load. """ res = commander.execute( name='open', raw_args='{} --forget'.format(project_path), response=environ.Response() ) res.thread.join() # Prevent threading race conditions project = ( cd.project.get_internal_project() if res.success else None ) if res.failed or not project: raise RuntimeError( 'Unable to open project at path "{}"'.format(project_path) ) os.chdir(project.source_directory) return cd.project
def test_run_no_project(self): """ should abort if no project is open """ r = environ.Response() run.execute( context=cli.make_command_context(name=run.NAME, response=r)) self.assert_has_error_code(r, 'NO_OPEN_PROJECT')
def test_long_remote_command(self, send_request: MagicMock): """ should successfully handle running longer commands """ running_response = environ.Response().update(run_status='running') done_response = environ.Response().update(run_status='complete') send_request.return_value = running_response thread = threads.send_remote_command('fake_command_name') thread.join(1) send_request.return_value = done_response thread.join() self.assertGreater(len(thread.responses), 1) last_response = thread.responses[-1] self.assertEqual(last_response.data['run_status'], 'complete') first_response = thread.responses[0] self.assertEqual(first_response.data['run_status'], 'running')
def test_send_request_valid(self, request: MagicMock, parse_http_response: MagicMock): """Should successfully send request""" request.return_value = HttpResponse() parse_http_response.return_value = environ.Response('test') response = comm.send_request(endpoint='/fake', method='post', data=dict(a=1, b=2)) self.assertEqual(response.identifier, 'test')
def test_remote_command(self, send_request: MagicMock): """ should execute the command and finish the thread """ response = environ.Response().update(run_status='complete') send_request.return_value = response thread = threads.send_remote_command('fake_command_name') thread.join() self.assertEqual(thread.responses[0], response)
def test_run_bokeh(self): """ """ support.open_project(self, '@examples:bokeh') r = environ.Response() commander.execute('run', '', r) r.thread.join() self.assertFalse(r.failed)
def send_request(endpoint: str, data: dict = None, remote_connection: 'environ.RemoteConnection' = None, method: str = None, timeout: int = 10, max_retries: int = 10, **kwargs) -> 'environ.Response': """ Sends a request to the remote kernel specified by the RemoteConnection object and processes the result. If the request fails or times out it will be retried until the max retries is reached. After that a failed response will be returned instead. :param endpoint: Remote endpoint where the request will be directed. :param data: An optional JSON-serializable dictionary containing the request body data. :param remote_connection: Defines the connection to the remote server where the request will be sent. :param method: The HTTP method type for the request, e.g. GET, POST. :param timeout: Number of seconds before the request aborts when trying to either connect to the target endpoint or receive data from the server. :param max_retries: Number of retry attempts to make before giving up if a non-HTTP error is encountered during communication. """ if max_retries < 0: return environ.Response().fail( code='COMMUNICATION_ERROR', error=None, message='Unable to communicate with the remote kernel.').console( whitespace=1).response url = assemble_url(endpoint, remote_connection) try: http_response = requests.request(method=method, url=url, json=data, timeout=10, **kwargs) except (requests.ConnectionError, requests.HTTPError, requests.Timeout): return send_request(endpoint=endpoint, data=data, remote_connection=remote_connection, method=method, timeout=timeout, max_retries=max_retries - 1, **kwargs) return parse_http_response(http_response)
def test_run_step_example(self): """ """ support.open_project(self, '@examples:hello_cauldron') r = environ.Response() commander.execute('run', '.', r) r.thread.join() self.assertFalse(r.failed)
def test_run_example(self): """ """ support.open_project(self, '@examples:hello_text') r = environ.Response() commander.execute('run', '', r) r.thread.join() self.assertFalse(r.failed) support.run_command('close')
def test_remote(self, sync_open: MagicMock): """ should successfully open project remotely """ sync_open.return_value = environ.Response() response = support.create_project( self, 'tester', confirm=False, remote_connection=environ.RemoteConnection(True, 'something.url')) self.assertTrue(response.success) self.assertGreater(sync_open.call_count, 0)
def test_parse_valid_http_response(self): """Should fail to send request""" source_response = environ.Response().update(test='hello_world') def json_mock(*args, **kwargs): return source_response.serialize() http_response = HttpResponse() http_response.json = json_mock response = comm.parse_http_response(http_response) self.assertEqual(source_response.data['test'], response.data['test'])
def deserialize_flask_response( flask_response: FlaskResponse) -> 'environ.Response': """ """ try: data = json.loads(flask_response.data.decode('utf-8', 'ignore')) response = environ.Response.deserialize(data) except Exception as error: response = environ.Response().fail( code='DESERIALIZE_FLASK_RESPONSE', message='Failed to deserialize flask response', error=error) return response
def send_request(endpoint: str, data: dict = None, remote_connection: 'environ.RemoteConnection' = None, method: str = None, **kwargs) -> 'environ.Response': """ """ url = assemble_url(endpoint, remote_connection) func = get_request_function(data, method) try: http_response = func(url, json=data, **kwargs) except Exception as error: return environ.Response().fail( code='CONNECTION_ERROR', error=error, message='Unable to communicate with the remote connection' ).console(whitespace=1).response return parse_http_response(http_response)