def test_open_local_or_remote_file__directory(tmpdir): """ Test the `open_local_or_remote_file` raises a ValueError for a given `Link` to a directory. """ link = Link(path_to_url(tmpdir.strpath)) session = Session() with pytest.raises(ValueError, match="Cannot open directory for read"): with open_local_or_remote_file(link, session): pass # pragma: no cover
def test_open_local_or_remote_file__local_file(tmp_path, content, content_length): """ Test the `open_local_or_remote_file` returns a context manager to a FileStream for a given `Link` to a local file. """ local_file_path = tmp_path / "foo.txt" local_file_path.write_bytes(content) link = Link(local_file_path.as_uri()) session = Session() with open_local_or_remote_file(link, session) as file_stream: assert file_stream.stream.read() == content assert file_stream.size == content_length
def test_open_local_or_remote_file__remote_file( tmp_path, content, content_length, expected_content_length ): """ Test the `open_local_or_remote_file` returns a context manager to a FileStream for a given `Link` to a remote file. """ link = Link("https://example.com/foo.txt") session = Session() response_file_path = tmp_path / "foo.txt" response_file_path.write_bytes(content) mock_response = mock.Mock() mock_response.raw = response_file_path.open("rb") mock_response.headers = {"content-length": content_length} with mock.patch.object(session, "get", return_value=mock_response): with open_local_or_remote_file(link, session) as file_stream: assert file_stream.stream.read() == content assert file_stream.size == expected_content_length mock_response.close.assert_called_once()
def open_local_or_remote_file(link: Link, session: Session) -> Iterator[FileStream]: """ Open local or remote file for reading. :type link: pip.index.Link :type session: requests.Session :raises ValueError: If link points to a local directory. :return: a context manager to a FileStream with the opened file-like object """ url = link.url_without_fragment if link.is_file: # Local URL local_path = url_to_path(url) if os.path.isdir(local_path): raise ValueError(f"Cannot open directory for read: {url}") else: st = os.stat(local_path) with open(local_path, "rb") as local_file: yield FileStream(stream=local_file, size=st.st_size) else: # Remote URL headers = {"Accept-Encoding": "identity"} response = session.get(url, headers=headers, stream=True) # Content length must be int or None content_length: Optional[int] try: content_length = int(response.headers["content-length"]) except (ValueError, KeyError, TypeError): content_length = None try: yield FileStream(stream=response.raw, size=content_length) finally: response.close()