Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Threading / Loops in Python Plugin
#11
(01-09-2024, 01:12 PM)JBreckeen Wrote: Thanks for the discussion.

I stepped away from this plugin for a bit - had to do some work.  I have gotten the "outbound" part of my integration working by having the Gimp plugin write a command .json and have my bridge script pick it up and do its thing.

But the issue I am having is trying to get the "looping" script to be able to execute an inbound command in Gimp.  The simple version would be that I want to have the Gimp plugin (running under Gimp's py2.7) constantly checking the command directory for a .json, and when it finds one it executes something such as

 pdb.gimp_file_save(image, drawable, savePath, savePath).




If I setup a static function that checks the directory once during the plugin load, it works.  But as soon as I put in checking loop (which is blocking of course), then Gimp will not continue the load.  So then I move the checking loop to a thread, but whenever I try to connect the threads, I get a crash.  I believe it comes from the two processes being in separate threads.



So what I really need is to have some way that the checking loop can execute the Gimp commands in Gimp's thread.



Hope that makes sense,





JBreckeen.

Looking at my code that runs in parallel with Gimp, the code doesn't use the simplified registration you have for Python-fu plugins with an auto-generated arguments dialog. It runs a registration "closer to the metal".
Reply
#12
Hello all - mainly Ofnuts!.  So back at doing some work on this.  I was able to get the Gimp->Prism Pipeline outbound comms to work.  But now I am trying to get the inbound to work.  I had to divide this up into three scripts:

 -  Prism_Menu: registers the menu items and sends cli command's to the bridge (outbound)
 -  Prism_Bridge: does not register as a plugin and runs in Py3.11 and communicates with Prism (outbound)
 -  Prism_Functions: registers as a plugin, starts the script server, and will execute python-fu procedures. (inbound)

I am using 2.99 (yes I know it is in development), but it is working for us and by the time I finally get this finished I don't want to write it again.

So to get my external script coming from Prism to communicate with Gimp, I have started using the script server - I could never get a non-blocking listening script to work.

The external script is sending:

       f'(python-fu-prism-saveAction "{filepath}")'

to the script server and is being receiving correctly:

ScriptFu server: received request #0 from IP address 127.0.0.1: (python-fu-prism-saveAction "N:/Data/Projects/Prism Tests/01_Production/Assets/Building/Scenefiles/gimp/Paint/Building_Paint_v003.xcf"),[queue length: 1] on Thu Apr 18 11:15:52 2024

But I need my functions plugin to be able to parse the arg of the file path it receives to use in the procedure (this is just the first bit of functionality - when I get this all working I will add more procedures).  As you can see with all the commented-out lines, I have tried a bunch of things I have found around the web.  But I cannot get anything to work.  If I hardcode the filePath either in the saveAction(), or PrismFunctions(Gimp.PlugIn) it works, but I cannot get it to use the passed argument.

So it boils down to does anybody know how to pass the received argument to the callback function?

FYI:  I might either be missing something simple, there may be a completely better way to do this, or it cannot be done in Gimp.



In the below code, the "data" print statement always show "data" is empty.

Prism_Fuctions.py:

...other code...
def saveAction(procedure, run_mode, data):

   print("\n*** IN saveAction ***\n")                          #   DEBUG

   print("*** data:  ", data, "\n\n")

   # filePath = data["filePath"]

   # print("*** filePath:  ", filePath, "\n\n")

   # filePath = r"C:\tmp\Building_Paint_v001.xcf"      #    HARDCODED FOR TESTING

   ### vvvv WORKING vvvvv ####
   # images = pdb.gimp_get_images()
   # imageList = images[1]
   # currentImage = imageList.data[0]

   # file = Gio.File.new_for_path(filePath)

   # # Save the image in the .xcf file format
   # pdb.gimp_xcf_save(image=currentImage , file=file)
   ### ^^^^ WORKING ^^^^ ####

   return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())


class PrismFunctions(Gimp.PlugIn):

   def __init__(self):
       super().__init__()
       self._filePath = ""                     #   NEEDED???

   ## Parameter: filePath ##
   # @GObject.Property(type=str,
   #                   nick= _("File Path"),
   #                   blurb= _("File Path"))
   
   # def filePath(self):
   #     return self._filePath
   
   # def set_filePath(self, file_path):
   #     self._filePath = file_path

   # @filePath.setter
   # def filePath(self, filePath):
   #     self._filePath = filePath

   __gproperties__ = {
       "filePath": (
           str,
           _("filePath"),
           "File Path",
           "File Path",
           GObject.ParamFlags.READWRITE,
           )
       }

   
   ## GimpPlugIn virtual methods ##
   def do_set_i18n(self, procname):
       return True, 'gimp30-python', None

   def do_query_procedures(self):
       return [ "python-fu-prism-saveAction" ]

   def do_create_procedure(self, name):

       procedure = None
       
       if name == 'python-fu-prism-saveAction':

           data = {"filePath": None}

           procedure = Gimp.Procedure.new(self,
                                       name,
                                       Gimp.PDBProcType.PLUGIN,
                                       # Gimp.PDBProcType.EXTENSION,  # Change to EXTENSION ???
                                       saveAction,
                                       data
                                       )
           
           procedure.set_documentation(_("Prism save action"),
                                       help_doc,
                                       "")
           
           procedure.set_attribution("Joshua Breckeen",
                                     "Prism Pipeline",
                                     "2024")
           
           procedure.add_argument_from_property(self, "filePath")

           # procedure.set_property("filePath", self._filePath)


           # # Get the list of arguments
           # arguments = procedure.get_arguments()
           
           # # The first (and only) argument should be the filePath
           # file_path = arguments[0]
           
           # # Set the filePath property with the received value
           # self.filePath = file_path


       else:
           procedure = None

       return procedure

   
   print("***** Loading Prism Functions ******")                   #   DEBUG
   time.sleep(.1)

Gimp.main(PrismFunctions.__gtype__, sys.argv)
Reply
#13
Asking the obvious  but you have:
Code:
def saveAction(procedure, run_mode, data):

But in script-fu you don't use the run-mode argument, so I wonder if your data wouldn't end up in the run_mode argument.

Also, you have this very complex architecture because you want to use Pythonv3 for your main code, but since you moved to Gimp3 you are now using Python v3 on the Gimp side of things so maybe you can simplify all this?
Reply
#14
But in script-fu you don't use the run-mode argument, so I wonder if your data wouldn't end up in the run_mode argument.

Good point.  As you know the docs are pretty scarce and I sorta had to add/remove args until it stopped throwing errors.  When you suggested that I got excited and tried.  But unfortunately, not.  It appears the second arg is:

<__gi__.GimpProcedureConfig-python-fu-prism-saveAction object at 0x000001b7ffd3fec0 (GimpProcedureConfig-python-fu-prism-saveAction at 0x000001b7ff9fdcc0)>


Also, you have this very complex architecture because you want to use Pythonv3 for your main code, but since you moved to Gimp3 you are now using Python v3 on the Gimp side of things so maybe you can simplify all this?

And thought of that.  But Gimp's Py3 does not play well with the Qt elements and enviro of the pipeline stuff.  And also I thought it best to keep it separate since Gimp's Py and our VFX Py will not necessarily be consistently in sync.  This was also since I could not get a listening script to work in Gimp 2 or 3, so chose 3.


But still have the issue of trying to get an argument passed to the procedure.  Unless there is another way?
Reply


Forum Jump: