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

Update to stac-pydantic 2.0.0 #181

Merged
merged 15 commits into from
Jul 23, 2021
Merged
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
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## UNRELEASED

* Upgrade to stac-pydantic 2.0.0 and stac-spec 1.0.0 (https://github.com/stac-utils/stac-fastapi/pull/181)

## 1.1.0 (2021-01-28)

Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ services:

database:
container_name: stac-db
image: bitner/pgstac:0.2.4
image: bitner/pgstac:0.2.7
environment:
- POSTGRES_USER=username
- POSTGRES_PASSWORD=password
Expand All @@ -92,7 +92,7 @@ services:
- ./stac_fastapi:/app/stac_fastapi
- ./scripts:/app/scripts
command: >
bash -c "sleep 10 && cd stac_fastapi/sqlalchemy && alembic upgrade head && python /app/scripts/ingest_joplin.py http://app-sqlalchemy:8081"
bash -c "./scripts/wait-for-it.sh app-sqlalchemy:8081 && cd stac_fastapi/sqlalchemy && alembic upgrade head && python /app/scripts/ingest_joplin.py http://app-sqlalchemy:8081"
depends_on:
- database
- app-sqlalchemy
Expand Down
10 changes: 8 additions & 2 deletions stac_fastapi/api/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@
"fastapi",
"attrs",
"pydantic[dotenv]",
"stac_pydantic==1.3.8",
"stac_pydantic==2.0.0",
]

extra_reqs = {
"dev": ["pytest", "pytest-cov", "pytest-asyncio", "pre-commit", "requests"],
"dev": [
"pytest",
"pytest-cov",
"pytest-asyncio",
"pre-commit",
"requests",
],
"docs": ["mkdocs", "mkdocs-material", "pdocs"],
}

Expand Down
3 changes: 2 additions & 1 deletion stac_fastapi/api/stac_fastapi/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from fastapi.openapi.utils import get_openapi
from stac_pydantic import Collection, Item, ItemCollection
from stac_pydantic.api import ConformanceClasses, LandingPage
from stac_pydantic.api.collections import Collections
from stac_pydantic.version import STAC_VERSION

from stac_fastapi.api.errors import DEFAULT_STATUS_CODES, add_exception_handlers
Expand Down Expand Up @@ -148,7 +149,7 @@ def register_core(self):
router.add_api_route(
name="Get Collections",
path="/collections",
response_model=List[Collection],
response_model=Collections,
response_model_exclude_unset=True,
response_model_exclude_none=True,
methods=["GET"],
Expand Down
1 change: 1 addition & 0 deletions stac_fastapi/api/stac_fastapi/api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


# TODO: Move to stac-pydantic
# Does that make sense now? The shift to json schema rather than a well-known enumeration makes that less obvious.
class ApiExtensions(enum.Enum):
"""Enumeration of available stac api extensions.

Expand Down
3 changes: 2 additions & 1 deletion stac_fastapi/api/stac_fastapi/api/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ def request_validation_exception_handler(
request: Request, exc: RequestValidationError
) -> JSONResponse:
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST, content={"detail": exc.errors()}
status_code=status.HTTP_400_BAD_REQUEST,
content={"detail": exc.errors()},
)

app.add_exception_handler(
Expand Down
6 changes: 5 additions & 1 deletion stac_fastapi/api/stac_fastapi/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ class ItemCollectionUri(CollectionUri):

def kwargs(self) -> Dict:
"""kwargs."""
return {"id": self.collectionId, "limit": self.limit, "token": self.token}
return {
"id": self.collectionId,
"limit": self.limit,
"token": self.token,
}


@attr.s
Expand Down
10 changes: 8 additions & 2 deletions stac_fastapi/extensions/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@
"fastapi",
"attrs",
"pydantic[dotenv]",
"stac_pydantic==1.3.8",
"stac_pydantic==2.0.0",
"stac-fastapi.types",
"stac-fastapi.api",
]

extra_reqs = {
"dev": ["pytest", "pytest-cov", "pytest-asyncio", "pre-commit", "requests"],
"dev": [
"pytest",
"pytest-cov",
"pytest-asyncio",
"pre-commit",
"requests",
],
"docs": ["mkdocs", "mkdocs-material", "pdocs"],
"tiles": ["titiler==0.2.*"],
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from fastapi import FastAPI
from pydantic import BaseModel
from stac_pydantic.collection import SpatialExtent
from stac_pydantic.shared import Link, MimeTypes, Relations
from stac_pydantic.links import Link, Relations
from stac_pydantic.shared import MimeTypes
from starlette.requests import Request
from starlette.responses import HTMLResponse, RedirectResponse

Expand Down
2 changes: 1 addition & 1 deletion stac_fastapi/pgstac/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"attrs",
"orjson",
"pydantic[dotenv]",
"stac_pydantic==1.3.8",
"stac_pydantic==2.0.0",
"stac-fastapi.types",
"stac-fastapi.api",
"stac-fastapi.extensions",
Expand Down
58 changes: 41 additions & 17 deletions stac_fastapi/pgstac/stac_fastapi/pgstac/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
from fastapi.responses import ORJSONResponse
from stac_pydantic import Collection, Item, ItemCollection
from stac_pydantic.api import ConformanceClasses, LandingPage
from stac_pydantic.shared import Link, MimeTypes, Relations
from stac_pydantic.api.collections import Collections
from stac_pydantic.links import Link, Relations
from stac_pydantic.shared import MimeTypes

from stac_fastapi.pgstac.models.links import CollectionLinks, ItemLinks, PagingLinks
from stac_fastapi.pgstac.types.search import PgstacSearch
Expand All @@ -24,6 +26,16 @@
class CoreCrudClient(BaseCoreClient):
"""Client for core endpoints defined by stac."""

landing_page_id: str = attr.ib(default="stac-api")
title: str = attr.ib(default="Arturo STAC API")
description: str = attr.ib(default="Arturo raster datastore")
conformance_classes: List[str] = attr.ib(
factory=lambda: [
"https://stacspec.org/STAC-api.html",
"http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#ats_geojson",
]
)

async def landing_page(self, **kwargs) -> ORJSONResponse:
"""Landing page.

Expand All @@ -35,8 +47,10 @@ async def landing_page(self, **kwargs) -> ORJSONResponse:
request = kwargs["request"]
base_url = str(request.base_url)
landing_page = LandingPage(
title="Arturo STAC API",
description="Arturo raster datastore",
id=self.landing_page_id,
title=self.title,
description=self.description,
conformsTo=self.conformance_classes,
links=[
Link(
rel=Relations.self,
Expand All @@ -47,24 +61,24 @@ async def landing_page(self, **kwargs) -> ORJSONResponse:
rel=Relations.docs,
type=MimeTypes.html,
title="OpenAPI docs",
href=urljoin(base_url, "/docs"),
href=urljoin(base_url, "docs"),
),
Link(
rel=Relations.conformance,
type=MimeTypes.json,
title="STAC/WFS3 conformance classes implemented by this server",
href=urljoin(base_url, "/conformance"),
href=urljoin(base_url, "conformance"),
),
Link(
rel=Relations.search,
type=MimeTypes.geojson,
title="STAC search",
href=urljoin(base_url, "/search"),
href=urljoin(base_url, "search"),
),
Link(
rel="data",
type=MimeTypes.json,
href=urljoin(base_url, "/collections"),
href=urljoin(base_url, "collections"),
),
],
)
Expand All @@ -81,14 +95,9 @@ async def landing_page(self, **kwargs) -> ORJSONResponse:

async def conformance(self, **kwargs) -> ConformanceClasses:
"""Conformance classes."""
return ConformanceClasses(
conformsTo=[
"https://stacspec.org/STAC-api.html",
"http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#ats_geojson",
]
)
return ConformanceClasses(conformsTo=self.conformance_classes)

async def _all_collections_func(self, **kwargs) -> List[Dict]:
async def _all_collections_func(self, **kwargs) -> List[Collection]:
"""Read all collections from the database."""
request = kwargs["request"]
pool = request.app.state.readpool
Expand All @@ -111,10 +120,25 @@ async def _all_collections_func(self, **kwargs) -> List[Dict]:

async def all_collections(self, **kwargs) -> ORJSONResponse:
"""Get all collections."""
request = kwargs["request"]
base_url = str(request.base_url)
url = str(request.url)
collections = await self._all_collections_func(**kwargs)
if collections is None or len(collections) < 1:
return ORJSONResponse([])
return ORJSONResponse([c.dict(exclude_none=True) for c in collections])
links = [
Link(rel=Relations.self, type=MimeTypes.json, href=url),
Link(rel=Relations.parent, type=MimeTypes.json, href=base_url),
Link(rel=Relations.root, type=MimeTypes.json, href=base_url),
]
if collections is None:
return ORJSONResponse(
Collections(collections=[], links=links).dict(exclude_none=True)
)
return ORJSONResponse(
Collections(
collections=[c.dict(exclude_none=True) for c in collections],
links=links,
).dict(exclude_none=True)
)

async def get_collection(self, id: str, **kwargs) -> ORJSONResponse:
"""Get collection by id.
Expand Down
4 changes: 2 additions & 2 deletions stac_fastapi/pgstac/stac_fastapi/pgstac/models/links.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from urllib.parse import ParseResult, parse_qs, unquote, urlencode, urljoin, urlparse

import attr
from stac_pydantic.api.extensions.paging import PaginationLink
from stac_pydantic.shared import Link, MimeTypes, Relations
from stac_pydantic.links import Link, PaginationLink, Relations
from stac_pydantic.shared import MimeTypes
from starlette.requests import Request

from stac_fastapi.extensions.third_party.tiles import OGCTileLink
Expand Down
4 changes: 2 additions & 2 deletions stac_fastapi/pgstac/stac_fastapi/pgstac/models/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from pydantic import BaseModel
from stac_pydantic import Collection as CollectionBase
from stac_pydantic import Item as ItemBase
from stac_pydantic.api.search import DATETIME_RFC339
from stac_pydantic.shared import Link
from stac_pydantic.links import Link
from stac_pydantic.shared import DATETIME_RFC339

# Be careful: https://github.com/samuelcolvin/pydantic/issues/1423#issuecomment-642797287
NumType = Union[float, int]
Expand Down
4 changes: 2 additions & 2 deletions stac_fastapi/pgstac/tests/clients/test_postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async def test_update_item(app_client, load_test_collection, load_test_item):

item.properties.description = "Update Test"

resp = await app_client.put(f"/collections/{coll.id}/items", json=item.dict())
resp = await app_client.put(f"/collections/{coll.id}/items", data=item.json())
assert resp.status_code == 200

resp = await app_client.get(f"/collections/{coll.id}/items/{item.id}")
Expand Down Expand Up @@ -113,7 +113,7 @@ async def test_get_collection_items(app_client, load_test_collection, load_test_
item.id = str(uuid.uuid4())
resp = await app_client.post(
f"/collections/{coll.id}/items",
json=item.dict(),
data=item.json(),
)
assert resp.status_code == 200

Expand Down
3 changes: 2 additions & 1 deletion stac_fastapi/pgstac/tests/data/joplin/collection.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"id": "joplin",
"description": "This imagery was acquired by the NOAA Remote Sensing Division to support NOAA national security and emergency response requirements. In addition, it will be used for ongoing research efforts for testing and developing standards for airborne digital imagery. Individual images have been combined into a larger mosaic and tiled for distribution. The approximate ground sample distance (GSD) for each pixel is 35 cm (1.14 feet).",
"stac_version": "1.0.0-beta.2",
"stac_version": "1.0.0",
"license": "public-domain",
"links": [],
"type": "collection",
"extent": {
"spatial": {
"bbox": [
Expand Down
Loading