mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge branch 'develop' into enhancement/AY-4919_Move-Resolve-client-code
This commit is contained in:
commit
2b95bb5e23
62 changed files with 303 additions and 40 deletions
|
|
@ -55,6 +55,7 @@ MOVED_ADDON_MILESTONE_VERSIONS = {
|
|||
"clockify": VersionInfo(0, 2, 0),
|
||||
"flame": VersionInfo(0, 2, 0),
|
||||
"max": VersionInfo(0, 2, 0),
|
||||
"photoshop": VersionInfo(0, 2, 0),
|
||||
"traypublisher": VersionInfo(0, 2, 0),
|
||||
"tvpaint": VersionInfo(0, 2, 0),
|
||||
"maya": VersionInfo(0, 2, 0),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from .version import __version__
|
||||
from .addon import (
|
||||
PHOTOSHOP_ADDON_ROOT,
|
||||
PhotoshopAddon,
|
||||
|
|
@ -6,6 +7,8 @@ from .addon import (
|
|||
|
||||
|
||||
__all__ = (
|
||||
"__version__",
|
||||
|
||||
"PHOTOSHOP_ADDON_ROOT",
|
||||
"PhotoshopAddon",
|
||||
"get_launch_script_path",
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
import os
|
||||
from ayon_core.addon import AYONAddon, IHostAddon
|
||||
|
||||
from .version import __version__
|
||||
|
||||
PHOTOSHOP_ADDON_ROOT = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
class PhotoshopAddon(AYONAddon, IHostAddon):
|
||||
name = "photoshop"
|
||||
version = __version__
|
||||
host_name = "photoshop"
|
||||
|
||||
def add_implementation_envs(self, env, _app):
|
||||
|
|
@ -33,4 +36,3 @@ def get_launch_script_path():
|
|||
return os.path.join(
|
||||
PHOTOSHOP_ADDON_ROOT, "api", "launch_script.py"
|
||||
)
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ ExManCmd /install {path to addon}/api/extension.zxp
|
|||
The easiest way to get the server and Photoshop launch is with:
|
||||
|
||||
```
|
||||
python -c ^"import ayon_core.hosts.photoshop;ayon_core.hosts.photoshop.launch(""C:\Program Files\Adobe\Adobe Photoshop 2020\Photoshop.exe"")^"
|
||||
python -c ^"import ayon_photoshop;ayon_photoshop.launch(""C:\Program Files\Adobe\Adobe Photoshop 2020\Photoshop.exe"")^"
|
||||
```
|
||||
|
||||
`avalon.photoshop.launch` launches the application and server, and also closes the server when Photoshop exists.
|
||||
|
|
@ -128,7 +128,7 @@ class CollectInstances(pyblish.api.ContextPlugin):
|
|||
import os
|
||||
|
||||
from ayon_core.pipeline import publish
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class ExtractImage(publish.Extractor):
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
|
@ -22,9 +22,9 @@ from ayon_core.pipeline.workfile import (
|
|||
)
|
||||
from ayon_core.pipeline.template_data import get_template_data_with_names
|
||||
from ayon_core.tools.utils import host_tools
|
||||
from ayon_core.tools.adobe_webserver.app import WebServerTool
|
||||
from ayon_core.pipeline.context_tools import change_current_context
|
||||
|
||||
from .webserver import WebServerTool
|
||||
from .ws_stub import PhotoshopServerStub
|
||||
|
||||
log = Logger.get_logger(__name__)
|
||||
|
|
@ -8,7 +8,7 @@ workfile or others.
|
|||
import os
|
||||
import sys
|
||||
|
||||
from ayon_core.hosts.photoshop.api.lib import main as host_main
|
||||
from ayon_photoshop.api.lib import main as host_main
|
||||
|
||||
# Get current file to locate start point of sys.argv
|
||||
CURRENT_FILE = os.path.abspath(__file__)
|
||||
|
|
@ -19,7 +19,7 @@ def safe_excepthook(*args):
|
|||
|
||||
|
||||
def main(*subprocess_args):
|
||||
from ayon_core.hosts.photoshop.api import PhotoshopHost
|
||||
from ayon_photoshop.api import PhotoshopHost
|
||||
|
||||
host = PhotoshopHost()
|
||||
install_host(host)
|
||||
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -21,8 +21,8 @@ from ayon_core.host import (
|
|||
)
|
||||
|
||||
from ayon_core.pipeline.load import any_outdated_containers
|
||||
from ayon_core.hosts.photoshop import PHOTOSHOP_ADDON_ROOT
|
||||
from ayon_core.tools.utils import get_ayon_qt_app
|
||||
from ayon_photoshop import PHOTOSHOP_ADDON_ROOT
|
||||
|
||||
from . import lib
|
||||
|
||||
241
server_addon/photoshop/client/ayon_photoshop/api/webserver.py
Normal file
241
server_addon/photoshop/client/ayon_photoshop/api/webserver.py
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
"""Webserver for communication with photoshop.
|
||||
|
||||
Aiohttp (Asyncio) based websocket server used for communication with host
|
||||
application.
|
||||
|
||||
This webserver is started in spawned Python process that opens DCC during
|
||||
its launch, waits for connection from DCC and handles communication going
|
||||
forward. Server is closed before Python process is killed.
|
||||
"""
|
||||
import os
|
||||
import logging
|
||||
import urllib
|
||||
import threading
|
||||
import asyncio
|
||||
import socket
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
from wsrpc_aiohttp import WSRPCClient
|
||||
|
||||
from ayon_core.pipeline import get_global_context
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WebServerTool:
|
||||
"""
|
||||
Basic POC implementation of asychronic websocket RPC server.
|
||||
Uses class in external_app_1.py to mimic implementation for single
|
||||
external application.
|
||||
'test_client' folder contains two test implementations of client
|
||||
"""
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
WebServerTool._instance = self
|
||||
|
||||
self.client = None
|
||||
self.handlers = {}
|
||||
self.on_stop_callbacks = []
|
||||
|
||||
port = None
|
||||
host_name = "localhost"
|
||||
websocket_url = os.getenv("WEBSOCKET_URL")
|
||||
if websocket_url:
|
||||
parsed = urllib.parse.urlparse(websocket_url)
|
||||
port = parsed.port
|
||||
host_name = parsed.netloc.split(":")[0]
|
||||
if not port:
|
||||
port = 8098 # fallback
|
||||
|
||||
self.port = port
|
||||
self.host_name = host_name
|
||||
|
||||
self.app = web.Application()
|
||||
|
||||
# add route with multiple methods for single "external app"
|
||||
self.webserver_thread = WebServerThread(self, self.port)
|
||||
|
||||
def add_route(self, *args, **kwargs):
|
||||
self.app.router.add_route(*args, **kwargs)
|
||||
|
||||
def add_static(self, *args, **kwargs):
|
||||
self.app.router.add_static(*args, **kwargs)
|
||||
|
||||
def start_server(self):
|
||||
if self.webserver_thread and not self.webserver_thread.is_alive():
|
||||
self.webserver_thread.start()
|
||||
|
||||
def stop_server(self):
|
||||
self.stop()
|
||||
|
||||
async def send_context_change(self, host):
|
||||
"""
|
||||
Calls running webserver to inform about context change
|
||||
|
||||
Used when new PS/AE should be triggered,
|
||||
but one already running, without
|
||||
this publish would point to old context.
|
||||
"""
|
||||
client = WSRPCClient(os.getenv("WEBSOCKET_URL"),
|
||||
loop=asyncio.get_event_loop())
|
||||
await client.connect()
|
||||
|
||||
context = get_global_context()
|
||||
project_name = context["project_name"]
|
||||
folder_path = context["folder_path"]
|
||||
task_name = context["task_name"]
|
||||
log.info("Sending context change to {}{}/{}".format(
|
||||
project_name, folder_path, task_name
|
||||
))
|
||||
|
||||
await client.call(
|
||||
'{}.set_context'.format(host),
|
||||
project=project_name,
|
||||
folder=folder_path,
|
||||
task=task_name
|
||||
)
|
||||
await client.close()
|
||||
|
||||
def port_occupied(self, host_name, port):
|
||||
"""
|
||||
Check if 'url' is already occupied.
|
||||
|
||||
This could mean, that app is already running and we are trying open it
|
||||
again. In that case, use existing running webserver.
|
||||
Check here is easier than capturing exception from thread.
|
||||
"""
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as con:
|
||||
result = con.connect_ex((host_name, port)) == 0
|
||||
|
||||
if result:
|
||||
print(f"Port {port} is already in use")
|
||||
return result
|
||||
|
||||
def call(self, func):
|
||||
log.debug("websocket.call {}".format(func))
|
||||
future = asyncio.run_coroutine_threadsafe(
|
||||
func,
|
||||
self.webserver_thread.loop
|
||||
)
|
||||
result = future.result()
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_instance():
|
||||
if WebServerTool._instance is None:
|
||||
WebServerTool()
|
||||
return WebServerTool._instance
|
||||
|
||||
@property
|
||||
def is_running(self):
|
||||
if not self.webserver_thread:
|
||||
return False
|
||||
return self.webserver_thread.is_running
|
||||
|
||||
def stop(self):
|
||||
if not self.is_running:
|
||||
return
|
||||
try:
|
||||
log.debug("Stopping websocket server")
|
||||
self.webserver_thread.is_running = False
|
||||
self.webserver_thread.stop()
|
||||
except Exception:
|
||||
log.warning(
|
||||
"Error has happened during Killing websocket server",
|
||||
exc_info=True
|
||||
)
|
||||
|
||||
def thread_stopped(self):
|
||||
for callback in self.on_stop_callbacks:
|
||||
callback()
|
||||
|
||||
|
||||
class WebServerThread(threading.Thread):
|
||||
""" Listener for websocket rpc requests.
|
||||
|
||||
It would be probably better to "attach" this to main thread (as for
|
||||
example Harmony needs to run something on main thread), but currently
|
||||
it creates separate thread and separate asyncio event loop
|
||||
"""
|
||||
def __init__(self, module, port):
|
||||
super(WebServerThread, self).__init__()
|
||||
|
||||
self.is_running = False
|
||||
self.port = port
|
||||
self.module = module
|
||||
self.loop = None
|
||||
self.runner = None
|
||||
self.site = None
|
||||
self.tasks = []
|
||||
|
||||
def run(self):
|
||||
self.is_running = True
|
||||
|
||||
try:
|
||||
log.info("Starting web server")
|
||||
self.loop = asyncio.new_event_loop() # create new loop for thread
|
||||
asyncio.set_event_loop(self.loop)
|
||||
|
||||
self.loop.run_until_complete(self.start_server())
|
||||
|
||||
websocket_url = "ws://localhost:{}/ws".format(self.port)
|
||||
|
||||
log.debug(
|
||||
"Running Websocket server on URL: \"{}\"".format(websocket_url)
|
||||
)
|
||||
|
||||
asyncio.ensure_future(self.check_shutdown(), loop=self.loop)
|
||||
self.loop.run_forever()
|
||||
except Exception:
|
||||
self.is_running = False
|
||||
log.warning(
|
||||
"Websocket Server service has failed", exc_info=True
|
||||
)
|
||||
raise
|
||||
finally:
|
||||
self.loop.close() # optional
|
||||
|
||||
self.is_running = False
|
||||
self.module.thread_stopped()
|
||||
log.info("Websocket server stopped")
|
||||
|
||||
async def start_server(self):
|
||||
""" Starts runner and TCPsite """
|
||||
self.runner = web.AppRunner(self.module.app)
|
||||
await self.runner.setup()
|
||||
self.site = web.TCPSite(self.runner, 'localhost', self.port)
|
||||
await self.site.start()
|
||||
|
||||
def stop(self):
|
||||
"""Sets is_running flag to false, 'check_shutdown' shuts server down"""
|
||||
self.is_running = False
|
||||
|
||||
async def check_shutdown(self):
|
||||
""" Future that is running and checks if server should be running
|
||||
periodically.
|
||||
"""
|
||||
while self.is_running:
|
||||
while self.tasks:
|
||||
task = self.tasks.pop(0)
|
||||
log.debug("waiting for task {}".format(task))
|
||||
await task
|
||||
log.debug("returned value {}".format(task.result))
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
log.debug("Starting shutdown")
|
||||
await self.site.stop()
|
||||
log.debug("Site stopped")
|
||||
await self.runner.cleanup()
|
||||
log.debug("Runner stopped")
|
||||
tasks = [task for task in asyncio.all_tasks() if
|
||||
task is not asyncio.current_task()]
|
||||
list(map(lambda task: task.cancel(), tasks)) # cancel all the tasks
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
log.debug(f'Finished awaiting cancelled tasks, results: {results}...')
|
||||
await self.loop.shutdown_asyncgens()
|
||||
# to really make sure everything else has time to stop
|
||||
await asyncio.sleep(0.07)
|
||||
self.loop.stop()
|
||||
|
|
@ -6,7 +6,7 @@ import json
|
|||
import attr
|
||||
from wsrpc_aiohttp import WebSocketAsync
|
||||
|
||||
from ayon_core.tools.adobe_webserver.app import WebServerTool
|
||||
from .webserver import WebServerTool
|
||||
|
||||
|
||||
@attr.s
|
||||
|
|
@ -7,7 +7,7 @@ from ayon_core.lib import (
|
|||
is_using_ayon_console,
|
||||
)
|
||||
from ayon_applications import PreLaunchHook, LaunchTypes
|
||||
from ayon_core.hosts.photoshop import get_launch_script_path
|
||||
from ayon_photoshop import get_launch_script_path
|
||||
|
||||
|
||||
def get_launch_kwargs(kwargs):
|
||||
|
|
@ -2,13 +2,13 @@ import re
|
|||
|
||||
import ayon_api
|
||||
|
||||
import ayon_core.hosts.photoshop.api as api
|
||||
from ayon_core.lib import prepare_template_data
|
||||
from ayon_core.pipeline import (
|
||||
AutoCreator,
|
||||
CreatedInstance
|
||||
)
|
||||
from ayon_core.hosts.photoshop.api.pipeline import cache_and_get_instances
|
||||
from ayon_photoshop import api
|
||||
from ayon_photoshop.api.pipeline import cache_and_get_instances
|
||||
|
||||
|
||||
class PSAutoCreator(AutoCreator):
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import ayon_api
|
||||
|
||||
import ayon_core.hosts.photoshop.api as api
|
||||
from ayon_core.hosts.photoshop.lib import PSAutoCreator, clean_product_name
|
||||
from ayon_photoshop import api
|
||||
from ayon_photoshop.lib import PSAutoCreator, clean_product_name
|
||||
from ayon_core.lib import BoolDef, prepare_template_data
|
||||
from ayon_core.pipeline.create import get_product_name, CreatedInstance
|
||||
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import re
|
||||
|
||||
from ayon_core.hosts.photoshop import api
|
||||
from ayon_core.lib import BoolDef
|
||||
from ayon_core.pipeline import (
|
||||
Creator,
|
||||
|
|
@ -9,8 +8,9 @@ from ayon_core.pipeline import (
|
|||
)
|
||||
from ayon_core.lib import prepare_template_data
|
||||
from ayon_core.pipeline.create import PRODUCT_NAME_ALLOWED_SYMBOLS
|
||||
from ayon_core.hosts.photoshop.api.pipeline import cache_and_get_instances
|
||||
from ayon_core.hosts.photoshop.lib import clean_product_name
|
||||
from ayon_photoshop import api
|
||||
from ayon_photoshop.api.pipeline import cache_and_get_instances
|
||||
from ayon_photoshop.lib import clean_product_name
|
||||
|
||||
|
||||
class ImageCreator(Creator):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.photoshop.lib import PSAutoCreator
|
||||
from ayon_photoshop.lib import PSAutoCreator
|
||||
|
||||
|
||||
class ReviewCreator(PSAutoCreator):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from ayon_core.hosts.photoshop.lib import PSAutoCreator
|
||||
from ayon_photoshop.lib import PSAutoCreator
|
||||
|
||||
|
||||
class WorkfileCreator(PSAutoCreator):
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import re
|
||||
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_core.hosts.photoshop.api import get_unique_layer_name
|
||||
from ayon_photoshop import api as photoshop
|
||||
from ayon_photoshop.api import get_unique_layer_name
|
||||
|
||||
|
||||
class ImageLoader(photoshop.PhotoshopLoader):
|
||||
|
|
@ -2,8 +2,8 @@ import os
|
|||
|
||||
import qargparse
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_core.hosts.photoshop.api import get_unique_layer_name
|
||||
from ayon_photoshop import api as photoshop
|
||||
from ayon_photoshop.api import get_unique_layer_name
|
||||
|
||||
|
||||
class ImageFromSequenceLoader(photoshop.PhotoshopLoader):
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import re
|
||||
|
||||
from ayon_core.pipeline import get_representation_path
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_core.hosts.photoshop.api import get_unique_layer_name
|
||||
from ayon_photoshop import api as photoshop
|
||||
from ayon_photoshop.api import get_unique_layer_name
|
||||
|
||||
|
||||
class ReferenceLoader(photoshop.PhotoshopLoader):
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
"""Close PS after publish. For Webpublishing only."""
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class ClosePS(pyblish.api.ContextPlugin):
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
from ayon_core.pipeline.create import get_product_name
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class CollectAutoImageRefresh(pyblish.api.ContextPlugin):
|
||||
|
|
@ -7,7 +7,7 @@ Provides:
|
|||
"""
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
from ayon_core.pipeline.create import get_product_name
|
||||
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import os
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
from ayon_core.pipeline.create import get_product_name
|
||||
|
||||
|
||||
|
|
@ -4,8 +4,8 @@ import re
|
|||
import pyblish.api
|
||||
|
||||
from ayon_core.lib import prepare_template_data, is_in_tests
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_core.settings import get_project_settings
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class CollectColorCodedInstances(pyblish.api.ContextPlugin):
|
||||
|
|
@ -2,7 +2,7 @@ import os
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class CollectCurrentFile(pyblish.api.ContextPlugin):
|
||||
|
|
@ -2,7 +2,7 @@ import os
|
|||
import re
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class CollectExtensionVersion(pyblish.api.ContextPlugin):
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.photoshop import api
|
||||
from ayon_photoshop import api
|
||||
|
||||
|
||||
class CollectImage(pyblish.api.InstancePlugin):
|
||||
|
|
@ -2,7 +2,7 @@ import os
|
|||
|
||||
import pyblish.api
|
||||
from ayon_core.pipeline import publish
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class ExtractImage(pyblish.api.ContextPlugin):
|
||||
|
|
@ -7,7 +7,7 @@ from ayon_core.lib import (
|
|||
get_ffmpeg_tool_args,
|
||||
)
|
||||
from ayon_core.pipeline import publish
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class ExtractReview(publish.Extractor):
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
from ayon_core.pipeline import publish
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class ExtractSaveScene(publish.Extractor):
|
||||
|
|
@ -3,7 +3,7 @@ import pyblish.api
|
|||
from ayon_core.pipeline.publish import get_errored_plugins_from_context
|
||||
from ayon_core.lib import version_up
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class IncrementWorkfile(pyblish.api.InstancePlugin):
|
||||
|
|
@ -6,7 +6,7 @@ from ayon_core.pipeline.publish import (
|
|||
PublishXmlValidationError,
|
||||
OptionalPyblishPluginMixin
|
||||
)
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
|
||||
|
||||
class ValidateInstanceFolderRepair(pyblish.api.Action):
|
||||
|
|
@ -2,7 +2,7 @@ import re
|
|||
|
||||
import pyblish.api
|
||||
|
||||
from ayon_core.hosts.photoshop import api as photoshop
|
||||
from ayon_photoshop import api as photoshop
|
||||
from ayon_core.pipeline.create import PRODUCT_NAME_ALLOWED_SYMBOLS
|
||||
from ayon_core.pipeline.publish import (
|
||||
ValidateContentsOrder,
|
||||
3
server_addon/photoshop/client/ayon_photoshop/version.py
Normal file
3
server_addon/photoshop/client/ayon_photoshop/version.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Package declaring AYON addon 'photoshop' version."""
|
||||
__version__ = "0.2.0"
|
||||
6
server_addon/photoshop/client/pyproject.toml
Normal file
6
server_addon/photoshop/client/pyproject.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[project]
|
||||
name="photoshop"
|
||||
description="AYON Phostoshop addon."
|
||||
|
||||
[ayon.runtimeDependencies]
|
||||
wsrpc_aiohttp = "^3.1.1" # websocket server
|
||||
|
|
@ -1,3 +1,10 @@
|
|||
name = "photoshop"
|
||||
title = "Photoshop"
|
||||
version = "0.1.3"
|
||||
version = "0.2.0"
|
||||
|
||||
client_dir = "ayon_photoshop"
|
||||
|
||||
ayon_required_addons = {
|
||||
"core": ">0.3.2",
|
||||
}
|
||||
ayon_compatible_addons = {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue