launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #24252
[Merge] ~cjwatson/launchpad:bs4-feeds into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:bs4-feeds into launchpad:master.
Commit message:
Port feed tests to Beautiful Soup 4
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/377977
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:bs4-feeds into launchpad:master.
diff --git a/lib/lp/bugs/stories/feeds/xx-bug-atom.txt b/lib/lp/bugs/stories/feeds/xx-bug-atom.txt
index 4b0faa4..840b943 100644
--- a/lib/lp/bugs/stories/feeds/xx-bug-atom.txt
+++ b/lib/lp/bugs/stories/feeds/xx-bug-atom.txt
@@ -1,10 +1,12 @@
= Atom Feeds =
Atom feeds produce XML not HTML. Therefore we must parse the output as XML
-using BeautifulStoneSoup instead of BSS or the helper functions.
+by asking BeautifulSoup to use lxml.
- >>> from BeautifulSoup import BeautifulStoneSoup as BSS
- >>> from BeautifulSoup import SoupStrainer
+ >>> from lp.services.beautifulsoup import (
+ ... BeautifulSoup4 as BeautifulSoup,
+ ... SoupStrainer4 as SoupStrainer,
+ ... )
>>> from lp.services.feeds.tests.helper import (
... parse_entries, parse_links, validate_feed)
@@ -26,25 +28,26 @@ point to the bugs themselves.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bugs in Jokosher']
>>> browser.url
'http://feeds.launchpad.test/jokosher/latest-bugs.atom'
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> print(extract_text(soup.find('id')))
tag:launchpad.net,2007-03-15:/bugs/jokosher
>>> alternate_links = parse_links(browser.contents, 'alternate')
>>> for link in alternate_links:
... print(link)
- <link rel="alternate" href="http://bugs.launchpad.test/jokosher" />
- <link rel="alternate" href="http://bugs.launchpad.test/bugs/12" />
- <link rel="alternate" href="http://bugs.launchpad.test/bugs/11" />
+ <link href="http://bugs.launchpad.test/jokosher" rel="alternate"/>
+ <link href="http://bugs.launchpad.test/bugs/12" rel="alternate"/>
+ <link href="http://bugs.launchpad.test/bugs/11" rel="alternate"/>
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/jokosher/latest-bugs.atom" />
+ <link href="http://feeds.launchpad.test/jokosher/latest-bugs.atom" rel="self"/>
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -83,19 +86,20 @@ as the latest bugs feed for a product.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bugs in The Mozilla Project']
>>> browser.url
'http://feeds.launchpad.test/mozilla/latest-bugs.atom'
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> print(extract_text(soup.find('id')))
tag:launchpad.net,2004-09-24:/bugs/mozilla
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/mozilla/latest-bugs.atom" />
+ <link href="http://feeds.launchpad.test/mozilla/latest-bugs.atom" rel="self"/>
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -144,19 +148,20 @@ of content as the latest bugs feed for a product.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bugs in Ubuntu']
>>> browser.url
'http://feeds.launchpad.test/ubuntu/latest-bugs.atom'
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> print(extract_text(soup.find('id')))
tag:launchpad.net,2006-10-16:/bugs/ubuntu
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/ubuntu/latest-bugs.atom" />
+ <link href="http://feeds.launchpad.test/ubuntu/latest-bugs.atom" rel="self"/>
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -214,11 +219,8 @@ The bug should be included in the feed.
Private teams should show as '-'.
- >>> entry_content = BSS(
- ... entry.find('content').text,
- ... convertEntities=BSS.HTML_ENTITIES)
- >>> soup = BSS(entry_content.text)
- >>> print([tr.findAll('td')[4].text for tr in soup.findAll('tr')[1:4]])
+ >>> soup = BeautifulSoup(entry.find('content').text, 'xml')
+ >>> print([tr.find_all('td')[4].text for tr in soup.find_all('tr')[1:4]])
[u'Mark Shuttleworth', u'-', u'-']
== Latest bugs for a source package ==
@@ -232,11 +234,12 @@ type of content as the latest bugs feed for a product.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bugs in thunderbird in Ubuntu']
>>> browser.url
'http://feeds.launchpad.test/ubuntu/+source/thunderbird/latest-bugs.atom'
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> print(extract_text(soup.find('id')))
tag:launchpad.net,2008:/bugs/ubuntu/+source/thunderbird
>>> entries = parse_entries(browser.contents)
@@ -264,19 +267,20 @@ type of content as the latest bugs feed for a product.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bugs in Hoary']
>>> browser.url
'http://feeds.launchpad.test/ubuntu/hoary/latest-bugs.atom'
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> print(extract_text(soup.find('id')))
tag:launchpad.net,2006-10-16:/bugs/ubuntu/hoary
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/ubuntu/hoary/latest-bugs.atom" />
+ <link href="http://feeds.launchpad.test/ubuntu/hoary/latest-bugs.atom" rel="self"/>
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -304,19 +308,20 @@ type of content as the latest bugs feed for a product.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bugs in 1.0']
>>> browser.url
'http://feeds.launchpad.test/firefox/1.0/latest-bugs.atom'
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> print(extract_text(soup.find('id')))
tag:launchpad.net,2005-06-06:/bugs/firefox/1.0
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/firefox/1.0/latest-bugs.atom" />
+ <link href="http://feeds.launchpad.test/firefox/1.0/latest-bugs.atom" rel="self"/>
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -342,19 +347,20 @@ This feed gets the latest bugs for a person.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bugs for Foo Bar']
>>> browser.url
'http://feeds.launchpad.test/~name16/latest-bugs.atom'
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> print(extract_text(soup.find('id')))
tag:launchpad.net,2005-06-06:/bugs/~name16
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/~name16/latest-bugs.atom" />
+ <link href="http://feeds.launchpad.test/~name16/latest-bugs.atom" rel="self"/>
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -417,17 +423,18 @@ some results.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bugs for Simple Team']
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> print(extract_text(soup.find('id')))
tag:launchpad.net,2007-02-21:/bugs/~simple-team
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/~simple-team/latest-bugs.atom" />
+ <link href="http://feeds.launchpad.test/~simple-team/latest-bugs.atom" rel="self"/>
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -445,19 +452,20 @@ This feed gets the latest bugs reported against any target.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Launchpad bugs']
>>> browser.url
'http://feeds.launchpad.test/bugs/latest-bugs.atom'
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> print(extract_text(soup.find('id')))
tag:launchpad.net,2008:/bugs
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/bugs/latest-bugs.atom" />
+ <link href="http://feeds.launchpad.test/bugs/latest-bugs.atom" rel="self"/>
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -508,10 +516,11 @@ The bug search feed can be tested after setting is_bug_search_feed_active
to True.
>>> browser.open(url)
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bugs from custom search']
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> feed_id = extract_text(soup.find('id'))
>>> print(feed_id)
tag:launchpad.net,2008:/+bugs.atom?field.scope.target=&field.scope=all&field.searchtext=&search=Search+Bug+Reports
@@ -523,7 +532,7 @@ to True.
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/bugs/+bugs.atom?field.scope.target=&field.scope=all&field.searchtext=&search=Search+Bug+Reports" />
+ <link href="http://feeds.launchpad.test/bugs/+bugs.atom?field.scope.target=&field.scope=all&field.searchtext=&search=Search+Bug+Reports" rel="self"/>
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -554,7 +563,7 @@ This feed shows the status of a single bug.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Bug 1']
>>> entries = parse_entries(browser.contents)
>>> print(len(entries))
@@ -565,7 +574,7 @@ This feed shows the status of a single bug.
>>> self_links = parse_links(browser.contents, 'self')
>>> for link in self_links:
... print(link)
- <link rel="self" href="http://feeds.launchpad.test/bugs/1/bug.atom" />
+ <link href="http://feeds.launchpad.test/bugs/1/bug.atom" rel="self"/>
== Feeds Configuration Options ==
diff --git a/lib/lp/bugs/stories/feeds/xx-bug-html.txt b/lib/lp/bugs/stories/feeds/xx-bug-html.txt
index fff1f4f..fa02653 100644
--- a/lib/lp/bugs/stories/feeds/xx-bug-html.txt
+++ b/lib/lp/bugs/stories/feeds/xx-bug-html.txt
@@ -5,15 +5,16 @@ The content of an HTML feed is very similar to an Atom feed, but is formatted
as HTML instead of Atom.
>>> from lp.services.beautifulsoup import (
- ... BeautifulSoup,
- ... SoupStrainer,
+ ... BeautifulSoup4 as BeautifulSoup,
+ ... SoupStrainer4 as SoupStrainer,
... )
Define a helper function for parsing the entries:
>>> def parse_entries(contents):
- ... entries = [tag for tag in BeautifulSoup(browser.contents,
- ... parseOnlyThese=SoupStrainer('tr'))]
+ ... entries = [
+ ... tag for tag in BeautifulSoup(
+ ... browser.contents, parse_only=SoupStrainer('tr'))]
... return entries
And two for printing the results:
diff --git a/lib/lp/code/stories/feeds/xx-branch-atom.txt b/lib/lp/code/stories/feeds/xx-branch-atom.txt
index db90f8f..74db8e1 100644
--- a/lib/lp/code/stories/feeds/xx-branch-atom.txt
+++ b/lib/lp/code/stories/feeds/xx-branch-atom.txt
@@ -1,10 +1,12 @@
= Atom Feeds For Branches =
Atom feeds produce XML not HTML. Therefore we must parse the output as XML
-using BeautifulStoneSoup instead of BeautifulSoup or the helper functions.
+by asking BeautifulSoup to use lxml.
- >>> from BeautifulSoup import BeautifulStoneSoup as BSS
- >>> from BeautifulSoup import SoupStrainer
+ >>> from lp.services.beautifulsoup import (
+ ... BeautifulSoup4 as BeautifulSoup,
+ ... SoupStrainer4 as SoupStrainer,
+ ... )
>>> from lp.services.feeds.tests.helper import (
... parse_ids, parse_links, validate_feed)
@@ -49,7 +51,7 @@ which will include an entry for each branch.
... browser.contents, browser.headers['content-type'], browser.url)
>>> validate_browser_feed(anon_browser)
No Errors
- >>> BSS(anon_browser.contents).title.contents
+ >>> BeautifulSoup(anon_browser.contents, 'xml').title.contents
[u'Branches for Mike Murphy']
>>> def print_parse_ids(browser):
... for id in parse_ids(browser.contents):
@@ -71,14 +73,15 @@ Ensure the self link is correct and there is only one.
... for link in parse_links(browser.contents, rel="self"):
... print(link)
>>> print_parse_links(anon_browser)
- <link rel="self" href="http://feeds.launchpad.test/~mike/branches.atom" />
+ <link href="http://feeds.launchpad.test/~mike/branches.atom" rel="self"/>
The <update> field for the feed will be the most recent value for the
updated field in all of the entries.
>>> strainer = SoupStrainer('updated')
- >>> updated_dates = [extract_text(tag) for tag in BSS(anon_browser.contents,
- ... parseOnlyThese=strainer)]
+ >>> updated_dates = [
+ ... extract_text(tag) for tag in BeautifulSoup(
+ ... anon_browser.contents, 'xml', parse_only=strainer)]
>>> feed_updated = updated_dates[0]
>>> entry_dates = sorted(updated_dates[1:], reverse=True)
>>> assert feed_updated == entry_dates[0], (
@@ -90,7 +93,7 @@ still be hidden:
>>> anon_browser.open('http://feeds.launchpad.test/~name12/branches.atom')
>>> validate_browser_feed(anon_browser)
No Errors
- >>> BSS(anon_browser.contents).title.contents
+ >>> BeautifulSoup(anon_browser.contents, 'xml').title.contents
[u'Branches for Sample Person']
>>> 'foo@localhost' in anon_browser.contents
False
@@ -125,7 +128,7 @@ branches listed, just an id for the feed.
>>> browser.open('http://feeds.launchpad.test/~landscape-developers/branches.atom')
>>> validate_browser_feed(browser)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Branches for Landscape Developers']
>>> print_parse_ids(browser)
<id>tag:launchpad.net,2006-07-11:/code/~landscape-developers</id>
@@ -139,7 +142,7 @@ which will include an entry for each branch.
>>> anon_browser.open('http://feeds.launchpad.test/fooix/branches.atom')
>>> validate_browser_feed(anon_browser)
No Errors
- >>> BSS(anon_browser.contents).title.contents
+ >>> BeautifulSoup(anon_browser.contents, 'xml').title.contents
[u'Branches for Fooix']
>>> print_parse_ids(anon_browser)
<id>tag:launchpad.net,...:/code/fooix</id>
@@ -148,14 +151,15 @@ which will include an entry for each branch.
<id>tag:launchpad.net,2007-12-01:/code/~mike/fooix/first</id>
>>> print_parse_links(anon_browser)
- <link rel="self" href="http://feeds.launchpad.test/fooix/branches.atom" />
+ <link href="http://feeds.launchpad.test/fooix/branches.atom" rel="self"/>
The <update> field for the feed will be the most recent value for the
updated field in all of the entries.
>>> strainer = SoupStrainer('updated')
- >>> updated_dates = [extract_text(tag) for tag in BSS(anon_browser.contents,
- ... parseOnlyThese=strainer)]
+ >>> updated_dates = [
+ ... extract_text(tag) for tag in BeautifulSoup(
+ ... anon_browser.contents, 'xml', parse_only=strainer)]
>>> feed_updated = updated_dates[0]
>>> entry_dates = sorted(updated_dates[1:], reverse=True)
>>> assert feed_updated == entry_dates[0], (
@@ -170,7 +174,7 @@ branches which will include an entry for each branch.
>>> anon_browser.open('http://feeds.launchpad.test/oh-man/branches.atom')
>>> validate_browser_feed(anon_browser)
No Errors
- >>> BSS(anon_browser.contents).title.contents
+ >>> BeautifulSoup(anon_browser.contents, 'xml').title.contents
[u'Branches for Oh Man']
>>> print_parse_ids(anon_browser)
<id>tag:launchpad.net,...:/code/oh-man</id>
@@ -182,14 +186,15 @@ branches which will include an entry for each branch.
<id>tag:launchpad.net,2007-12-01:/code/~mike/fooix/first</id>
>>> print_parse_links(anon_browser)
- <link rel="self" href="http://feeds.launchpad.test/oh-man/branches.atom" />
+ <link href="http://feeds.launchpad.test/oh-man/branches.atom" rel="self"/>
The <update> field for the feed will be the most recent value for the
updated field in all of the entries.
>>> strainer = SoupStrainer('updated')
- >>> updated_dates = [extract_text(tag) for tag in BSS(anon_browser.contents,
- ... parseOnlyThese=strainer)]
+ >>> updated_dates = [
+ ... extract_text(tag) for tag in BeautifulSoup(
+ ... anon_browser.contents, 'xml', parse_only=strainer)]
>>> feed_updated = updated_dates[0]
>>> entry_dates = sorted(updated_dates[1:], reverse=True)
>>> assert feed_updated == entry_dates[0], (
@@ -206,7 +211,7 @@ different entry.
>>> validate_feed(browser.contents,
... browser.headers['content-type'], browser.url)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Latest Revisions for Branch lp://dev/~mark/firefox/release--0.9.1']
>>> print(browser.url)
http://feeds.launchpad.test/~mark/firefox/release--0.9.1/branch.atom
@@ -214,17 +219,19 @@ different entry.
The first <id> in a feed identifies the feed. Each entry then has its
own <id>, which in the case of a single branch feed will be identical.
- >>> soup = BSS(browser.contents, parseOnlyThese=SoupStrainer('id'))
+ >>> soup = BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=SoupStrainer('id'))
>>> ids = parse_ids(browser.contents)
>>> for id_ in ids:
... print(id_)
<id>tag:launchpad.net,2006-10-16:/code/~mark/firefox/release--0.9.1</id>
<id>tag:launchpad.net,2005-03-09:/code/~mark/firefox/release--0.9.1/revision/1</id>
>>> print_parse_links(browser)
- <link rel="self" href="http://feeds.launchpad.test/~mark/firefox/release--0.9.1/branch.atom" />
+ <link href="http://feeds.launchpad.test/~mark/firefox/release--0.9.1/branch.atom" rel="self"/>
>>> strainer = SoupStrainer('updated')
- >>> updated_dates = [extract_text(tag) for tag in BSS(browser.contents,
- ... parseOnlyThese=strainer)]
+ >>> updated_dates = [
+ ... extract_text(tag) for tag in BeautifulSoup(
+ ... browser.contents, 'xml', parse_only=strainer)]
The update date for the entire feed (updated_dates[0]) must be equal
to the update_date of the first entry in the feed (updated_dates[1]).
diff --git a/lib/lp/code/stories/feeds/xx-revision-atom.txt b/lib/lp/code/stories/feeds/xx-revision-atom.txt
index 0ef5eae..3638b09 100644
--- a/lib/lp/code/stories/feeds/xx-revision-atom.txt
+++ b/lib/lp/code/stories/feeds/xx-revision-atom.txt
@@ -1,9 +1,9 @@
= Atom Feeds For Revisions =
Atom feeds produce XML not HTML. Therefore we must parse the output as XML
-using BeautifulStoneSoup instead of BeautifulSoup or the helper functions.
+by asking BeautifulSoup to use lxml.
- >>> from BeautifulSoup import BeautifulStoneSoup as BSS
+ >>> from lp.services.beautifulsoup import BeautifulSoup4 as BeautifulSoup
>>> from lp.services.feeds.tests.helper import (
... parse_ids, parse_links, validate_feed)
@@ -75,7 +75,7 @@ that have been committed by that person (or attributed to that person).
... browser.contents, browser.headers['content-type'], browser.url)
>>> validate_browser_feed(anon_browser)
No Errors
- >>> BSS(anon_browser.contents).title.contents
+ >>> BeautifulSoup(anon_browser.contents, 'xml').title.contents
[u'Latest Revisions by Mike Murphy']
>>> def print_parse_ids(browser):
... for id in parse_ids(browser.contents):
@@ -96,7 +96,7 @@ Ensure the self link is correct and there is only one.
... for link in parse_links(browser.contents, rel="self"):
... print(link)
>>> print_parse_links(anon_browser)
- <link rel="self" href="http://feeds.launchpad.test/~mike/revisions.atom" />
+ <link href="http://feeds.launchpad.test/~mike/revisions.atom" rel="self"/>
If we look at the feed for a team, we get revisions created by any member
of that team.
@@ -104,7 +104,7 @@ of that team.
>>> browser.open('http://feeds.launchpad.test/~m-team/revisions.atom')
>>> validate_browser_feed(browser)
No Errors
- >>> BSS(browser.contents).title.contents
+ >>> BeautifulSoup(browser.contents, 'xml').title.contents
[u'Latest Revisions by members of The M Team']
>>> print_parse_ids(browser)
<id>tag:launchpad.net,...:/code/~m-team</id>
@@ -122,7 +122,7 @@ that have been committed on branches for the product.
>>> anon_browser.open('http://feeds.launchpad.test/fooix/revisions.atom')
>>> validate_browser_feed(anon_browser)
No Errors
- >>> BSS(anon_browser.contents).title.contents
+ >>> BeautifulSoup(anon_browser.contents, 'xml').title.contents
[u'Latest Revisions for Fooix']
Ignore the date associated with the id of 'fooix' as this is the date created
@@ -136,7 +136,7 @@ for the product, which will be different each time the test is run.
Ensure the self link points to the feed location and there is only one.
>>> print_parse_links(anon_browser)
- <link rel="self" href="http://feeds.launchpad.test/fooix/revisions.atom" />
+ <link href="http://feeds.launchpad.test/fooix/revisions.atom" rel="self"/>
== Feed for a project group's revisions ==
@@ -147,7 +147,7 @@ branch for any product that is associated with the project group.
>>> anon_browser.open('http://feeds.launchpad.test/fubar/revisions.atom')
>>> validate_browser_feed(anon_browser)
No Errors
- >>> BSS(anon_browser.contents).title.contents
+ >>> BeautifulSoup(anon_browser.contents, 'xml').title.contents
[u'Latest Revisions for Fubar']
Ignore the date associated with the id of 'fubar' as this is the date created
@@ -163,4 +163,4 @@ of the project group, which will be different each time the test is run.
Ensure the self link points to the feed location and there is only one.
>>> print_parse_links(anon_browser)
- <link rel="self" href="http://feeds.launchpad.test/fubar/revisions.atom" />
+ <link href="http://feeds.launchpad.test/fubar/revisions.atom" rel="self"/>
diff --git a/lib/lp/services/feeds/doc/feeds.txt b/lib/lp/services/feeds/doc/feeds.txt
index 35086d2..02315cb 100644
--- a/lib/lp/services/feeds/doc/feeds.txt
+++ b/lib/lp/services/feeds/doc/feeds.txt
@@ -157,7 +157,7 @@ we are testing xhtml encoding here in case we need it in the future.
>>> xhtml = FeedTypedData("<b> and and &</b><hr/>",
... content_type="xhtml")
>>> xhtml.content
- u'<b> and \xa0 and &</b><hr />'
+ u'<b> and \xa0 and &</b><hr/>'
== validate_feed() helper function ==
diff --git a/lib/lp/services/feeds/feed.py b/lib/lp/services/feeds/feed.py
index 9462062..143121c 100644
--- a/lib/lp/services/feeds/feed.py
+++ b/lib/lp/services/feeds/feed.py
@@ -27,7 +27,7 @@ from zope.component import getUtility
from zope.datetime import rfc1123_date
from zope.interface import implementer
-from lp.services.beautifulsoup import BeautifulSoup
+from lp.services.beautifulsoup import BeautifulSoup4 as BeautifulSoup
from lp.services.config import config
from lp.services.feeds.interfaces.feed import (
IFeed,
@@ -302,9 +302,7 @@ class FeedTypedData:
if self.content_type in ('text', 'html'):
altered_content = html_escape(altered_content)
elif self.content_type == 'xhtml':
- soup = BeautifulSoup(
- altered_content,
- convertEntities=BeautifulSoup.HTML_ENTITIES)
+ soup = BeautifulSoup(altered_content)
altered_content = unicode(soup)
return altered_content
diff --git a/lib/lp/services/feeds/stories/xx-links.txt b/lib/lp/services/feeds/stories/xx-links.txt
index 83110fd..23e467b 100644
--- a/lib/lp/services/feeds/stories/xx-links.txt
+++ b/lib/lp/services/feeds/stories/xx-links.txt
@@ -11,13 +11,13 @@ launchpad.test to provide links to corresponding Atom feeds.
The root launchpad.test url will have a link to the Atom feed which
displays the most recent announcements for all the projects.
- >>> from lp.services.beautifulsoup import BeautifulSoup
+ >>> from lp.services.beautifulsoup import BeautifulSoup4 as BeautifulSoup
>>> browser.open('http://launchpad.test/')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/announcements.atom"
- title="All Announcements" />]
+ [<link href="http://feeds.launchpad.test/announcements.atom"
+ rel="alternate" title="All Announcements"
+ type="application/atom+xml"/>]
The http://launchpad.test/+announcements page also displays recent
announcements for all the projects so it should have a link to the same
@@ -26,9 +26,9 @@ feed.
>>> browser.open('http://launchpad.test/+announcements')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/announcements.atom"
- title="All Announcements" />]
+ [<link href="http://feeds.launchpad.test/announcements.atom"
+ rel="alternate" title="All Announcements"
+ type="application/atom+xml"/>]
== Single Bug Feed ==
@@ -38,9 +38,9 @@ atom feed for that one bug.
>>> browser.open('http://bugs.launchpad.test/firefox/+bug/1')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/bugs/1/bug.atom"
- title="Bug 1 Feed" />]
+ [<link href="http://feeds.launchpad.test/bugs/1/bug.atom"
+ rel="alternate" title="Bug 1 Feed"
+ type="application/atom+xml"/>]
But if the bug is private, there should be no link.
@@ -80,15 +80,15 @@ branches.
>>> browser.open('http://launchpad.test/~stevea')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/~stevea/latest-bugs.atom"
- title="Latest Bugs for Steve Alexander" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/~stevea/branches.atom"
- title="Latest Branches for Steve Alexander" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/~stevea/revisions.atom"
- title="Latest Revisions by Steve Alexander" />]
+ [<link href="http://feeds.launchpad.test/~stevea/latest-bugs.atom"
+ rel="alternate" title="Latest Bugs for Steve Alexander"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/~stevea/branches.atom"
+ rel="alternate" title="Latest Branches for Steve Alexander"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/~stevea/revisions.atom"
+ rel="alternate" title="Latest Revisions by Steve Alexander"
+ type="application/atom+xml"/>]
On the bugs subdomain, only a link to the bugs feed will be included,
not the branches link.
@@ -96,9 +96,9 @@ not the branches link.
>>> browser.open('http://bugs.launchpad.test/~stevea')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/~stevea/latest-bugs.atom"
- title="Latest Bugs for Steve Alexander" />]
+ [<link href="http://feeds.launchpad.test/~stevea/latest-bugs.atom"
+ rel="alternate" title="Latest Bugs for Steve Alexander"
+ type="application/atom+xml"/>]
== Latest Bugs, Branches, and Announcements for a Product ==
@@ -112,27 +112,27 @@ main product page.
>>> browser.open('http://launchpad.test/jokosher')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/jokosher/announcements.atom"
- title="Announcements for Jokosher" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/jokosher/latest-bugs.atom"
- title="Latest Bugs for Jokosher" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/jokosher/branches.atom"
- title="Latest Branches for Jokosher" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/jokosher/revisions.atom"
- title="Latest Revisions for Jokosher" />]
+ [<link href="http://feeds.launchpad.test/jokosher/announcements.atom"
+ rel="alternate" title="Announcements for Jokosher"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/jokosher/latest-bugs.atom"
+ rel="alternate" title="Latest Bugs for Jokosher"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/jokosher/branches.atom"
+ rel="alternate" title="Latest Branches for Jokosher"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/jokosher/revisions.atom"
+ rel="alternate" title="Latest Revisions for Jokosher"
+ type="application/atom+xml"/>]
Only bug feeds should be linked to on bugs.launchpad.test.
>>> browser.open('http://bugs.launchpad.test/jokosher')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/jokosher/latest-bugs.atom"
- title="Latest Bugs for Jokosher" />]
+ [<link href="http://feeds.launchpad.test/jokosher/latest-bugs.atom"
+ rel="alternate" title="Latest Bugs for Jokosher"
+ type="application/atom+xml"/>]
== Escaping the title ==
@@ -160,18 +160,22 @@ it must have quotes and html escaped.
>>> browser.open('http://launchpad.test/bad-displayname')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/bad-displayname/announcements.atom"
- title='Announcements for Bad displayname"><script>alert("h4x0r")</script>' />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/bad-displayname/latest-bugs.atom"
- title='Latest Bugs for Bad displayname"><script>alert("h4x0r")</script>' />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/bad-displayname/branches.atom"
- title='Latest Branches for Bad displayname"><script>alert("h4x0r")</script>' />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/bad-displayname/revisions.atom"
- title='Latest Revisions for Bad displayname"><script>alert("h4x0r")</script>' />]
+ [<link href="http://feeds.launchpad.test/bad-displayname/announcements.atom"
+ rel="alternate"
+ title='Announcements for Bad displayname"><script>alert("h4x0r")</script>'
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/bad-displayname/latest-bugs.atom"
+ rel="alternate"
+ title='Latest Bugs for Bad displayname"><script>alert("h4x0r")</script>'
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/bad-displayname/branches.atom"
+ rel="alternate"
+ title='Latest Branches for Bad displayname"><script>alert("h4x0r")</script>'
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/bad-displayname/revisions.atom"
+ rel="alternate"
+ title='Latest Revisions for Bad displayname"><script>alert("h4x0r")</script>'
+ type="application/atom+xml"/>]
== Latest Bugs for a ProjectGroup ==
@@ -184,27 +188,27 @@ on the main project group page.
>>> browser.open('http://launchpad.test/gnome')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/gnome/announcements.atom"
- title="Announcements for GNOME" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/gnome/latest-bugs.atom"
- title="Latest Bugs for GNOME" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/gnome/branches.atom"
- title="Latest Branches for GNOME" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/gnome/revisions.atom"
- title="Latest Revisions for GNOME" />]
+ [<link href="http://feeds.launchpad.test/gnome/announcements.atom"
+ rel="alternate" title="Announcements for GNOME"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/gnome/latest-bugs.atom"
+ rel="alternate" title="Latest Bugs for GNOME"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/gnome/branches.atom"
+ rel="alternate" title="Latest Branches for GNOME"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/gnome/revisions.atom"
+ rel="alternate" title="Latest Revisions for GNOME"
+ type="application/atom+xml"/>]
Only bug feeds should be linked to on bugs.launchpad.test.
>>> browser.open('http://bugs.launchpad.test/gnome')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/gnome/latest-bugs.atom"
- title="Latest Bugs for GNOME" />]
+ [<link href="http://feeds.launchpad.test/gnome/latest-bugs.atom"
+ rel="alternate" title="Latest Bugs for GNOME"
+ type="application/atom+xml"/>]
The default view for a project group on bugs.launchpad.test is +bugs. The
default bug listing matches the latest-bugs atom feed, but any search
@@ -231,21 +235,21 @@ An announcements feed link should also be shown on the main distro page.
>>> browser.open('http://launchpad.test/ubuntu')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/ubuntu/announcements.atom"
- title="Announcements for Ubuntu" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/ubuntu/latest-bugs.atom"
- title="Latest Bugs for Ubuntu" />]
+ [<link href="http://feeds.launchpad.test/ubuntu/announcements.atom"
+ rel="alternate" title="Announcements for Ubuntu"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/ubuntu/latest-bugs.atom"
+ rel="alternate" title="Latest Bugs for Ubuntu"
+ type="application/atom+xml"/>]
Only bug feeds should be linked to on bugs.launchpad.test.
>>> browser.open('http://bugs.launchpad.test/ubuntu')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/ubuntu/latest-bugs.atom"
- title="Latest Bugs for Ubuntu" />]
+ [<link href="http://feeds.launchpad.test/ubuntu/latest-bugs.atom"
+ rel="alternate" title="Latest Bugs for Ubuntu"
+ type="application/atom+xml"/>]
== Latest Bugs for a Distroseries ==
@@ -256,9 +260,10 @@ show a link to the atom feed for that distroseries' latest bugs.
>>> browser.open('http://bugs.launchpad.test/ubuntu/hoary')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
+ [<link
href="http://feeds.launchpad.test/ubuntu/hoary/latest-bugs.atom"
- title="Latest Bugs for Hoary" />]
+ rel="alternate" title="Latest Bugs for Hoary"
+ type="application/atom+xml"/>]
== Latest Bugs for a Product Series ==
@@ -269,9 +274,9 @@ show a link to the atom feed for that product series' latest bugs.
>>> browser.open('http://bugs.launchpad.test/firefox/1.0')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/firefox/1.0/latest-bugs.atom"
- title="Latest Bugs for 1.0" />]
+ [<link href="http://feeds.launchpad.test/firefox/1.0/latest-bugs.atom"
+ rel="alternate" title="Latest Bugs for 1.0"
+ type="application/atom+xml"/>]
== Latest Bugs for a Source Package ==
@@ -282,9 +287,10 @@ show a link to the atom feed for that source package's latest bugs.
>>> browser.open('http://bugs.launchpad.test/ubuntu/+source/cnews')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
+ [<link
href="http://feeds.launchpad.test/ubuntu/+source/cnews/latest-bugs.atom"
- title="Latest Bugs for cnews in Ubuntu" />]
+ rel="alternate" title="Latest Bugs for cnews in Ubuntu"
+ type="application/atom+xml"/>]
== Latest Branches for a ProjectGroup ==
@@ -295,12 +301,14 @@ to the atom feed for that project group's latest branches.
>>> browser.open('http://code.launchpad.test/mozilla')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
+ [<link
href="http://feeds.launchpad.test/mozilla/branches.atom"
- title="Latest Branches for The Mozilla Project" />,
- <link rel="alternate" type="application/atom+xml"
+ rel="alternate" title="Latest Branches for The Mozilla Project"
+ type="application/atom+xml"/>,
+ <link
href="http://feeds.launchpad.test/mozilla/revisions.atom"
- title="Latest Revisions for The Mozilla Project" />]
+ rel="alternate" title="Latest Revisions for The Mozilla Project"
+ type="application/atom+xml"/>]
== Latest Branches for a Product ==
@@ -311,12 +319,13 @@ to the atom feed for that product's latest branches.
>>> browser.open('http://code.launchpad.test/firefox')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/firefox/branches.atom"
- title="Latest Branches for Mozilla Firefox" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/firefox/revisions.atom"
- title="Latest Revisions for Mozilla Firefox" />]
+ [<link href="http://feeds.launchpad.test/firefox/branches.atom"
+ rel="alternate" title="Latest Branches for Mozilla Firefox"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/firefox/revisions.atom"
+ rel="alternate"
+ title="Latest Revisions for Mozilla Firefox"
+ type="application/atom+xml"/>]
== Latest Branches for a Person ==
@@ -327,12 +336,12 @@ to the atom feed for that person's latest branches.
>>> browser.open('http://code.launchpad.test/~mark')
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/~mark/branches.atom"
- title="Latest Branches for Mark Shuttleworth" />,
- <link rel="alternate" type="application/atom+xml"
- href="http://feeds.launchpad.test/~mark/revisions.atom"
- title="Latest Revisions by Mark Shuttleworth" />]
+ [<link href="http://feeds.launchpad.test/~mark/branches.atom"
+ rel="alternate" title="Latest Branches for Mark Shuttleworth"
+ type="application/atom+xml"/>,
+ <link href="http://feeds.launchpad.test/~mark/revisions.atom"
+ rel="alternate" title="Latest Revisions by Mark Shuttleworth"
+ type="application/atom+xml"/>]
== Latest Revisions on a Branch ==
@@ -344,9 +353,11 @@ atom feed for that branch's revisions.
>>> browser.open(url)
>>> soup = BeautifulSoup(browser.contents)
>>> soup.head.findAll('link', type='application/atom+xml')
- [<link rel="alternate" type="application/atom+xml"
+ [<link
href="http://feeds.launchpad.test/~mark/firefox/release--0.9.1/branch.atom"
- title="Latest Revisions for Branch lp://dev/~mark/firefox/release--0.9.1" />]
+ rel="alternate"
+ title="Latest Revisions for Branch lp://dev/~mark/firefox/release--0.9.1"
+ type="application/atom+xml"/>]
But if the branch is private, there should be no link.
diff --git a/lib/lp/services/feeds/stories/xx-security.txt b/lib/lp/services/feeds/stories/xx-security.txt
index ea7122d..2e441df 100644
--- a/lib/lp/services/feeds/stories/xx-security.txt
+++ b/lib/lp/services/feeds/stories/xx-security.txt
@@ -4,32 +4,32 @@ Feeds do not display private bugs
Feeds never contain private bugs, as we are serving feeds over HTTP.
First, set all the bugs to private.
- >>> from zope.security.interfaces import Unauthorized
- >>> from BeautifulSoup import BeautifulStoneSoup as BSS
- >>> from lp.services.database.interfaces import IStore
>>> import transaction
- >>> from lp.bugs.model.bug import Bug
+ >>> from zope.security.interfaces import Unauthorized
>>> from lp.app.enums import InformationType
+ >>> from lp.bugs.model.bug import Bug
+ >>> from lp.services.beautifulsoup import BeautifulSoup4 as BeautifulSoup
+ >>> from lp.services.database.interfaces import IStore
>>> IStore(Bug).find(Bug).set(information_type=InformationType.USERDATA)
>>> transaction.commit()
There should be zero entries in these feeds, since all the bugs are private.
>>> browser.open('http://feeds.launchpad.test/jokosher/latest-bugs.atom')
- >>> BSS(browser.contents)('entry')
+ >>> BeautifulSoup(browser.contents, 'xml')('entry')
[]
>>> browser.open('http://feeds.launchpad.test/mozilla/latest-bugs.atom')
- >>> BSS(browser.contents)('entry')
+ >>> BeautifulSoup(browser.contents, 'xml')('entry')
[]
>>> browser.open('http://feeds.launchpad.test/~name16/latest-bugs.atom')
- >>> BSS(browser.contents)('entry')
+ >>> BeautifulSoup(browser.contents, 'xml')('entry')
[]
>>> browser.open(
... 'http://feeds.launchpad.test/~simple-team/latest-bugs.atom')
- >>> BSS(browser.contents)('entry')
+ >>> BeautifulSoup(browser.contents, 'xml')('entry')
[]
>>> from lp.services.config import config
@@ -41,52 +41,52 @@ There should be zero entries in these feeds, since all the bugs are private.
>>> browser.open('http://feeds.launchpad.test/bugs/+bugs.atom?'
... 'field.searchtext=&search=Search+Bug+Reports&'
... 'field.scope=all&field.scope.target=')
- >>> BSS(browser.contents)('entry')
+ >>> BeautifulSoup(browser.contents, 'xml')('entry')
[]
There should be just one <tr> elements for the table header in
these HTML feeds, since all the bugs are private.
>>> browser.open('http://feeds.launchpad.test/jokosher/latest-bugs.html')
- >>> len(BSS(browser.contents)('tr'))
+ >>> len(BeautifulSoup(browser.contents, 'xml')('tr'))
1
- >>> print extract_text(BSS(browser.contents)('tr')[0])
+ >>> print extract_text(BeautifulSoup(browser.contents, 'xml')('tr')[0])
Bugs in Jokosher
>>> browser.open('http://feeds.launchpad.test/mozilla/latest-bugs.html')
- >>> len(BSS(browser.contents)('tr'))
+ >>> len(BeautifulSoup(browser.contents, 'xml')('tr'))
1
- >>> print extract_text(BSS(browser.contents)('tr')[0])
+ >>> print extract_text(BeautifulSoup(browser.contents, 'xml')('tr')[0])
Bugs in The Mozilla Project
>>> browser.open('http://feeds.launchpad.test/~name16/latest-bugs.html')
- >>> len(BSS(browser.contents)('tr'))
+ >>> len(BeautifulSoup(browser.contents, 'xml')('tr'))
1
- >>> print extract_text(BSS(browser.contents)('tr')[0])
+ >>> print extract_text(BeautifulSoup(browser.contents, 'xml')('tr')[0])
Bugs for Foo Bar
>>> browser.open(
... 'http://feeds.launchpad.test/~simple-team/latest-bugs.html')
- >>> len(BSS(browser.contents)('tr'))
+ >>> len(BeautifulSoup(browser.contents, 'xml')('tr'))
1
- >>> print extract_text(BSS(browser.contents)('tr')[0])
+ >>> print extract_text(BeautifulSoup(browser.contents, 'xml')('tr')[0])
Bugs for Simple Team
>>> browser.open('http://feeds.launchpad.test/bugs/+bugs.html?'
... 'field.searchtext=&search=Search+Bug+Reports&'
... 'field.scope=all&field.scope.target=')
- >>> len(BSS(browser.contents)('tr'))
+ >>> len(BeautifulSoup(browser.contents, 'xml')('tr'))
1
>>> try:
... browser.open('http://feeds.launchpad.test/bugs/1/bug.html')
... except Unauthorized:
... print "Shouldn't raise Unauthorized exception"
- >>> BSS(browser.contents)('entry')
+ >>> BeautifulSoup(browser.contents, 'xml')('entry')
[]
Revert configuration change after tests are finished.
diff --git a/lib/lp/services/feeds/tests/helper.py b/lib/lp/services/feeds/tests/helper.py
index e0a96aa..826df83 100644
--- a/lib/lp/services/feeds/tests/helper.py
+++ b/lib/lp/services/feeds/tests/helper.py
@@ -31,9 +31,11 @@ from zope.interface import (
implementer,
Interface,
)
-from BeautifulSoup import BeautifulStoneSoup as BSS
-from BeautifulSoup import SoupStrainer
+from lp.services.beautifulsoup import (
+ BeautifulSoup4 as BeautifulSoup,
+ SoupStrainer4 as SoupStrainer,
+ )
from lp.services.webapp.publisher import LaunchpadView
@@ -62,25 +64,23 @@ class ThingFeedView(LaunchpadView):
def parse_entries(contents):
"""Define a helper function for parsing feed entries."""
strainer = SoupStrainer('entry')
- entries = [tag for tag in BSS(contents,
- parseOnlyThese=strainer)]
+ entries = [
+ tag for tag in BeautifulSoup(contents, 'xml', parse_only=strainer)]
return entries
def parse_links(contents, rel):
"""Define a helper function for parsing feed links."""
strainer = SoupStrainer('link', rel=rel)
- entries = [tag for tag in BSS(contents,
- parseOnlyThese=strainer,
- selfClosingTags=['link'])]
+ entries = [
+ tag for tag in BeautifulSoup(contents, 'xml', parse_only=strainer)]
return entries
def parse_ids(contents):
"""Define a helper function for parsing ids."""
strainer = SoupStrainer('id')
- ids = [tag for tag in BSS(contents,
- parseOnlyThese=strainer)]
+ ids = [tag for tag in BeautifulSoup(contents, 'xml', parse_only=strainer)]
return ids