feed: Implement feed.fetch()
authorW. Trevor King <wking@tremily.us>
Sun, 30 Jun 2013 14:04:48 +0000 (10:04 -0400)
committerW. Trevor King <wking@tremily.us>
Sun, 30 Jun 2013 16:26:17 +0000 (12:26 -0400)
Add __version__, __url__, and USER_AGENT to the package namespace, so
we have a useful user agent to use when fetching.  The fetch code can
hard-code UTF-8 as the feed charset, because RFC 5545, section 6
(Internationalization Considerations) reads:

  Applications MUST generate iCalendar streams in the UTF-8 charset
  and MUST accept an iCalendar stream in the UTF-8 or US-ASCII
  charset.

From a character conversion standpoint, that means we can always use
UTF-8, because US-ASCII is a subset of UTF-8.

pycalendar/__init__.py
pycalendar/feed.py

index b98f1648fbd537dcaaf3dc1283834dea4e906f4b..247a580286221c0dd42a73f8fc53db70d8bb044e 100644 (file)
@@ -1 +1,6 @@
 # Copyright
+
+__version__ = '0.1'
+__url__ = 'https://pypi.python.org/pypi/{}/'.format(__name__)
+
+USER_AGENT = '{}/{} +{}'.format(__name__, __version__, __url__)
index b4a90c1f97b1828f53aa0b287e6d14e3e51e6a13..52240c21057aa9577fce99dae9366c8a5f3d3eab 100644 (file)
@@ -1,22 +1,38 @@
 # Copyright
 
+import urllib.request as _urllib_request
+
+from . import USER_AGENT as _USER_AGENT
+
+
 class Feed (object):
     r"""An iCalendar feed (:RFC:`5545`)
 
-    >>> f = Feed(url='http://example.com/calendar.ics')
-    >>> f
-    <Feed url:http://example.com/calendar.ics>
+    Figure out where the example feed is located, relative to the
+    directory from which you run this doctest (i.e., the project's
+    root directory).
+
+    >>> import os
+    >>> root_dir = os.curdir
+    >>> data_file = os.path.abspath(os.path.join(
+    ...         root_dir, 'test', 'data', 'geohash.ics'))
+    >>> url = 'file://{}'.format(data_file.replace(os.sep, '/'))
+
+    Create a new feed pointing to this URL.
+
+    >>> f = Feed(url=url)
+    >>> f  # doctest: +ELLIPSIS
+    <Feed url:file://.../test/data/geohash.ics>
     >>> print(f)
     <BLANKLINE>
 
-    We can't fetch this dummy url, so load the content by hand.
+    Load the feed content.
+
+    >>> f.fetch()
+
+    The ``.__str__`` method displays the feed content using Python's
+    universal newlines.
 
-    >>> import os
-    >>> root_dir = os.curdir
-    >>> data_file = os.path.join(os.curdir, 'test', 'data', 'geohash.ics')
-    >>> with open(data_file, 'r') as data:
-    ...     f.content = data.read().replace('\n', data.newlines)
-    ...     assert data.newlines == '\r\n', data.newlines
     >>> print(f)  # doctest: +REPORT_UDIFF
     BEGIN:VCALENDAR
     VERSION:2.0
@@ -42,9 +58,12 @@ class Feed (object):
     >>> stream.getvalue()  # doctest: +ELLIPSIS
     'BEGIN:VCALENDAR\r\nVERSION:2.0\r\n...END:VCALENDAR\r\n'
     """
-    def __init__(self, url, content=None):
+    def __init__(self, url, content=None, user_agent=None):
         self.url = url
         self.content = content
+        if user_agent is None:
+            user_agent = _USER_AGENT
+        self.user_agent = user_agent
 
     def __str__(self):
         if self.content:
@@ -55,7 +74,19 @@ class Feed (object):
         return '<{} url:{}>'.format(type(self).__name__, self.url)
 
     def fetch(self):
-        raise NotImplementedError()
+        request = _urllib_request.Request(
+            url=self.url,
+            headers={
+                'User-Agent': self.user_agent,
+                },
+            )
+        with _urllib_request.urlopen(url=request) as f:
+            info = f.info()
+            content_type = info.get('Content-type', None)
+            if content_type != 'text/calendar':
+                raise ValueError(content_type)
+            byte_content = f.read()
+        self.content = str(byte_content, encoding='UTF-8')
 
     def write(self, stream):
         stream.write(self.content)