Skip to content

Commit

Permalink
Add broadcasts endpoint (#49)
Browse files Browse the repository at this point in the history
* Add broadcasts
* Add usecases and update readme
  • Loading branch information
mbonnefoy committed Dec 4, 2020
1 parent a309cf6 commit 3ffa02e
Show file tree
Hide file tree
Showing 12 changed files with 428 additions and 0 deletions.
19 changes: 19 additions & 0 deletions README.md
Expand Up @@ -24,6 +24,7 @@ We support all the endpoints available in our API.

* `oauth2`
* `accounts`
* `broadcasts`
* `events`
* `places`

Expand Down Expand Up @@ -70,6 +71,24 @@ for event in phq.events.search(q='Katy Perry', rank_level=[4, 5], category='conc

Please refer to our [Events endpoint documentation](https://docs.predicthq.com/resources/events/) for the lists of search parameters and event fields available.

### Broadcasts endpoint

Additional examples are available in [usecases/broadcasts](https://github.com/predicthq/sdk-py/tree/master/usecases/broadcasts) folder.

The following example searches for the broadcasts with PHQ viewership gte 100 and with event (the physical event the broadcast links to) label 'nfl'.

```Python
from predicthq import Client

phq = Client(access_token="abc123")


for broadcast in phq.broadcasts.search(phq_viewership__gte=100, event__label='nfl'):
print(broadcast.event.title, broadcast.phq_viewership, broadcast.event.labels, broadcast.dates.start.strftime('%Y-%m-%d'))
```

Please refer to our [Broadcasts endpoint documentation](https://docs.predicthq.com/resources/broadcasts/) for the lists of search parameters and broadcast fields available.

### Places endpoint

Additional examples are available in [usecases/places.py](https://github.com/predicthq/sdk-py/tree/master/usecases/places.py) file.
Expand Down
1 change: 1 addition & 0 deletions predicthq/client.py
Expand Up @@ -27,6 +27,7 @@ def __init__(self, access_token=None):
def initialize_endpoints(self):
from predicthq import endpoints
self.oauth2 = endpoints.OAuth2Endpoint(proxy(self))
self.broadcasts = endpoints.BroadcastsEndpoint(proxy(self))
self.events = endpoints.EventsEndpoint(proxy(self))
self.accounts = endpoints.AccountsEndpoint(proxy(self))
self.places = endpoints.PlacesEndpoint(proxy(self))
Expand Down
10 changes: 10 additions & 0 deletions predicthq/endpoints/__init__.py
@@ -1,4 +1,14 @@
from .oauth2 import OAuth2Endpoint
from .v1.accounts import AccountsEndpoint
from .v1.broadcasts import BroadcastsEndpoint
from .v1.events import EventsEndpoint
from .v1.places import PlacesEndpoint


__all__ = [
'OAuth2Endpoint',
'AccountsEndpoint',
'BroadcastsEndpoint',
'EventsEndpoint',
'PlacesEndpoint',
]
8 changes: 8 additions & 0 deletions predicthq/endpoints/v1/broadcasts/__init__.py
@@ -0,0 +1,8 @@
from .endpoint import BroadcastsEndpoint
from .schemas import Broadcast


__all__ = [
'BroadcastsEndpoint',
'Broadcast'
]
11 changes: 11 additions & 0 deletions predicthq/endpoints/v1/broadcasts/endpoint.py
@@ -0,0 +1,11 @@
from predicthq.endpoints.base import UserBaseEndpoint
from predicthq.endpoints.decorators import accepts, returns
from .schemas import BroadcastResultSet, SearchParams


class BroadcastsEndpoint(UserBaseEndpoint):

@accepts(SearchParams)
@returns(BroadcastResultSet)
def search(self, **params):
return self.client.get(self.build_url('v1', 'broadcasts'), params=params)
159 changes: 159 additions & 0 deletions predicthq/endpoints/v1/broadcasts/schemas.py
@@ -0,0 +1,159 @@
from predicthq.endpoints.schemas import (
PaginatedMixin, SortableMixin,
BooleanType, DateTimeRange, DateTimeType, FloatType, IntRange, IntType,
ListType, Model, ModelType, ResultSet, ResultType, StringType
)


class BroadcastEventParams(Model):

class Options:
serialize_when_none = False

event_id = ListType(StringType)
category = ListType(StringType)
label = ListType(StringType)


class BroadcastLocationParams(Model):

class Options:
serialize_when_none = False

place_id = ListType(StringType)


class SearchParams(PaginatedMixin, SortableMixin, Model):

class Options:
serialize_when_none = False

broadcast_id = ListType(StringType)
location = ModelType(BroadcastLocationParams)
phq_viewership = ModelType(IntRange)
start = ModelType(DateTimeRange)
updated = ModelType(DateTimeRange)
record_status = ListType(StringType(choices=('active', 'deleted'), default='active'))
broadcast_status = ListType(StringType(choices=('scheduled', 'cancelled')))
event = ModelType(BroadcastEventParams)


class GeoPoint(Model):

lat = FloatType()
lon = FloatType()


class BroadcastEventEntities(Model):

class Options:
serialize_when_none = False

entity_id = StringType()
type = StringType()
name = StringType()
formatted_address = StringType()


class BroadcastEventLocation(Model):

class Options:
serialize_when_none = False

geopoint = ModelType(GeoPoint)
place_hierarchies = ListType(ListType(StringType))
country = StringType()


class BroadcastEventDates(Model):

class Options:
serialize_when_none = False

start = DateTimeType()
end = DateTimeType()
start_local = DateTimeType()
end_local = DateTimeType()
timezone = StringType()

# predicted_end_local is a paid feature.
# It will only show up in your response body if you
# have subscribed to it.
predicted_end_local = DateTimeType()


class BroadcastEvent(Model):

class Options:
serialize_when_none = False

event_id = StringType()
title = StringType()
category = StringType()
labels = ListType(StringType)
dates = ModelType(BroadcastEventDates)
location = ModelType(BroadcastEventLocation)
entities = ListType(ModelType(BroadcastEventEntities))

# The following fields are paid features.
# They will only show up in your response body if you
# have subscribed to them.
phq_attendance = IntType()
phq_rank = IntType()
local_rank = IntType()
aviation_rank = IntType()


class Place(Model):

class Options:
serialize_when_none = False

place_id = StringType()
type = StringType()
name = StringType()
county = StringType()
region = StringType()
country = StringType()


class BroadcastLocation(Model):

class Options:
serialize_when_none = False

geopoint = ModelType(GeoPoint)
place_hierarchies = ListType(ListType(StringType))
places = ListType(ModelType(Place))
country = StringType()


class BroadcastDates(Model):

class Options:
serialize_when_none = False

start = DateTimeType()
start_local = DateTimeType()
timezone = StringType()


class Broadcast(Model):

class Options:
serialize_when_none = False

broadcast_id = StringType()
updated = DateTimeType()
dates = ModelType(BroadcastDates)
location = ModelType(BroadcastLocation)
phq_viewership = IntType()
record_status = StringType()
broadcast_status = StringType()
event = ModelType(BroadcastEvent)


class BroadcastResultSet(ResultSet):

overflow = BooleanType()
results = ResultType(Broadcast)
6 changes: 6 additions & 0 deletions predicthq/endpoints/v1/events/__init__.py
@@ -1,2 +1,8 @@
from .endpoint import EventsEndpoint
from .schemas import Event


__all__ = [
'EventsEndpoint',
'Event'
]
6 changes: 6 additions & 0 deletions predicthq/endpoints/v1/places/__init__.py
@@ -1,2 +1,8 @@
from .endpoint import PlacesEndpoint
from .schemas import Place


__all__ = [
'PlacesEndpoint',
'Place'
]
63 changes: 63 additions & 0 deletions tests/endpoints/v1/test_broadcasts.py
@@ -0,0 +1,63 @@
import unittest

from predicthq.endpoints.v1.broadcasts.schemas import BroadcastResultSet
from tests import with_mock_client, with_mock_responses, with_client


class BroadcastsTest(unittest.TestCase):

@with_mock_client()
def test_search_params_underscores(self, client):
client.broadcasts.search(
broadcast_id='broadcast_id',
location__place_id='place_id',
phq_viewership__gte=1, phq_viewership__lte=10,
start__gte='2020-10-01', start__lt='2020-10-15', start__tz='Pacific/Auckland',
updated__gte='2020-11-01', updated__lt='2020-11-30', updated__tz='Pacific/Auckland',
record_status=['active', 'deleted'], broadcast_status=['scheduled', 'cancelled'],
event__event_id='event_id', event__category='sports', event__label=['sport', 'nfl']
)

client.request.assert_called_once_with(
'get', '/v1/broadcasts/', params={
'broadcast_id': 'broadcast_id',
'location.place_id': 'place_id',
'phq_viewership.gte': 1, 'phq_viewership.lte': 10,
'start.gte': '2020-10-01T00:00:00.000000', 'start.lt': '2020-10-15T23:59:59.999999', 'start.tz': 'Pacific/Auckland',
'updated.gte': '2020-11-01T00:00:00.000000', 'updated.lt': '2020-11-30T23:59:59.999999', 'updated.tz': 'Pacific/Auckland',
'record_status': 'active,deleted', 'broadcast_status': 'scheduled,cancelled',
'event.event_id': 'event_id', 'event.category': 'sports', 'event.label': 'sport,nfl'
}
)

@with_mock_client()
def test_search_params_dicts(self, client):
client.broadcasts.search(
broadcast_id='broadcast_id',
location={'place_id': 'place_id'},
phq_viewership={'gte': 1, 'lte': 10},
start={'gte': '2020-10-01', 'lt': '2020-10-15', 'tz': 'Pacific/Auckland'},
updated={'gte': '2020-11-01', 'lt': '2020-11-30', 'tz': 'Pacific/Auckland'},
record_status=['active', 'deleted'], broadcast_status=['scheduled', 'cancelled'],
event={'event_id': 'event_id', 'category': 'sports', 'label': ['sport', 'nfl']}
)

client.request.assert_called_once_with(
'get', '/v1/broadcasts/', params={
'broadcast_id': 'broadcast_id',
'location.place_id': 'place_id',
'phq_viewership.gte': 1, 'phq_viewership.lte': 10,
'start.gte': '2020-10-01T00:00:00.000000', 'start.lt': '2020-10-15T23:59:59.999999', 'start.tz': 'Pacific/Auckland',
'updated.gte': '2020-11-01T00:00:00.000000', 'updated.lt': '2020-11-30T23:59:59.999999', 'updated.tz': 'Pacific/Auckland',
'record_status': 'active,deleted', 'broadcast_status': 'scheduled,cancelled',
'event.event_id': 'event_id', 'event.category': 'sports', 'event.label': 'sport,nfl'
}
)

@with_client()
@with_mock_responses()
def test_search(self, client, responses):
result = client.broadcasts.search(broadcast_id='PmJUAWRQLsKkg9MGTQU2JA')
assert isinstance(result, BroadcastResultSet)
assert result.count == len(list(result.iter_all()))
assert len(responses.calls) == 1

0 comments on commit 3ffa02e

Please sign in to comment.