Skip to content

Commit 1d3b0dc

Browse files
author
api.jscudder
committed
Adding modules for Blogger service.
1 parent 7e06b5c commit 1d3b0dc

7 files changed

Lines changed: 352 additions & 96 deletions

File tree

src/gdata/__init__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,29 @@ def ItemsPerPageFromString(xml_string):
237237
return atom.CreateClassFromXMLString(ItemsPerPage, xml_string)
238238

239239

240+
class ExtendedProperty(atom.AtomBase):
241+
"""The Google Calendar extendedProperty element"""
242+
243+
_tag = 'extendedProperty'
244+
_namespace = GDATA_NAMESPACE
245+
_children = atom.AtomBase._children.copy()
246+
_attributes = atom.AtomBase._attributes.copy()
247+
_attributes['name'] = 'name'
248+
_attributes['value'] = 'value'
249+
250+
def __init__(self, name=None, value=None, extension_elements=None,
251+
extension_attributes=None, text=None):
252+
self.name = name
253+
self.value = value
254+
self.text = text
255+
self.extension_elements = extension_elements or []
256+
self.extension_attributes = extension_attributes or {}
257+
258+
259+
def ExtendedPropertyFromString(xml_string):
260+
return atom.CreateClassFromXMLString(ExtendedProperty, xml_string)
261+
262+
240263
class GDataEntry(atom.Entry, LinkFinder):
241264
"""Extends Atom Entry to provide data processing"""
242265

src/gdata/blogger/service.py

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,29 @@ def __init__(self, email=None, password=None, source=None,
3232
server=server,
3333
additional_headers=additional_headers)
3434

35-
def GetBlogFeed(self, uri):
35+
def GetBlogFeed(self, uri=None):
36+
"""Retrieve a list of the blogs to which the current user may manage."""
37+
if not uri:
38+
uri = 'http://www.blogger.com/feeds/default/blogs'
3639
return self.Get(uri, converter=gdata.blogger.BlogFeedFromString)
3740

38-
def GetBlogCommentFeed(self, uri):
39-
return self.Get(uri, converter=gdata.blogger.BlogCommentFeedFromString)
41+
def GetBlogCommentFeed(self, blog_id=None, uri=None):
42+
"""Retrieve a list of the comments for this blog."""
43+
if blog_id:
44+
uri = 'http://www.blogger.com/feeds/%s/comments/default' % blog_id
45+
return self.Get(uri, converter=gdata.blogger.CommentFeedFromString)
4046

41-
def GetBlogPostFeed(self, uri):
47+
def GetBlogPostFeed(self, blog_id=None, uri=None):
48+
if blog_id:
49+
uri = 'http://www.blogger.com/feeds/%s/posts/default' % blog_id
4250
return self.Get(uri, converter=gdata.blogger.BlogPostFeedFromString)
4351

44-
def GetPostCommentFeed(self, uri):
45-
return self.Get(uri, converter=gdata.blogger.PostCommentFeedFromString)
52+
def GetPostCommentFeed(self, blog_id=None, post_id=None, uri=None):
53+
"""Retrieve a list of the comments for this particular blog post."""
54+
if blog_id and post_id:
55+
uri = 'http://www.blogger.com/feeds/%s/%s/comments/default' % (blog_id,
56+
post_id)
57+
return self.Get(uri, converter=gdata.blogger.CommentFeedFromString)
4658

4759
def AddPost(self, entry, blog_id=None, uri=None):
4860
if blog_id:
@@ -56,7 +68,70 @@ def UpdatePost(self, entry, uri=None):
5668
return self.Put(entry, uri,
5769
converter=gdata.blogger.BlogPostEntryFromString)
5870

59-
def PostComment(self, comment_entry, blog_id=None, post_id=None, uri=None):
60-
# TODO
61-
pass
71+
def DeletePost(self, entry=None, uri=None):
72+
if not uri:
73+
uri = entry.GetEditLink().href
74+
return self.Delete(uri)
75+
76+
def AddComment(self, comment_entry, blog_id=None, post_id=None, uri=None):
77+
"""Adds a new comment to the specified blog post."""
78+
if blog_id and post_id:
79+
uri = 'http://www.blogger.com/feeds/%s/%s/comments/default' % (
80+
blog_id, post_id)
81+
return self.Post(comment_entry, uri,
82+
converter=gdata.blogger.CommentEntryFromString)
83+
84+
def DeleteComment(self, entry=None, uri=None):
85+
if not uri:
86+
uri = entry.GetEditLink().href
87+
return self.Delete(uri)
88+
89+
90+
class BlogQuery(gdata.service.Query):
91+
92+
def __init__(self, feed=None, params=None, categories=None, blog_id=None):
93+
"""Constructs a query object for the list of a user's Blogger blogs.
94+
95+
Args:
96+
feed: str (optional) The beginning of the URL to be queried. If the
97+
feed is not set, and there is no blog_id passed in, the default
98+
value is used ('http://www.blogger.com/feeds/default/blogs').
99+
params: dict (optional)
100+
categories: list (optional)
101+
blog_id: str (optional)
102+
"""
103+
if not feed and blog_id:
104+
feed = 'http://www.blogger.com/feeds/default/blogs/%s' % blog_id
105+
elif not feed:
106+
feed = 'http://www.blogger.com/feeds/default/blogs'
107+
gdata.service.Query.__init__(self, feed=feed, params=params,
108+
categories=categories)
109+
110+
111+
class BlogPostQuery(gdata.service.Query):
112+
113+
def __init__(self, feed=None, params=None, categories=None, blog_id=None,
114+
post_id=None):
115+
if not feed and blog_id and post_id:
116+
feed = 'http://www.blogger.com/feeds/%s/posts/default/%s' % (blog_id,
117+
post_id)
118+
elif not feed and blog_id:
119+
feed = 'http://www.blogger.com/feeds/%s/posts/default' % blog_id
120+
gdata.service.Query.__init__(self, feed=feed, params=params,
121+
categories=categories)
122+
123+
124+
class BlogCommentQuery(gdata.service.Query):
62125

126+
def __init__(self, feed=None, params=None, categories=None, blog_id=None,
127+
post_id=None, comment_id=None):
128+
if not feed and blog_id and comment_id:
129+
feed = 'http://www.blogger.com/feeds/%s/comments/default/%s' % (
130+
blog_id, comment_id)
131+
elif not feed and blog_id and post_id:
132+
feed = 'http://www.blogger.com/feeds/%s/%s/comments/default' % (
133+
blog_id, post_id)
134+
elif not feed and blog_id:
135+
feed = 'http://www.blogger.com/feeds/%s/comments/default' % blog_id
136+
gdata.service.Query.__init__(self, feed=feed, params=params,
137+
categories=categories)

src/gdata/calendar/__init__.py

Lines changed: 18 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -257,23 +257,25 @@ class CalendarEventCommentFeed(gdata.GDataFeed, gdata.LinkFinder):
257257
[CalendarEventCommentEntry])
258258

259259

260-
class ExtendedProperty(atom.AtomBase):
261-
"""The Google Calendar extendedProperty element"""
262-
263-
_tag = 'extendedProperty'
264-
_namespace = gdata.GDATA_NAMESPACE
265-
_children = atom.AtomBase._children.copy()
266-
_attributes = atom.AtomBase._attributes.copy()
267-
_attributes['name'] = 'name'
268-
_attributes['value'] = 'value'
260+
#class ExtendedProperty(atom.AtomBase):
261+
# """The Google Calendar extendedProperty element"""
262+
#
263+
# _tag = 'extendedProperty'
264+
# _namespace = gdata.GDATA_NAMESPACE
265+
# _children = atom.AtomBase._children.copy()
266+
# _attributes = atom.AtomBase._attributes.copy()
267+
# _attributes['name'] = 'name'
268+
# _attributes['value'] = 'value'
269+
#
270+
# def __init__(self, name=None, value=None, extension_elements=None,
271+
# extension_attributes=None, text=None):
272+
# self.name = name
273+
# self.value = value
274+
# self.text = text
275+
# self.extension_elements = extension_elements or []
276+
# self.extension_attributes = extension_attributes or {}
269277

270-
def __init__(self, name=None, value=None, extension_elements=None,
271-
extension_attributes=None, text=None):
272-
self.name = name
273-
self.value = value
274-
self.text = text
275-
self.extension_elements = extension_elements or []
276-
self.extension_attributes = extension_attributes or {}
278+
ExtendedProperty = gdata.ExtendedProperty
277279

278280

279281
class Reminder(atom.AtomBase):
@@ -925,74 +927,3 @@ def CalendarEventFeedFromString(xml_string):
925927

926928
def CalendarEventCommentFeedFromString(xml_string):
927929
return atom.CreateClassFromXMLString(CalendarEventCommentFeed, xml_string)
928-
929-
930-
# Code to create atom feeds from element trees
931-
#_CalendarListFeedFromElementTree = atom._AtomInstanceFromElementTree(
932-
# CalendarListFeed, 'feed', atom.ATOM_NAMESPACE)
933-
#_CalendarListEntryFromElementTree = atom._AtomInstanceFromElementTree(
934-
# CalendarListEntry, 'entry', atom.ATOM_NAMESPACE)
935-
#_CalendarAclFeedFromElementTree = atom._AtomInstanceFromElementTree(
936-
# CalendarAclFeed, 'feed', atom.ATOM_NAMESPACE)
937-
#_CalendarAclEntryFromElementTree = atom._AtomInstanceFromElementTree(
938-
# CalendarAclEntry, 'entry', atom.ATOM_NAMESPACE)
939-
#_CalendarEventFeedFromElementTree = atom._AtomInstanceFromElementTree(
940-
# CalendarEventFeed, 'feed', atom.ATOM_NAMESPACE)
941-
#_CalendarEventEntryFromElementTree = atom._AtomInstanceFromElementTree(
942-
# CalendarEventEntry, 'entry', atom.ATOM_NAMESPACE)
943-
#_CalendarEventCommentFeedFromElementTree = atom._AtomInstanceFromElementTree(
944-
# CalendarEventCommentFeed, 'feed', atom.ATOM_NAMESPACE)
945-
#_CalendarEventCommentEntryFromElementTree = atom._AtomInstanceFromElementTree(
946-
# CalendarEventCommentEntry, 'entry', atom.ATOM_NAMESPACE)
947-
#_WhereFromElementTree = atom._AtomInstanceFromElementTree(
948-
# Where, 'where', gdata.GDATA_NAMESPACE)
949-
#_WhenFromElementTree = atom._AtomInstanceFromElementTree(
950-
# When, 'when', gdata.GDATA_NAMESPACE)
951-
#_WhoFromElementTree = atom._AtomInstanceFromElementTree(
952-
# Who, 'who', gdata.GDATA_NAMESPACE)
953-
#_VisibilityFromElementTree= atom._AtomInstanceFromElementTree(
954-
# Visibility, 'visibility', gdata.GDATA_NAMESPACE)
955-
#_TransparencyFromElementTree = atom._AtomInstanceFromElementTree(
956-
# Transparency, 'transparency', gdata.GDATA_NAMESPACE)
957-
#_CommentsFromElementTree = atom._AtomInstanceFromElementTree(
958-
# Comments, 'comments', gdata.GDATA_NAMESPACE)
959-
#_EventStatusFromElementTree = atom._AtomInstanceFromElementTree(
960-
# EventStatus, 'eventStatus', gdata.GDATA_NAMESPACE)
961-
#_SendEventNotificationsFromElementTree = atom._AtomInstanceFromElementTree(
962-
# SendEventNotifications, 'sendEventNotifications', GCAL_NAMESPACE)
963-
#_QuickAddFromElementTree = atom._AtomInstanceFromElementTree(
964-
# QuickAdd, 'quickadd', GCAL_NAMESPACE)
965-
#_AttendeeStatusFromElementTree = atom._AtomInstanceFromElementTree(
966-
# AttendeeStatus, 'attendeeStatus', gdata.GDATA_NAMESPACE)
967-
#_AttendeeTypeFromElementTree = atom._AtomInstanceFromElementTree(
968-
# AttendeeType, 'attendeeType', gdata.GDATA_NAMESPACE)
969-
#_ExtendedPropertyFromElementTree = atom._AtomInstanceFromElementTree(
970-
# ExtendedProperty, 'extendedProperty', gdata.GDATA_NAMESPACE)
971-
#_RecurrenceFromElementTree = atom._AtomInstanceFromElementTree(
972-
# Recurrence, 'recurrence', gdata.GDATA_NAMESPACE)
973-
#_RecurrenceExceptionFromElementTree = atom._AtomInstanceFromElementTree(
974-
# RecurrenceException, 'recurrenceException', gdata.GDATA_NAMESPACE)
975-
#_OriginalEventFromElementTree = atom._AtomInstanceFromElementTree(
976-
# OriginalEvent, 'originalEvent', gdata.GDATA_NAMESPACE)
977-
#_ColorFromElementTree = atom._AtomInstanceFromElementTree(
978-
# Color, 'color', GCAL_NAMESPACE)
979-
#_HiddenFromElementTree = atom._AtomInstanceFromElementTree(
980-
# Hidden, 'hidden', GCAL_NAMESPACE)
981-
#_SelectedFromElementTree = atom._AtomInstanceFromElementTree(
982-
# Selected, 'selected', GCAL_NAMESPACE)
983-
#_TimezoneFromElementTree = atom._AtomInstanceFromElementTree(
984-
# Timezone, 'timezone', GCAL_NAMESPACE)
985-
#_AccessLevelFromElementTree = atom._AtomInstanceFromElementTree(
986-
# AccessLevel, 'accesslevel', GCAL_NAMESPACE)
987-
#_ReminderFromElementTree = atom._AtomInstanceFromElementTree(
988-
# Reminder, 'reminder', gdata.GDATA_NAMESPACE)
989-
#_ScopeFromElementTree = atom._AtomInstanceFromElementTree(
990-
# Scope, 'scope', GACL_NAMESPACE)
991-
#_RoleFromElementTree = atom._AtomInstanceFromElementTree(
992-
# Role, 'role', GACL_NAMESPACE)
993-
#_WebContentLinkFromElementTree = atom._AtomInstanceFromElementTree(
994-
# WebContentLink, 'link', atom.ATOM_NAMESPACE)
995-
#_WebContentFromElementTree = atom._AtomInstanceFromElementTree(
996-
# WebContent, 'webContent', GCAL_NAMESPACE)
997-
#_WebContentGadgetPrefFromElementTree = atom._AtomInstanceFromElementTree(
998-
# WebContentGadgetPref, 'webContentGadgetPref', GCAL_NAMESPACE)

tests/gdata_tests/blogger/__init__.py

Whitespace-only changes.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/python
2+
#
3+
# Copyright (C) 2007 Google Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
"""Unit tests to exercise server interactions for blogger."""
19+
20+
__author__ = 'api.jscudder (Jeffrey Scudder)'
21+
22+
import unittest
23+
import getpass
24+
import atom
25+
from gdata import test_data
26+
import gdata.blogger
27+
import gdata.blogger.service
28+
29+
username = ''
30+
password = ''
31+
test_blog_id = ''
32+
33+
class BloggerCrudTests(unittest.TestCase):
34+
35+
def setUp(self):
36+
self.client = gdata.blogger.service.BloggerService(email=username,
37+
password=password, source='GoogleInc-PythonBloggerUnitTests-1')
38+
# TODO: if the test_blog_id is not set, get the list of the user's blogs
39+
# and prompt for which blog to add the test posts to.
40+
self.client.ProgrammaticLogin()
41+
42+
def testPostDraftUpdateAndDelete(self):
43+
new_entry = gdata.blogger.BlogPostEntry(title=atom.Title(
44+
text='Unit Test Post'))
45+
new_entry.content = atom.Content('text', None, 'Hello World')
46+
# Make this post a draft so it will not appear publicly on the blog.
47+
new_entry.control = atom.Control(draft=atom.Draft(text='yes'))
48+
new_entry.AddLabel('test')
49+
50+
posted = self.client.AddPost(new_entry, blog_id=test_blog_id)
51+
52+
self.assertEquals(posted.title.text, new_entry.title.text)
53+
# Should be one category in the posted entry for the 'test' label.
54+
self.assertEquals(len(posted.category), 1)
55+
self.assert_(isinstance(posted, gdata.blogger.BlogPostEntry))
56+
57+
# Change the title and add more labels.
58+
posted.title.text = 'Updated'
59+
posted.AddLabel('second')
60+
updated = self.client.UpdatePost(entry=posted)
61+
62+
self.assertEquals(updated.title.text, 'Updated')
63+
self.assertEquals(len(updated.category), 2)
64+
65+
# Cleanup and delete the draft blog post.
66+
self.client.DeletePost(entry=posted)
67+
68+
def testAddComment(self):
69+
# Create a test post to add comments to.
70+
new_entry = gdata.blogger.BlogPostEntry(title=atom.Title(
71+
text='Comments Test Post'))
72+
new_entry.content = atom.Content('text', None, 'Hello Comments')
73+
target_post = self.client.AddPost(new_entry, blog_id=test_blog_id)
74+
75+
blog_id = target_post.GetBlogId()
76+
post_id = target_post.GetPostId()
77+
78+
new_comment = gdata.blogger.CommentEntry()
79+
new_comment.content = atom.Content(text='Test comment')
80+
posted = self.client.AddComment(new_comment, blog_id=blog_id,
81+
post_id=post_id)
82+
self.assertEquals(posted.content.text, new_comment.content.text)
83+
84+
# Cleanup and delete the comment test blog post.
85+
self.client.DeletePost(entry=target_post)
86+
87+
88+
class BloggerQueryTests(unittest.TestCase):
89+
90+
def testConstructBlogQuery(self):
91+
pass
92+
93+
def testConstructBlogQuery(self):
94+
pass
95+
96+
def testConstructBlogQuery(self):
97+
pass
98+
99+
100+
if __name__ == '__main__':
101+
print ('NOTE: Please run these tests only with a test account. ' +
102+
'The tests may delete or update your data.')
103+
username = raw_input('Please enter your username: ')
104+
password = getpass.getpass()
105+
test_blog_id = raw_input('Please enter the blog id for the test blog: ')
106+
unittest.main()
107+

0 commit comments

Comments
 (0)