ytsm/external/pytaw/tests/test_pytaw.py

165 lines
5.0 KiB
Python

import pytest
import logging
import sys
import collections
from datetime import datetime, timedelta
from googleapiclient.errors import HttpError
from pytaw import YouTube
from pytaw.youtube import Resource, Video, AttributeDef
logging.basicConfig(stream=sys.stdout) # show log output when run with pytest -s
log = logging.getLogger(__name__)
log.setLevel(logging.INFO)
@pytest.fixture
def youtube():
"""A YouTube instance initialised with a developer key loaded from config.ini"""
return YouTube()
@pytest.fixture
def video(youtube):
"""A Video instance for the classic video 'Me at the zoo'"""
return youtube.video('jNQXAC9IVRw')
@pytest.fixture
def channel(youtube):
"""A Channel instance for the 'YouTube Help' channel"""
return youtube.channel('UCMDQxm7cUx3yXkfeHa5zJIQ')
@pytest.fixture
def search(youtube):
"""A ListResponse instance corresponding to a search for the query 'python'"""
return youtube.search()
@pytest.fixture
def video_search(youtube):
"""A ListResponse instance corresponding to a video search for the query 'python'"""
return youtube.search(q='python', type='video')
@pytest.fixture
def video_search_array(youtube):
"""An array of video searches with a wide range of results (zero to millions)."""
one_minute_ago = datetime.utcnow() - timedelta(minutes=1)
five_minutes_ago = datetime.utcnow() - timedelta(minutes=5)
return [
#
# no results
youtube.search(q='minecraft', type='video', publishedBefore=datetime(2000, 1, 1)),
#
# less than 100 results
youtube.search(q='minecraft', type='video', publishedBefore=datetime(2005, 7, 1)),
#
# over 100 results
youtube.search(q='minecraft', type='video', publishedBefore=datetime(2006, 1, 1)),
#
# variable number of results (hundreds or thousands...?)
youtube.search(q='minecraft', type='video', publishedAfter=one_minute_ago),
youtube.search(q='minecraft', type='video', publishedAfter=five_minutes_ago),
#
# over a million results
youtube.search(q='minecraft', type='video'),
youtube.search(q='minecraft'),
]
class TestResource:
def test_equality(self, search):
a = search[0]
b = search[0]
c = search[1]
assert a == b
assert a != c
def test_unknown_attribute(self, video):
with pytest.raises(AttributeError):
_ = video.attribute_name_which_definitely_will_never_exist
def test_unknown_part_in_attributedef(self, video):
video.ATTRIBUTE_DEFS['x'] = AttributeDef('nonexistant_part', 'x')
with pytest.raises(HttpError):
_ = video.x
def test_unknown_attribute_name_in_attributedef(self, video):
video.ATTRIBUTE_DEFS['x'] = AttributeDef('snippet', 'nonexistant_attribute')
assert video.x is None
class TestVideo:
def test_bad_video_id(self, youtube):
video = youtube.video('not_a_valid_youtube_video_id')
assert video is None
def test_title(self, video):
assert video.title == "Me at the zoo"
def test_published_at(self, video):
assert video.published_at.isoformat() == '2005-04-24T03:31:52+00:00'
def test_n_views(self, video):
assert video.n_views > int(40e6)
def test_tags(self, video):
assert video.tags == ['jawed', 'karim', 'elephant', 'zoo', 'youtube', 'first', 'video']
def test_duration(self, video):
assert video.duration.total_seconds() == 19
class TestChannel:
def test_title(self, channel):
assert channel.title == "YouTube Help"
class TestSearch:
def test_video_search_returns_a_video(self, video_search):
assert isinstance(video_search[0], Video)
def test_video_search_has_many_results(self, video_search):
# make video_search unlazy (populate pageInfo attributes)
_ = video_search[0]
assert video_search.total_results > 10000
def test_search_iteration(self, search):
"""Simply iterate over a search, creating all resources, to check for exceptions."""
for resource in search:
log.debug(resource)
class TestListResponse:
def test_if_iterable(self, search):
assert isinstance(search, collections.Iterator)
def test_integer_indexing(self, search):
assert isinstance(search[0], Resource)
def test_slice_indexing(self, search):
assert isinstance(search[1:3], list)
def test_full_listing_iteration(self, video_search_array):
"""Iterate over all search results to check no exceptions are raised when paging etc.
Even if millions of results are found, the API will never return more than 500 (by
design), so we're okay to just bang right through the search results generator for the
whole array of video searches.
"""
for i, search in enumerate(video_search_array):
c = 0
for _ in search:
c += 1
log.debug(f"checked first {c} results (search #{i})")