def test_response(): response = Response( method='get', url='test_url', headers=CaseInsensitiveDict({'foo': 'bar'}), status_text='baz', status_code=200, raw_body='true', ) assert response.method == 'get' assert response.url == 'test_url' assert response.headers == {'foo': 'bar'} assert response.status_code == 200 assert response.status_text == 'baz' assert response.body is True assert response.raw_body == 'true' assert response.error_code is None assert response.error_message is None test_body = '{"errorNum": 1, "errorMessage": "qux"}' response = Response( method='get', url='test_url', headers=CaseInsensitiveDict({'foo': 'bar'}), status_text='baz', status_code=200, raw_body=test_body, ) assert response.method == 'get' assert response.url == 'test_url' assert response.headers == {'foo': 'bar'} assert response.status_code == 200 assert response.status_text == 'baz' assert response.body == {'errorNum': 1, 'errorMessage': 'qux'} assert response.raw_body == test_body assert response.error_code == 1 assert response.error_message == 'qux' response = Response( method='get', url='test_url', headers=CaseInsensitiveDict({'foo': 'bar'}), status_text='baz', status_code=200, raw_body='invalid', ) assert response.method == 'get' assert response.url == 'test_url' assert response.headers == {'foo': 'bar'} assert response.status_code == 200 assert response.status_text == 'baz' assert response.body == 'invalid' assert response.raw_body == 'invalid' assert response.error_code is None assert response.error_message is None
def put(self, url, data, params=None, headers=None, auth=None): """Execute an HTTP **PUT** method. :param url: request URL :type url: str | unicode :param data: request payload :type data: str | unicode | dict :param params: request parameters :type params: dict :param headers: request headers :type headers: dict :param auth: username and password tuple :type auth: tuple :returns: ArangoDB HTTP response object :rtype: arango.response.Response """ res = self._session.put(url=url, data=data, params=params, headers=headers, auth=auth, verify=self._check_cert) return Response(url=url, method="put", headers=res.headers, http_code=res.status_code, http_text=res.reason, body=res.text)
def put(self, url, data=None, params=None, headers=None, auth=None): """HTTP PUT method. :param url: request URL :type url: str :param data: request payload :type data: str or dict or None :param params: request parameters :type params: dict or None :param headers: request headers :type headers: dict or None :param auth: username and password tuple :type auth: tuple or None :returns: ArangoDB http response object :rtype: arango.response.Response """ res = self.session.put( url=url, data=data, params=params, headers=headers, ) return Response(method="put", url=url, headers=res.headers, status_code=res.status_code, content=res.text, status_text=res.reason)
def send_request(self, session, method, url, params=None, data=None, headers=None, auth=None): # Add your own debug statement. self._logger.debug('Sending request to {}'.format(url)) # Send a request. response = session.request(method=method, url=url, params=params, data=data, headers=headers, verify=self.cert) self._logger.debug('Got {}'.format(response.status_code)) # Return an instance of arango.response.Response. return Response( method=response.request.method, url=response.url, headers=response.headers, status_code=response.status_code, status_text=response.reason, raw_body=response.text, )
def options(self, url, data=None, params=None, headers=None, auth=None): """HTTP OPTIONS method. :param url: request URL :type url: str :param data: request payload :type data: str or dict or None :param params: request parameters :type params: dict or None :param headers: request headers :type headers: dict or None :param auth: username and password tuple :type auth: tuple or None :returns: ArangoDB http response object :rtype: arango.response.Response """ res = self.session.options( url=url, data="" if data is None else data, params={} if params is None else params, headers={} if headers is None else headers, ) return Response(method="options", url=url, headers=res.headers, status_code=res.status_code, content=res.text, status_text=res.reason)
def delete(self, url, params=None, headers=None, auth=None): """HTTP DELETE method. :param url: request URL :type url: str :param params: request parameters :type params: dict or None :param headers: request headers :type headers: dict or None :param auth: username and password tuple :type auth: tuple or None :returns: ArangoDB http response object :rtype: arango.response.Response """ res = self.session.delete( url=url, params=params, headers=headers, auth=auth, ) return Response(method="delete", url=url, headers=res.headers, status_code=res.status_code, content=res.text, status_text=res.reason)
def delete(self, url, data=None, params=None, headers=None, auth=None): """Execute an HTTP **DELETE** method. :param url: request URL :type url: str :param data: request payload :type data: str | dict :param params: request parameters :type params: dict :param headers: request headers :type headers: dict :param auth: username and password tuple :type auth: tuple :returns: ArangoDB HTTP response object :rtype: arango.response.Response """ res = self._session.delete(url=url, data=data, params=params, headers=headers, auth=auth) return Response(url=url, method="delete", headers=res.headers, http_code=res.status_code, http_text=res.reason, body=res.text)
def commit(self): """Execute the queued API requests in a single HTTP call. If `return_response` was set to ``True`` during initialization, the responses are saved within an :class:`arango.batch.BatchJob` object for later retrieval via its :func:`~arango.batch.BatchJob.result` method :raises arango.exceptions.BatchExecuteError: if the batch request cannot be executed """ try: if not self._requests: return raw_data = '' for content_id, request in enumerate(self._requests, start=1): raw_data += '--XXXsubpartXXX\r\n' raw_data += 'Content-Type: application/x-arango-batchpart\r\n' raw_data += 'Content-Id: {}\r\n\r\n'.format(content_id) raw_data += '{}\r\n'.format(request.stringify()) raw_data += '--XXXsubpartXXX--\r\n\r\n' res = self.post( endpoint='/_api/batch', headers={ 'Content-Type': ('multipart/form-data; boundary=XXXsubpartXXX') }, data=raw_data, ) if res.status_code not in HTTP_OK: raise BatchExecuteError(res) if not self._return_result: return for index, raw_response in enumerate( res.raw_body.split('--XXXsubpartXXX')[1:-1]): request = self._requests[index] handler = self._handlers[index] job = self._batch_jobs[index] res_parts = raw_response.strip().split('\r\n') raw_status, raw_body = res_parts[3], res_parts[-1] _, status_code, status_text = raw_status.split(' ', 2) try: result = handler( Response(method=request.method, url=self._url_prefix + request.endpoint, headers=request.headers, http_code=int(status_code), http_text=status_text, body=raw_body)) except ArangoError as err: job.update(status='error', result=err) else: job.update(status='done', result=result) finally: self._requests = [] self._handlers = [] self._batch_jobs = []
def test_response(conn): response = Response( method="get", url="test_url", headers={"foo": "bar"}, status_text="baz", status_code=200, raw_body="true", ) conn.prep_response(response) assert response.method == "get" assert response.url == "test_url" assert response.headers == {"foo": "bar"} assert response.status_code == 200 assert response.status_text == "baz" assert response.raw_body == "true" assert response.body is True assert response.error_code is None assert response.error_message is None assert response.is_success is True test_body = '{"errorNum": 1, "errorMessage": "qux"}' response = Response( method="get", url="test_url", headers={"foo": "bar"}, status_text="baz", status_code=200, raw_body=test_body, ) conn.prep_response(response) assert response.method == "get" assert response.url == "test_url" assert response.headers == {"foo": "bar"} assert response.status_code == 200 assert response.status_text == "baz" assert response.raw_body == test_body assert response.body == {"errorMessage": "qux", "errorNum": 1} assert response.error_code == 1 assert response.error_message == "qux" assert response.is_success is False
def send_request( self, session: Session, method: str, url: str, headers: Optional[Headers] = None, params: Optional[MutableMapping[str, str]] = None, data: Union[str, MultipartEncoder, None] = None, auth: Optional[Tuple[str, str]] = None, ) -> Response: """Send an HTTP request. :param session: Requests session object. :type session: requests.Session :param method: HTTP method in lowercase (e.g. "post"). :type method: str :param url: Request URL. :type url: str :param headers: Request headers. :type headers: dict :param params: URL (query) parameters. :type params: dict :param data: Request payload. :type data: str | MultipartEncoder | None :param auth: Username and password. :type auth: tuple :returns: HTTP response. :rtype: arango.response.Response """ response = session.request( method=method, url=url, params=params, data=data, headers=headers, auth=auth, timeout=self.REQUEST_TIMEOUT, ) return Response( method=method, url=response.url, headers=response.headers, status_code=response.status_code, status_text=response.reason, raw_body=response.text, )
def send_request(self, session, method, url, params=None, data=None, headers=None, auth=None): response = session.request( method=method, url=url, params=params, data=data, headers=headers, auth=auth, timeout=self.timeout ) return Response( method=response.request.method, url=response.url, headers=response.headers, status_code=response.status_code, status_text=response.reason, raw_body=response.text, )
def send_request(self, session, method, url, params=None, data=None, headers=None, auth=None): """Send an HTTP request. :param session: Requests session object. :type session: requests.Session :param method: HTTP method in lowercase (e.g. "post"). :type method: str | unicode :param url: Request URL. :type url: str | unicode :param headers: Request headers. :type headers: dict :param params: URL (query) parameters. :type params: dict :param data: Request payload. :type data: str | unicode | bool | int | list | dict :param auth: Username and password. :type auth: tuple :returns: HTTP response. :rtype: arango.response.Response """ response = session.request( method=method, url=url, params=params, data=data, headers=headers, auth=auth, ) return Response( method=response.request.method, url=response.url, headers=response.headers, status_code=response.status_code, status_text=response.reason, raw_body=response.text, )
def build_error_response(self, parent_response, body): """Build and return a bulk error response. :param parent_response: Parent response. :type parent_response: arango.response.Response :param body: Error response body. :type body: dict :return: Child bulk error response. :rtype: arango.response.Response """ response = Response( method=parent_response.method, url=parent_response.url, headers=parent_response.headers, status_code=parent_response.status_code, status_text=parent_response.status_text, raw_body=self.serialize(body), ) response.body = body response.error_code = body['errorNum'] response.error_message = body['errorMessage'] response.is_success = False return response
def commit(self): """Execute the queued requests in a single batch API request. If **return_result** parameter was set to True during initialization, :class:`arango.job.BatchJob` instances are populated with results. :return: Batch jobs or None if **return_result** parameter was set to False during initialization. :rtype: [arango.job.BatchJob] | None :raise arango.exceptions.BatchStateError: If batch state is invalid (e.g. batch was already committed or size of response from server did not match the expected). :raise arango.exceptions.BatchExecuteError: If commit fails. """ if self._committed: raise BatchStateError('batch already committed') else: self._committed = True if len(self._queue) == 0: return self.jobs # Boundary used for multipart request boundary = uuid4().hex # Build the batch request payload buffer = [] for req, job in self._queue.values(): buffer.append('--{}'.format(boundary)) buffer.append('Content-Type: application/x-arango-batchpart') buffer.append('Content-Id: {}'.format(job.id)) buffer.append('\r\n' + self._stringify_request(req)) buffer.append('--{}--'.format(boundary)) request = Request( method='post', endpoint='/_api/batch', headers={ 'Content-Type': 'multipart/form-data; boundary={}'.format(boundary) }, data='\r\n'.join(buffer), ) with suppress_warning('requests.packages.urllib3.connectionpool'): resp = self._conn.send_request(request) if not resp.is_success: raise BatchExecuteError(resp, request) if not self._return_result: return None url_prefix = resp.url.strip('/_api/batch') raw_resps = resp.raw_body.split('--{}'.format(boundary))[1:-1] if len(self._queue) != len(raw_resps): raise BatchStateError( 'expecting {} parts in batch response but got {}'.format( len(self._queue), len(raw_resps))) for raw_resp in raw_resps: # Parse and breakdown the batch response body resp_parts = raw_resp.strip().split('\r\n') raw_content_id = resp_parts[1] raw_body = resp_parts[-1] raw_status = resp_parts[3] job_id = raw_content_id.split(' ')[1] _, status_code, status_text = raw_status.split(' ', 2) # Update the corresponding batch job queued_req, queued_job = self._queue[job_id] queued_job._status = 'done' resp = Response(method=queued_req.method, url=url_prefix + queued_req.endpoint, headers={}, status_code=int(status_code), status_text=status_text, raw_body=raw_body) queued_job._response = self._conn.prep_response(resp) return self.jobs
def commit(self): """Execute the queued requests in a single transaction API request. If **return_result** parameter was set to True during initialization, :class:`arango.job.TransactionJob` instances are populated with results. :return: Transaction jobs or None if **return_result** parameter was set to False during initialization. :rtype: [arango.job.TransactionJob] | None :raise arango.exceptions.TransactionStateError: If the transaction was already committed. :raise arango.exceptions.TransactionExecuteError: If commit fails. """ if self._committed: raise TransactionStateError('transaction already committed') self._committed = True if len(self._queue) == 0: return self.jobs write_collections = set() if isinstance(self._write, string_types): write_collections.add(self._write) elif self._write is not None: write_collections |= set(self._write) read_collections = set() if isinstance(self._read, string_types): read_collections.add(self._read) elif self._read is not None: read_collections |= set(self._read) # Buffer for building the transaction javascript command cmd_buffer = [ 'var db = require("internal").db', 'var gm = require("@arangodb/general-graph")', 'var result = {}' ] for req, job in self._queue.values(): if isinstance(req.read, string_types): read_collections.add(req.read) elif req.read is not None: read_collections |= set(req.read) if isinstance(req.write, string_types): write_collections.add(req.write) elif req.write is not None: write_collections |= set(req.write) cmd_buffer.append('result["{}"] = {}'.format(job.id, req.command)) cmd_buffer.append('return result;') data = { 'action': 'function () {{ {} }}'.format(';'.join(cmd_buffer)), 'collections': { 'read': list(read_collections), 'write': list(write_collections), 'allowImplicit': True } } if self._timeout is not None: data['lockTimeout'] = self._timeout if self._sync is not None: data['waitForSync'] = self._sync request = Request( method='post', endpoint='/_api/transaction', data=data, ) resp = self._conn.send_request(request) if not resp.is_success: raise TransactionExecuteError(resp, request) if not self._return_result: return None result = resp.body['result'] for req, job in self._queue.values(): job._response = Response(method=req.method, url=self._conn.url_prefix + req.endpoint, headers={}, status_code=200, status_text='OK', raw_body=result.get(job.id)) job._status = 'done' return self.jobs