comparison mercurial/util.py @ 36395:01e29e885600

util: add a file object proxy that can read at most N bytes Sometimes we have data of a known size within a stream. For performance reasons, we don't want to pre-read this data (we want to allow consumers to read on demand). For simplicitly reasons, we don't want callers to necessarily know their data is coming from within an outer stream and there is a limit to how much they should read. The class introduced by this commit provides a very simple proxy around an underlying file object that allows the consumer to .read() up to N bytes from the file object. Attempts to read past this many bytes results in a simulated EOF. Differential Revision: https://phab.mercurial-scm.org/D2377
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 21 Feb 2018 13:41:20 -0800
parents 1fa33bd848ee
children 0cb09c322647
comparison
equal deleted inserted replaced
36394:a2d11d23bb25 36395:01e29e885600
1977 if not s: 1977 if not s:
1978 break 1978 break
1979 if limit: 1979 if limit:
1980 limit -= len(s) 1980 limit -= len(s)
1981 yield s 1981 yield s
1982
1983 class cappedreader(object):
1984 """A file object proxy that allows reading up to N bytes.
1985
1986 Given a source file object, instances of this type allow reading up to
1987 N bytes from that source file object. Attempts to read past the allowed
1988 limit are treated as EOF.
1989
1990 It is assumed that I/O is not performed on the original file object
1991 in addition to I/O that is performed by this instance. If there is,
1992 state tracking will get out of sync and unexpected results will ensue.
1993 """
1994 def __init__(self, fh, limit):
1995 """Allow reading up to <limit> bytes from <fh>."""
1996 self._fh = fh
1997 self._left = limit
1998
1999 def read(self, n=-1):
2000 if not self._left:
2001 return b''
2002
2003 if n < 0:
2004 n = self._left
2005
2006 data = self._fh.read(min(n, self._left))
2007 self._left -= len(data)
2008 assert self._left >= 0
2009
2010 return data
1982 2011
1983 def makedate(timestamp=None): 2012 def makedate(timestamp=None):
1984 '''Return a unix timestamp (or the current time) as a (unixtime, 2013 '''Return a unix timestamp (or the current time) as a (unixtime,
1985 offset) tuple based off the local timezone.''' 2014 offset) tuple based off the local timezone.'''
1986 if timestamp is None: 2015 if timestamp is None: