Skip to content

Commit

Permalink
Refactor embedding to PyEmbed class
Browse files Browse the repository at this point in the history
  • Loading branch information
matt-thomson committed Jan 20, 2014
1 parent c66fddb commit ecd3f8e
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 82 deletions.
28 changes: 26 additions & 2 deletions pyembed/core/__init__.py
Expand Up @@ -20,7 +20,31 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from pyembed.core import consumer
from pyembed.core.render import DefaultRenderer

class PyEmbedError(Exception):

'''Generic error class for PyEmbed.'''
class PyEmbed(object):

def __init__(self, renderer=DefaultRenderer()):
"""OEmbed consumer with automatic discovery.
:param renderer: (optional) renderer to render the response.
"""
self.renderer = renderer

def embed(self,
url,
max_width=None,
max_height=None):
"""Returns an HTML representation of a resource, given a URL. This
can be directly embedded in a web page.
:param url: the content URL.
:param max_width: (optional) the maximum width of the embedded resource.
:param max_height: (optional) the maximum height of the embedded resource.
:returns: an HTML representation of the resource.
:raises PyEmbedError: if there is an error fetching the response.
"""
response = consumer.get_oembed_response(url, max_width, max_height)
return self.renderer.render(url, response)
25 changes: 2 additions & 23 deletions pyembed/core/consumer.py
Expand Up @@ -20,7 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from pyembed.core import discovery, parse, render, PyEmbedError
from pyembed.core import discovery, parse
from pyembed.core.error import PyEmbedError

import requests

Expand All @@ -30,28 +31,6 @@ class PyEmbedConsumerError(PyEmbedError):
"""Thrown if there is an error discovering an OEmbed URL."""


def embed(url,
max_width=None,
max_height=None,
renderer=None):
"""Returns an HTML representation of a resource, given a URL. This can be
directly embedded in a web page.
:param url: the content URL.
:param max_width: (optional) the maximum width of the embedded resource.
:param max_height: (optional) the maximum height of the embedded resource.
:param renderer: (optional) renderer to render the response.
:returns: an HTML representation of the resource.
:raises PyEmbedError: if there is an error fetching the response.
"""
response = get_oembed_response(url, max_width, max_height)

if renderer is None:
renderer = render.DefaultRenderer()

return renderer.render(url, response)


def get_oembed_response(url, max_width=None, max_height=None):
"""Fetches an OEmbed response for a given content URL.
Expand Down
2 changes: 1 addition & 1 deletion pyembed/core/discovery.py
Expand Up @@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from pyembed.core import PyEmbedError
from pyembed.core.error import PyEmbedError

import requests
from bs4 import BeautifulSoup
Expand Down
26 changes: 26 additions & 0 deletions pyembed/core/error.py
@@ -0,0 +1,26 @@
# The MIT License(MIT)

# Copyright (c) 2013-2014 Matt Thomson

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


class PyEmbedError(Exception):

'''Generic error class for PyEmbed.'''
4 changes: 2 additions & 2 deletions pyembed/core/parse.py
Expand Up @@ -20,8 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from pyembed.core import PyEmbedError
from . import response
from pyembed.core.error import PyEmbedError
from pyembed.core import response

from bs4 import BeautifulSoup
import json
Expand Down
2 changes: 1 addition & 1 deletion pyembed/core/render.py
Expand Up @@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from pyembed.core import PyEmbedError
from pyembed.core.error import PyEmbedError


class PyEmbedRenderer(object):
Expand Down
45 changes: 0 additions & 45 deletions pyembed/core/test/consumer_test.py
Expand Up @@ -94,48 +94,3 @@ def test_should_raise_error_on_request_error():
mock_get.return_value = response

consumer.get_oembed_response('http://example.com/')


def test_should_embed():
with patch('pyembed.core.consumer.get_oembed_response') as mock_get:
response = Mock()
response.type = 'rich'
response.html = '<h1>hello</h1>'

mock_get.return_value = response

result = consumer.embed('http://example.com/')
assert_that(result, equal_to('<h1>hello</h1>'))

mock_get.assert_called_with('http://example.com/', None, None)


def test_should_embed_with_max_width_and_height():
with patch('pyembed.core.consumer.get_oembed_response') as mock_get:
response = Mock()
response.type = 'rich'
response.html = '<h1>hello</h1>'

mock_get.return_value = response

result = consumer.embed('http://example.com/', 100, 200)
assert_that(result, equal_to('<h1>hello</h1>'))

mock_get.assert_called_with('http://example.com/', 100, 200)


def test_should_embed_with_custom_renderer():
with patch('pyembed.core.consumer.get_oembed_response') as mock_get:
response = Mock()
response.type = 'rich'
response.html = '<h1>hello</h1>'

renderer = Mock()
renderer.render = lambda content_url, response: '<h1>hi</h1>'

mock_get.return_value = response

result = consumer.embed('http://example.com/', 100, 200, renderer)
assert_that(result, equal_to('<h1>hi</h1>'))

mock_get.assert_called_with('http://example.com/', 100, 200)
73 changes: 73 additions & 0 deletions pyembed/core/test/embed_test.py
@@ -0,0 +1,73 @@
# The MIT License(MIT)

# Copyright (c) 2013-2014 Matt Thomson

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from pyembed.core import PyEmbed

from hamcrest import assert_that, equal_to
from mock import patch, Mock

import pytest


def test_should_embed():
with patch('pyembed.core.consumer.get_oembed_response') as mock_get:
response = Mock()
response.type = 'rich'
response.html = '<h1>hello</h1>'

mock_get.return_value = response

result = PyEmbed().embed('http://example.com/')
assert_that(result, equal_to('<h1>hello</h1>'))

mock_get.assert_called_with('http://example.com/', None, None)


def test_should_embed_with_max_width_and_height():
with patch('pyembed.core.consumer.get_oembed_response') as mock_get:
response = Mock()
response.type = 'rich'
response.html = '<h1>hello</h1>'

mock_get.return_value = response

result = PyEmbed().embed('http://example.com/', 100, 200)
assert_that(result, equal_to('<h1>hello</h1>'))

mock_get.assert_called_with('http://example.com/', 100, 200)


def test_should_embed_with_custom_renderer():
with patch('pyembed.core.consumer.get_oembed_response') as mock_get:
response = Mock()
response.type = 'rich'
response.html = '<h1>hello</h1>'

renderer = Mock()
renderer.render = lambda content_url, response: '<h1>hi</h1>'

mock_get.return_value = response

result = PyEmbed(renderer).embed('http://example.com/', 100, 200)
assert_that(result, equal_to('<h1>hi</h1>'))

mock_get.assert_called_with('http://example.com/', 100, 200)
16 changes: 8 additions & 8 deletions pyembed/core/test/integration_test.py
Expand Up @@ -20,41 +20,41 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from pyembed.core import consumer, render
from pyembed.core import PyEmbed
from pyembed.core.render import PyEmbedRenderer

from hamcrest import assert_that, contains_string, equal_to
import pytest


class DummyRenderer(render.PyEmbedRenderer):
class DummyRenderer(PyEmbedRenderer):

def render(self, content_url, response):
return "%s by %s from %s" % \
(response.title, response.author_name, content_url)


def test_should_get_correct_embedding():
embedding = consumer.embed(
embedding = PyEmbed().embed(
'https://twitter.com/BarackObama/status/266031293945503744')
assert_that(embedding, contains_string('Four more years.'))


def test_should_get_another_correct_embedding():
embedding = consumer.embed(
embedding = PyEmbed().embed(
'http://www.flickr.com/photos/hansjuul/7899334594')
assert_that(embedding, contains_string('.jpg'))


def test_should_embed_with_maximum_height():
embedding = consumer.embed(
embedding = PyEmbed().embed(
'http://www.youtube.com/watch?v=9bZkp7q19f0', max_height=200)
assert_that(embedding, contains_string('height="200"'))


def test_should_embed_with_custom_renderer():
embedding = consumer.embed(
'http://www.youtube.com/watch?v=qrO4YZeyl0I',
renderer=DummyRenderer())
embedding = PyEmbed(renderer=DummyRenderer()).embed(
'http://www.youtube.com/watch?v=qrO4YZeyl0I')
assert_that(embedding, equal_to(
'Lady Gaga - Bad Romance by LadyGagaVEVO from ' +
'http://www.youtube.com/watch?v=qrO4YZeyl0I'))

0 comments on commit ecd3f8e

Please sign in to comment.