-1

minimum working code :

step1_failed = False
try:
    print("step #1")
except:
    step1_failed = True
print("step #2")  # always appening after step #1 but before step #3 regardless of if step #1 failed or not
if not step1_failed:
    print("step #3") # only if step #1 execute without error

My question is : is there a better way of doing this that i don't see ?

Ideally without any dummy variable like step1_failed.

I thought that maybe "finally" and "else" was the answers but finally happen after the else and i need to do something before the else statement.

The use case of this is for PyQt5, I want to disconnect a signal and reconnect it after doing something to avoid unwanted recursion. But I need to reconnect it, only if it was connected at first.

Here is my PyQt5 code to understand why i need this :

def somefunction():
    connected_at_first = True  # assuming it was connected
    try:
        lineedit1.textChanged.disconnect(somefunction)  # throw a TypeError if it is not connected
    except TypeError:
        connected_at_first = False  # happen only if lineedit1 wasn't connected

    lineedit1.setText("always happening !")

    # reconnecting lineedit1 if it was connected at the beginning
    if connected_at_first:
        lineedit1.textChanged.connect(somefunction)
patate1684
  • 639
  • 3
  • 17
  • I can't put step #2 as the last line before except because if step #1 fail, step #2 will not be execute. I need step #2 to always be execute regardless of step #1. – patate1684 Jul 15 '21 at 15:52
  • 1
    @not_speshal OP says step 2 has to happen before step 3 – ChrisOram Jul 15 '21 at 15:52
  • https://stackoverflow.com/q/21586643/1126841 is related, if not a duplicate. – chepner Jul 15 '21 at 15:53
  • I found stackoverflow.com/q/21586643/1126841 before posting this question but it's not really what i am looking for. this question is more about how to change connection from one to another and not about doing something in the middle. – patate1684 Jul 15 '21 at 15:57

3 Answers3

1

If you want to avoid recursion, you can use blockSignals():

def somefunction():
    blocked = lineedit1.blockSignals(True)
    lineedit1.setText("always happening !")
    lineedit1.blockSignals(blocked)

Otherwise, use a simple flag:

class SomeClass(QtWidgets.QWidget):
    signalFlag = False
    # ...
    def somefunction(self):
        if self.signalFlag:
            return
        self.signalFlag = True
        self.lineEdit.setText("always happening !")
        self.signalFlag = False
musicamante
  • 41,230
  • 6
  • 33
  • 58
1

I don't know if there's a cleaner way, but your approach can be wrapped in a context manager.

from contextlib import contextmanager

def tempdisconnect(o, f)
    connected = True
    try:
        o.disconnect(f)
    except TypeError:
        connected = False

    yield

    if connected:
        o.connect(f)

with tempdisconnect(lineedit1.textChanged, somefunction):
    lineedit1.setText("always happening !")

A better API for disconnect would be to return either the function being disconnected (similar to how signal.signal works), or return None. Then tempdisconnect could be written

def tempdisconnect(o, f):
    old = o.disconnect(f)
    yield
    o.connect(old)

This also assumes that o.connect(None) is a no-op, so that it remains unconnected before and after the body of the with statement.

chepner
  • 497,756
  • 71
  • 530
  • 681
0

Base on the answers of chepner, I modified his code to be able to remove duplicate connect of the same function and to handle multiple function.

from contextlib import contextmanager

@contextmanager
def tempdisconnect(signal, func):
    if not isinstance(func, (tuple, list)):
        func = (func,)
    connected = [True] * len(func)

    for i in range(len(func)):
        a = 0
        try:
            while True:
                signal.disconnect(func[i])
                a += 1
        except TypeError:
            if a == 0:
                connected[i] = False

    yield

    if connected != False:
        for i in range(len(func)):
            if connected[i]:
                signal.connect(func[i])

usage :

# Disconnect somefunction (even if it was accidently connected multiple times)
with tempdisconnect(lineEdit1.textChanged, somefunction):
    lineEdit1.setText("hello")

or

# Disconnect somefunc1, somefunc2, somefunc3
with tempdisconnect(lineEdit1.textChanged, (somefunc1, somefunc2, somefunc3)):
    lineEdit1.setText("hello")
patate1684
  • 639
  • 3
  • 17