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

Add FastAPI migration of licenses endpoints #11056

Merged
merged 18 commits into from
Jan 8, 2021
Merged
Show file tree
Hide file tree
Changes from 17 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
73 changes: 73 additions & 0 deletions lib/galaxy/managers/licenses.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,74 @@
import json
import logging
from typing import List

from pkg_resources import resource_string
from pydantic import (
BaseModel,
Field,
HttpUrl
)

from galaxy import exceptions

log = logging.getLogger(__name__)


# https://github.com/spdx/license-list-data/blob/master/accessingLicenses.md#license-list-table-of-contents
class LicenseMetadataModel(BaseModel):
licenseId: str = Field(
title="Identifier",
description="SPDX Identifier",
example="Apache-2.0"
)
name: str = Field(
title="Name",
description="Full name of the license",
example="Apache License 2.0"
)
reference: str = Field(
title="Reference",
description="Reference to the HTML format for the license file",
example="./Apache-2.0.html"
)
referenceNumber: int = Field(
title="Reference number",
description="*Deprecated* - this field is generated and is no longer in use"
)
isDeprecatedLicenseId: bool = Field(
title="Deprecated License",
description="True if the entire license is deprecated",
example=False
)
isOsiApproved: bool = Field(
title="OSI approved",
description="Indicates if the [OSI](https://opensource.org/) has approved the license",
example=True
)
seeAlso: List[HttpUrl] = Field(
title="Reference URLs",
description="Cross reference URL pointing to additional copies of the license"
)
detailsUrl: HttpUrl = Field(
title="Details URL",
description="URL to the SPDX json details for this license",
example="http://spdx.org/licenses/Apache-2.0.json"
)
recommended: bool = Field(
title="Recommended",
description="True if this license is recommended to be used"
)
url: HttpUrl = Field(
title="URL",
description="License URL",
example="http://www.apache.org/licenses/LICENSE-2.0"
)
spdxUrl: HttpUrl = Field(
title="SPDX URL",
example="https://spdx.org/licenses/Apache-2.0.html"
)


# https://docs.google.com/document/d/16vnRtDjrx5eHSl4jXs2vMaDTI6luyyLzU6xMvRHsnbI/edit#heading=h.1pihjj16olz2
RECOMMENDED_LICENSES = [
"Apache-2.0",
Expand Down Expand Up @@ -57,3 +121,12 @@ def get(self, uri):
return {
"url": uri
}

def get_licenses(self) -> List[LicenseMetadataModel]:
return SPDX_LICENSES["licenses"]

def get_license_by_id(self, id: str) -> LicenseMetadataModel:
license = self.get(id)
if license.get("licenseId", None) is None:
raise exceptions.ObjectNotFound(f"License '{id}' not found")
return LicenseMetadataModel(**license)
51 changes: 49 additions & 2 deletions lib/galaxy/webapps/galaxy/api/licenses.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,54 @@
from galaxy.managers.licenses import LicensesManager
from typing import List

from fastapi import (
Depends,
Path
)
from fastapi.routing import APIRouter
from fastapi_utils.cbv import cbv

from galaxy.managers.licenses import (
LicenseMetadataModel,
LicensesManager
)
from galaxy.web import expose_api_anonymous_and_sessionless
from galaxy.webapps.base.controller import BaseAPIController

router = APIRouter(tags=['licenses'])

LicenseIdPath: str = Path(
..., # Mark this Path parameter as required
title="SPDX license short ID",
description="The [SPDX license short identifier](https://spdx.github.io/spdx-spec/appendix-I-SPDX-license-list/)",
example="Apache-2.0"
)


def get_licenses_manager() -> LicensesManager:
return LicensesManager()


@cbv(router)
class FastAPILicenses:
licenses_manager: LicensesManager = Depends(get_licenses_manager)

@router.get('/api/licenses',
summary="Lists all available SPDX licenses",
response_model=List[LicenseMetadataModel],
response_description="List of SPDX licenses")
async def index(self) -> List[LicenseMetadataModel]:
"""Returns an index with all the available [SPDX licenses](https://spdx.org/licenses/)."""
return self.licenses_manager.get_licenses()

@router.get('/api/licenses/{id}',
summary="Gets the SPDX license metadata associated with the short identifier",
response_model=LicenseMetadataModel,
response_description="SPDX license metadata")
async def get(self, id=LicenseIdPath) -> LicenseMetadataModel:
"""Returns the license metadata associated with the given
[SPDX license short ID](https://spdx.github.io/spdx-spec/appendix-I-SPDX-license-list/)."""
return self.licenses_manager.get_license_by_id(id)


class LicensesController(BaseAPIController):

Expand All @@ -25,4 +72,4 @@ def get(self, trans, id, **kwd):
Return license metadata by URI or SPDX id.
"""
license_id = id
return self.licenses_manager.get(license_id)
return self.licenses_manager.get_license_by_id(license_id)
16 changes: 15 additions & 1 deletion lib/galaxy/webapps/galaxy/fast_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@
from starlette.responses import Response

from galaxy.exceptions import MessageException
from galaxy.web.framework.decorators import api_error_message, validation_error_to_message_exception
from galaxy.web.framework.decorators import (
api_error_message,
validation_error_to_message_exception
)

# https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-tags
api_tags_metadata = [
{
"name": "licenses",
"description": "Operations with [SPDX licenses](https://spdx.org/licenses/).",
},
]


def add_exception_handler(
Expand All @@ -30,6 +41,7 @@ async def message_exception_middleware(request: Request, exc: MessageException)
)



mvdbeek marked this conversation as resolved.
Show resolved Hide resolved
def initialize_fast_app(gx_app):
app = FastAPI()

Expand All @@ -39,9 +51,11 @@ def initialize_fast_app(gx_app):
job_lock,
jobs,
roles,
licenses
)
app.include_router(jobs.router)
app.include_router(job_lock.router)
app.include_router(roles.router)
app.include_router(licenses.router)
app.mount('/', wsgi_handler)
return app
23 changes: 23 additions & 0 deletions lib/galaxy_test/api/test_licenses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from ._framework import ApiTestCase


class LicensesApiTestCase(ApiTestCase):

def test_index(self):
response = self._get("licenses")
self._assert_status_code_is(response, 200)

def test_get_license(self):
licenseId = "Apache-2.0"
response = self._get(f"licenses/{licenseId}")
self._assert_status_code_is(response, 200)
self._assert_matches_license_id(licenseId, response.json())

def test_404_on_unknown_license(self):
licenseId = "unknown"
response = self._get(f"licenses/{licenseId}")
self._assert_status_code_is(response, 404)
davelopez marked this conversation as resolved.
Show resolved Hide resolved

def _assert_matches_license_id(self, license_id, json_response):
self._assert_has_key(json_response, "licenseId")
assert json_response["licenseId"] == license_id