def report_speed(self): now = time() if now - self._prev_time >= self._update_interval: downloaded = self.status.downloaded try: speed = ((downloaded - self._prev_bytes) / (now - self._prev_time)) except ZeroDivisionError: speed = 0 if not self.status.total_size: self._status_line = PROGRESS_NO_CONTENT_LENGTH.format( downloaded=humanize_bytes(downloaded), speed=humanize_bytes(speed), ) else: try: percentage = downloaded / self.status.total_size * 100 except ZeroDivisionError: percentage = 0 if not speed: eta = '-:--:--' else: s = int((self.status.total_size - downloaded) / speed) h, s = divmod(s, 60 * 60) m, s = divmod(s, 60) eta = '{0}:{1:0>2}:{2:0>2}'.format(h, m, s) self._status_line = PROGRESS.format( percentage=percentage, downloaded=humanize_bytes(downloaded), speed=humanize_bytes(speed), eta=eta, ) self._prev_time = now self._prev_bytes = downloaded self.output.write( CLEAR_LINE + ' ' + SPINNER[self._spinner_pos] + ' ' + self._status_line ) self.output.flush() self._spinner_pos = (self._spinner_pos + 1 if self._spinner_pos + 1 != len(SPINNER) else 0)
def start(self, response): """ Initiate and return a stream for `response` body with progress callback attached. Can be called only once. :param response: Initiated response object with headers already fetched :type response: requests.models.Response :return: RawStream, output_file """ assert not self.status.time_started try: total_size = int(response.headers['Content-Length']) except (KeyError, ValueError, TypeError): total_size = None if self._output_file: if self._resume and response.status_code == PARTIAL_CONTENT: total_size = parse_content_range( response.headers.get('Content-Range'), self._resumed_from) else: self._resumed_from = 0 try: self._output_file.seek(0) self._output_file.truncate() except IOError: pass # stdout else: # TODO: Should the filename be taken from response.history[0].url? # Output file not specified. Pick a name that doesn't exist yet. fn = None if 'Content-Disposition' in response.headers: fn = filename_from_content_disposition( response.headers['Content-Disposition']) if not fn: fn = filename_from_url( url=response.url, content_type=response.headers.get('Content-Type'), ) self._output_file = open(get_unique_filename(fn), mode='a+b') self.status.started(resumed_from=self._resumed_from, total_size=total_size) stream = RawStream(msg=HTTPResponse(response), with_headers=False, with_body=True, on_body_chunk_downloaded=self.chunk_downloaded, chunk_size=1024 * 8) self._progress_reporter.output.write( 'Downloading %sto "%s"\n' % ((humanize_bytes(total_size) + ' ' if total_size is not None else ''), self._output_file.name)) self._progress_reporter.start() return stream, self._output_file
def start(self, initial_url: str, final_response: requests.Response) -> Tuple[RawStream, IO]: """ Initiate and return a stream for `response` body with progress callback attached. Can be called only once. :param initial_url: The original requested URL :param final_response: Initiated response object with headers already fetched :return: RawStream, output_file """ assert not self.status.time_started # FIXME: some servers still might sent Content-Encoding: gzip # <https://github.com/httpie/httpie/issues/423> try: total_size = int(final_response.headers['Content-Length']) except (KeyError, ValueError, TypeError): total_size = None if not self._output_file: self._output_file = self._get_output_file_from_response( initial_url=initial_url, final_response=final_response, ) else: # `--output, -o` provided if self._resume and final_response.status_code == PARTIAL_CONTENT: total_size = parse_content_range( final_response.headers.get('Content-Range'), self._resumed_from) else: self._resumed_from = 0 try: self._output_file.seek(0) self._output_file.truncate() except IOError: pass # stdout self.status.started(resumed_from=self._resumed_from, total_size=total_size) stream = RawStream(msg=HTTPResponse(final_response), with_headers=False, with_body=True, on_body_chunk_downloaded=self.chunk_downloaded, chunk_size=1024 * 8) self._progress_reporter.output.write( 'Downloading %sto "%s"\n' % ((humanize_bytes(total_size) + ' ' if total_size is not None else ''), self._output_file.name)) self._progress_reporter.start() return stream, self._output_file
def sum_up(self): actually_downloaded = (self.status.downloaded - self.status.resumed_from) time_taken = self.status.time_finished - self.status.time_started self.output.write(CLEAR_LINE) try: speed = actually_downloaded / time_taken except ZeroDivisionError: # Either time is 0 (not all systems provide `time.time` # with a better precision than 1 second), and/or nothing # has been downloaded. speed = actually_downloaded self.output.write(SUMMARY.format( downloaded=humanize_bytes(actually_downloaded), total=(self.status.total_size and humanize_bytes(self.status.total_size)), speed=humanize_bytes(speed), time=time_taken, )) self.output.flush()
def sum_up(self): actually_downloaded = ( self.status.downloaded - self.status.resumed_from) time_taken = self.status.time_finished - self.status.time_started self.output.write(CLEAR_LINE) try: speed = actually_downloaded / time_taken except ZeroDivisionError: # Either time is 0 (not all systems provide `time.time` # with a better precision than 1 second), and/or nothing # has been downloaded. speed = actually_downloaded self.output.write(SUMMARY.format( downloaded=humanize_bytes(actually_downloaded), total=(self.status.total_size and humanize_bytes(self.status.total_size)), speed=humanize_bytes(speed), time=time_taken, )) self.output.flush()
def start(self, response): """ Initiate and return a stream for `response` body with progress callback attached. Can be called only once. :param response: Initiated response object with headers already fetched :type response: requests.models.Response :return: RawStream, output_file """ assert not self.status.time_started try: total_size = int(response.headers['Content-Length']) except (KeyError, ValueError, TypeError): total_size = None if self._output_file: if self._resume and response.status_code == PARTIAL_CONTENT: total_size = parse_content_range( response.headers.get('Content-Range'), self._resumed_from ) else: self._resumed_from = 0 try: self._output_file.seek(0) self._output_file.truncate() except IOError: pass # stdout else: # TODO: Should the filename be taken from response.history[0].url? # Output file not specified. Pick a name that doesn't exist yet. filename = None if 'Content-Disposition' in response.headers: filename = filename_from_content_disposition( response.headers['Content-Disposition']) if not filename: filename = filename_from_url( url=response.url, content_type=response.headers.get('Content-Type'), ) self._output_file = open(get_unique_filename(filename), mode='a+b') self.status.started( resumed_from=self._resumed_from, total_size=total_size ) stream = RawStream( msg=HTTPResponse(response), with_headers=False, with_body=True, on_body_chunk_downloaded=self.chunk_downloaded, chunk_size=1024 * 8 ) self._progress_reporter.output.write( 'Downloading %sto "%s"\n' % ( (humanize_bytes(total_size) + ' ' if total_size is not None else ''), self._output_file.name ) ) self._progress_reporter.start() return stream, self._output_file