# Setting widget variable from --python-code on Slicer.exe start

**URL:** <https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908>\
**Category:** Development\
**Created:** [June 17, 2022, 2:33am UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908 "2022-06-17T02:33:59Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![talmazov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/talmazov/32/3966_2.png) [@talmazov](https://discourse.slicer.org/u/talmazov)\
**Post date:** [June 17, 2022, 2:33am UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/1 "2022-06-17T02:33:59Z")

</div>

Hey all,  
I am launching 3d slicer via python script using subprocess as such

> Slicer.exe --python-code slicer.util.getModule(‘BlenderMonitor’).widgetRepresentation().self().test = ‘TESTING’

in the python widget I have

```auto
class BlenderMonitorWidget:
    def __init__ (self, parent = None):
        if not parent:
            self.parent = slicer.qMRMLWidget()
            self.parent.setLayout(qt.QVBoxLayout())
            self.parent.setMRMLScene(slicer.mrmlScene)
        else:
            self.parent = parent
        self.layout = self.parent.layout()
        if not parent:
            self.setup()
            self.parent.show()
        self.watching = True #False before but now we are automating things
        self.sock = None
        self.sliceSock = None
        self.host_address = asyncsock.address[0]
        self.host_port = asyncsock.address[1]
        self.SlicerSelectedModelsList = []
        #self.toSync = []
        #slice list
        self.sliceViewCache = {}
        #self.workingVolume = None
        self.test = None

```

for some reason when I try to set self.test on launch, once 3d slicer starts I check the variable and it is still None.  
how can i set self.test automatically as 3D slicer is loading? I’ve tried it with other variables and it doesn’t seem to work. Thoughts?

Best,  
Georgi

---

<div class="post-metadata">

**Author:** ![mau\_igna\_06](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/mau_igna_06/32/9056_2.png) [@mau\_igna\_06](https://discourse.slicer.org/u/mau_igna_06)\
**Post date:** [June 17, 2022, 8:11am UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/2 "2022-06-17T08:11:16Z")

</div>

Hi Georgi

Did you add your module to the additional-paths ?

---

<div class="post-metadata">

**Author:** ![talmazov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/talmazov/32/3966_2.png) [@talmazov](https://discourse.slicer.org/u/talmazov)\
**Post date:** [June 17, 2022, 12:19pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/3 "2022-06-17T12:19:56Z")

</div>

here?  
I added it before, module loads.  
If i do

```auto
slicer.util.getModule(‘BlenderMonitor’).widgetRepresentation().self().test = ‘TESTING’

```

in the python CLI console once 3d slicer is launched it works. its only on startup via --python-code

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/0/b/0b1581be23b5ddd1fbb241583ef5d69fa01ae168.png)

---

<div class="post-metadata">

**Author:** ![mau\_igna\_06](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/mau_igna_06/32/9056_2.png) [@mau\_igna\_06](https://discourse.slicer.org/u/mau_igna_06)\
**Post date:** [June 17, 2022, 12:45pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/4 "2022-06-17T12:45:21Z")

</div>

Try adding it in the same line of code

When you are opening the app I mean

---

<div class="post-metadata">

**Author:** ![talmazov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/talmazov/32/3966_2.png) [@talmazov](https://discourse.slicer.org/u/talmazov)\
**Post date:** [June 17, 2022, 1:14pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/5 "2022-06-17T13:14:16Z")

</div>

hey,  
apologies but i am not following.  
Do you mean adding the module path via code?  
I found this but the links are broken: [Can I add an "additional module path" with python code](https://discourse.slicer.org/t/can-i-add-an-additional-module-path-with-python-code/6189)

~Georgi

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [June 17, 2022, 6:20pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/6 "2022-06-17T18:20:26Z")

</div>

If a command-line argument contains spaces then you must put the argument between quotes (`"`). If this is cumbersome then you can write your custom startup code into a .py file and run it by using the `--python-script` argument.

Widget representation of a module may not be created or fully initialized until you actually open the module, so you may want to first call `slicer.util.selectedModule('BlenderMonitor')` and then get the module widget.

---

<div class="post-metadata">

**Author:** ![talmazov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/talmazov/32/3966_2.png) [@talmazov](https://discourse.slicer.org/u/talmazov)\
**Post date:** [June 17, 2022, 9:55pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/7 "2022-06-17T21:55:33Z")

</div>

Hey,  
Thank you for the suggestion. Let me provide some more code context.  
Below is my test script I launch from Python IDLE

```auto
import subprocess

slicer_startup_parameters = ''.join((
  "slicer.util.selectModule('BlenderMonitor')\n",
  "slicer.util.getModule('BlenderMonitor').widgetRepresentation().self().connect_to_blender(55)"))
subprocess.Popen(["C:\\ProgramData\\NA-MIC\\Slicer 4.11.20210226\\Slicer.exe", "--python-code", slicer_startup_parameters])

```

below is part of the code from my 3d slicer widget i am trying to work with.

```auto
class BlenderMonitorWidget:
    def __init__ (self, parent = None):
        if not parent:
            self.parent = slicer.qMRMLWidget()
            self.parent.setLayout(qt.QVBoxLayout())
            self.parent.setMRMLScene(slicer.mrmlScene)
        else:
            self.parent = parent
        self.layout = self.parent.layout()
        if not parent:
            self.setup()
            self.parent.show()
        self.host_address = asyncsock.address[0]
        self.host_port = 5959

    def setup(self):
        # Instantiate and connect widgets ...
        
    def connect_to_blender(self, port):
        self.host_port = port
        print(self.host_port)

```

I created a separate function `connect_to_blender(self,port)` that takes int port value when 3D slicer is launched with `--python-code`

the first paramater, `selectModule`, works well and slicer switches to the widget on startup. when `connect_to_blender` is called after, i do not see the print statement in the console when slicer is finished startup and `--python-code` has been fully executed  
 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/d/2/d26710a6896361d89409d8a50d1512b054639e18.png)

and when I try to access `host_port` via the console, the value of the variable has not changed. in `--python-code` i pass int 55, the hard-coded value is 5959  
 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/b/0/b06728acc6a7f628e4f0d5c9023baad9eeec0ac0.png)

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [June 18, 2022, 1:12pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/8 "2022-06-18T13:12:16Z")

</div>

I’m not sure if newline character is acceptable in command-line arguments. If you need to run multiple commands, pass multiple arguments, etc. then it is safer to use `--python-script` argument, see a complete example here: [SlicerRT/BatchProcessing at master · SlicerRt/SlicerRT · GitHub](https://github.com/SlicerRt/SlicerRT/tree/master/BatchProcessing)

---

<div class="post-metadata">

**Author:** ![talmazov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/talmazov/32/3966_2.png) [@talmazov](https://discourse.slicer.org/u/talmazov)\
**Post date:** [June 18, 2022, 2:03pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/9 "2022-06-18T14:03:23Z")

</div>

hey,  
multiline arguments work with --python-code  
The code below, for example, works just fine for me using \t and \n

> ```
> slicer_startup_parameters = ''.join((
> "dicomDataDir = '%s'\n"%os.path.dirname(context.scene.DICOM_dir).replace(os.sep, '/'),
> "loadedNodeIDs = []\n",
> "from DICOMLib import DICOMUtils\n",
> "with DICOMUtils.TemporaryDICOMDatabase() as db:\n",
> "\tDICOMUtils.importDicom(dicomDataDir, db)\n",
> "\tpatientUIDs = db.patients()\n",
> "\tfor patientUID in patientUIDs:\n",
> "\t\tloadedNodeIDs.extend(DICOMUtils.loadPatientByUID(patientUID))\n",
> "slicer.util.selectModule('BlenderMonitor')\n",
> "slicer.util.setSliceViewerLayers(background=slicer.util.getNode(loadedNodeIDs[0]))\n",
> "slicer.util.getModule('BlenderMonitor').widgetRepresentation().self().workingVolume = slicer.util.getNode(loadedNodeIDs[0])"
> ))
> 
> ```

its just that you cannot set variables on startup. I have some ideas how to work around that via configuration file. I just wanted to check if there was a solution to this as it is easier to pass data directly

best,  
Georgi

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [June 18, 2022, 2:26pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/10 "2022-06-18T14:26:00Z")

</div>

Could you provide a complete, minimal example that reproduces the problem? (your `BlenderMonitorWidget` example was not a complete script file that I could use for testing)

Passing of parameters via `--python-code` works welll for example in SlicerJupyter:

> <https://github.com/Slicer/SlicerJupyter/blob/master/JupyterKernel/Resources/kernel-template.json.in>

---

<div class="post-metadata">

**Author:** ![talmazov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/talmazov/32/3966_2.png) [@talmazov](https://discourse.slicer.org/u/talmazov)\
**Post date:** [June 19, 2022, 4:09pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/11 "2022-06-19T16:09:27Z")

</div>

Hey,  
I have provided working examples that you should be able to use to reproduce the problem.  
I am just trying to set the variable self.host\_port on start-up via —python-code

> <https://gist.github.com/talmazov/b294c11c0a6a25fe3c8889cc57419b3a>

BlenderTest.py is the add-on module, please add via additional modules path

start\_slicer.py is the startup code. Please set your 3D slicer install directory.

Keep me posted.

Best,  
Georgi

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [June 20, 2022, 1:24am UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/12 "2022-06-20T01:24:12Z")

</div>

Maybe newline character can be passed through inside command-line arguments in certain situations, but I would not even attempt that. Especially because it is not necessary. You can separate commands by semicolon instead. For example, this works well for me:

```auto
import subprocess

slicer_startup_parameters = """print('Connecting to Blender...')
slicer.util.selectModule('BlenderTest')
slicer.util.getModuleWidget('BlenderTest').connect_to_blender(55)
""".replace('\n', ';')

subprocess.Popen([r"c:\Users\andra\AppData\Local\NA-MIC\Slicer 5.0.2\Slicer.exe", "--python-code", slicer_startup_parameters])

```

Note that on Windows, the Slicer installer registers `Slicer.exe` with the last installed instance, so you can start the application without knowing the full path, like this:

```auto
subprocess.Popen(["Slicer.exe", "--python-code", slicer_startup_parameters])

```

---

<div class="post-metadata">

**Author:** ![talmazov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/talmazov/32/3966_2.png) [@talmazov](https://discourse.slicer.org/u/talmazov)\
**Post date:** [June 28, 2022, 4:50pm UTC](https://discourse.slicer.org/t/setting-widget-variable-from-python-code-on-slicer-exe-start/23908/13 "2022-06-28T16:50:12Z")

</div>

Hey,  
Apologies it took me a while to respond, thank you so much for your help.  
For future reference to those who stumble on this post I would like to elaborate on the solution.  
@lassoan thank you for the suggestion of improving on the string formatting. Use of

> “\n” and “\t”

within the string was not a problem. Although for future reference it is good to know that I can separate commands inline with semicolon “;”  
The real problem was that I was trying to set

> self.host\_port

by accessing

> slicer.util.getModule(‘BlenderMonitor’).widgetRepresentation().self().[widget init var]

Reviewing @lassoan suggestion, widget class functions are more appropriately accessed by the

> slicer.util.getModuleWidget().[widget class method] ()

method. When I switched to getModuleWidget() and wrapped self.host\_port variable in the self.connect\_to\_blender() method I was able to pass and set self.host\_port on widget startup.

TL;DR @lassoan code suggestions worked well, use of semicolon was not necessary and use of \n and \t in string formatting is acceptable when --python-code
