Addon: store available job types on scene

Storing the available job types on the Scene makes it possible to restore
the Flamenco job submission UI without communication with the Manager.
This commit is contained in:
Sybren A. Stüvel 2022-03-14 15:36:44 +01:00
parent c8ae856131
commit b993f38889
2 changed files with 78 additions and 31 deletions

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import json
import logging import logging
import uuid import uuid
from typing import TYPE_CHECKING, Callable, Optional, Union from typing import TYPE_CHECKING, Callable, Optional, Union
@ -11,13 +12,19 @@ from . import job_types_propgroup
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
if TYPE_CHECKING: if TYPE_CHECKING:
from flamenco.manager.models import AvailableJobType, SubmittedJob, JobSettings from flamenco.manager.models import (
AvailableJobType,
_available_job_types: Optional[list[AvailableJobType]] = None AvailableJobTypes,
SubmittedJob,
JobSettings,
)
else: else:
AvailableJobTypes = object
AvailableJobType = object
SubmittedJob = object SubmittedJob = object
JobSettings = object JobSettings = object
_available_job_types = None
_available_job_types: Optional[list[AvailableJobType]] = None
# Items for a bpy.props.EnumProperty() # Items for a bpy.props.EnumProperty()
_job_type_enum_items: list[ _job_type_enum_items: list[
@ -27,10 +34,7 @@ _job_type_enum_items: list[
_selected_job_type_propgroup: Optional[job_types_propgroup.JobTypePropertyGroup] = None _selected_job_type_propgroup: Optional[job_types_propgroup.JobTypePropertyGroup] = None
def fetch_available_job_types(api_client): def fetch_available_job_types(api_client, scene: bpy.types.Scene):
global _available_job_types
global _job_type_enum_items
from flamenco.manager import ApiClient from flamenco.manager import ApiClient
from flamenco.manager.api import jobs_api from flamenco.manager.api import jobs_api
from flamenco.manager.model.available_job_types import AvailableJobTypes from flamenco.manager.model.available_job_types import AvailableJobTypes
@ -40,20 +44,53 @@ def fetch_available_job_types(api_client):
job_api_instance = jobs_api.JobsApi(api_client) job_api_instance = jobs_api.JobsApi(api_client)
response: AvailableJobTypes = job_api_instance.get_job_types() response: AvailableJobTypes = job_api_instance.get_job_types()
_clear_available_job_types() _clear_available_job_types(scene)
# Store the response JSON on the scene. This is used when the blend file is
# loaded (and thus the _available_job_types global variable is still empty)
# to generate the PropertyGroup of the selected job type.
scene.flamenco_available_job_types_json = json.dumps(response.to_dict())
_store_available_job_types(response)
def _store_available_job_types(available_job_types: AvailableJobTypes) -> None:
global _available_job_types
global _job_type_enum_items
job_types = available_job_types.job_types
# Remember the available job types. # Remember the available job types.
_available_job_types = response.job_types _available_job_types = job_types
if _available_job_types is None: if _available_job_types is None:
_job_type_enum_items = [] _job_type_enum_items = []
else: else:
# Convert from API response type to list suitable for an EnumProperty. # Convert from API response type to list suitable for an EnumProperty.
_job_type_enum_items = [ _job_type_enum_items = [
(job_type.name, job_type.label, "") for job_type in _available_job_types (job_type.name, job_type.label, "") for job_type in job_types
] ]
_job_type_enum_items.insert(0, ("", "Select a Job Type", "", 0, 0)) _job_type_enum_items.insert(0, ("", "Select a Job Type", "", 0, 0))
def _available_job_types_from_json(job_types_json: str) -> None:
"""Convert JSON to AvailableJobTypes object, and update global variables for it."""
from flamenco.manager.models import AvailableJobTypes
from flamenco.manager.configuration import Configuration
from flamenco.manager.model_utils import validate_and_convert_types
json_dict = json.loads(job_types_json)
dummy_cfg = Configuration()
job_types = validate_and_convert_types(
json_dict, (AvailableJobTypes,), ["job_types"], True, True, dummy_cfg
)
assert isinstance(
job_types, AvailableJobTypes
), "expected AvailableJobTypes, got %s" % type(job_types)
_store_available_job_types(job_types)
def are_job_types_available() -> bool: def are_job_types_available() -> bool:
"""Returns whether job types have been fetched and are available.""" """Returns whether job types have been fetched and are available."""
return bool(_job_type_enum_items) return bool(_job_type_enum_items)
@ -127,7 +164,7 @@ def job_for_scene(scene: bpy.types.Scene) -> Optional[SubmittedJob]:
return job return job
def _clear_available_job_types(): def _clear_available_job_types(scene: bpy.types.Scene):
global _available_job_types global _available_job_types
global _job_type_enum_items global _job_type_enum_items
@ -135,13 +172,14 @@ def _clear_available_job_types():
_available_job_types = None _available_job_types = None
_job_type_enum_items.clear() _job_type_enum_items.clear()
scene.flamenco_available_job_types_json = ""
def _clear_job_type_propgroup(): def _clear_job_type_propgroup():
global _selected_job_type_propgroup global _selected_job_type_propgroup
try: try:
del bpy.types.WindowManager.flamenco_job_settings del bpy.types.Scene.flamenco_job_settings
except AttributeError: except AttributeError:
pass pass
@ -151,15 +189,7 @@ def _clear_job_type_propgroup():
_selected_job_type_propgroup = None _selected_job_type_propgroup = None
if TYPE_CHECKING: def active_job_type(scene: bpy.types.Scene) -> Optional[AvailableJobType]:
from flamenco.manager.model.available_job_type import (
AvailableJobType as _AvailableJobType,
)
else:
_AvailableJobType = object
def active_job_type(scene: bpy.types.Scene) -> Optional[_AvailableJobType]:
"""Return the active job type. """Return the active job type.
Returns a flamenco.manager.model.available_job_type.AvailableJobType, Returns a flamenco.manager.model.available_job_type.AvailableJobType,
@ -179,6 +209,17 @@ def _get_job_types_enum_items(dummy1, dummy2):
return _job_type_enum_items return _job_type_enum_items
@bpy.app.handlers.persistent
def restore_available_job_types(dummy1, dummy2):
scene = bpy.context.scene
job_types_json = getattr(scene, "flamenco_available_job_types_json", "")
if not job_types_json:
_clear_available_job_types(scene)
return
_available_job_types_from_json(job_types_json)
update_job_type_properties(scene)
def discard_flamenco_data(): def discard_flamenco_data():
if _available_job_types: if _available_job_types:
_available_job_types.clear() _available_job_types.clear()
@ -194,16 +235,22 @@ def register() -> None:
) )
bpy.types.Scene.flamenco_available_job_types_json = bpy.props.StringProperty( bpy.types.Scene.flamenco_available_job_types_json = bpy.props.StringProperty(
name="Available Job Types", name="Available Job Types, stored as JSON string",
) )
bpy.app.handlers.load_factory_startup_post.append(restore_available_job_types)
bpy.app.handlers.load_post.append(restore_available_job_types)
def unregister() -> None: def unregister() -> None:
del bpy.types.Scene.flamenco_job_type to_del = (
(bpy.types.Scene, "flamenco_job_type"),
(bpy.types.Scene, "flamenco_job_settings"),
(bpy.types.Scene, "flamenco_available_job_types_json"),
)
for ob, attr in to_del:
try: try:
# This property doesn't always exist. delattr(ob, attr)
del bpy.types.Scene.flamenco_job_settings
except AttributeError: except AttributeError:
pass pass

View File

@ -48,7 +48,7 @@ class FLAMENCO_OT_fetch_job_types(FlamencoOpMixin, bpy.types.Operator):
old_job_type_name = getattr(scene, "flamenco_job_type", "") old_job_type_name = getattr(scene, "flamenco_job_type", "")
try: try:
job_types.fetch_available_job_types(api_client) job_types.fetch_available_job_types(api_client, scene)
except ApiException as ex: except ApiException as ex:
self.report({"ERROR"}, "Error getting job types: %s" % ex) self.report({"ERROR"}, "Error getting job types: %s" % ex)
return {"CANCELLED"} return {"CANCELLED"}