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

[DEV-13108]: Ootb/Gallery #357

Merged
merged 17 commits into from
Feb 24, 2025
22 changes: 10 additions & 12 deletions .harness/prinputset.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
inputSet:
name: pr-input-set
tags: {}
identifier: prinputset
orgIdentifier: default
projectIdentifier: IPA_Release
@@ -9,19 +10,10 @@ inputSet:
ci:
codebase:
build:
type: PR
type: branch
spec:
number: <+trigger.prNumber>
branch: <+trigger.branch>
stages:
- stage:
identifier: build_info
type: CI
spec:
infrastructure:
type: KubernetesDirect
spec:
nodeSelector:
node_group: <+input>
- parallel:
- stage:
identifier: code_checks
@@ -40,7 +32,7 @@ inputSet:
value: <+input>
- name: ruff
type: String
value: <+input>
value: ruff format --check indico tests
- name: mypy
type: String
value: <+input>
@@ -84,6 +76,12 @@ inputSet:
- name: RUN_UNITTESTS
type: String
value: "TRUE"
- name: RUN_PRERELEASE
type: String
value: "FALSE"
- name: RUN_RELEASE
type: String
value: "FALSE"
- name: RUN_PUBLISH
type: String
value: "FALSE"
19 changes: 15 additions & 4 deletions indico/client/request.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from enum import Enum
from typing import Any, Dict, Union
from typing import Any, Dict, List, Optional, Union

from indico.errors import IndicoRequestError
from indico.errors import IndicoInputError, IndicoRequestError


class HTTPMethod(Enum):
@@ -73,9 +73,20 @@ def __init__(self, query: str, variables: Dict[str, Any] = None):
self.has_next_page = True
super().__init__(query, variables=variables)

def process_response(self, response):
def process_response(self, response, nested_keys: Optional[List[str]] = None):
response = super().process_response(response)
_pg = next(iter(response.values()))["pageInfo"]
if nested_keys:
_pg = response
for key in nested_keys:
if key not in _pg.keys():
raise IndicoInputError(
f"Nested key not found in response: {key}",
)
_pg = _pg[key]
_pg = _pg["pageInfo"]
else:
_pg = next(iter(response.values()))["pageInfo"]

self.has_next_page = _pg["hasNextPage"]
self.variables["after"] = _pg["endCursor"] if self.has_next_page else None
return response
1 change: 0 additions & 1 deletion indico/config/config.py
Original file line number Diff line number Diff line change
@@ -34,7 +34,6 @@ class IndicoConfig:
_disable_cookie_domain: bool = False

def __init__(self, **kwargs):

self.host: str = os.getenv("INDICO_HOST")
self.protocol: str = os.getenv("INDICO_PROTOCOL", "https")
self.serializer: str = os.getenv("INDICO_SERIALIZER", "msgpack")
5 changes: 3 additions & 2 deletions indico/errors.py
Original file line number Diff line number Diff line change
@@ -43,5 +43,6 @@ def __init__(self):
class IndicoHibernationError(IndicoError):
def __init__(self, after):
self.after = after
super().__init__(f"Platform is currently hibernating. Wait {after} seconds and retry this request.")

super().__init__(
f"Platform is currently hibernating. Wait {after} seconds and retry this request."
)
34 changes: 34 additions & 0 deletions indico/filters/__init__.py
Original file line number Diff line number Diff line change
@@ -252,3 +252,37 @@ def __init__(
),
}
super().__init__(**kwargs)


class ComponentBlueprintFilter(Filter):
"""
Create a Filter when querying for ComponentBlueprints.

Args:
name (str): name of the component blueprint
component_type (str): type of the component blueprint
component_family (str): family of the component blueprint
tags (list): tags of the component blueprint
"""

__options__ = (
"name",
"component_type",
"component_family",
"tags",
)

def __init__(
self,
name: Union[str, None] = None,
component_type: Union[str, None] = None,
component_family: Union[str, None] = None,
tags: Union[List[str], None] = None,
):
kwargs = {
"name": name,
"componentType": component_type,
"componentFamily": component_family,
"tags": tags,
}
super().__init__(**kwargs)
2 changes: 1 addition & 1 deletion indico/http/retry.py
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@
from functools import wraps



def retry(
ExceptionTypes: t.Type[Exception], tries: int = 3, delay: int = 1, backoff: int = 2
) -> t.Callable:
@@ -32,6 +31,7 @@ def retry_fn(*args: t.Any, **kwargs: t.Any) -> t.Any:

return retry_decorator


def aioretry(
ExceptionTypes: t.Type[Exception],
tries: int = 3,
4 changes: 4 additions & 0 deletions indico/http/serialization.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Handles deserialization / decoding of responses
"""

import gzip
import io
import json
@@ -42,6 +43,7 @@ def deserialize(response, force_json=False, force_decompress=False):
content_type, charset, content.decode("ascii", "ignore")
)


async def aio_deserialize(response, force_json=False, force_decompress=False):
content_type, params = parse_header(response.headers.get("Content-Type"))
content = await response.read()
@@ -63,11 +65,13 @@ async def aio_deserialize(response, force_json=False, force_decompress=False):
content_type, charset, content.decode("ascii", "ignore")
)


def parse_header(header: str) -> tuple[str, dict[str, str]]:
email = EmailMessage()
email["Content-Type"] = header
return email.get_content_type(), email["Content-Type"].params


def raw_bytes(content, *args, **kwargs):
return content

12 changes: 10 additions & 2 deletions indico/queries/document_report.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
""""""

from typing import List, Union

from indico import PagedRequest
@@ -53,9 +54,16 @@ class GetDocumentReport(PagedRequest):
"""

def __init__(
self, filters: Union[dict, DocumentReportFilter] = None, limit: int = None, all_submissions = False
self,
filters: Union[dict, DocumentReportFilter] = None,
limit: int = None,
all_submissions=False,
):
variables = {"filters": filters, "limit": limit, "allSubmissions": all_submissions}
variables = {
"filters": filters,
"limit": limit,
"allSubmissions": all_submissions,
}
super().__init__(self.query, variables=variables)

def process_response(self, response):
20 changes: 16 additions & 4 deletions indico/queries/documents.py
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@


class _DocumentExtraction(GraphQLRequest):

query = """
mutation($files: [FileInput], $jsonConfig: JSONString, $ocrEngine: OCREngine) {
documentExtraction(files: $files, jsonConfig: $jsonConfig, ocrEngine: $ocrEngine) {
@@ -22,7 +21,12 @@ def __init__(self, files, json_config={"preset_config": "legacy"}, ocr_engine=No
if json_config and type(json_config) == dict:
json_config = json.dumps(json_config)
super().__init__(
query=self.query, variables={"files": files, "jsonConfig": json_config, "ocrEngine": ocr_engine}
query=self.query,
variables={
"files": files,
"jsonConfig": json_config,
"ocrEngine": ocr_engine,
},
)

def process_response(self, response):
@@ -67,7 +71,11 @@ class DocumentExtraction(RequestChain):
"""

def __init__(
self, files: List[str], json_config: dict = None, upload_batch_size: int = None, ocr_engine: str = "OMNIPAGE"
self,
files: List[str],
json_config: dict = None,
upload_batch_size: int = None,
ocr_engine: str = "OMNIPAGE",
):
self.files = files
self.json_config = json_config
@@ -83,4 +91,8 @@ def requests(self):
)
else:
yield UploadDocument(files=self.files)
yield _DocumentExtraction(files=self.previous, json_config=self.json_config, ocr_engine=self.ocr_engine)
yield _DocumentExtraction(
files=self.previous,
json_config=self.json_config,
ocr_engine=self.ocr_engine,
)
1 change: 0 additions & 1 deletion indico/queries/forms.py
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@


class _FormPreprocessing(GraphQLRequest):

query = """
mutation($files: [FileInput]) {
activeFormFields(
120 changes: 120 additions & 0 deletions indico/queries/gallery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
from typing import Dict, Optional, Union

from indico.client.request import GraphQLRequest, PagedRequest
from indico.filters import ComponentBlueprintFilter
from indico.types.component_blueprint import BlueprintPage, BlueprintTags


class ListGallery(PagedRequest):
"""
List all blueprints available in the gallery.

Args:
filters (ComponentBlueprintFilter): filters to apply to the blueprints
limit (int): maximum number of blueprints to return
order_by (str): order to sort the blueprints by
desc (bool): whether to sort the blueprints in descending order
"""

query = """
query getGalleryBlueprints($desc: Boolean, $orderBy: COMPONENTBLUEPRINT_COLUMN_ENUM, $skip: Int, $limit: Int, $after: Int, $before: Int, $filters: ComponentBlueprintFilter) {
gallery {
component {
blueprintsPage(
skip: $skip
before: $before
after: $after
limit: $limit
desc: $desc
orderBy: $orderBy
filters: $filters
) {
componentBlueprints {
id
name
componentType
icon
description
enabled
footer
tags
modelOptions
}
pageInfo {
startCursor
endCursor
hasNextPage
aggregateCount
}
}
}
}
}
"""

def __init__(
self,
filters: Optional[Union[Dict, ComponentBlueprintFilter]] = None,
limit: int = 100,
order_by: str = "ID",
desc: bool = False,
**kwargs,
):
super().__init__(
self.query,
variables={
"filters": filters,
"limit": limit,
"orderBy": order_by,
"desc": desc,
**kwargs,
},
)

def process_response(self, response) -> BlueprintPage:
response = super().process_response(
response, nested_keys=["gallery", "component", "blueprintsPage"]
)
return BlueprintPage(
blueprints=[
component
for component in response["gallery"]["component"]["blueprintsPage"][
"componentBlueprints"
]
]
)


class GetGalleryTags(GraphQLRequest):
"""
List all blueprint tags available in the gallery.

Args:
component_family (str): the family of components to filter by
"""

query = """
query getGalleryBlueprints($componentFamily: ComponentFamily) {
gallery {
component {
availableTags(componentFamily: $componentFamily) {
tag
value
}
}
}
}
"""

def __init__(self, component_family: Optional[str] = None):
self.component_family = component_family
super().__init__(
self.query,
variables={"componentFamily": component_family},
)

def process_response(self, response) -> BlueprintTags:
response = super().process_response(response)
return BlueprintTags(
tags=[tag for tag in response["gallery"]["component"]["availableTags"]]
)
Loading