def create_full_filename(basename, filename): """Create a full filename based on the given basename and filename. Args: basename: The basename to use if filename is a directory. filename: The path to a folder or file where you want to save. Return: The full absolute path, or None if filename creation was not possible. """ # Remove chars which can't be encoded in the filename encoding. # See https://github.com/qutebrowser/qutebrowser/issues/427 encoding = sys.getfilesystemencoding() filename = utils.force_encoding(filename, encoding) basename = utils.force_encoding(basename, encoding) if os.path.isabs(filename) and (os.path.isdir(filename) or filename.endswith(os.sep)): # We got an absolute directory from the user, so we save it under # the default filename in that directory. return os.path.join(filename, basename) elif os.path.isabs(filename): # We got an absolute filename from the user, so we save it under # that filename. return filename return None
def start_download_checked(target, tab): """First check if dest is already a file, then start the download. Args: target: The DownloadTarget where the resulting file should be saved. tab: Specify the tab whose page should be loaded. """ if not isinstance(target, downloads.FileDownloadTarget): _start_download(target, tab) return # The default name is 'page title.mhtml' title = tab.title() default_name = utils.sanitize_filename(title + '.mhtml') # Remove characters which cannot be expressed in the file system encoding encoding = sys.getfilesystemencoding() default_name = utils.force_encoding(default_name, encoding) dest = utils.force_encoding(target.filename, encoding) dest = os.path.expanduser(dest) # See if we already have an absolute path path = downloads.create_full_filename(default_name, dest) if path is None: # We still only have a relative path, prepend download_dir and # try again. path = downloads.create_full_filename( default_name, os.path.join(downloads.download_dir(), dest)) downloads.last_used_directory = os.path.dirname(path) # Avoid downloading files if we can't save the output anyway... # Yes, this is prone to race conditions, but we're checking again before # saving the file anyway. if not os.path.isdir(os.path.dirname(path)): folder = os.path.dirname(path) message.error("Directory {} does not exist.".format(folder)) return target = downloads.FileDownloadTarget(path) if not os.path.isfile(path): _start_download(target, tab=tab) return q = usertypes.Question() q.mode = usertypes.PromptMode.yesno q.title = "Overwrite existing file?" q.text = "<b>{}</b> already exists. Overwrite?".format( html.escape(path)) q.completed.connect(q.deleteLater) q.answered_yes.connect(functools.partial( _start_download, target, tab=tab)) message.global_bridge.ask(q, blocking=False)
def start_download_checked(dest, web_view): """First check if dest is already a file, then start the download. Args: dest: The filename where the resulting file should be saved. web_view: Specify the webview whose page should be loaded. """ # The default name is 'page title.mht' title = web_view.title() default_name = utils.sanitize_filename(title + '.mht') # Remove characters which cannot be expressed in the file system encoding encoding = sys.getfilesystemencoding() default_name = utils.force_encoding(default_name, encoding) dest = utils.force_encoding(dest, encoding) dest = os.path.expanduser(dest) # See if we already have an absolute path path = downloads.create_full_filename(default_name, dest) if path is None: # We still only have a relative path, prepend download_dir and # try again. path = downloads.create_full_filename( default_name, os.path.join(downloads.download_dir(), dest)) downloads.last_used_directory = os.path.dirname(path) # Avoid downloading files if we can't save the output anyway... # Yes, this is prone to race conditions, but we're checking again before # saving the file anyway. if not os.path.isdir(os.path.dirname(path)): folder = os.path.dirname(path) message.error(web_view.win_id, "Directory {} does not exist.".format(folder)) return if not os.path.isfile(path): _start_download(path, web_view=web_view) return q = usertypes.Question() q.mode = usertypes.PromptMode.yesno q.text = "{} exists. Overwrite?".format(path) q.completed.connect(q.deleteLater) q.answered_yes.connect( functools.partial(_start_download, path, web_view=web_view)) message_bridge = objreg.get('message-bridge', scope='window', window=web_view.win_id) message_bridge.ask(q, blocking=False)
def start_download_checked(dest, web_view): """First check if dest is already a file, then start the download. Args: dest: The filename where the resulting file should be saved. web_view: Specify the webview whose page should be loaded. """ # The default name is 'page title.mht' title = web_view.title() default_name = utils.sanitize_filename(title + '.mht') # Remove characters which cannot be expressed in the file system encoding encoding = sys.getfilesystemencoding() default_name = utils.force_encoding(default_name, encoding) dest = utils.force_encoding(dest, encoding) dest = os.path.expanduser(dest) # See if we already have an absolute path path = downloads.create_full_filename(default_name, dest) if path is None: # We still only have a relative path, prepend download_dir and # try again. path = downloads.create_full_filename( default_name, os.path.join(downloads.download_dir(), dest)) downloads.last_used_directory = os.path.dirname(path) # Avoid downloading files if we can't save the output anyway... # Yes, this is prone to race conditions, but we're checking again before # saving the file anyway. if not os.path.isdir(os.path.dirname(path)): folder = os.path.dirname(path) message.error(web_view.win_id, "Directory {} does not exist.".format(folder)) return if not os.path.isfile(path): _start_download(path, web_view=web_view) return q = usertypes.Question() q.mode = usertypes.PromptMode.yesno q.text = "{} exists. Overwrite?".format(path) q.completed.connect(q.deleteLater) q.answered_yes.connect(functools.partial( _start_download, path, web_view=web_view)) message_bridge = objreg.get('message-bridge', scope='window', window=web_view.win_id) message_bridge.ask(q, blocking=False)
def set_filename(self, filename): """Set the filename to save the download to. Args: filename: The full filename to save the download to. None: special value to stop the download. """ if self.fileobj is not None: raise ValueError("fileobj was already set! filename: {}, " "existing: {}, fileobj {}".format( filename, self._filename, self.fileobj)) filename = os.path.expanduser(filename) # Remove chars which can't be encoded in the filename encoding. # See https://github.com/The-Compiler/qutebrowser/issues/427 encoding = sys.getfilesystemencoding() filename = utils.force_encoding(filename, encoding) if not self._create_full_filename(filename): # We only got a filename (without directory) or a relative path # from the user, so we append that to the default directory and # try again. self._create_full_filename(os.path.join(_download_dir(), filename)) log.downloads.debug("Setting filename to {}".format(filename)) if os.path.isfile(self._filename): # The file already exists, so ask the user if it should be # overwritten. self._ask_overwrite_question() else: self._create_fileobj()
def set_filename(self, filename): """Set the filename to save the download to. Args: filename: The full filename to save the download to. None: special value to stop the download. """ global last_used_directory if self.fileobj is not None: raise ValueError("fileobj was already set! filename: {}, " "existing: {}, fileobj {}".format( filename, self._filename, self.fileobj)) filename = os.path.expanduser(filename) # Remove chars which can't be encoded in the filename encoding. # See https://github.com/The-Compiler/qutebrowser/issues/427 encoding = sys.getfilesystemencoding() filename = utils.force_encoding(filename, encoding) self._filename = create_full_filename(self.basename, filename) if self._filename is None: # We only got a filename (without directory) or a relative path # from the user, so we append that to the default directory and # try again. self._filename = create_full_filename( self.basename, os.path.join(download_dir(), filename)) # At this point, we have a misconfigured XDG_DOWNLOAd_DIR, as # download_dir() + filename is still no absolute path. # The config value is checked for "absoluteness", but # ~/.config/user-dirs.dirs may be misconfigured and a non-absolute path # may be set for XDG_DOWNLOAD_DIR if self._filename is None: message.error( self._win_id, "XDG_DOWNLOAD_DIR points to a relative path - please check" " your ~/.config/user-dirs.dirs. The download is saved in" " your home directory.", ) # fall back to $HOME as download_dir self._filename = create_full_filename( self.basename, os.path.expanduser(os.path.join('~', filename))) self.basename = os.path.basename(self._filename) last_used_directory = os.path.dirname(self._filename) log.downloads.debug("Setting filename to {}".format(filename)) if os.path.isfile(self._filename): # The file already exists, so ask the user if it should be # overwritten. txt = self._filename + " already exists. Overwrite?" self._ask_confirm_question(txt) # FIFO, device node, etc. Make sure we want to do this elif (os.path.exists(self._filename) and not os.path.isdir(self._filename)): txt = (self._filename + " already exists and is a special file. " "Write to this?") self._ask_confirm_question(txt) else: self._create_fileobj()
def get_request(self, request, *, fileobj=None, filename=None, prompt_download_directory=None, **kwargs): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. fileobj: The file object to write the answer to. filename: A path to write the data to. prompt_download_directory: Whether to prompt for the download dir or automatically download. If None, the config is used. **kwargs: Passed to fetch_request. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) suggested_fn = urlutils.filename_from_url(request.url()) if prompt_download_directory is None: prompt_download_directory = config.get( 'storage', 'prompt-download-directory') if not prompt_download_directory and not fileobj: filename = config.get('storage', 'download-directory') if fileobj is not None or filename is not None: return self.fetch_request(request, fileobj=fileobj, filename=filename, suggested_filename=suggested_fn, **kwargs) if suggested_fn is None: suggested_fn = 'qutebrowser-download' else: encoding = sys.getfilesystemencoding() suggested_fn = utils.force_encoding(suggested_fn, encoding) q = self._prepare_question() q.default = _path_suggestion(suggested_fn) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) q.answered.connect(lambda fn: self.fetch_request( request, filename=fn, suggested_filename=suggested_fn, **kwargs)) message_bridge.ask(q, blocking=False) return None
def get_request(self, request, *, fileobj=None, filename=None, prompt_download_directory=None, **kwargs): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. fileobj: The file object to write the answer to. filename: A path to write the data to. prompt_download_directory: Whether to prompt for the download dir or automatically download. If None, the config is used. **kwargs: Passed to fetch_request. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) suggested_fn = urlutils.filename_from_url(request.url()) if prompt_download_directory is None: prompt_download_directory = config.get( 'storage', 'prompt-download-directory') if not prompt_download_directory and not fileobj: filename = config.get('storage', 'download-directory') if fileobj is not None or filename is not None: return self.fetch_request(request, fileobj=fileobj, filename=filename, suggested_filename=suggested_fn, **kwargs) if suggested_fn is None: suggested_fn = 'qutebrowser-download' else: encoding = sys.getfilesystemencoding() suggested_fn = utils.force_encoding(suggested_fn, encoding) q = self._prepare_question() q.default = _path_suggestion(suggested_fn) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) q.answered.connect( lambda fn: self.fetch_request(request, filename=fn, suggested_filename=suggested_fn, **kwargs)) message_bridge.ask(q, blocking=False) return None
def _finished(self, url, item): """Callback when a single asset is downloaded. Args: url: The original url of the asset as QUrl. item: The DownloadItem given by the DownloadManager """ if self.writer is None: raise AssertionError self.pending_downloads.remove((url, item)) mime = item.raw_headers.get(b'Content-Type', b'') # Note that this decoding always works and doesn't produce errors # RFC 7230 (https://tools.ietf.org/html/rfc7230) states: # Historically, HTTP has allowed field content with text in the # ISO-8859-1 charset [ISO-8859-1], supporting other charsets only # through use of [RFC2047] encoding. In practice, most HTTP header # field values use only a subset of the US-ASCII charset [USASCII]. # Newly defined header fields SHOULD limit their field values to # US-ASCII octets. A recipient SHOULD treat other octets in field # content (obs-text) as opaque data. mime = mime.decode('iso-8859-1') if mime.lower() == 'text/css' or url.fileName().endswith('.css'): # We can't always assume that CSS files are UTF-8, but CSS files # shouldn't contain many non-ASCII characters anyway (in most # cases). Using "ignore" lets us decode the file even if it's # invalid UTF-8 data. # The file written to the MHTML file won't be modified by this # decoding, since there we're taking the original bytestream. try: css_string = item.fileobj.getvalue().decode('utf-8') except UnicodeDecodeError: log.downloads.warning("Invalid UTF-8 data in {}".format(url)) css_string = item.fileobj.getvalue().decode('utf-8', 'ignore') import_urls = _get_css_imports(css_string) for import_url in import_urls: absolute_url = url.resolved(QUrl(import_url)) self._fetch_url(absolute_url) encode = E_QUOPRI if mime.startswith('text/') else E_BASE64 # Our MHTML handler refuses non-ASCII headers. This will replace every # non-ASCII char with '?'. This is probably okay, as official Content- # Type headers contain ASCII only anyway. Anything else is madness. mime = utils.force_encoding(mime, 'ascii') self.writer.add_file(urlutils.encoded_url(url), item.fileobj.getvalue(), mime, encode) item.fileobj.actual_close() if self.pending_downloads: return self._finish_file()
def _finished(self, url, item): """Callback when a single asset is downloaded. Args: url: The original url of the asset as QUrl. item: The DownloadItem given by the DownloadManager """ self.pending_downloads.remove((url, item)) mime = item.raw_headers.get(b'Content-Type', b'') # Note that this decoding always works and doesn't produce errors # RFC 7230 (https://tools.ietf.org/html/rfc7230) states: # Historically, HTTP has allowed field content with text in the # ISO-8859-1 charset [ISO-8859-1], supporting other charsets only # through use of [RFC2047] encoding. In practice, most HTTP header # field values use only a subset of the US-ASCII charset [USASCII]. # Newly defined header fields SHOULD limit their field values to # US-ASCII octets. A recipient SHOULD treat other octets in field # content (obs-text) as opaque data. mime = mime.decode('iso-8859-1') if mime.lower() == 'text/css' or url.fileName().endswith('.css'): # We can't always assume that CSS files are UTF-8, but CSS files # shouldn't contain many non-ASCII characters anyway (in most # cases). Using "ignore" lets us decode the file even if it's # invalid UTF-8 data. # The file written to the MHTML file won't be modified by this # decoding, since there we're taking the original bytestream. try: css_string = item.fileobj.getvalue().decode('utf-8') except UnicodeDecodeError: log.downloads.warning("Invalid UTF-8 data in {}".format(url)) css_string = item.fileobj.getvalue().decode('utf-8', 'ignore') import_urls = _get_css_imports(css_string) for import_url in import_urls: absolute_url = url.resolved(QUrl(import_url)) self._fetch_url(absolute_url) encode = E_QUOPRI if mime.startswith('text/') else E_BASE64 # Our MHTML handler refuses non-ASCII headers. This will replace every # non-ASCII char with '?'. This is probably okay, as official Content- # Type headers contain ASCII only anyway. Anything else is madness. mime = utils.force_encoding(mime, 'ascii') self.writer.add_file(urlutils.encoded_url(url), item.fileobj.getvalue(), mime, encode) item.fileobj.actual_close() if self.pending_downloads: return self._finish_file()
def get_request(self, request, page=None, fileobj=None, filename=None, auto_remove=False): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. page: The QWebPage to use. fileobj: The file object to write the answer to. filename: A path to write the data to. auto_remove: Whether to remove the download even if ui -> remove-finished-downloads is set to false. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt-project.org/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) suggested_fn = urlutils.filename_from_url(request.url()) if fileobj is not None or filename is not None: return self.fetch_request(request, page, fileobj, filename, auto_remove, suggested_fn) encoding = sys.getfilesystemencoding() suggested_fn = utils.force_encoding(suggested_fn, encoding) q = self._prepare_question() q.default = _path_suggestion(suggested_fn) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) q.answered.connect( lambda fn: self.fetch_request(request, page, filename=fn, auto_remove=auto_remove, suggested_filename=suggested_fn)) message_bridge.ask(q, blocking=False) return None
def ask_for_filename(suggested_filename, win_id, *, parent=None, prompt_download_directory=None): """Prepare a question for a download-path. If a filename can be determined directly, it is returned instead. Returns a (filename, question)-namedtuple, in which one component is None. filename is a string, question is a usertypes.Question. The question has a special .ask() method that takes no arguments for convenience, as this function does not yet ask the question, it only prepares it. Args: suggested_filename: The "default"-name that is pre-entered as path. win_id: The window where the question will be asked. parent: The parent of the question (a QObject). prompt_download_directory: If this is something else than None, it will overwrite the storage->prompt-download-directory setting. """ if prompt_download_directory is None: prompt_download_directory = config.get('storage', 'prompt-download-directory') if not prompt_download_directory: return DownloadPath(filename=download_dir(), question=None) encoding = sys.getfilesystemencoding() suggested_filename = utils.force_encoding(suggested_filename, encoding) q = usertypes.Question(parent) q.text = "Save file to:" q.mode = usertypes.PromptMode.text q.completed.connect(q.deleteLater) q.default = path_suggestion(suggested_filename) message_bridge = objreg.get('message-bridge', scope='window', window=win_id) q.ask = lambda: message_bridge.ask(q, blocking=False) return DownloadPath(filename=None, question=q)
def get_request(self, request, page=None, fileobj=None, filename=None, auto_remove=False): """Start a download with a QNetworkRequest. Args: request: The QNetworkRequest to download. page: The QWebPage to use. fileobj: The file object to write the answer to. filename: A path to write the data to. auto_remove: Whether to remove the download even if ui -> remove-finished-downloads is set to false. Return: If the download could start immediately, (fileobj/filename given), the created DownloadItem. If not, None. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt-project.org/browse/QTBUG-42757 request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, QNetworkRequest.AlwaysNetwork) suggested_fn = urlutils.filename_from_url(request.url()) if fileobj is not None or filename is not None: return self.fetch_request(request, page, fileobj, filename, auto_remove, suggested_fn) if suggested_fn is None: suggested_fn = 'qutebrowser-download' else: encoding = sys.getfilesystemencoding() suggested_fn = utils.force_encoding(suggested_fn, encoding) q = self._prepare_question() q.default = _path_suggestion(suggested_fn) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) q.answered.connect( lambda fn: self.fetch_request(request, page, filename=fn, auto_remove=auto_remove, suggested_filename=suggested_fn)) message_bridge.ask(q, blocking=False) return None
def get_filename_question(*, suggested_filename, url, parent=None): """Get a Question object for a download-path. Args: suggested_filename: The "default"-name that is pre-entered as path. url: The URL the download originated from. parent: The parent of the question (a QObject). """ encoding = sys.getfilesystemencoding() suggested_filename = utils.force_encoding(suggested_filename, encoding) q = usertypes.Question(parent) q.title = "Save file to:" q.text = "Please enter a location for <b>{}</b>".format( html.escape(url.toDisplayString())) q.mode = usertypes.PromptMode.download q.completed.connect(q.deleteLater) q.default = _path_suggestion(suggested_filename) return q
def get_filename_question(*, suggested_filename, url, parent=None): """Get a Question object for a download-path. Args: suggested_filename: The "default"-name that is pre-entered as path. url: The URL the download originated from. parent: The parent of the question (a QObject). """ encoding = sys.getfilesystemencoding() suggested_filename = utils.force_encoding(suggested_filename, encoding) q = usertypes.Question(parent) q.title = "Save file to:" q.text = "Please enter a location for <b>{}</b>".format( html.escape(url.toDisplayString())) q.mode = usertypes.PromptMode.text q.completed.connect(q.deleteLater) q.default = _path_suggestion(suggested_filename) return q
def set_filename(self, filename): """Set the filename to save the download to. Args: filename: The full filename to save the download to. None: special value to stop the download. """ global last_used_directory if self.fileobj is not None: raise ValueError("fileobj was already set! filename: {}, " "existing: {}, fileobj {}".format( filename, self._filename, self.fileobj)) filename = os.path.expanduser(filename) # Remove chars which can't be encoded in the filename encoding. # See https://github.com/The-Compiler/qutebrowser/issues/427 encoding = sys.getfilesystemencoding() filename = utils.force_encoding(filename, encoding) self._filename = create_full_filename(self.basename, filename) if self._filename is None: # We only got a filename (without directory) or a relative path # from the user, so we append that to the default directory and # try again. self._filename = create_full_filename( self.basename, os.path.join(download_dir(), filename)) self.basename = os.path.basename(self._filename) last_used_directory = os.path.dirname(self._filename) log.downloads.debug("Setting filename to {}".format(filename)) if os.path.isfile(self._filename): # The file already exists, so ask the user if it should be # overwritten. txt = self._filename + " already exists. Overwrite?" self._ask_confirm_question(txt) # FIFO, device node, etc. Make sure we want to do this elif (os.path.exists(self._filename) and not os.path.isdir(self._filename)): txt = (self._filename + " already exists and is a special file. " "Write to this?") self._ask_confirm_question(txt) else: self._create_fileobj()
def set_filename(self, filename): """Set the filename to save the download to. Args: filename: The full filename to save the download to. None: special value to stop the download. """ if self.fileobj is not None: raise ValueError("fileobj was already set! filename: {}, " "existing: {}, fileobj {}".format( filename, self._filename, self.fileobj)) filename = os.path.expanduser(filename) # Remove chars which can't be encoded in the filename encoding. # See https://github.com/The-Compiler/qutebrowser/issues/427 encoding = sys.getfilesystemencoding() filename = utils.force_encoding(filename, encoding) if os.path.isabs(filename) and os.path.isdir(filename): # We got an absolute directory from the user, so we save it under # the default filename in that directory. self._filename = os.path.join(filename, self.basename) elif os.path.isabs(filename): # We got an absolute filename from the user, so we save it under # that filename. self._filename = filename self.basename = os.path.basename(self._filename) else: # We only got a filename (without directory) from the user, so we # save it under that filename in the default directory. download_dir = config.get('storage', 'download-directory') if download_dir is None: download_dir = standarddir.get( QStandardPaths.DownloadLocation) self._filename = os.path.join(download_dir, filename) self.basename = filename log.downloads.debug("Setting filename to {}".format(filename)) if os.path.isfile(self._filename): # The file already exists, so ask the user if it should be # overwritten. self._ask_overwrite_question() else: self._create_fileobj()
def get_tmpfile(self, suggested_name): """Return a temporary file in the temporary downloads directory. The files are kept as long as qutebrowser is running and automatically cleaned up at program exit. Args: suggested_name: str of the "suggested"/original filename. Used as a suffix, so any file extenions are preserved. Return: A tempfile.NamedTemporaryFile that should be used to save the file. """ tmpdir = self._get_tmpdir() encoding = sys.getfilesystemencoding() suggested_name = utils.force_encoding(suggested_name, encoding) # Make sure that the filename is not too long suggested_name = utils.elide_filename(suggested_name, 50) fobj = tempfile.NamedTemporaryFile(dir=tmpdir.name, delete=False, suffix=suggested_name) self.files.append(fobj) return fobj
def test_fitting_ascii(self, inp, enc, expected): """Test force_encoding will yield expected text.""" assert utils.force_encoding(inp, enc) == expected
def fetch(self, reply, fileobj=None, filename=None, auto_remove=False): """Download a QNetworkReply to disk. Args: reply: The QNetworkReply to download. fileobj: The file object to write the answer to. filename: A path to write the data to. auto_remove: Whether to remove the download even if ui -> remove-finished-downloads is set to false. Return: The created DownloadItem. """ if fileobj is not None and filename is not None: raise TypeError("Only one of fileobj/filename may be given!") if filename is not None: suggested_filename = os.path.basename(filename) elif fileobj is not None and getattr(fileobj, 'name', None): suggested_filename = fileobj.name else: _inline, suggested_filename = http.parse_content_disposition(reply) log.downloads.debug("fetch: {} -> {}".format(reply.url(), suggested_filename)) download = DownloadItem(reply, self._win_id, self) download.cancelled.connect( functools.partial(self.remove_item, download)) if config.get('ui', 'remove-finished-downloads') or auto_remove: download.finished.connect( functools.partial(self.remove_item, download)) download.data_changed.connect( functools.partial(self.on_data_changed, download)) download.error.connect(self.on_error) download.redirected.connect( functools.partial(self.on_redirect, download)) download.do_retry.connect(self.fetch) download.basename = suggested_filename idx = len(self.downloads) + 1 self.beginInsertRows(QModelIndex(), idx, idx) self.downloads.append(download) self.endInsertRows() if filename is not None: download.set_filename(filename) elif fileobj is not None: download.set_fileobj(fileobj) download.autoclose = False else: q = self._prepare_question() encoding = sys.getfilesystemencoding() suggested_filename = utils.force_encoding(suggested_filename, encoding) q.default = suggested_filename q.answered.connect(download.set_filename) q.cancelled.connect(download.cancel) download.cancelled.connect(q.abort) download.error.connect(q.abort) message_bridge = objreg.get('message-bridge', scope='window', window=self._win_id) message_bridge.ask(q, blocking=False) return download
def test_fitting_ascii(self): """Test with a text fitting into ascii.""" text = 'hello world' self.assertEqual(utils.force_encoding(text, 'ascii'), text)
def test_fitting_utf8(self): """Test with a text fitting into utf-8.""" text = 'hellö wörld' self.assertEqual(utils.force_encoding(text, 'utf-8'), text)
def test_not_fitting_ascii(self): """Test with a text not fitting into ascii.""" text = 'hellö wörld' self.assertEqual(utils.force_encoding(text, 'ascii'), 'hell? w?rld')