from pyticketswitch.exceptions import IntegrityError
from pyticketswitch.cost_range import CostRange
from pyticketswitch.ticket_type import TicketType
from pyticketswitch.content import Content
from pyticketswitch.media import Media
from pyticketswitch.review import Review
from pyticketswitch.availability import AvailabilityDetails
from pyticketswitch.field import Field
from pyticketswitch.mixins import JSONMixin, PaginationMixin
from pyticketswitch.currency import CurrencyMeta
[docs]class Event(JSONMixin, object):
"""Describes a product in the ticketswitch system.
Attributes:
id (str): the identifier for the event.
status (str): status of the event.
description (str): human readable name for the event.
source (str): the backend system from wich the event originates.
source_code (str): the internal code for the backend system.
event_type (str): the type of the event.
venue (str): a human readable description of the venue.
classes (dict): a dictionary of class descriptions that the event
belongs to keyed on class identifier.
filters (list): a list of filters that the event belongs to.
postcode (str): venue post code.
city (str): human readable venue city.
city_code (str): venue city code
country (str): human readable country name.
country_code (str): ISO 3166-1 country code.
latitude (float): latitude of the venue.
longitude (float): longitude of the venue.
max_running_time (int): maximum running time of a performance in
minutes.
min_running_time (int): minimum running time of a performance in
minutes.
show_performance_time (bool): indicates that the performance time
for this event is relevant and should be shown.
has_performances (bool): indicates that the event has performances.
is_seated (bool): indicates the event is seated.
needs_departure_date (bool): indicates that ticket purchases for this
event will require a departure date.
needs_duration (bool): indicates that ticket purchases for this
event will require a duration.
needs_performance (bool): indicates that you should ask your customer
what date/time they want to attend this event on.
See :ref:`Events that don't need performance selection
<events_that_dont_need_performance_selection>` for more
information.
upsell_list (list): list of event id's.
cost_range (:class:`CostRange <pyticketswitch.cost_range.CostRange>`):
pricing summary from cached availability. Only present when
requested.
no_singles_cost_range (:class:`CostRange <pyticketswitch.cost_range.CostRange>`):
pricining summary from cached availability. Only present when
requested.
cost_range_details (:class:`CostRangeDetails <pyticketswitch.cost_range.CostRangeDetails>`):
summary pricing information broken down by availability. This is
cached data. Only present when requested.
content (dict): dictionary of
:class:`Content <pyticketswitch.content.Content>` objects
indexed on content name. Only present when requested.
fields (dict): dictionary of
:class:`Field <pyticketswitch.content.Content>` objects
indexed on field name. Only present when requested.
event_info (str): event info in plain text. Only present when
requested.
event_info_html (str): event info as HTML. Only present when requested.
venue_addr (str): venue address in plain text. Only present when
requested.
venue_addr_html (str): venue address as HTML. Only present when requested.
venue_info (str): venue info in plain text. Only present when
requested.
venue_info_html (str): venue info as HTML. Only present when requested.
media (dict): dictionary of :class:`Media <pyticketswitch.media.Media>`
objects indexed on media name. Only present when requested.
reviews (list): list of :class:`Reviews <pyticketswitch.review.Review>`
objects. Only present when requested.
critic_review_percent (float): summary of critic review star rating.
rated from 1 (lowest) to 5 (highest).
availability_details (:class:`AvailabilityDetails <pyticketswitch.availability.AvailabilityDetails>`):
summary of availability details from cached data. Only present when
requested.
component_events (list): list of :class:`Events <pyticketswitch.event.Event>`
objects that comprise a meta event.
valid_quantities (list): list of valid quanities available for
purchase. from cached data, only available when requested by
**get_events** or **get_event**.
raw (dict): the raw data used to generate the object.
is_addon (bool): indicates that the event is an addon.
is_auto_quantity_add_on (bool): Indicates whether add on quantity will
be modified based on the number of ticket orders, if true number
of add ons will be equal to total number of tickets for all
parent events in the trolley.
is_date_matched_add_on (bool): indicates whether an addon should match
it's parent event's date
is_time_matched_add_on (bool): indicates whether an addon should match
it's parent event's time
area_code (str): the internal code for the area. This is for internal
use only.
venue_code (str): the internal code for the venue. This is for internal
use only.
venue_is_enforced (bool): indicates if the venue is enforced. This is
for internal use only.
lingo_code (str): a code for the type of event, e.g. theatre or
attraction. This is for internal use only.
"""
def __init__(self, id_, status=None, event_type=None, source=None,
source_code=None, venue=None, description=None, postcode=None,
classes=None, filters=None, upsell_list=None, city=None,
city_code=None, country=None, country_code=None,
latitude=None, longitude=None, needs_departure_date=False,
needs_duration=False, addon_events=None, upsell_events=None,
needs_performance=False, has_performances=False,
is_seated=False, show_performance_time=False,
min_running_time=None, max_running_time=None, cost_range=None,
no_singles_cost_range=None, cost_range_details=None,
content=None, event_info_html=None, event_info=None,
venue_addr_html=None, venue_addr=None, venue_info=None,
venue_info_html=None, media=None, reviews=None,
critic_review_percent=None, availability_details=None,
component_events=None, valid_quantities=None, fields=None,
raw=None, is_add_on=False, area_code=None,
venue_code=None, venue_is_enforced=None,
lingo_code=None, is_auto_quantity_add_on=False,
is_date_matched_add_on=False, is_time_matched_add_on=False):
self.id = id_
self.status = status
self.description = description
self.source = source
self.source_code = source_code
self.event_type = event_type
self.venue = venue
self.classes = classes
self.filters = filters
self.postcode = postcode
self.city = city
self.city_code = city_code
self.country = country
self.country_code = country_code
self.latitude = latitude
self.longitude = longitude
self.max_running_time = max_running_time
self.min_running_time = min_running_time
self.show_performance_time = show_performance_time
self.has_performances = has_performances
self.is_seated = is_seated
self.needs_departure_date = needs_departure_date
self.needs_duration = needs_duration
self.needs_performance = needs_performance
self.addon_events = addon_events
self.upsell_events = upsell_events
# TODO This will be removed from the API soon
self.upsell_list = upsell_list
self.cost_range = cost_range
self.no_singles_cost_range = no_singles_cost_range
self.cost_range_details = cost_range_details
self.content = content
self.fields = fields
self.event_info = event_info
self.event_info_html = event_info_html
self.venue_addr = venue_addr
self.venue_addr_html = venue_addr_html
self.venue_info = venue_info
self.venue_info_html = venue_info_html
self.media = media
self.reviews = reviews
self.critic_review_percent = critic_review_percent
self.availability_details = availability_details
self.component_events = component_events
self.valid_quantities = valid_quantities
self.raw = raw
self.is_add_on = is_add_on
self.is_auto_quantity_add_on = is_auto_quantity_add_on
self.is_date_matched_add_on = is_date_matched_add_on
self.is_time_matched_add_on = is_time_matched_add_on
self.venue_code = venue_code
self.area_code = area_code
self.venue_is_enforced = venue_is_enforced
self.lingo_code = lingo_code
[docs] @classmethod
def class_dict_from_api_data(cls, data):
"""Creates a dict of Event data from a raw ticketswitch API call
Args:
data (dict): the part of the response from a ticketswitch API call
that concerns a event.
Returns:
dict: a new dict populated with the data from the api for creating
an :class:`Event <pyticketswitch.event.Event>` object
"""
id_ = data.get('event_id')
if not id_:
raise IntegrityError("event_id not found in event data", data=data)
geo_data = data.get('geo_data', {})
# the raw field 'has_no_perfs' is a negative flag, so I'm inverting it
has_performances = not data.get('has_no_perfs', False)
api_cost_range = data.get('cost_range', {})
api_no_singles_cost_range = api_cost_range.get('no_singles_cost_range', {})
cost_range = None
no_singles_cost_range = None
if api_cost_range:
api_cost_range['singles'] = True
cost_range = CostRange.from_api_data(api_cost_range)
if api_no_singles_cost_range:
api_no_singles_cost_range['singles'] = False
no_singles_cost_range = CostRange.from_api_data(
api_no_singles_cost_range)
api_cost_range_details = data.get('cost_range_details', {})
ticket_type_list = api_cost_range_details.get('ticket_type', [])
cost_range_details = [
TicketType.from_api_data(ticket_type)
for ticket_type in ticket_type_list
]
api_content = data.get('structured_info', {})
content = {
key: Content.from_api_data(value)
for key, value in api_content.items()
}
fields = {
field.get('custom_field_name'): Field.from_api_data(field)
for field in data.get('custom_fields', {})
}
media = {}
api_media = data.get('media', {})
for asset in api_media.get('media_asset', []):
new_media = Media.from_api_data(asset)
media[new_media.name] = new_media
api_video = data.get('video_iframe')
if api_video:
kwargs = {
'secure_complete_url': api_video.get('video_iframe_url_when_secure'),
'insecure_complete_url': api_video.get('video_iframe_url_when_insecure'),
'caption': api_video.get('video_iframe_caption'),
'caption_html': api_video.get('video_iframe_caption_html'),
'width': api_video.get('video_iframe_width'),
'height': api_video.get('video_iframe_height'),
'name': 'video',
}
new_video = Media.from_api_data(kwargs)
media['video'] = new_video
api_reviews = data.get('reviews', {})
reviews = [
Review.from_api_data(api_review)
for api_review in api_reviews.get('review', [])
]
availability_details = AvailabilityDetails.from_api_data(
data.get('avail_details', {}))
api_component_events = data.get('meta_event_component_events', {})
component_events = [
Event.from_api_data(meta_event)
for meta_event in api_component_events.get('event', [])
]
lingo_code = None
raw_lingo_data = data.get('lingo_data')
if raw_lingo_data:
lingo_code = raw_lingo_data.get('lingo_code')
kwargs = {
'id_': id_,
'description': data.get('event_desc', None),
'status': data.get('event_status'),
'event_type': data.get('event_type'),
'source_code': data.get('source_code'),
'source': data.get('source_desc'),
'venue': data.get('venue_desc'),
'classes': data.get('classes'),
#TODO: don't actually know what filters look like yet...
'filters': data.get('custom_filter', []),
'fields': fields,
'postcode': data.get('postcode'),
'city': data.get('city_desc'),
'city_code': data.get('city_code'),
'country': data.get('country_desc'),
'country_code': data.get('country_code'),
'latitude': geo_data.get('latitude'),
'longitude': geo_data.get('longitude'),
'max_running_time': data.get('max_running_time'),
'min_running_time': data.get('min_running_time'),
'has_performances': has_performances,
'show_performance_time': data.get('show_perf_time', False),
'is_seated': data.get('is_seated', False),
'needs_departure_date': data.get('need_departure_date', False),
'needs_duration': data.get('need_duration', False),
'needs_performance': data.get('need_performance', False),
'upsell_list': data.get('event_upsell_list', {}).get('event_id', []),
'cost_range': cost_range,
'no_singles_cost_range': no_singles_cost_range,
'cost_range_details': cost_range_details,
# extra info
'event_info_html': data.get('event_info_html'),
'event_info': data.get('event_info'),
'venue_addr_html': data.get('venue_addr_html'),
'venue_addr': data.get('venue_addr'),
'venue_info': data.get('venue_info'),
'venue_info_html': data.get('venue_info_html'),
'content': content,
'media': media,
'reviews': reviews,
'critic_review_percent': data.get('critic_review_percent'),
'availability_details': availability_details,
'component_events': component_events,
'valid_quantities': data.get('valid_quantities'),
'raw': data,
'is_add_on': data.get('is_add_on', False),
'is_auto_quantity_add_on': data.get('is_auto_quantity_add_on', False),
'is_date_matched_add_on': data.get('is_date_matched_add_on', False),
'is_time_matched_add_on': data.get('is_time_matched_add_on', False),
'venue_code': data.get('venue_code'),
'area_code': data.get('area_code'),
'lingo_code': lingo_code,
}
return kwargs
[docs] @classmethod
def from_api_data(cls, data):
"""Creates a new Event object from API data from ticketswitch.
Args:
data (dict): the part of the response from a ticketswitch API call
that concerns a event.
Returns:
:class:`Event <pyticketswitch.event.Event>`: a new
:class:`Event <pyticketswitch.event.Event>` object
populated with the data from the api.
"""
kwargs = cls.class_dict_from_api_data(data)
return cls(**kwargs)
[docs] @classmethod
def from_events_by_id_api_data(cls, data):
"""Creates a new Event object from API data from the events_by_id call.
Args:
data (dict): the part of the response from the ticketswitch
`events_by_id` API call containing events and other data.
Returns:
:class:`Event <pyticketswitch.event.Event>`: a new
:class:`Event <pyticketswitch.event.EVent>` object populated with
the data from the API.
"""
kwargs = cls.class_dict_from_api_data(data.get('event'))
if data.get('add_ons'):
addons=[
Event.from_api_data(raw_addon)
for raw_addon in data.get('add_ons')
]
kwargs.update(addon_events=addons)
if data.get('upsells'):
upsells=[
Event.from_api_data(raw_upsell)
for raw_upsell in data.get('upsells')
]
kwargs.update(upsell_events=upsells)
if data.get('venue_is_enforced') is not None:
kwargs.update(venue_is_enforced=data.get('venue_is_enforced'))
if data.get('valid_quantities') is not None:
kwargs.update(valid_quantities=data.get('valid_quantities'))
return cls(**kwargs)
def __repr__(self):
return u'<Event {}:{}>'.format(
self.id, self.description.encode('ascii', 'ignore'))