Merge lp:~sinzui/launchpad/dedup-preferred-launguages-0 into lp:launchpad

Proposed by Curtis Hovey on 2010-09-12
Status: Merged
Approved by: Aaron Bentley on 2010-09-13
Approved revision: 11539
Merged at revision: 11549
Proposed branch: lp:~sinzui/launchpad/dedup-preferred-launguages-0
Merge into: lp:launchpad
Diff against target: 511 lines (+93/-82) 18 files modified
To merge this branch: bzr merge lp:~sinzui/launchpad/dedup-preferred-launguages-0
Reviewer Review Type Date Requested Status
Aaron Bentley 2010-09-12 Approve on 2010-09-13
Review via email: mp+35228@code.launchpad.net

Description of the Change

This is my branch to move geoip to lp.services so that I can fix a bug.

    lp:~sinzui/launchpad/dedup-preferred-launguages-0
    Diff size: 512
    Launchpad bug:
          https://bugs.launchpad.net/bugs/636453
    Test command: ./bin/test -vv -m geoip
    Pre-implementation: no one
    Target release: 10.10

Move geoip to lp.services
-------------------------

The fix for the duplicate preferred language requires a change to the
geoip module which is in a deprecated location. The code should be migrated
before the fix is made.

Rules
-----

    * Move geoip to lp.services.geoip.
    * Move geoip's components to lp.services.geoip.helpers

QA
--

    * View your preferred languages.
    * Verify the page states your browser and location languages.

Lint
----

Linting changed files:
  lib/canonical/launchpad/configure.zcml
  lib/canonical/launchpad/helpers.py
  lib/canonical/launchpad/interfaces/__init__.py
  lib/canonical/launchpad/zcml/configure.zcml
  lib/canonical/widgets/location.py
  lib/lp/registry/browser/distribution.py
  lib/lp/registry/browser/person.py
  lib/lp/services/configure.zcml
  lib/lp/services/geoip/
  lib/lp/services/apachelogparser/base.py
  lib/lp/services/geoip/__init__.py
  lib/lp/services/geoip/configure.zcml
  lib/lp/services/geoip/doc/
  lib/lp/services/geoip/helpers.py
  lib/lp/services/geoip/model.py
  lib/lp/services/geoip/tests/
  lib/lp/services/geoip/doc/geoip.txt
  lib/lp/services/geoip/tests/test_doc.py
  lib/lp/services/geoip/tests/test_request_country.py
  lib/lp/translations/browser/translations.py
  lib/lp/translations/doc/preferred-languages.txt

Test
----

No test changes, but I renamed test_request_country.py to test_doc.py and
revised it to run doctests from the doc dir and inline doctests from the
module.

Implementation
--------------

The is mostly mechanical changes to import or stylistic changes to quiet
lint. Note that I consilodated the lp.services ZCML registrations in
lib/lp/services/configure.zcml.

To post a comment you must log in.
Aaron Bentley (abentley) :
review: Approve

Preview Diff

1=== modified file 'lib/canonical/launchpad/configure.zcml'
2--- lib/canonical/launchpad/configure.zcml 2010-08-17 13:58:57 +0000
3+++ lib/canonical/launchpad/configure.zcml 2010-09-12 16:06:00 +0000
4@@ -31,8 +31,6 @@
5 <include package="lp.translations" />
6 <include package="lp.testopenid" />
7 <include package="lp.blueprints" />
8- <include package="lp.services.comments" />
9- <include package="lp.services.fields" />
10 <include package="lp.vostok" />
11
12 <browser:url
13
14=== modified file 'lib/canonical/launchpad/helpers.py'
15--- lib/canonical/launchpad/helpers.py 2010-08-20 20:31:18 +0000
16+++ lib/canonical/launchpad/helpers.py 2010-09-12 16:06:00 +0000
17@@ -25,18 +25,18 @@
18 from zope.security.interfaces import ForbiddenAttribute
19
20 import canonical
21-from canonical.launchpad.interfaces import (
22- ILaunchBag,
23+from canonical.launchpad.interfaces import ILaunchBag
24+from lp.services.geoip.interfaces import (
25 IRequestLocalLanguages,
26 IRequestPreferredLanguages,
27 )
28
29-# pylint: disable-msg=W0102
30+
31 def text_replaced(text, replacements, _cache={}):
32 """Return a new string with text replaced according to the dict provided.
33
34- The keys of the dict are substrings to find, the values are what to replace
35- found substrings with.
36+ The keys of the dict are substrings to find, the values are what to
37+ replace found substrings with.
38
39 :arg text: An unicode or str to do the replacement.
40 :arg replacements: A dictionary with the replacements that should be done
41@@ -78,13 +78,16 @@
42 # Make a copy of the replacements dict, as it is mutable, but we're
43 # keeping a cached reference to it.
44 replacements_copy = dict(replacements)
45+
46 def matchobj_replacer(matchobj):
47 return replacements_copy[matchobj.group()]
48+
49 regexsub = re.compile(join_char.join(L)).sub
50+
51 def replacer(s):
52 return regexsub(matchobj_replacer, s)
53+
54 _cache[cachekey] = replacer
55-
56 return _cache[cachekey](text)
57
58
59@@ -98,7 +101,7 @@
60 def join_lines(*lines):
61 """Concatenate a list of strings, adding a newline at the end of each."""
62
63- return ''.join([ x + '\n' for x in lines ])
64+ return ''.join([x + '\n' for x in lines])
65
66
67 def string_to_tarfile(s):
68@@ -169,7 +172,7 @@
69 in the database.
70 """
71 # All chars should be lower case, underscores and spaces become dashes.
72- return text_replaced(invalid_name.lower(), {'_': '-', ' ':'-'})
73+ return text_replaced(invalid_name.lower(), {'_': '-', ' ': '-'})
74
75
76 def browserLanguages(request):
77@@ -193,8 +196,7 @@
78
79 p = subprocess.Popen(
80 command, env=env, stdin=subprocess.PIPE,
81- stdout=subprocess.PIPE, stderr=subprocess.STDOUT
82- )
83+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
84 (output, nothing) = p.communicate(input)
85 return output
86
87@@ -247,7 +249,7 @@
88 3: {'.': ' (!) ',
89 '@': ' (at) '},
90 4: {'.': ' {dot} ',
91- '@': ' {at} '}
92+ '@': ' {at} '},
93 }
94
95
96@@ -444,12 +446,13 @@
97 >>> filenameToContentType('test.tgz')
98 'application/octet-stream'
99 """
100- ftmap = {".dsc": "text/plain",
101- ".changes": "text/plain",
102- ".deb": "application/x-debian-package",
103- ".udeb": "application/x-debian-package",
104- ".txt": "text/plain",
105- ".txt.gz": "text/plain", # For the build master logs
106+ ftmap = {".dsc": "text/plain",
107+ ".changes": "text/plain",
108+ ".deb": "application/x-debian-package",
109+ ".udeb": "application/x-debian-package",
110+ ".txt": "text/plain",
111+ # For the build master logs
112+ ".txt.gz": "text/plain",
113 }
114 for ending in ftmap:
115 if fname.endswith(ending):
116
117=== modified file 'lib/canonical/launchpad/interfaces/__init__.py'
118--- lib/canonical/launchpad/interfaces/__init__.py 2010-08-20 12:42:25 +0000
119+++ lib/canonical/launchpad/interfaces/__init__.py 2010-09-12 16:06:00 +0000
120@@ -71,7 +71,6 @@
121 from lp.bugs.interfaces.externalbugtracker import *
122 from lp.registry.interfaces.featuredproject import *
123 from lp.soyuz.interfaces.files import *
124-from canonical.launchpad.interfaces.geoip import *
125 from lp.registry.interfaces.gpg import *
126 from canonical.launchpad.interfaces.gpghandler import *
127 from lp.hardwaredb.interfaces.hwdb import *
128
129=== modified file 'lib/canonical/launchpad/zcml/configure.zcml'
130--- lib/canonical/launchpad/zcml/configure.zcml 2010-08-11 15:47:27 +0000
131+++ lib/canonical/launchpad/zcml/configure.zcml 2010-09-12 16:06:00 +0000
132@@ -37,7 +37,6 @@
133 <!-- Event configuration -->
134
135 <!-- Special Utilities -->
136- <include file="geoip.zcml" />
137 <include file="gpghandler.zcml" />
138 <include file="searchservice.zcml" />
139
140
141=== modified file 'lib/canonical/widgets/location.py'
142--- lib/canonical/widgets/location.py 2010-07-15 10:55:27 +0000
143+++ lib/canonical/widgets/location.py 2010-09-12 16:06:00 +0000
144@@ -24,12 +24,12 @@
145
146 from canonical.config import config
147 from canonical.launchpad import _
148-from canonical.launchpad.interfaces.geoip import IGeoIPRecord
149-from lp.registry.interfaces.location import IObjectWithLocation
150 from canonical.launchpad.validators import LaunchpadValidationError
151 from canonical.launchpad.webapp.interfaces import (
152 ILaunchBag, IMultiLineWidgetLayout)
153 from canonical.launchpad.webapp.tales import ObjectImageDisplayAPI
154+from lp.registry.interfaces.location import IObjectWithLocation
155+from lp.services.geoip.interfaces import IGeoIPRecord
156
157
158 class ILocationWidget(IInputWidget, IBrowserWidget, IMultiLineWidgetLayout):
159
160=== modified file 'lib/lp/registry/browser/distribution.py'
161--- lib/lp/registry/browser/distribution.py 2010-09-10 13:29:42 +0000
162+++ lib/lp/registry/browser/distribution.py 2010-09-12 16:06:00 +0000
163@@ -48,10 +48,6 @@
164 from canonical.launchpad.components.decoratedresultset import (
165 DecoratedResultSet,
166 )
167-from canonical.launchpad.components.request_country import (
168- ipaddress_from_request,
169- request_country,
170- )
171 from canonical.launchpad.helpers import english_list
172 from canonical.launchpad.webapp import (
173 action,
174@@ -109,6 +105,10 @@
175 )
176 from lp.registry.interfaces.product import IProduct
177 from lp.registry.interfaces.series import SeriesStatus
178+from lp.services.geoip.helpers import (
179+ ipaddress_from_request,
180+ request_country,
181+ )
182 from lp.services.propertycache import cachedproperty
183 from lp.soyuz.browser.packagesearch import PackageSearchViewBase
184 from lp.soyuz.enums import ArchivePurpose
185
186=== modified file 'lib/lp/registry/browser/person.py'
187--- lib/lp/registry/browser/person.py 2010-09-10 12:24:03 +0000
188+++ lib/lp/registry/browser/person.py 2010-09-12 16:06:00 +0000
189@@ -159,7 +159,6 @@
190 IEmailAddress,
191 IEmailAddressSet,
192 )
193-from canonical.launchpad.interfaces.geoip import IRequestPreferredLanguages
194 from canonical.launchpad.interfaces.gpghandler import (
195 GPGKeyNotFoundError,
196 IGPGHandler,
197@@ -300,6 +299,7 @@
198 IWikiNameSet,
199 )
200 from lp.services.fields import LocationField
201+from lp.services.geoip.interfaces import IRequestPreferredLanguages
202 from lp.services.openid.adapters.openid import CurrentOpenIDEndPoint
203 from lp.services.openid.browser.openiddiscovery import (
204 XRDSContentNegotiationMixin,
205
206=== modified file 'lib/lp/services/apachelogparser/base.py'
207--- lib/lp/services/apachelogparser/base.py 2010-08-30 17:12:59 +0000
208+++ lib/lp/services/apachelogparser/base.py 2010-09-12 16:06:00 +0000
209@@ -11,13 +11,13 @@
210 from zope.component import getUtility
211
212 from canonical.config import config
213-from canonical.launchpad.interfaces.geoip import IGeoIP
214 from canonical.launchpad.webapp.interfaces import (
215 DEFAULT_FLAVOR,
216 IStoreSelector,
217 MAIN_STORE,
218 )
219 from lp.services.apachelogparser.model.parsedapachelog import ParsedApacheLog
220+from lp.services.geoip.interfaces import IGeoIP
221
222
223 parser = apachelog.parser(apachelog.formats['extended'])
224
225=== modified file 'lib/lp/services/configure.zcml'
226--- lib/lp/services/configure.zcml 2010-08-20 12:11:28 +0000
227+++ lib/lp/services/configure.zcml 2010-09-12 16:06:00 +0000
228@@ -6,8 +6,11 @@
229 <adapter factory=".propertycache.get_default_cache"/>
230 <adapter factory=".propertycache.PropertyCacheManager"/>
231 <adapter factory=".propertycache.DefaultPropertyCacheManager"/>
232+ <include package=".comments" />
233 <include package=".database" />
234 <include package=".features" />
235+ <include package=".fields" />
236+ <include package=".geoip" />
237 <include package=".inlinehelp" file="meta.zcml" />
238 <include package=".job" />
239 <include package=".memcache" />
240
241=== added directory 'lib/lp/services/geoip'
242=== added file 'lib/lp/services/geoip/__init__.py'
243--- lib/lp/services/geoip/__init__.py 1970-01-01 00:00:00 +0000
244+++ lib/lp/services/geoip/__init__.py 2010-09-12 16:06:00 +0000
245@@ -0,0 +1,3 @@
246+# Copyright 2010 Canonical Ltd. This software is licensed under the
247+# GNU Affero General Public License version 3 (see the file LICENSE).
248+"""Launchpad integration of the GEOIP library."""
249
250=== renamed file 'lib/canonical/launchpad/zcml/geoip.zcml' => 'lib/lp/services/geoip/configure.zcml'
251--- lib/canonical/launchpad/zcml/geoip.zcml 2009-07-13 18:15:02 +0000
252+++ lib/lp/services/geoip/configure.zcml 2010-09-12 16:06:00 +0000
253@@ -1,4 +1,4 @@
254-<!-- Copyright 2009 Canonical Ltd. This software is licensed under the
255+<!-- Copyright 2009-2010 Canonical Ltd. This software is licensed under the
256 GNU Affero General Public License version 3 (see the file LICENSE).
257 -->
258
259@@ -9,34 +9,34 @@
260 xmlns:zope="http://namespaces.zope.org/zope"
261 i18n_domain="launchpad">
262
263- <class class="canonical.launchpad.utilities.geoip.GeoIP">
264- <allow interface="canonical.launchpad.interfaces.IGeoIP" />
265+ <class class="lp.services.geoip.model.GeoIP">
266+ <allow interface="lp.services.geoip.interfaces.IGeoIP" />
267 </class>
268
269 <securedutility
270- class="canonical.launchpad.utilities.geoip.GeoIP"
271- provides="canonical.launchpad.interfaces.IGeoIP">
272- <allow interface="canonical.launchpad.interfaces.IGeoIP" />
273+ class="lp.services.geoip.model.GeoIP"
274+ provides="lp.services.geoip.interfaces.IGeoIP">
275+ <allow interface="lp.services.geoip.interfaces.IGeoIP" />
276 </securedutility>
277
278 <adapter
279 for="zope.publisher.interfaces.browser.IBrowserRequest"
280- factory="canonical.launchpad.utilities.geoip.RequestLocalLanguages"
281- provides="canonical.launchpad.interfaces.IRequestLocalLanguages" />
282-
283- <adapter
284- for="zope.publisher.interfaces.browser.IBrowserRequest"
285- factory="canonical.launchpad.utilities.geoip.RequestPreferredLanguages"
286- provides="canonical.launchpad.interfaces.IRequestPreferredLanguages" />
287-
288- <adapter
289- for="zope.publisher.interfaces.browser.IBrowserRequest"
290- factory="canonical.launchpad.components.request_country.request_country"
291- provides="canonical.launchpad.interfaces.ICountry" />
292-
293- <adapter
294- for="zope.publisher.interfaces.browser.IBrowserRequest"
295- factory="canonical.launchpad.utilities.geoip.GeoIPRequest"
296- provides="canonical.launchpad.interfaces.IGeoIPRecord" />
297+ factory="lp.services.geoip.model.RequestLocalLanguages"
298+ provides="lp.services.geoip.interfaces.IRequestLocalLanguages" />
299+
300+ <adapter
301+ for="zope.publisher.interfaces.browser.IBrowserRequest"
302+ factory="lp.services.geoip.model.RequestPreferredLanguages"
303+ provides="lp.services.geoip.interfaces.IRequestPreferredLanguages" />
304+
305+ <adapter
306+ for="zope.publisher.interfaces.browser.IBrowserRequest"
307+ factory="lp.services.geoip.helpers.request_country"
308+ provides="lp.services.worlddata.interfaces.country.ICountry" />
309+
310+ <adapter
311+ for="zope.publisher.interfaces.browser.IBrowserRequest"
312+ factory="lp.services.geoip.model.GeoIPRequest"
313+ provides="lp.services.geoip.interfaces.IGeoIPRecord" />
314
315 </configure>
316
317=== added directory 'lib/lp/services/geoip/doc'
318=== renamed file 'lib/canonical/launchpad/doc/geoip.txt' => 'lib/lp/services/geoip/doc/geoip.txt'
319--- lib/canonical/launchpad/doc/geoip.txt 2009-04-17 10:32:16 +0000
320+++ lib/lp/services/geoip/doc/geoip.txt 2010-09-12 16:06:00 +0000
321@@ -1,10 +1,11 @@
322-= GeoIP =
323+GeoIP
324+=====
325
326 GeoIP allows us to guess the location of a user based on his IP address.
327 Our IGeoIP utility provides a couple methods to get location information
328 from a given IP address.
329
330- >>> from canonical.launchpad.interfaces.geoip import IGeoIP
331+ >>> from lp.services.geoip.interfaces import IGeoIP
332 >>> geoip = getUtility(IGeoIP)
333
334 The getCountryByAddr() method will return the country of the given IP
335@@ -80,14 +81,13 @@
336 request's originating IP address.
337
338 >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest
339- >>> from canonical.launchpad.interfaces.geoip import IGeoIPRecord
340+ >>> from lp.services.geoip.interfaces import IGeoIPRecord
341 >>> request = LaunchpadTestRequest()
342
343 Since our request won't have an originating IP address, we'll use that
344 same South African IP address.
345
346- >>> from canonical.launchpad.components.request_country import (
347- ... ipaddress_from_request)
348+ >>> from lp.services.geoip.helpers import ipaddress_from_request
349 >>> print ipaddress_from_request(request)
350 None
351 >>> geoip_request = IGeoIPRecord(request)
352
353=== renamed file 'lib/canonical/launchpad/components/request_country.py' => 'lib/lp/services/geoip/helpers.py'
354--- lib/canonical/launchpad/components/request_country.py 2010-08-20 20:31:18 +0000
355+++ lib/lp/services/geoip/helpers.py 2010-09-12 16:06:00 +0000
356@@ -7,10 +7,14 @@
357
358 from zope.component import getUtility
359
360-from canonical.launchpad.interfaces import IGeoIP
361-
362-
363-__all__ = ['request_country', 'ipaddress_from_request']
364+from lp.services.geoip.interfaces import IGeoIP
365+
366+
367+__all__ = [
368+ 'request_country',
369+ 'ipaddress_from_request',
370+ ]
371+
372
373 def request_country(request):
374 """Adapt a request to the country in which the request was made.
375@@ -26,8 +30,10 @@
376 return getUtility(IGeoIP).getCountryByAddr(ipaddress)
377 return None
378
379+
380 _ipaddr_re = re.compile('\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?')
381
382+
383 def ipaddress_from_request(request):
384 """Determine the IP address for this request.
385
386@@ -67,8 +73,7 @@
387 ipaddresses = [
388 addr for addr in ipaddresses
389 if not (addr.startswith('127.')
390- or _ipaddr_re.search(addr) is None)
391- ]
392+ or _ipaddr_re.search(addr) is None)]
393
394 if ipaddresses:
395 # If we have more than one, have a guess.
396
397=== renamed file 'lib/canonical/launchpad/interfaces/geoip.py' => 'lib/lp/services/geoip/interfaces.py'
398=== renamed file 'lib/canonical/launchpad/utilities/geoip.py' => 'lib/lp/services/geoip/model.py'
399--- lib/canonical/launchpad/utilities/geoip.py 2010-08-24 10:45:57 +0000
400+++ lib/lp/services/geoip/model.py 2010-09-12 16:06:00 +0000
401@@ -16,10 +16,8 @@
402 from zope.interface import implements
403
404 from canonical.config import config
405-from canonical.launchpad.components.request_country import (
406- ipaddress_from_request,
407- )
408-from canonical.launchpad.interfaces.geoip import (
409+from lp.services.geoip.helpers import ipaddress_from_request
410+from lp.services.geoip.interfaces import (
411 IGeoIP,
412 IGeoIPRecord,
413 IRequestLocalLanguages,
414
415=== added directory 'lib/lp/services/geoip/tests'
416=== added file 'lib/lp/services/geoip/tests/__init__.py'
417=== renamed file 'lib/canonical/launchpad/components/tests/test_request_country.py' => 'lib/lp/services/geoip/tests/test_doc.py'
418--- lib/canonical/launchpad/components/tests/test_request_country.py 2010-08-20 20:31:18 +0000
419+++ lib/lp/services/geoip/tests/test_doc.py 2010-09-12 16:06:00 +0000
420@@ -1,19 +1,23 @@
421-# Copyright 2009 Canonical Ltd. This software is licensed under the
422+# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
423 # GNU Affero General Public License version 3 (see the file LICENSE).
424
425-"""Module docstring goes here."""
426+"""Test GEOIP documentation."""
427
428 __metaclass__ = type
429
430+import os
431 from doctest import DocTestSuite
432-import unittest
433+
434+from canonical.testing.layers import LaunchpadFunctionalLayer
435+from lp.services.testing import build_test_suite
436+
437+
438+here = os.path.dirname(os.path.realpath(__file__))
439
440
441 def test_suite():
442- import canonical.launchpad.components.request_country
443- return DocTestSuite(canonical.launchpad.components.request_country)
444-
445-if __name__ == '__main__':
446- DEFAULT = test_suite()
447- unittest.main(defaultTest='DEFAULT')
448-
449+ import lp.services.geoip.helpers
450+ inline_doctest = DocTestSuite(lp.services.geoip.helpers)
451+ suite = build_test_suite(here, {}, layer=LaunchpadFunctionalLayer)
452+ suite.addTest(inline_doctest)
453+ return suite
454
455=== renamed file 'lib/canonical/launchpad/components/ftests/test_request_country.py' => 'lib/lp/services/geoip/tests/test_request_country.py'
456--- lib/canonical/launchpad/components/ftests/test_request_country.py 2010-08-20 20:31:18 +0000
457+++ lib/lp/services/geoip/tests/test_request_country.py 2010-09-12 16:06:00 +0000
458@@ -1,4 +1,4 @@
459-# Copyright 2009 Canonical Ltd. This software is licensed under the
460+# Copyright 2009-2010 Canonical Ltd. This software is licensed under the
461 # GNU Affero General Public License version 3 (see the file LICENSE).
462
463 """Functional tests for request_country"""
464@@ -6,12 +6,12 @@
465
466 import unittest
467
468-from canonical.launchpad.components.request_country import request_country
469 from canonical.launchpad.ftests import (
470 ANONYMOUS,
471 login,
472 logout,
473 )
474+from lp.services.geoip.helpers import request_country
475 from canonical.testing import LaunchpadFunctionalLayer
476
477
478
479=== modified file 'lib/lp/translations/browser/translations.py'
480--- lib/lp/translations/browser/translations.py 2010-08-24 10:45:57 +0000
481+++ lib/lp/translations/browser/translations.py 2010-09-12 16:06:00 +0000
482@@ -19,7 +19,6 @@
483
484 from canonical.config import config
485 from canonical.launchpad import helpers
486-from canonical.launchpad.interfaces.geoip import IRequestPreferredLanguages
487 from canonical.launchpad.interfaces.launchpad import (
488 ILaunchpadCelebrities,
489 IRosettaApplication,
490@@ -35,6 +34,7 @@
491 from canonical.launchpad.webapp.interfaces import ILaunchpadRoot
492 from lp.registry.interfaces.person import IPersonSet
493 from lp.registry.interfaces.product import IProductSet
494+from lp.services.geoip.interfaces import IRequestPreferredLanguages
495 from lp.services.propertycache import cachedproperty
496 from lp.services.worlddata.interfaces.country import ICountry
497 from lp.translations.publisher import TranslationsLayer
498
499=== modified file 'lib/lp/translations/doc/preferred-languages.txt'
500--- lib/lp/translations/doc/preferred-languages.txt 2009-10-22 11:55:51 +0000
501+++ lib/lp/translations/doc/preferred-languages.txt 2010-09-12 16:06:00 +0000
502@@ -3,8 +3,7 @@
503 in ASCII we just skip them.
504
505 >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest
506- >>> from canonical.launchpad.utilities.geoip import (
507- ... RequestPreferredLanguages)
508+ >>> from lp.services.geoip.model import RequestPreferredLanguages
509
510 >>> langs = {'HTTP_ACCEPT_LANGUAGE': 'pt_BR, Espa\xf1ol'}
511 >>> request = LaunchpadTestRequest(**langs)