blob: 8c6dcca5aa1a781275b6f024e7315d74f9811b08 [file] [log] [blame]
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001"""Response classes used by urllib.
2
3The base class, addbase, defines a minimal file-like interface,
4including read() and readline(). The typical response object is an
5addinfourl instance, which defines an info() method that returns
6headers and a geturl() method that returns the url.
7"""
8
9class addbase(object):
10 """Base class for addinfo and addclosehook."""
11
12 # XXX Add a method to expose the timeout on the underlying socket?
13
14 def __init__(self, fp):
15 # TODO(jhylton): Is there a better way to delegate using io?
16 self.fp = fp
17 self.read = self.fp.read
18 self.readline = self.fp.readline
19 # TODO(jhylton): Make sure an object with readlines() is also iterable
Antoine Pitroub353c122009-02-11 00:39:14 +000020 if hasattr(self.fp, "readlines"):
21 self.readlines = self.fp.readlines
Jeremy Hylton1afc1692008-06-18 20:49:58 +000022 if hasattr(self.fp, "fileno"):
23 self.fileno = self.fp.fileno
24 else:
25 self.fileno = lambda: None
Raymond Hettinger038018a2011-06-26 14:29:35 +020026
27 def __iter__(self):
28 # Assigning `__iter__` to the instance doesn't work as intended
29 # because the iter builtin does something like `cls.__iter__(obj)`
30 # and thus fails to find the _bound_ method `obj.__iter__`.
31 # Returning just `self.fp` works for built-in file objects but
32 # might not work for general file-like objects.
33 return iter(self.fp)
Jeremy Hylton1afc1692008-06-18 20:49:58 +000034
35 def __repr__(self):
36 return '<%s at %r whose fp = %r>' % (self.__class__.__name__,
37 id(self), self.fp)
38
39 def close(self):
40 self.read = None
41 self.readline = None
42 self.readlines = None
43 self.fileno = None
44 if self.fp: self.fp.close()
45 self.fp = None
46
Jeremy Hyltonb476d592009-03-26 21:34:20 +000047 def __enter__(self):
48 if self.fp is None:
49 raise ValueError("I/O operation on closed file")
50 return self
51
52 def __exit__(self, type, value, traceback):
53 self.close()
54
Jeremy Hylton1afc1692008-06-18 20:49:58 +000055class addclosehook(addbase):
56 """Class to add a close hook to an open file."""
57
58 def __init__(self, fp, closehook, *hookargs):
59 addbase.__init__(self, fp)
60 self.closehook = closehook
61 self.hookargs = hookargs
62
63 def close(self):
64 addbase.close(self)
65 if self.closehook:
66 self.closehook(*self.hookargs)
67 self.closehook = None
68 self.hookargs = None
69
70class addinfo(addbase):
71 """class to add an info() method to an open file."""
72
73 def __init__(self, fp, headers):
74 addbase.__init__(self, fp)
75 self.headers = headers
76
77 def info(self):
78 return self.headers
79
80class addinfourl(addbase):
81 """class to add info() and geturl() methods to an open file."""
82
83 def __init__(self, fp, headers, url, code=None):
84 addbase.__init__(self, fp)
85 self.headers = headers
86 self.url = url
87 self.code = code
88
89 def info(self):
90 return self.headers
91
92 def getcode(self):
93 return self.code
94
95 def geturl(self):
96 return self.url