i tried to juggle things around with a
__getattr__()
method and finally eliminated the recursion. but it still ran a finite
2 times. no idea why that happens. but i will try
__getattribute__()
and see if i can make that work.
the class is emulating
open() and is intercepting
close(). it needs to pass everything else straight through. it's a no-compress version of the class described
here.
i know you want to see my code. please focus on this issue in this thread.
this it class topen in file "topen.py":
import io,os,sys,time
_separator = '_'
class topen(io.IOBase):
"""Class for opening a file with temporary output name and automatic rename on close if write."""
# this class also adds the name= keyword argument (no default)
# name is require by positional args or by keyword args
# this class is like ztopen but without compression
def __init__(self,*args,**kwargs):
if args:
args = list(args)
if 'name' in kwargs:
raise TypeError('name given twice')
fname = args.pop(0)
if args:
if 'mode' in kwargs:
raise TypeError('mode given twice')
modes = args.pop(0)
elif 'mode' in kwargs:
modes = kwargs.pop('mode')
else:
raise TypeError('mode not given')
elif 'name' in kwargs:
fname = kwargs.pop('name')
modes = kwargs.pop('mode','r')
else:
raise TypeError('name not given')
if 'x' in modes and isinstance(fname,(str,bytes)) and os.path.exists(fname):
raise TypeError(f'{fname!r} refers to a name that already exists')
fname = os.fspath(fname)
if isinstance(fname,bytes):
fname = ''.join(chr(x)for x in fname)
if isinstance(modes,bytes):
modes = ''.join(chr(x)for x in modes)
if isinstance(fname,str) and '+' not in modes:
rname = 'x' in modes or 'w' in modes
oname = fname+_separator+str(int(time.time()*3906250)) if rname else fname
elif isinstance(fname,int):
rname = False
oname = fname
else:
raise TypeError()
print(f'opening file {oname!r} with mode {modes!r}',file=sys.stderr,flush=1)
ofile = open(oname,modes,*args,**kwargs)
if ofile is None:
raise(f'failed to open file {oname!r}')
self.rname = rname
self.ofile = ofile
self.oname = oname
self.fname = fname
def close(self):
if self.rname:
print(f'close {self.oname!r} and rename it to {self.fname!r}',file=sys.stderr,flush=1)
self.ofile.close()
return os.rename(self.oname,self.fname)
else:
print(f'close {self.oname!r}',file=sys.stderr,flush=1)
return self.ofile.close()
def __getattr__(self,*args):
print(f'__getattr__ for {args!r}',file=sys.stderr,flush=1)
return getattr(self.ofile,*args)
here is the test script in file "trytopen.py":
from topen import topen
f=topen('foo','w')
print('bar',file=f)
f.close()
i plan to try with
with in test 2 or 3.
here is the output i get:
Output:
lt2a/phil /home/phil 188> py trytopen.py
opening file 'foo_6224487216638762' with mode 'w'
__getattr__ for ('write',)
__getattr__ for ('write',)
close 'foo_6224487216638762' and rename it to 'foo'
__getattr__ for ('__IOBase_closed',)
close 'foo_6224487216638762' and rename it to 'foo'
lt2a/phil /home/phil 189>