Skip to content

Commit 9f5f3f5

Browse files
authored
Merge pull request #66 from tobinus/#65-encoding-on-write
Use encoding when writing file, fixes #65
2 parents e855004 + fae1615 commit 9f5f3f5

17 files changed

+96
-15
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
- Support for Python 3.3, due to its age and lack of support, and bugs with
1717
installing `tinytag`.
1818

19+
### Fixed
20+
21+
- `UnicodeEncodeError` when writing a podcast with non-ASCII characters to file
22+
in an environment where Python defaults to ASCII encoding.
23+
- Incompatibility with unicode strings on Python 2.7.
24+
1925

2026
## [1.0.0] - 2017-05-24
2127
### Added
2228

2329
- The Podcast and Episode classes for easily generating a podcast out of data,
2430
and related utilities and classes.
31+
32+
[1.0.0]: https://github.com/tobinus/python-podgen/compare/290045ac...v1.0.0

podgen/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
:copyright: 2016, Thorben Dahl <[email protected]>
1111
:license: FreeBSD and LGPL, see license.* for more details.
1212
"""
13+
# Support for Python 2.7
14+
from __future__ import absolute_import, division, print_function, unicode_literals
15+
from builtins import *
16+
1317
from .podcast import Podcast
1418
from .episode import Episode
1519
from .media import Media

podgen/__main__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
88
:license: FreeBSD and LGPL, see license.* for more details.
99
'''
10+
# Support for Python 2.7
11+
from __future__ import absolute_import, division, print_function, unicode_literals
12+
from builtins import *
1013

1114
import sys
1215
import datetime

podgen/category.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
:copyright: 2016, Thorben Dahl <[email protected]>
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
"""
11+
# Support for Python 2.7
12+
from __future__ import absolute_import, division, print_function, unicode_literals
13+
from builtins import *
14+
15+
1116
class Category(object):
1217
"""Immutable class representing an iTunes category.
1318

podgen/episode.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
"""
11+
# Support for Python 2.7
12+
from __future__ import absolute_import, division, print_function, unicode_literals
13+
from builtins import *
14+
from future.utils import iteritems
15+
1116
import warnings
1217

1318
from lxml import etree
@@ -18,8 +23,6 @@
1823
from podgen.not_supported_by_itunes_warning import NotSupportedByItunesWarning
1924
from podgen.util import formatRFC2822, listToHumanreadableStr
2025
from podgen.compat import string_types
21-
from builtins import str
22-
from future.utils import iteritems
2326

2427

2528
class Episode(object):
@@ -503,14 +506,14 @@ def image(self, image):
503506
def explicit(self):
504507
"""Whether this podcast episode contains material which may be
505508
inappropriate for children.
506-
509+
507510
The value of the podcast's explicit attribute is used by default, if
508511
this is kept as ``None``.
509512
510513
If you set this to ``True``, an "explicit" parental advisory
511-
graphic will appear in the Name column in iTunes. If the value is
512-
``False``, the parental advisory type is considered Clean, meaning that
513-
no explicit language or adult content is included anywhere in this
514+
graphic will appear in the Name column in iTunes. If the value is
515+
``False``, the parental advisory type is considered Clean, meaning that
516+
no explicit language or adult content is included anywhere in this
514517
episode, and a "clean" graphic will appear.
515518
516519
:type: :obj:`bool`

podgen/media.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@
99
:copyright: 2016, Thorben Dahl <[email protected]>
1010
:license: FreeBSD and LGPL, see license.* for more details.
1111
"""
12+
# Support for Python 2.7
13+
from __future__ import absolute_import, division, print_function, unicode_literals
14+
from builtins import *
15+
from future.moves.urllib.parse import urlparse
16+
from future.utils import raise_from
17+
1218
import os
1319
import tempfile
1420
import warnings
15-
from future.moves.urllib.parse import urlparse
16-
from future.utils import raise_from
1721
import datetime
1822

1923
from tinytag import TinyTag

podgen/not_supported_by_itunes_warning.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,10 @@
99
:copyright: 2016, Thorben Dahl <[email protected]>
1010
:license: FreeBSD and LGPL, see license.* for more details.
1111
"""
12+
# Support for Python 2.7
13+
from __future__ import absolute_import, division, print_function, unicode_literals
14+
from builtins import *
15+
16+
1217
class NotSupportedByItunesWarning(UserWarning):
1318
pass

podgen/person.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
:copyright: 2016, Thorben Dahl <[email protected]>
1010
:license: FreeBSD and LGPL, see license.* for more details.
1111
"""
12+
# Support for Python 2.7
13+
from __future__ import absolute_import, division, print_function, unicode_literals
14+
from builtins import *
15+
16+
1217
class Person(object):
1318
"""Data-oriented class representing a single person or entity.
1419

podgen/podcast.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
1111
"""
12+
# Support for Python 2.7
13+
from __future__ import absolute_import, division, print_function, unicode_literals
14+
from builtins import *
1215
from future.utils import iteritems
16+
1317
from lxml import etree
1418
from datetime import datetime
1519
import dateutil.parser
@@ -668,7 +672,8 @@ def rss_file(self, filename, minimize=False,
668672
669673
File-like objects given to this method will not be closed.
670674
671-
:param filename: Name of file to write, or a file-like object, or a URL.
675+
:param filename: Name of file to write, or a file-like object (accepting
676+
string/unicode, not bytes).
672677
:type filename: str or fd
673678
:param minimize: Set to True to disable splitting the feed into multiple
674679
lines and adding properly indentation, saving bytes at the cost of
@@ -686,7 +691,7 @@ def rss_file(self, filename, minimize=False,
686691
# Have we got a filename, or a file-like object?
687692
if isinstance(filename, string_types):
688693
# It is a string, assume it is filename
689-
with open(filename, "w") as fd:
694+
with open(filename, "w", encoding=encoding) as fd:
690695
fd.write(rss)
691696
elif hasattr(filename, "write"):
692697
# It is file-like enough to fool us

podgen/tests/test_category.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
:copyright: 2016, Thorben Dahl <[email protected]>
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
"""
11+
# Support for Python 2.7
12+
from __future__ import absolute_import, division, print_function, unicode_literals
13+
from builtins import *
14+
1115
import unittest
1216

1317
from podgen import Category

podgen/tests/test_episode.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
:copyright: 2016, Thorben Dahl <[email protected]>
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
"""
11+
# Support for Python 2.7
12+
from __future__ import absolute_import, division, print_function, unicode_literals
13+
from builtins import *
1114

1215
import unittest
1316
import warnings
@@ -20,6 +23,7 @@
2023
import pytz
2124
from dateutil.parser import parse as parsedate
2225

26+
2327
class TestBaseEpisode(unittest.TestCase):
2428

2529
def setUp(self):

podgen/tests/test_media.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88
:copyright: 2016, Thorben Dahl <[email protected]>
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
"""
11+
# Support for Python 2.7
12+
from __future__ import absolute_import, division, print_function, unicode_literals
13+
from builtins import *
14+
from future.utils import iteritems
15+
1116
import os
1217
import tempfile
1318

1419
import pickle
15-
from future.utils import iteritems
1620
import unittest
1721
import warnings
1822
from datetime import timedelta

podgen/tests/test_person.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
:copyright: 2016, Thorben Dahl <[email protected]>
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
"""
11+
# Support for Python 2.7
12+
from __future__ import absolute_import, division, print_function, unicode_literals
13+
from builtins import *
14+
1115
import unittest
1216
from podgen import Person
1317

podgen/tests/test_podcast.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,18 @@
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
"""
1111

12+
# Support for Python 2.7
13+
from __future__ import absolute_import, division, print_function, unicode_literals
14+
from builtins import *
15+
from future.utils import raise_from
16+
1217
import unittest
1318
import warnings
19+
import locale
1420

1521
from lxml import etree
1622
import tempfile
1723
import os
18-
from future.utils import raise_from
1924

2025
from podgen import NotSupportedByItunesWarning, Person, Category, Podcast
2126
import podgen.version
@@ -26,6 +31,8 @@
2631
class TestPodcast(unittest.TestCase):
2732

2833
def setUp(self):
34+
self.existing_locale = locale.setlocale(locale.LC_ALL, None)
35+
locale.setlocale(locale.LC_ALL, 'C')
2936

3037
fg = Podcast()
3138

@@ -36,7 +43,8 @@ def setUp(self):
3643

3744
self.name = 'Some Testfeed'
3845

39-
self.author = Person('John Doe', '[email protected]')
46+
# Use character not in ASCII to catch encoding errors
47+
self.author = Person('Jon Døll', '[email protected]')
4048

4149
self.website = 'http://example.com'
4250
self.description = 'This is a cool feed!'
@@ -99,6 +107,9 @@ def noop(*args, **kwargs):
99107
pass
100108
warnings.showwarning = noop
101109

110+
def tearDown(self):
111+
locale.setlocale(locale.LC_ALL, self.existing_locale)
112+
102113
def test_constructor(self):
103114
# Overwrite fg from setup
104115
self.fg = Podcast(
@@ -167,16 +178,17 @@ def getRssFeedFileContents(self, fg, **kwargs):
167178
# Keep track of our temporary file and its filename
168179
filename = None
169180
file = None
181+
encoding = 'UTF-8'
170182
try:
171183
# Get our temporary file name
172184
file = tempfile.NamedTemporaryFile(delete=False)
173185
filename = file.name
174186
# Close the file; we will just use its name
175187
file.close()
176188
# Write the RSS to the file (overwriting it)
177-
fg.rss_file(filename=filename, **kwargs)
189+
fg.rss_file(filename=filename, encoding=encoding, **kwargs)
178190
# Read the resulting RSS
179-
with open(filename, "r") as myfile:
191+
with open(filename, "r", encoding=encoding) as myfile:
180192
rssString = myfile.read()
181193
finally:
182194
# We don't need the file any longer, so delete it

podgen/tests/test_util.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
:copyright: 2016, Thorben Dahl <[email protected]>
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
"""
11+
# Support for Python 2.7
12+
from __future__ import absolute_import, division, print_function, unicode_literals
13+
from builtins import *
14+
1115
import unittest
1216
from podgen import util
1317

podgen/util.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
1010
:license: FreeBSD and LGPL, see license.* for more details.
1111
"""
12+
# Support for Python 2.7
13+
from __future__ import absolute_import, division, print_function, unicode_literals
14+
from builtins import *
15+
1216
import sys, locale
1317

1418

podgen/version.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
:license: FreeBSD and LGPL, see license.* for more details.
1010
1111
"""
12+
# Support for Python 2.7
13+
from __future__ import absolute_import, division, print_function, unicode_literals
14+
from builtins import *
1215

1316
'Version of python-podgen represented as tuple'
1417
version = (1, 0, 0)

0 commit comments

Comments
 (0)