Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement write_to_disk for uri backends #164

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions ethpm/backends/base.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
from abc import ABC, abstractmethod
from pathlib import Path
import shutil
import tempfile
from typing import Union

from eth_typing import URI

from ethpm.exceptions import CannotHandleURI


class BaseURIBackend(ABC):
"""
Expand Down Expand Up @@ -34,3 +39,19 @@ def fetch_uri_contents(self, uri: URI) -> Union[bytes, URI]:
Fetch the contents stored at a URI.
"""
pass

def write_to_disk(self, uri: URI, target_path: Path) -> None:
"""
Writes the contents of target URI to target path.
Raises exception if target path exists.
"""
contents = self.fetch_uri_contents(uri)
if target_path.exists():
raise CannotHandleURI(
f"Uri: {uri} cannot be written to disk since target path ({target_path}) "
"already exists. Please provide a target_path that does not exist."
)
with tempfile.NamedTemporaryFile() as temp:
temp.write(contents)
temp.seek(0)
shutil.copyfile(temp.name, target_path)
8 changes: 4 additions & 4 deletions ethpm/backends/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class GithubOverHTTPSBackend(BaseURIBackend):
Base class for all URIs pointing to a content-addressed Github URI.
"""

@property
def base_uri(self) -> str:
return GITHUB_API_AUTHORITY

def can_resolve_uri(self, uri: URI) -> bool:
return is_valid_content_addressed_github_uri(uri)

Expand All @@ -43,7 +47,3 @@ def fetch_uri_contents(self, uri: URI) -> bytes:
decoded_contents = base64.b64decode(contents["content"])
validate_blob_uri_contents(decoded_contents, uri)
return decoded_contents

@property
def base_uri(self) -> str:
return GITHUB_API_AUTHORITY
8 changes: 7 additions & 1 deletion ethpm/backends/ipfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pathlib import Path
from typing import Dict, List, Type

from eth_typing import URI
from eth_utils import import_string, to_bytes
import ipfshttpclient

Expand Down Expand Up @@ -59,7 +60,7 @@ class IPFSOverHTTPBackend(BaseIPFSBackend):
def __init__(self) -> None:
self.client = ipfshttpclient.connect(self.base_uri)

def fetch_uri_contents(self, uri: str) -> bytes:
def fetch_uri_contents(self, uri: URI) -> bytes:
ipfs_hash = extract_ipfs_path_from_uri(uri)
contents = self.client.cat(ipfs_hash)
validation_hash = generate_file_hash(contents)
Expand Down Expand Up @@ -108,6 +109,11 @@ def fetch_uri_contents(self, uri: str) -> bytes:
"IPFS gateway is currently disabled, please use a different IPFS backend."
)

def write_to_disk(self, uri: URI, target_path: Path) -> None:
raise CannotHandleURI(
"IPFS gateway is currently disabled, please use a different IPFS backend."
)


class InfuraIPFSBackend(IPFSOverHTTPBackend):
"""
Expand Down
27 changes: 19 additions & 8 deletions tests/ethpm/backends/test_http_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,34 @@
from ethpm.constants import GITHUB_API_AUTHORITY
from ethpm.exceptions import CannotHandleURI, ValidationError

BLOB_URI = "https://api.github.com/repos/ethpm/py-ethpm/git/blobs/a7232a93f1e9e75d606f6c1da18aa16037e03480"

@pytest.mark.parametrize(
"uri",
(
"https://api.github.com/repos/ethpm/py-ethpm/git/blobs/a7232a93f1e9e75d606f6c1da18aa16037e03480",
),
)
def test_github_over_https_backend_fetch_uri_contents(uri, owned_contract, w3):

def test_github_over_https_backend_fetch_uri_contents(owned_contract, w3):
# these tests may occassionally fail CI as a result of their network requests
backend = GithubOverHTTPSBackend()
assert backend.base_uri == GITHUB_API_AUTHORITY
# integration with Package.from_uri
owned_package = Package.from_uri(uri, w3)
owned_package = Package.from_uri(BLOB_URI, w3)
assert owned_package.name == "owned"


def test_github_over_https_backend_raises_error_with_invalid_content_hash(w3):
invalid_uri = "https://api.github.com/repos/ethpm/py-ethpm/git/blobs/a7232a93f1e9e75d606f6c1da18aa16037e03123"
with pytest.raises(HTTPError):
Package.from_uri(invalid_uri, w3)


def test_github_backend_writes_to_disk(tmp_path):
backend = GithubOverHTTPSBackend()
contents = backend.fetch_uri_contents(BLOB_URI)
target_path = tmp_path / "github_uri.txt"
backend.write_to_disk(BLOB_URI, target_path)
assert target_path.read_bytes() == contents


def test_github_backend_write_to_disk_raises_exception_if_target_exists(tmp_path):
target_path = tmp_path / "test.txt"
target_path.touch()
with pytest.raises(CannotHandleURI, match="cannot be written to disk."):
GithubOverHTTPSBackend().write_to_disk(BLOB_URI, target_path)
18 changes: 18 additions & 0 deletions tests/ethpm/backends/test_ipfs_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
get_ipfs_backend_class,
)
from ethpm.constants import INFURA_GATEWAY_MULTIADDR
from ethpm.exceptions import CannotHandleURI

OWNED_MANIFEST_PATH = V2_PACKAGES_DIR / "owned" / "1.0.0.json"

Expand Down Expand Up @@ -116,3 +117,20 @@ def test_pin_assets_to_dummy_backend(dummy_ipfs_backend):
assert "StandardToken.sol" in dir_names
assert "QmRJHLmPVct2rbBpdGjP3xkXbF7romQigtmcs8TRfV1yC7" in dir_hashes
assert "2865" in dir_sizes


def test_ipfs_backend_write_to_disk(tmp_path):
ipfs_uri = "ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGV"
backend = LocalIPFSBackend()
contents = backend.fetch_uri_contents(ipfs_uri)
target_path = tmp_path / "ipfs_uri.txt"
backend.write_to_disk(ipfs_uri, target_path)
assert target_path.read_bytes() == contents


def test_ipfs_backend_write_to_disk_raises_exception_if_target_exists(tmp_path):
ipfs_uri = "ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGV"
target_path = tmp_path / "test.txt"
target_path.touch()
with pytest.raises(CannotHandleURI, match="cannot be written to disk."):
LocalIPFSBackend().write_to_disk(ipfs_uri, target_path)