Skip to content

[DEV-13108]: Ootb/Gallery #357

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

Merged
merged 17 commits into from
Feb 24, 2025
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
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
Expand All @@ -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
Expand All @@ -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>
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion indico/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
5 changes: 3 additions & 2 deletions indico/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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
Expand Up @@ -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:
Expand All @@ -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,
Expand Down
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
Expand Down Expand Up @@ -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()
Expand All @@ -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

Expand Down
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
Expand Down Expand Up @@ -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):
Expand Down
20 changes: 16 additions & 4 deletions indico/queries/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@


class _DocumentExtraction(GraphQLRequest):

query = """
mutation($files: [FileInput], $jsonConfig: JSONString, $ocrEngine: OCREngine) {
documentExtraction(files: $files, jsonConfig: $jsonConfig, ocrEngine: $ocrEngine) {
Expand All @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Up @@ -7,7 +7,6 @@


class _FormPreprocessing(GraphQLRequest):

query = """
mutation($files: [FileInput]) {
activeFormFields(
Expand Down
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