Skip to content

Commit 18d54f5

Browse files
committed
2 parents e0332a2 + d588751 commit 18d54f5

File tree

6 files changed

+56
-9
lines changed

6 files changed

+56
-9
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
- name: Install aiopmtiles
3232
run: |
3333
python -m pip install --upgrade pip
34-
python -m pip install .["test","aws"]
34+
python -m pip install .["test","aws","gcp"]
3535
3636
- name: run pre-commit
3737
if: ${{ matrix.python-version == env.LATEST_PY_VERSION }}

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Issues and pull requests are more than welcome.
77
```bash
88
$ git clone https://github.com/developmentseed/aiopmtiles.git
99
$ cd aiopmtiles
10-
$ python -m pip install -e .["test","dev","aws"]
10+
$ python -m pip install -e .["test","dev","aws","gcp"]
1111
```
1212

1313
You can then run the tests with the following command:

aiopmtiles/io.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
"""FileSystems for PMTiles Reader."""
22

33
import abc
4-
import os
54
from contextlib import AsyncExitStack
65
from dataclasses import dataclass, field
7-
from typing import Any, Dict, Optional
6+
from typing import Any
87
from urllib.parse import urlparse
98

109
import aiofiles
@@ -16,6 +15,12 @@
1615
except ImportError: # pragma: nocover
1716
aioboto3 = None # type: ignore
1817

18+
try:
19+
from gcloud.aio.storage import Storage as GcpStorage
20+
21+
except ImportError: # pragma: nocover
22+
GcpStorage = None # type: ignore
23+
1924

2025
@dataclass
2126
class FileSystem(abc.ABC):
@@ -49,6 +54,9 @@ def create_from_filepath(cls, filepath: str, **kwargs: Any) -> "FileSystem":
4954
elif parsed.scheme == "s3":
5055
return S3FileSystem(filepath, **kwargs)
5156

57+
elif parsed.scheme == "gs":
58+
return GcsFileSystem(filepath, **kwargs)
59+
5260
elif parsed.scheme == "file":
5361
return LocalFileSystem(filepath, **kwargs)
5462

@@ -132,3 +140,31 @@ async def __aenter__(self):
132140
)
133141
self._obj = await self._resource.Object(parsed.netloc, parsed.path.strip("/"))
134142
return self
143+
144+
145+
@dataclass
146+
class GcsFileSystem(FileSystem):
147+
"""GCS filesystem"""
148+
149+
_client: GcpStorage = field(init=False)
150+
_bucket: str = field(init=False)
151+
_obj: str = field(init=False)
152+
153+
def __post_init__(self):
154+
"""Check for dependency."""
155+
assert (
156+
GcpStorage is not None
157+
), "'gcloud-aio-storage' must be installed to use GCS FileSystem"
158+
159+
async def get(self, offset: int, length: int) -> bytes:
160+
"""Perform a range request"""
161+
headers = {"Range": f"bytes={offset}-{offset + length}"}
162+
return await self._client.download(self._bucket, self._obj, headers=headers)
163+
164+
async def __aenter__(self):
165+
"""Async context management"""
166+
parsed_path = urlparse(self.filepath)
167+
self._client = await self.ctx.enter_async_context(GcpStorage())
168+
self._bucket = parsed_path.netloc
169+
self._obj = parsed_path.path.strip("/")
170+
return self

docs/docs/usage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ async def metadata(url: str = Query(..., description="PMTiles archive URL.")):
2929
async with Reader(url) as src:
3030
return await src.metadata()
3131

32-
@spp.get("/tiles/{z}/{x}/{y}", response_class=Response)
32+
@app.get("/tiles/{z}/{x}/{y}", response_class=Response)
3333
async def tiles(
3434
z: int = Path(ge=0, le=30, description="TMS tiles's zoom level"),
3535
x: int = Path(description="TMS tiles's column"),

pyproject.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ dependencies = [
2828
aws = [
2929
"aioboto3"
3030
]
31+
gcp = [
32+
"gcloud-aio-auth",
33+
"gcloud-aio-storage"
34+
]
3135
test = [
3236
"pytest",
3337
"pytest-cov",
@@ -69,9 +73,9 @@ parallel = true
6973

7074
[tool.coverage.report]
7175
exclude_lines = [
72-
"no cov",
73-
"if __name__ == .__main__.:",
74-
"if TYPE_CHECKING:",
76+
"no cov",
77+
"if __name__ == .__main__.:",
78+
"if TYPE_CHECKING:",
7579
]
7680

7781
[tool.isort]

tests/test_io.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44

55
import pytest
66

7-
from aiopmtiles.io import FileSystem, HttpFileSystem, LocalFileSystem, S3FileSystem
7+
from aiopmtiles.io import (
8+
FileSystem,
9+
GcsFileSystem,
10+
HttpFileSystem,
11+
LocalFileSystem,
12+
S3FileSystem,
13+
)
814

915
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), "fixtures")
1016
VECTOR_PMTILES = os.path.join(FIXTURES_DIR, "protomaps(vector)ODbL_firenze.pmtiles")
@@ -16,6 +22,7 @@
1622
("myfile.pmtiles", LocalFileSystem),
1723
("file:///myfile.pmtiles", LocalFileSystem),
1824
("s3://bucket/myfile.pmtiles", S3FileSystem),
25+
("gs://bucket/myfile.pmtiles", GcsFileSystem),
1926
("http://url.io/myfile.pmtiles", HttpFileSystem),
2027
("https://url.io/myfile.pmtiles", HttpFileSystem),
2128
],

0 commit comments

Comments
 (0)