pyblish / pyblish-qml

Pyblish QML frontend for Maya 2013+, Houdini 11+, Nuke 8+ and more
GNU Lesser General Public License v3.0
114 stars 44 forks source link

Fix custom registered test not being passed from client to server #364

Closed jboisvertrodeofx closed 4 years ago

jboisvertrodeofx commented 4 years ago

This is a fix for a bug where the registered test function (i.e. the function registered with pyblish.logic.register_test) is not passed from the pyblish-qml client to the server, which ends up always using the default test function.

The issue was discussed with more details and a code sample here: https://github.com/pyblish/pyblish-qml/issues/363

mottosso commented 4 years ago

Thanks for this!

I had a look at whether there was a way we can avoid modifying the JSON encoding/decoding, and think I found something that works.

I wasn't able to push to your PR, but here's the commit I made as an old school "patch" that you can apply on your end.

Let me know what you think!

$ cd pyblish_qml
$ git patch 0001-Simplify-passing-test-through-JSON.patch

0001-Simplify-passing-test-through-JSON.patch

From f011b126c0b458a792d7b8ca49d5ff963ea985c3 Mon Sep 17 00:00:00 2001
From: Marcus Ottosson <konstruktion@gmail.com>
Date: Fri, 1 May 2020 08:20:01 +0100
Subject: [PATCH] Simplify passing test through JSON

---
 pyblish_qml/app.py         |  2 +-
 pyblish_qml/ipc/client.py  | 12 +++++++-----
 pyblish_qml/ipc/server.py  |  5 +----
 pyblish_qml/ipc/service.py |  4 ++++
 pyblish_qml/util.py        | 32 --------------------------------
 5 files changed, 13 insertions(+), 42 deletions(-)

diff --git a/pyblish_qml/app.py b/pyblish_qml/app.py
index 198005d..c5a12b4 100644
--- a/pyblish_qml/app.py
+++ b/pyblish_qml/app.py
@@ -241,7 +241,7 @@ class Application(QtGui.QGuiApplication):
         def _listen():
             while True:
                 line = self.host.channels["parent"].get()
-                payload = json.loads(line, cls=util.SetJSONDecoder)["payload"]
+                payload = json.loads(line)["payload"]

                 # We can't call methods directly, as we are running
                 # in a thread. Instead, we emit signals that do the
diff --git a/pyblish_qml/ipc/client.py b/pyblish_qml/ipc/client.py
index ee68e80..8a90891 100644
--- a/pyblish_qml/ipc/client.py
+++ b/pyblish_qml/ipc/client.py
@@ -21,7 +21,6 @@ import threading
 import pyblish.api
 import pyblish.plugin

-from ..util import SetJSONEncoder, SetJSONDecoder
 from ..vendor import six
 from ..vendor.six.moves import queue

@@ -49,6 +48,10 @@ class Proxy(object):

     def test(self, **vars):
         """Vars can only be passed as a non-keyword argument"""
+
+        # -> Support JSON, see #364
+        vars["ordersWithError"] = list(vars["ordersWithError"])
+
         return self._dispatch("test", kwargs=vars)

     def ping(self):
@@ -160,8 +163,7 @@ class Proxy(object):
                     "args": args or list(),
                     "kwargs": kwargs or dict(),
                 }
-            },
-            cls=SetJSONEncoder,
+            }
         )

         # This should never happen. Each request is immediately
@@ -181,9 +183,9 @@ class Proxy(object):
             message = self.channels["response"].get()

             if six.PY3:
-                response = json.loads(message, cls=SetJSONDecoder)
+                response = json.loads(message)
             else:
-                response = _byteify(json.loads(message, object_hook=_byteify, cls=SetJSONDecoder))
+                response = _byteify(json.loads(message, object_hook=_byteify))

         except TypeError as e:
             raise e
diff --git a/pyblish_qml/ipc/server.py b/pyblish_qml/ipc/server.py
index cd5656c..0ecce99 100644
--- a/pyblish_qml/ipc/server.py
+++ b/pyblish_qml/ipc/server.py
@@ -22,7 +22,6 @@ import subprocess
 import time

 from .. import _state
-from ..util import SetJSONEncoder, SetJSONDecoder
 from ..vendor import six

 CREATE_NO_WINDOW = 0x08000000
@@ -91,7 +90,6 @@ class Proxy(object):
                     "kwargs": kwargs or dict(),
                 }
             },
-            cls=SetJSONEncoder,
         )

         if six.PY3:
@@ -245,7 +243,7 @@ class Server(object):
                     line = line.decode("utf8")

                 try:
-                    response = json.loads(line, cls=SetJSONDecoder)
+                    response = json.loads(line)
                 except Exception:
                     if last_msg_newline:
                         # last newline message was a real newline
@@ -292,7 +290,6 @@ class Server(object):
                                 "header": "pyblish-qml:popen.response",
                                 "payload": result
                             },
-                            cls=SetJSONEncoder,
                         )

                         if six.PY3:
diff --git a/pyblish_qml/ipc/service.py b/pyblish_qml/ipc/service.py
index c911bdc..168f482 100644
--- a/pyblish_qml/ipc/service.py
+++ b/pyblish_qml/ipc/service.py
@@ -33,6 +33,10 @@ class Service(object):

     def test(self, **vars):
         test = pyblish.logic.registered_test()
+
+        # -> Support test, see #364
+        vars["ordersWithError"] = set(vars["ordersWithError"])
+
         return test(**vars)

     def ping(self):
diff --git a/pyblish_qml/util.py b/pyblish_qml/util.py
index a174f30..4df7f42 100644
--- a/pyblish_qml/util.py
+++ b/pyblish_qml/util.py
@@ -295,35 +295,3 @@ def SlotSentinel(*args):
         return wrapper

     return slotdecorator
-
-
-class SetJSONEncoder(json.JSONEncoder):
-    """JSON encoder that supports encoding Python sets"""
-    def default(self, obj):
-        if isinstance(obj, set):
-            return {"_python_set": list(obj)}
-        return json.JSONEncoder.default(self, obj)
-
-
-class SetJSONDecoder(json.JSONDecoder):
-    """JSON decoder that supports decoding Python sets"""
-    def decode(self, s, **kwargs):
-        decoded = super(SetJSONDecoder, self).decode(s, **kwargs)
-        return self._convert_python_sets(decoded)
-
-    @classmethod
-    def _convert_python_sets(cls, obj):
-        if isinstance(obj, dict):
-            if "_python_set" in obj:
-                return set(cls._convert_python_sets(obj["_python_set"]))
-            else:
-                new_obj = dict()
-                for key, value in obj.items():
-                    new_obj[key] = cls._convert_python_sets(value)
-                return new_obj
-        elif isinstance(obj, list):
-            new_obj = list()
-            for value in obj:
-                new_obj.append(cls._convert_python_sets(value))
-            return new_obj
-        return obj
-- 
2.16.1.windows.3
jboisvertrodeofx commented 4 years ago

Hey @mottosso sorry about the delay, I was off for the last 3 days. I applied your patch and tested it, and it seems that everything still works!

mottosso commented 4 years ago

Great news! Merging and releasing this. Thanks @jboisvertrodeofx.