getting file size for all dict files to be downloaded. coming to be 400mb or so.
[worddb.git] / libs / openid / yadis / manager.py
blob709adb7d49e30b35be41e8e57de5db108c00bc0b
1 class YadisServiceManager(object):
2 """Holds the state of a list of selected Yadis services, managing
3 storing it in a session and iterating over the services in order."""
5 def __init__(self, starting_url, yadis_url, services, session_key):
6 # The URL that was used to initiate the Yadis protocol
7 self.starting_url = starting_url
9 # The URL after following redirects (the identifier)
10 self.yadis_url = yadis_url
12 # List of service elements
13 self.services = list(services)
15 self.session_key = session_key
17 # Reference to the current service object
18 self._current = None
20 def __len__(self):
21 """How many untried services remain?"""
22 return len(self.services)
24 def __iter__(self):
25 return self
27 def next(self):
28 """Return the next service
30 self.current() will continue to return that service until the
31 next call to this method."""
32 try:
33 self._current = self.services.pop(0)
34 except IndexError:
35 raise StopIteration
36 else:
37 return self._current
39 def current(self):
40 """Return the current service.
42 Returns None if there are no services left.
43 """
44 return self._current
46 def forURL(self, url):
47 return url in [self.starting_url, self.yadis_url]
49 def started(self):
50 """Has the first service been returned?"""
51 return self._current is not None
53 def store(self, session):
54 """Store this object in the session, by its session key."""
55 session[self.session_key] = self
57 class Discovery(object):
58 """State management for discovery.
60 High-level usage pattern is to call .getNextService(discover) in
61 order to find the next available service for this user for this
62 session. Once a request completes, call .finish() to clean up the
63 session state.
65 @ivar session: a dict-like object that stores state unique to the
66 requesting user-agent. This object must be able to store
67 serializable objects.
69 @ivar url: the URL that is used to make the discovery request
71 @ivar session_key_suffix: The suffix that will be used to identify
72 this object in the session object.
73 """
75 DEFAULT_SUFFIX = 'auth'
76 PREFIX = '_yadis_services_'
78 def __init__(self, session, url, session_key_suffix=None):
79 """Initialize a discovery object"""
80 self.session = session
81 self.url = url
82 if session_key_suffix is None:
83 session_key_suffix = self.DEFAULT_SUFFIX
85 self.session_key_suffix = session_key_suffix
87 def getNextService(self, discover):
88 """Return the next authentication service for the pair of
89 user_input and session. This function handles fallback.
92 @param discover: a callable that takes a URL and returns a
93 list of services
95 @type discover: str -> [service]
98 @return: the next available service
99 """
100 manager = self.getManager()
101 if manager is not None and not manager:
102 self.destroyManager()
104 if not manager:
105 yadis_url, services = discover(self.url)
106 manager = self.createManager(services, yadis_url)
108 if manager:
109 service = manager.next()
110 manager.store(self.session)
111 else:
112 service = None
114 return service
116 def cleanup(self, force=False):
117 """Clean up Yadis-related services in the session and return
118 the most-recently-attempted service from the manager, if one
119 exists.
121 @param force: True if the manager should be deleted regardless
122 of whether it's a manager for self.url.
124 @return: current service endpoint object or None if there is
125 no current service
127 manager = self.getManager(force=force)
128 if manager is not None:
129 service = manager.current()
130 self.destroyManager(force=force)
131 else:
132 service = None
134 return service
136 ### Lower-level methods
138 def getSessionKey(self):
139 """Get the session key for this starting URL and suffix
141 @return: The session key
142 @rtype: str
144 return self.PREFIX + self.session_key_suffix
146 def getManager(self, force=False):
147 """Extract the YadisServiceManager for this object's URL and
148 suffix from the session.
150 @param force: True if the manager should be returned
151 regardless of whether it's a manager for self.url.
153 @return: The current YadisServiceManager, if it's for this
154 URL, or else None
156 manager = self.session.get(self.getSessionKey())
157 if (manager is not None and (manager.forURL(self.url) or force)):
158 return manager
159 else:
160 return None
162 def createManager(self, services, yadis_url=None):
163 """Create a new YadisService Manager for this starting URL and
164 suffix, and store it in the session.
166 @raises KeyError: When I already have a manager.
168 @return: A new YadisServiceManager or None
170 key = self.getSessionKey()
171 if self.getManager():
172 raise KeyError('There is already a %r manager for %r' %
173 (key, self.url))
175 if not services:
176 return None
178 manager = YadisServiceManager(self.url, yadis_url, services, key)
179 manager.store(self.session)
180 return manager
182 def destroyManager(self, force=False):
183 """Delete any YadisServiceManager with this starting URL and
184 suffix from the session.
186 If there is no service manager or the service manager is for a
187 different URL, it silently does nothing.
189 @param force: True if the manager should be deleted regardless
190 of whether it's a manager for self.url.
192 if self.getManager(force=force) is not None:
193 key = self.getSessionKey()
194 del self.session[key]