how to acces the block inside of a context manager as sourcecode

D

Daniel

Hello,

I need to access the code inside of a context manager, i.e. the call to

with myManager(v=5) as x:
a=b
c=sin(x)


should cause the following output (minus the first line, if that's easier):


with myManager(v=5) as x: # I could live without this line
a=b
c=sin(x)


I can get the line number from the traceback (see below), and try to
find the block in the source, but that seems ugly to me.



class MyManager(object):
def __init__(self,name='name'):
# how to access the source code inside of the with block ?
f = traceback.extract_stack()
print f[0]

def __enter__(self):
pass

def __exit__(self,type,value,traceback):
if type is not None:
print 'exception'
pass



Any ideas?

Daniel
 
A

Aaron Brady

Hello,

I need to access the code inside of a context manager, i.e. the call to

with myManager(v=5) as x:
        a=b
        c=sin(x)

should cause the following output (minus the first line, if that's easier):

with myManager(v=5) as x: # I could live without this line
        a=b
        c=sin(x)

I can get the line number from the traceback (see below), and try to
find the block in the source, but that seems ugly to me.

class MyManager(object):
    def __init__(self,name='name'):
        # how to access the source code inside of the with block ?
        f = traceback.extract_stack()
        print f[0]

    def __enter__(self):
        pass

    def __exit__(self,type,value,traceback):
        if type is not None:
            print 'exception'
        pass

Any ideas?

Daniel

There isn't a solution in the general case, because strings can be
executed. However, 'inspect.currentframe()' and
'inspect.getsourcelines(object)' can handle some cases, and your idea
is (I believe) how getsourcelines works itself. You can probably do
it without a context manager, e.g. 'print_next_lines( 5 )' or
'print_prior_lines( 2 )', dedenting as needed.
 
D

Daniel

Hi Aaron,

let me give you the reason for the context manager:
I am driving handware with a python script, basically a data acquisition
program which looks like this:


with dataStore('measurement1.dat') as d:
magnet.setField(0)
r1=doExperiment(voltage=0.345, current=0.346, temperature=33)
magnet.setField(1)
r2=doExperiment(voltage=0.32423, current=0.3654, temperature=45)
d.append(r2-r1)

the script does the measuring and the context manager stores the result
(r1 and r2), at the end the result is printed.

The source code serves as the documentation (it contains many parameters
that need to be well documented), so I print the source code, cut it out
and glue it into my lab notebook.
Now I want to automate this process, i.e. the dataStore should print the
sourcecode.

Daniel
 
A

Aaron Brady

See below.

Hi Aaron,

let me give you the reason for the context manager:
I am driving handware with a python script, basically a data acquisition
program which looks like this:

with dataStore('measurement1.dat') as d:
        magnet.setField(0)
        r1=doExperiment(voltage=0.345, current=0.346, temperature=33)
        magnet.setField(1)
        r2=doExperiment(voltage=0.32423, current=0.3654, temperature=45)
        d.append(r2-r1)

the script does the measuring and the context manager stores the result
(r1 and r2), at the end the result is printed.

The source code serves as the documentation (it contains many parameters
that need to be well documented), so I print the source code, cut it out
and glue it into my lab notebook.
Now I want to automate this process, i.e. the dataStore should print the
sourcecode.

Daniel

Hi. It is not the role of a 'dataStore' object in your object model,
which is why, ideally, you would separate those two functions.
However, if 'dataStore' always needs the printing functionality, you
could built it in for practical reasons. That has the benefit that
you don't need to specify, such as 'print_next_lines( 5 )', how many
lines to print, since the context manager can count for you, and if
you add a line, you won't need to change to 'print_next_lines( 6 )'.
Lastly, you could use two con. managers, such as:

with printing:
with dataStore('measurement1.dat') as d:
magnet.setField(0)

You may or may not find that relevant.

Here is some code and output:

import inspect
class CM( object ):
def __enter__(self):
self.startline= inspect.stack( )[ 1 ][ 0 ].f_lineno
def __exit__(self, exc_type, exc_value, traceback):
endline= inspect.stack( )[ 1 ][ 0 ].f_lineno
print self.startline, endline

with CM(): #line 9
a= 0
b= 1
c= 2

with CM(): #line 14
d= 3
e= 4

/Output:

9 12
14 16
 
D

Daniel

Hi Aaron,

the dataStore combines both the printing and analysis (it will create a
report).
Unfortunately the end of the block already needs to be known in
__enter__, as the report starts to print during the measurement.
I decided to do it the following way:

__enter__ gets the start line number using the idea you proposed.
then the program reads the number of lines that are indented with
respect to the with block. This could cause problems for strange
indenting, but this should not happen in my application. Unfortunately I
could not use the ast module, because the comments are an important part
of the report.

Thank you for your ideas

Daniel




class CM( object ):
def __enter__(self):
self.startline= inspect.stack( )[ 1 ][ 0 ].f_lineno
print 'startline',self.startline
filename = inspect.stack( )[-1][1]

def getIndentation(line):
# TODO: handle comments and docstrings correctly
return len(line) - len(line.lstrip())

with open(filename,'r') as f:
lines=f.readlines()[self.startline-1:]
indent0=getIndentation(lines[0])
indent =[getIndentation(i)-indent0 for i in lines[1:]]
nlines = [n for l,n in zip(indent,xrange(1,1000000)) if l >
0][0]
self.callingCode = lines[:self.startline+nlines]

print self.callingCode


def __exit__(self, exc_type, exc_value, traceback):
pass

if __name__ == '__main__':
with CM():
print 'in first'
a= 0
b= 1
c= 2
print 'end of first'

with CM():
d= 3
e= 4
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top