-1

I have an app that creates Python code and runs it. During this process there are two method assignments that I'd like to clear as they create an error in the second run:

push = Writer.Push  
...  
def appPush(self):
    push(self)
    dumpRow(self)
...  
Writer.Push=appPush

It's a legacy code I have to fix. If you run this more than once, Python announces that there's a recursion.
I've been looking for a way to clear the environment but 'os.system('CLS')' didn't help. How can I clean those assignments?
Thanks.

Edit:
It IS legacy code. I'm not very familiar with it yet. My app creates Python code that contains general stuff (like the bit I've posted above) and a translation of the user's workflow to Python. If the user creates a flow that ends up calling 'appPush', the application has to be restarted after 1 run.
I can add stuff after the above code. What I'm looking for is a way to clear the interpreter's environment from those assignment. Is it possible?

Noich
  • 14,631
  • 15
  • 62
  • 90
  • 1
    Do you want to clear the console? – UltraInstinct Jul 09 '12 at 11:50
  • I don't want a clear screen (no need for many \n). I want those assignments undone somehow. – Noich Jul 09 '12 at 11:51
  • 2
    I need to see more code to understand your problem. `os.system('cls')` is *not* what you want there. – cha0site Jul 09 '12 at 11:52
  • This is the problem. Those 2 assignments cause a recursion together when code containing them runs more than once. 'appPush' is calling itself recursively. – Noich Jul 09 '12 at 11:54
  • If it's written the way you currently have it, where everything is in the same method or whatever, it shouldn't call itself recursively because it would be a different `appPush` every time. It might call `dumpRow` more times then you want, though. So I'm asking for more context to see how you're getting recursion here. – cha0site Jul 09 '12 at 11:58
  • Can't you change the creation of these assignments directly in the "app that creates python code" ? If not, I guess it's because it's legacy, right ? Where exactly do you want to control the situation ? – Emmanuel Jul 09 '12 at 12:01

3 Answers3

2

OK, I see what your problem is.

This code:

push = Writer.Push  
def appPush(self):
    push(self)
    dumpRow(self)
Writer.Push=appPush

Would cause infinite recursion if push were ever changed to appPush. What you basically want there is a decorator, so if you could change that to:

def appPushCreator(func):
    def appPush(self):
        func(self)
        dumpRow(self)
    return appPush

Writer.Push = appPushCreator(Writer.Push)

This would keep the implied semantics of doing another dumpRow every time you used that bit of code.

I don't think you can fix your error by only adding code after the broken bit. You can't 'clear the environment' and get your original Writer.Push back.

cha0site
  • 10,517
  • 3
  • 33
  • 51
  • This seems to be just the thing I needed, Thanks! Now I'd like to dig in some documentation so I can understand it completely. Any recommendations? – Noich Jul 09 '12 at 12:56
  • 1
    @Noich: This actually runs into some subtlety with Python's lexical closure definition. It's the sort of fun you encounter when you use functional programming but don't disallow side-effects. It's discussed in this SO question: http://stackoverflow.com/questions/233673/lexical-closures-in-python – cha0site Jul 09 '12 at 14:46
1

Something like this should work:

real_push = None
if real_push is None:
    real_push = push
Writer.Push = real_push

It might work better to put in code before the broken code:

real_push = None
if real_push is None:
    real_push = Writer.Push
Writer.Push = real_push

Essentially you're trying to make the code idempotent i.e. running it more than once has the same effect as running it once.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
0

You can't just test Writer.Push is appPush in Python 2.x because Writer.Push gets wrapped in an unbound method, but you can access attributes on Writer.Push and they go through to the original function. Also, if you use an attribute that means it doesn't matter if you don't have the original patch function around to test against. That means this should work:

def appPush(self):
    push(self)
    dumpRow(self)
appPush.is_patch = True
...

if not hasattr(Writer.Push, 'is_patch'):
    push = Writer.Push
    Writer.Push=appPush

Note that you want to move the assignment to push inside the if to avoid overwriting it when the code runs for a second time.

Duncan
  • 92,073
  • 11
  • 122
  • 156