From b64540e37213b2279d247d7cb2e98e505db953cd Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Wed, 11 Mar 2009 05:48:59 +0000 Subject: For compatibility with python-3.0, inherit from ObjectProxy instead of inheriting directly from file. (trunk r12640) svn path=/main/branches/2.1.6/; revision=12912 --- pym/portage/util.py | 212 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 123 insertions(+), 89 deletions(-) diff --git a/pym/portage/util.py b/pym/portage/util.py index 4ba80b1c5..2b5a1f214 100644 --- a/pym/portage/util.py +++ b/pym/portage/util.py @@ -333,6 +333,65 @@ def writedict(mydict,myfilename,writekey=True): return 0 return 1 +class ObjectProxy(object): + + """ + Object that acts as a proxy to another object, forwarding + attribute accesses and method calls. This can be useful + for implementing lazy initialization. + """ + + def _get_target(self): + raise NotImplementedError(self) + + def __getattribute__(self, attr): + result = object.__getattribute__(self, '_get_target')() + return getattr(result, attr) + + def __setattr__(self, attr, value): + result = object.__getattribute__(self, '_get_target')() + setattr(result, attr, value) + + def __call__(self, *args, **kwargs): + result = object.__getattribute__(self, '_get_target')() + return result(*args, **kwargs) + + def __setitem__(self, key, value): + object.__getattribute__(self, '_get_target')()[key] = value + + def __getitem__(self, key): + return object.__getattribute__(self, '_get_target')()[key] + + def __delitem__(self, key): + del object.__getattribute__(self, '_get_target')()[key] + + def __contains__(self, key): + return key in object.__getattribute__(self, '_get_target')() + + def __iter__(self): + return iter(object.__getattribute__(self, '_get_target')()) + + def __len__(self): + return len(object.__getattribute__(self, '_get_target')()) + + def __repr__(self): + return repr(object.__getattribute__(self, '_get_target')()) + + def __str__(self): + return str(object.__getattribute__(self, '_get_target')()) + + def __hash__(self): + return hash(object.__getattribute__(self, '_get_target')()) + + def __eq__(self, other): + return object.__getattribute__(self, '_get_target')() == other + + def __ne__(self, other): + return object.__getattribute__(self, '_get_target')() != other + + def __nonzero__(self): + return bool(object.__getattribute__(self, '_get_target')()) + class _tolerant_shlex(shlex.shlex): def sourcehook(self, newfile): try: @@ -342,7 +401,7 @@ class _tolerant_shlex(shlex.shlex): (self.infile, str(e)), noiselevel=-1) return (newfile, StringIO.StringIO()) -class _insert_newline_eof(file): +class _insert_newline_eof(ObjectProxy): """ Read functions insert anywhere from 0 and 2 newlines just before eof. This is useful as a workaround for avoiding a silent error in shlex that @@ -350,32 +409,53 @@ class _insert_newline_eof(file): trailing newline after the source statement. """ + def __init__(self, *pargs, **kargs): + ObjectProxy.__init__(self) + object.__setattr__(self, '_file', open(*pargs, **kargs)) + + def _get_target(self): + return object.__getattribute__(self, '_file') + + def __getattribute__(self, attr): + if attr in ('read', 'readline', 'readlines'): + return object.__getattribute__(self, attr) + return getattr(object.__getattribute__(self, '_file'), attr) + def read(self, *args): - if hasattr(self, "_got_eof"): + try: + object.__getattribute__(self, '_got_eof') return "" - rval = file.read(self, *args) + except AttributeError: + pass + rval = object.__getattribute__(self, '_file').read(*args) if rval and not args and rval[-1:] != "\n": rval += "\n" if not rval: - self._got_eof = True + object.__setattr__(self, '_got_eof', True) return "\n" return rval def readline(self, *args): - if hasattr(self, "_got_eof"): + try: + object.__getattribute__(self, '_got_eof') return "" - rval = file.readline(self, *args) + except AttributeError: + pass + rval = object.__getattribute__(self, '_file').readline(*args) if rval and rval[-1:] != "\n": rval += "\n" if not rval: - self._got_eof = True + object.__setattr__(self, '_got_eof', True) rval = "\n" return rval def readlines(self, *args): - if hasattr(self, "_got_eof"): + try: + object.__getattribute__(self, '_got_eof') return [] - lines = file.readlines(self, *args) + except AttributeError: + pass + lines = object.__getattribute__(self, '_file').readlines(*args) if lines and lines[-1][-1:] != "\n": lines[-1] += "\n" return lines @@ -390,7 +470,7 @@ def getconfig(mycfg, tolerant=0, allow_sourcing=False, expand=True): expand_map = {} mykeys = {} try: - f = _insert_newline_eof(mycfg, 'rb') + f = _insert_newline_eof(mycfg) except IOError, e: if e.errno == PermissionDenied.errno: raise PermissionDenied(mycfg) @@ -881,7 +961,7 @@ def apply_secpass_permissions(filename, uid=-1, gid=-1, mode=-1, mask=-1, stat_cached=stat_cached, follow_links=follow_links) return all_applied -class atomic_ofstream(file): +class atomic_ofstream(ObjectProxy): """Write a file atomically via os.rename(). Atomic replacement prevents interprocess interference and prevents corruption of the target file when the write is interrupted (for example, when an 'out of space' @@ -889,71 +969,84 @@ class atomic_ofstream(file): def __init__(self, filename, mode='w', follow_links=True, **kargs): """Opens a temporary filename.pid in the same directory as filename.""" - self._aborted = False + ObjectProxy.__init__(self) + object.__setattr__(self, '_aborted', False) if follow_links: canonical_path = os.path.realpath(filename) - self._real_name = canonical_path + object.__setattr__(self, '_real_name', canonical_path) tmp_name = "%s.%i" % (canonical_path, os.getpid()) try: - super(atomic_ofstream, self).__init__(tmp_name, mode=mode, **kargs) + object.__setattr__(self, '_file', + open(tmp_name, mode=mode, **kargs)) return - except (OSError, IOError), e: + except IOError, e: if canonical_path == filename: raise writemsg("!!! Failed to open file: '%s'\n" % tmp_name, noiselevel=-1) writemsg("!!! %s\n" % str(e), noiselevel=-1) - self._real_name = filename + object.__setattr__(self, '_real_name', filename) tmp_name = "%s.%i" % (filename, os.getpid()) - super(atomic_ofstream, self).__init__(tmp_name, mode=mode, **kargs) + object.__setattr__(self, '_file', open(tmp_name, mode=mode, **kargs)) + + def _get_target(self): + return object.__getattribute__(self, '_file') + + def __getattribute__(self, attr): + if attr in ('close', 'abort', '__del__'): + return object.__getattribute__(self, attr) + return getattr(object.__getattribute__(self, '_file'), attr) def close(self): """Closes the temporary file, copies permissions (if possible), and performs the atomic replacement via os.rename(). If the abort() method has been called, then the temp file is closed and removed.""" - if not self.closed: + f = object.__getattribute__(self, '_file') + real_name = object.__getattribute__(self, '_real_name') + if not f.closed: try: - super(atomic_ofstream, self).close() - if not self._aborted: + f.close() + if not object.__getattribute__(self, '_aborted'): try: - apply_stat_permissions(self.name, os.stat(self._real_name)) + apply_stat_permissions(f.name, os.stat(real_name)) except OperationNotPermitted: pass except FileNotFound: pass - except OSError, oe: # from the above os.stat call + except OSError as oe: # from the above os.stat call if oe.errno in (errno.ENOENT, errno.EPERM): pass else: raise - os.rename(self.name, self._real_name) + os.rename(f.name, real_name) finally: # Make sure we cleanup the temp file # even if an exception is raised. try: - os.unlink(self.name) - except OSError, oe: + os.unlink(f.name) + except OSError as oe: pass def abort(self): """If an error occurs while writing the file, the user should call this method in order to leave the target file unchanged. This will call close() automatically.""" - if not self._aborted: - self._aborted = True + if not object.__getattribute__(self, '_aborted'): + object.__setattr__(self, '_aborted', True) self.close() def __del__(self): """If the user does not explicitely call close(), it is assumed that an error has occurred, so we abort().""" - if not self.closed: + f = object.__getattribute__(self, '_file') + if not f.closed: self.abort() # ensure destructor from the base class is called - base_destructor = getattr(super(atomic_ofstream, self), '__del__', None) + base_destructor = getattr(ObjectProxy, '__del__', None) if base_destructor is not None: - base_destructor() + base_destructor(self) def write_atomic(file_path, content): f = None @@ -1001,65 +1094,6 @@ def ensure_dirs(dir_path, *args, **kwargs): perms_modified = apply_permissions(dir_path, *args, **kwargs) return created_dir or perms_modified -class ObjectProxy(object): - - """ - Object that acts as a proxy to another object, forwarding - attribute accesses and method calls. This can be useful - for implementing lazy initialization. - """ - - def _get_target(self): - raise NotImplementedError(self) - - def __getattribute__(self, attr): - result = object.__getattribute__(self, '_get_target')() - return getattr(result, attr) - - def __setattr__(self, attr, value): - result = object.__getattribute__(self, '_get_target')() - setattr(result, attr, value) - - def __call__(self, *args, **kwargs): - result = object.__getattribute__(self, '_get_target')() - return result(*args, **kwargs) - - def __setitem__(self, key, value): - object.__getattribute__(self, '_get_target')()[key] = value - - def __getitem__(self, key): - return object.__getattribute__(self, '_get_target')()[key] - - def __delitem__(self, key): - del object.__getattribute__(self, '_get_target')()[key] - - def __contains__(self, key): - return key in object.__getattribute__(self, '_get_target')() - - def __iter__(self): - return iter(object.__getattribute__(self, '_get_target')()) - - def __len__(self): - return len(object.__getattribute__(self, '_get_target')()) - - def __repr__(self): - return repr(object.__getattribute__(self, '_get_target')()) - - def __str__(self): - return str(object.__getattribute__(self, '_get_target')()) - - def __hash__(self): - return hash(object.__getattribute__(self, '_get_target')()) - - def __eq__(self, other): - return object.__getattribute__(self, '_get_target')() == other - - def __ne__(self, other): - return object.__getattribute__(self, '_get_target')() != other - - def __nonzero__(self): - return bool(object.__getattribute__(self, '_get_target')()) - class LazyItemsDict(dict): """A mapping object that behaves like a standard dict except that it allows for lazy initialization of values via callable objects. Lazy items can be -- cgit v1.2.3-1-g7c22