blob: b43e57595b0ca67f15b9988f27a1b8930126f65a [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):
Brett Cannone73b2bb2011-03-15 18:45:13 -040040 if self.fp:
41 self.fp.close()
42 self.fp = None
Jeremy Hylton1afc1692008-06-18 20:49:58 +000043 self.read = None
44 self.readline = None
45 self.readlines = None
46 self.fileno = None
Brett Cannone73b2bb2011-03-15 18:45:13 -040047 self.__iter__ = None
48 self.__next__ = None
Jeremy Hylton1afc1692008-06-18 20:49:58 +000049
Jeremy Hyltonb476d592009-03-26 21:34:20 +000050 def __enter__(self):
51 if self.fp is None:
52 raise ValueError("I/O operation on closed file")
53 return self
54
55 def __exit__(self, type, value, traceback):
56 self.close()
57
Jeremy Hylton1afc1692008-06-18 20:49:58 +000058class addclosehook(addbase):
59 """Class to add a close hook to an open file."""
60
61 def __init__(self, fp, closehook, *hookargs):
62 addbase.__init__(self, fp)
63 self.closehook = closehook
64 self.hookargs = hookargs
65
66 def close(self):
67 addbase.close(self)
68 if self.closehook:
69 self.closehook(*self.hookargs)
70 self.closehook = None
71 self.hookargs = None
72
73class addinfo(addbase):
74 """class to add an info() method to an open file."""
75
76 def __init__(self, fp, headers):
77 addbase.__init__(self, fp)
78 self.headers = headers
79
80 def info(self):
81 return self.headers
82
83class addinfourl(addbase):
84 """class to add info() and geturl() methods to an open file."""
85
86 def __init__(self, fp, headers, url, code=None):
87 addbase.__init__(self, fp)
88 self.headers = headers
89 self.url = url
90 self.code = code
91
92 def info(self):
93 return self.headers
94
95 def getcode(self):
96 return self.code
97
98 def geturl(self):
99 return self.url