renumbering chapters >= 19

This commit is contained in:
Luciano Ramalho
2021-09-10 12:34:39 -03:00
parent cbd13885fc
commit 4ae4096c4c
154 changed files with 7 additions and 1134 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env python3
import shelve
from schedule_v2 import DB_NAME, CONFERENCE, load_db
from schedule_v2 import DbRecord, Event
with shelve.open(DB_NAME) as db:
if CONFERENCE not in db:
load_db(db)
DbRecord.set_db(db)
event = DbRecord.fetch('event.33950')
print(event)
print(event.venue)
print(event.venue.name)
for spkr in event.speakers:
print(f'{spkr.serial}:', spkr.name)
print(repr(Event.venue))
event2 = DbRecord.fetch('event.33451')
print(event2)
print(event2.fetch)
print(event2.venue)

View File

@@ -0,0 +1,65 @@
"""
explore0.py: Script to explore the OSCON schedule feed
# tag::EXPLORE0_DEMO[]
>>> import json
>>> raw_feed = json.load(open('data/osconfeed.json'))
>>> feed = FrozenJSON(raw_feed) # <1>
>>> len(feed.Schedule.speakers) # <2>
357
>>> feed.keys()
dict_keys(['Schedule'])
>>> sorted(feed.Schedule.keys()) # <3>
['conferences', 'events', 'speakers', 'venues']
>>> for key, value in sorted(feed.Schedule.items()): # <4>
... print(f'{len(value):3} {key}')
...
1 conferences
484 events
357 speakers
53 venues
>>> feed.Schedule.speakers[-1].name # <5>
'Carina C. Zona'
>>> talk = feed.Schedule.events[40]
>>> type(talk) # <6>
<class 'explore0.FrozenJSON'>
>>> talk.name
'There *Will* Be Bugs'
>>> talk.speakers # <7>
[3471, 5199]
>>> talk.flavor # <8>
Traceback (most recent call last):
...
KeyError: 'flavor'
# end::EXPLORE0_DEMO[]
"""
# tag::EXPLORE0[]
from collections import abc
class FrozenJSON:
"""A read-only façade for navigating a JSON-like object
using attribute notation
"""
def __init__(self, mapping):
self.__data = dict(mapping) # <1>
def __getattr__(self, name): # <2>
try:
return getattr(self.__data, name) # <3>
except AttributeError:
return FrozenJSON.build(self.__data[name]) # <4>
@classmethod
def build(cls, obj): # <5>
if isinstance(obj, abc.Mapping): # <6>
return cls(obj)
elif isinstance(obj, abc.MutableSequence): # <7>
return [cls.build(item) for item in obj]
else: # <8>
return obj
# end::EXPLORE0[]

View File

@@ -0,0 +1,78 @@
"""
explore1.py: Script to explore the OSCON schedule feed
>>> import json
>>> raw_feed = json.load(open('data/osconfeed.json'))
>>> feed = FrozenJSON(raw_feed)
>>> len(feed.Schedule.speakers)
357
>>> sorted(feed.Schedule.keys())
['conferences', 'events', 'speakers', 'venues']
>>> for key, value in sorted(feed.Schedule.items()):
... print(f'{len(value):3} {key}')
...
1 conferences
484 events
357 speakers
53 venues
>>> feed.Schedule.speakers[-1].name
'Carina C. Zona'
>>> talk = feed.Schedule.events[40]
>>> type(talk)
<class 'explore1.FrozenJSON'>
>>> talk.name
'There *Will* Be Bugs'
>>> talk.speakers
[3471, 5199]
>>> talk.flavor
Traceback (most recent call last):
...
KeyError: 'flavor'
Handle keywords by appending a `_`.
# tag::EXPLORE1_DEMO[]
>>> grad = FrozenJSON({'name': 'Jim Bo', 'class': 1982})
>>> grad.name
'Jim Bo'
>>> grad.class_
1982
# end::EXPLORE1_DEMO[]
"""
from collections import abc
import keyword
class FrozenJSON:
"""A read-only façade for navigating a JSON-like object
using attribute notation
"""
# tag::EXPLORE1[]
def __init__(self, mapping):
self.__data = {}
for key, value in mapping.items():
if keyword.iskeyword(key): # <1>
key += '_'
self.__data[key] = value
# end::EXPLORE1[]
def __getattr__(self, name):
if hasattr(self.__data, name):
return getattr(self.__data, name)
else:
return FrozenJSON.build(self.__data[name])
@classmethod
def build(cls, obj):
if isinstance(obj, abc.Mapping):
return cls(obj)
elif isinstance(obj, abc.MutableSequence):
return [cls.build(item) for item in obj]
else: # <8>
return obj

View File

@@ -0,0 +1,54 @@
"""
explore2.py: Script to explore the OSCON schedule feed
>>> import json
>>> raw_feed = json.load(open('data/osconfeed.json'))
>>> feed = FrozenJSON(raw_feed)
>>> len(feed.Schedule.speakers)
357
>>> sorted(feed.Schedule.keys())
['conferences', 'events', 'speakers', 'venues']
>>> feed.Schedule.speakers[-1].name
'Carina C. Zona'
>>> talk = feed.Schedule.events[40]
>>> talk.name
'There *Will* Be Bugs'
>>> talk.speakers
[3471, 5199]
>>> talk.flavor
Traceback (most recent call last):
...
KeyError: 'flavor'
"""
# tag::EXPLORE2[]
from collections import abc
import keyword
class FrozenJSON:
"""A read-only façade for navigating a JSON-like object
using attribute notation
"""
def __new__(cls, arg): # <1>
if isinstance(arg, abc.Mapping):
return super().__new__(cls) # <2>
elif isinstance(arg, abc.MutableSequence): # <3>
return [cls(item) for item in arg]
else:
return arg
def __init__(self, mapping):
self.__data = {}
for key, value in mapping.items():
if keyword.iskeyword(key):
key += '_'
self.__data[key] = value
def __getattr__(self, name):
if hasattr(self.__data, name):
return getattr(self.__data, name)
else:
return FrozenJSON(self.__data[name]) # <4>
# end::EXPLORE2[]

View File

@@ -0,0 +1,32 @@
{ "Schedule":
{ "conferences": [{"serial": 115 }],
"events": [
{ "serial": 34505,
"name": "Why Schools Don´t Use Open Source to Teach Programming",
"event_type": "40-minute conference session",
"time_start": "2014-07-23 11:30:00",
"time_stop": "2014-07-23 12:10:00",
"venue_serial": 1462,
"description": "Aside from the fact that high school programming...",
"website_url": "http://oscon.com/oscon2014/public/schedule/detail/34505",
"speakers": [157509],
"categories": ["Education"] }
],
"speakers": [
{ "serial": 157509,
"name": "Robert Lefkowitz",
"photo": null,
"url": "http://sharewave.com/",
"position": "CTO",
"affiliation": "Sharewave",
"twitter": "sharewaveteam",
"bio": "Robert ´r0ml´ Lefkowitz is the CTO at Sharewave, a startup..." }
],
"venues": [
{ "serial": 1462,
"name": "F151",
"category": "Conference Venues" }
]
}
}

View File

@@ -0,0 +1,20 @@
>>> import json
>>> with open('data/osconfeed.json') as fp:
... feed = json.load(fp) # <1>
>>> sorted(feed['Schedule'].keys()) # <2>
['conferences', 'events', 'speakers', 'venues']
>>> for key, value in sorted(feed['Schedule'].items()):
... print(f'{len(value):3} {key}') # <3>
...
1 conferences
484 events
357 speakers
53 venues
>>> feed['Schedule']['speakers'][-1]['name'] # <4>
'Carina C. Zona'
>>> feed['Schedule']['speakers'][-1]['serial'] # <5>
141590
>>> feed['Schedule']['events'][40]['name']
'There *Will* Be Bugs'
>>> feed['Schedule']['events'][40]['speakers'] # <6>
[3471, 5199]

View File

@@ -0,0 +1,2 @@
#!/bin/bash
pytest --doctest-modules $2 $1 test_$1

View File

@@ -0,0 +1,39 @@
"""
schedule_v1.py: traversing OSCON schedule data
# tag::SCHEDULE1_DEMO[]
>>> records = load(JSON_PATH) # <1>
>>> speaker = records['speaker.3471'] # <2>
>>> speaker # <3>
<Record serial=3471>
>>> speaker.name, speaker.twitter # <4>
('Anna Martelli Ravenscroft', 'annaraven')
# end::SCHEDULE1_DEMO[]
"""
# tag::SCHEDULE1[]
import json
JSON_PATH = 'data/osconfeed.json'
class Record:
def __init__(self, **kwargs):
self.__dict__.update(kwargs) # <1>
def __repr__(self):
cls_name = self.__class__.__name__
return f'<{cls_name} serial={self.serial!r}>' # <2>
def load(path=JSON_PATH):
records = {} # <3>
with open(path) as fp:
raw_data = json.load(fp) # <4>
for collection, raw_records in raw_data['Schedule'].items(): # <5>
record_type = collection[:-1] # <6>
for raw_record in raw_records:
key = f'{record_type}.{raw_record["serial"]}' # <7>
records[key] = Record(**raw_record) # <8>
return records
# end::SCHEDULE1[]

View File

@@ -0,0 +1,76 @@
"""
schedule_v2.py: property to get venue linked to an event
# tag::SCHEDULE2_DEMO[]
>>> event = Record.fetch('event.33950') # <1>
>>> event # <2>
<Event 'There *Will* Be Bugs'>
>>> event.venue # <3>
<Record serial=1449>
>>> event.venue.name # <4>
'Portland 251'
>>> event.venue_serial # <5>
1449
# end::SCHEDULE2_DEMO[]
"""
# tag::SCHEDULE2_RECORD[]
import inspect # <1>
import json
JSON_PATH = 'data/osconfeed.json'
class Record:
__index = None # <2>
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __repr__(self):
cls_name = self.__class__.__name__
return f'<{cls_name} serial={self.serial!r}>'
@staticmethod # <3>
def fetch(key):
if Record.__index is None: # <4>
Record.__index = load()
return Record.__index[key] # <5>
# end::SCHEDULE2_RECORD[]
# tag::SCHEDULE2_EVENT[]
class Event(Record): # <1>
def __repr__(self):
if hasattr(self, 'name'): # <2>
cls_name = self.__class__.__name__
return f'<{cls_name} {self.name!r}>'
else:
return super().__repr__()
@property
def venue(self):
key = f'venue.{self.venue_serial}'
return self.__class__.fetch(key) # <3>
# end::SCHEDULE2_EVENT[]
# tag::SCHEDULE2_LOAD[]
def load(path=JSON_PATH):
records = {}
with open(path) as fp:
raw_data = json.load(fp)
for collection, raw_records in raw_data['Schedule'].items():
record_type = collection[:-1] # <1>
cls_name = record_type.capitalize() # <2>
cls = globals().get(cls_name, Record) # <3>
if inspect.isclass(cls) and issubclass(cls, Record): # <4>
factory = cls # <5>
else:
factory = Record # <6>
for raw_record in raw_records: # <7>
key = f'{record_type}.{raw_record["serial"]}'
records[key] = factory(**raw_record) # <8>
return records
# end::SCHEDULE2_LOAD[]

View File

@@ -0,0 +1,86 @@
"""
schedule_v3.py: property to get list of event speakers
>>> event = Record.fetch('event.33950')
>>> event
<Event 'There *Will* Be Bugs'>
>>> event.venue
<Record serial=1449>
>>> event.venue_serial
1449
>>> event.venue.name
'Portland 251'
# tag::SCHEDULE3_DEMO[]
>>> for spkr in event.speakers:
... print(f'{spkr.serial}: {spkr.name}')
3471: Anna Martelli Ravenscroft
5199: Alex Martelli
# end::SCHEDULE3_DEMO[]
"""
import inspect
import json
JSON_PATH = 'data/osconfeed.json'
class Record:
__index = None
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __repr__(self):
cls_name = self.__class__.__name__
return f'<{cls_name} serial={self.serial!r}>'
@staticmethod
def fetch(key):
if Record.__index is None:
Record.__index = load()
return Record.__index[key]
class Event(Record):
def __repr__(self):
if hasattr(self, 'name'): # <3>
cls_name = self.__class__.__name__
return f'<{cls_name} {self.name!r}>'
else:
return super().__repr__() # <4>
@property
def venue(self):
key = f'venue.{self.venue_serial}'
return self.__class__.fetch(key)
# tag::SCHEDULE3_SPEAKERS[]
@property
def speakers(self):
spkr_serials = self.__dict__['speakers'] # <1>
fetch = self.__class__.fetch
return [fetch(f'speaker.{key}')
for key in spkr_serials] # <2>
# end::SCHEDULE3_SPEAKERS[]
def load(path=JSON_PATH):
records = {}
with open(path) as fp:
raw_data = json.load(fp)
for collection, raw_records in raw_data['Schedule'].items():
record_type = collection[:-1]
cls_name = record_type.capitalize()
cls = globals().get(cls_name, Record)
if inspect.isclass(cls) and issubclass(cls, Record):
factory = cls
else:
factory = Record
for raw_record in raw_records:
key = f'{record_type}.{raw_record["serial"]}'
records[key] = factory(**raw_record)
return records

View File

@@ -0,0 +1,94 @@
"""
schedule_v4.py: homegrown cached property for speakers
>>> event = Record.fetch('event.33950')
# tag::SCHEDULE4_DEMO[]
>>> event # <1>
<Event 'There *Will* Be Bugs'>
>>> event.venue # <2>
<Record serial=1449>
>>> event.venue.name # <3>
'Portland 251'
>>> for spkr in event.speakers: # <4>
... print(f'{spkr.serial}: {spkr.name}')
...
3471: Anna Martelli Ravenscroft
5199: Alex Martelli
# end::SCHEDULE4_DEMO[]
"""
import json
import inspect
JSON_PATH = 'data/osconfeed.json'
class Record:
__index = None
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __repr__(self):
cls_name = self.__class__.__name__
return f'<{cls_name} serial={self.serial!r}>'
@staticmethod
def fetch(key):
if Record.__index is None:
Record.__index = load()
return Record.__index[key]
# tag::SCHEDULE4_INIT[]
class Event(Record):
def __init__(self, **kwargs):
self.__speaker_objs = None
super().__init__(**kwargs)
# end::SCHEDULE4_INIT[]
def __repr__(self):
if hasattr(self, 'name'):
cls_name = self.__class__.__name__
return f'<{cls_name} {self.name!r}>'
else:
return super().__repr__() # <4>
@property
def venue(self):
key = f'venue.{self.venue_serial}'
return self.__class__.fetch(key)
# tag::SCHEDULE4_CACHE[]
@property
def speakers(self):
if self.__speaker_objs is None:
spkr_serials = self.__dict__['speakers']
fetch = self.__class__.fetch
self.__speaker_objs = [fetch(f'speaker.{key}')
for key in spkr_serials]
return self.__speaker_objs
# end::SCHEDULE4_CACHE[]
def load(path=JSON_PATH):
records = {}
with open(path) as fp:
raw_data = json.load(fp)
for collection, raw_records in raw_data['Schedule'].items():
record_type = collection[:-1]
cls_name = record_type.capitalize()
cls = globals().get(cls_name, Record)
if inspect.isclass(cls) and issubclass(cls, Record):
factory = cls
else:
factory = Record
for raw_record in raw_records:
key = f'{record_type}.{raw_record["serial"]}'
records[key] = factory(**raw_record)
return records

View File

@@ -0,0 +1,86 @@
"""
schedule_v4.py: homegrown cached property for speakers
>>> event = Record.fetch('event.33950')
# tag::SCHEDULE4_DEMO[]
>>> event # <1>
<Event 'There *Will* Be Bugs'>
>>> event.venue # <2>
<Record serial=1449>
>>> event.venue.name # <3>
'Portland 251'
>>> for spkr in event.speakers: # <4>
... print(f'{spkr.serial}: {spkr.name}')
3471: Anna Martelli Ravenscroft
5199: Alex Martelli
# end::SCHEDULE4_DEMO[]
"""
import inspect
import json
JSON_PATH = 'data/osconfeed.json'
class Record:
__index = None
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __repr__(self):
cls_name = self.__class__.__name__
return f'<{cls_name} serial={self.serial!r}>'
@staticmethod
def fetch(key):
if Record.__index is None:
Record.__index = load()
return Record.__index[key]
class Event(Record):
def __repr__(self):
if hasattr(self, 'name'):
cls_name = self.__class__.__name__
return f'<{cls_name} {self.name!r}>'
else:
return super().__repr__() # <4>
@property
def venue(self):
key = f'venue.{self.venue_serial}'
return self.__class__.fetch(key)
# tag::SCHEDULE4_HASATTR_CACHE[]
@property
def speakers(self):
if not hasattr(self, '__speaker_objs'): # <1>
spkr_serials = self.__dict__['speakers']
fetch = self.__class__.fetch
self.__speaker_objs = [fetch(f'speaker.{key}')
for key in spkr_serials]
return self.__speaker_objs # <2>
# end::SCHEDULE4_HASATTR_CACHE[]
def load(path=JSON_PATH):
records = {}
with open(path) as fp:
raw_data = json.load(fp)
for collection, raw_records in raw_data['Schedule'].items():
record_type = collection[:-1]
cls_name = record_type.capitalize()
cls = globals().get(cls_name, Record)
if inspect.isclass(cls) and issubclass(cls, Record):
factory = cls
else:
factory = Record
for raw_record in raw_records:
key = f'{record_type}.{raw_record["serial"]}'
records[key] = factory(**raw_record)
return records

View File

@@ -0,0 +1,89 @@
"""
schedule_v5.py: cached properties using functools
>>> event = Record.fetch('event.33950')
>>> event
<Event 'There *Will* Be Bugs'>
>>> event.venue
<Record serial=1449>
>>> event.venue_serial
1449
>>> event.venue.name
'Portland 251'
# tag::SCHEDULE3_DEMO[]
>>> for spkr in event.speakers: # <3>
... print(f'{spkr.serial}: {spkr.name}')
...
3471: Anna Martelli Ravenscroft
5199: Alex Martelli
# end::SCHEDULE3_DEMO[]
"""
import json
import inspect
from functools import cached_property, cache
JSON_PATH = 'data/osconfeed.json'
class Record:
__index = None
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __repr__(self):
cls_name = self.__class__.__name__
return f'<{cls_name} serial={self.serial!r}>'
@staticmethod
def fetch(key):
if Record.__index is None:
Record.__index = load()
return Record.__index[key]
class Event(Record):
def __repr__(self):
if hasattr(self, 'name'):
cls_name = self.__class__.__name__
return f'<{cls_name} {self.name!r}>'
else:
return super().__repr__()
# tag::SCHEDULE5_CACHED_PROPERTY[]
@cached_property
def venue(self):
key = f'venue.{self.venue_serial}'
return self.__class__.fetch(key)
# end::SCHEDULE5_CACHED_PROPERTY[]
# tag::SCHEDULE5_PROPERTY_OVER_CACHE[]
@property # <1>
@cache # <2>
def speakers(self):
spkr_serials = self.__dict__['speakers']
fetch = self.__class__.fetch
return [fetch(f'speaker.{key}')
for key in spkr_serials]
# end::SCHEDULE5_PROPERTY_OVER_CACHE[]
def load(path=JSON_PATH):
records = {}
with open(path) as fp:
raw_data = json.load(fp)
for collection, raw_records in raw_data['Schedule'].items():
record_type = collection[:-1]
cls_name = record_type.capitalize()
cls = globals().get(cls_name, Record)
if inspect.isclass(cls) and issubclass(cls, Record):
factory = cls
else:
factory = Record
for raw_record in raw_records:
key = f'{record_type}.{raw_record["serial"]}'
records[key] = factory(**raw_record)
return records

View File

@@ -0,0 +1,24 @@
import pytest
import schedule_v1 as schedule
@pytest.yield_fixture
def records():
yield schedule.load(schedule.JSON_PATH)
def test_load(records):
assert len(records) == 895
def test_record_attr_access():
rec = schedule.Record(spam=99, eggs=12)
assert rec.spam == 99
assert rec.eggs == 12
def test_venue_record(records):
venue = records['venue.1469']
assert venue.serial == 1469
assert venue.name == 'Exhibit Hall C'

View File

@@ -0,0 +1,48 @@
import pytest
import schedule_v2 as schedule
@pytest.yield_fixture
def records():
yield schedule.load(schedule.JSON_PATH)
def test_load(records):
assert len(records) == 895
def test_record_attr_access():
rec = schedule.Record(spam=99, eggs=12)
assert rec.spam == 99
assert rec.eggs == 12
def test_venue_record(records):
venue = records['venue.1469']
assert venue.serial == 1469
assert venue.name == 'Exhibit Hall C'
def test_fetch_speaker_record():
speaker = schedule.Record.fetch('speaker.3471')
assert speaker.name == 'Anna Martelli Ravenscroft'
def test_event_type():
event = schedule.Record.fetch('event.33950')
assert type(event) is schedule.Event
assert repr(event) == "<Event 'There *Will* Be Bugs'>"
def test_event_repr():
event = schedule.Record.fetch('event.33950')
assert repr(event) == "<Event 'There *Will* Be Bugs'>"
event2 = schedule.Event(serial=77, kind='show')
assert repr(event2) == '<Event serial=77>'
def test_event_venue():
event = schedule.Record.fetch('event.33950')
assert event.venue_serial == 1449
assert event.venue == schedule.Record.fetch('venue.1449')
assert event.venue.name == 'Portland 251'

View File

@@ -0,0 +1,59 @@
import pytest
import schedule_v3 as schedule
@pytest.yield_fixture
def records():
yield schedule.load(schedule.JSON_PATH)
def test_load(records):
assert len(records) == 895
def test_record_attr_access():
rec = schedule.Record(spam=99, eggs=12)
assert rec.spam == 99
assert rec.eggs == 12
def test_venue_record(records):
venue = records['venue.1469']
assert venue.serial == 1469
assert venue.name == 'Exhibit Hall C'
def test_fetch_speaker_record():
speaker = schedule.Record.fetch('speaker.3471')
assert speaker.name == 'Anna Martelli Ravenscroft'
def test_event_type():
event = schedule.Record.fetch('event.33950')
assert type(event) is schedule.Event
assert repr(event) == "<Event 'There *Will* Be Bugs'>"
def test_event_repr():
event = schedule.Record.fetch('event.33950')
assert repr(event) == "<Event 'There *Will* Be Bugs'>"
event2 = schedule.Event(serial=77, kind='show')
assert repr(event2) == '<Event serial=77>'
def test_event_venue():
event = schedule.Record.fetch('event.33950')
assert event.venue_serial == 1449
assert event.venue == schedule.Record.fetch('venue.1449')
assert event.venue.name == 'Portland 251'
def test_event_speakers():
event = schedule.Record.fetch('event.33950')
assert len(event.speakers) == 2
anna, alex = [schedule.Record.fetch(f'speaker.{s}') for s in (3471, 5199)]
assert event.speakers == [anna, alex]
def test_event_no_speakers():
event = schedule.Record.fetch('event.36848')
assert event.speakers == []

View File

@@ -0,0 +1,59 @@
import pytest
import schedule_v4 as schedule
@pytest.yield_fixture
def records():
yield schedule.load(schedule.JSON_PATH)
def test_load(records):
assert len(records) == 895
def test_record_attr_access():
rec = schedule.Record(spam=99, eggs=12)
assert rec.spam == 99
assert rec.eggs == 12
def test_venue_record(records):
venue = records['venue.1469']
assert venue.serial == 1469
assert venue.name == 'Exhibit Hall C'
def test_fetch_speaker_record():
speaker = schedule.Record.fetch('speaker.3471')
assert speaker.name == 'Anna Martelli Ravenscroft'
def test_event_type():
event = schedule.Record.fetch('event.33950')
assert type(event) is schedule.Event
assert repr(event) == "<Event 'There *Will* Be Bugs'>"
def test_event_repr():
event = schedule.Record.fetch('event.33950')
assert repr(event) == "<Event 'There *Will* Be Bugs'>"
event2 = schedule.Event(serial=77, kind='show')
assert repr(event2) == '<Event serial=77>'
def test_event_venue():
event = schedule.Record.fetch('event.33950')
assert event.venue_serial == 1449
assert event.venue == schedule.Record.fetch('venue.1449')
assert event.venue.name == 'Portland 251'
def test_event_speakers():
event = schedule.Record.fetch('event.33950')
assert len(event.speakers) == 2
anna, alex = [schedule.Record.fetch(f'speaker.{s}') for s in (3471, 5199)]
assert event.speakers == [anna, alex]
def test_event_no_speakers():
event = schedule.Record.fetch('event.36848')
assert event.speakers == []

View File

@@ -0,0 +1,59 @@
import pytest
import schedule_v5 as schedule
@pytest.yield_fixture
def records():
yield schedule.load(schedule.JSON_PATH)
def test_load(records):
assert len(records) == 895
def test_record_attr_access():
rec = schedule.Record(spam=99, eggs=12)
assert rec.spam == 99
assert rec.eggs == 12
def test_venue_record(records):
venue = records['venue.1469']
assert venue.serial == 1469
assert venue.name == 'Exhibit Hall C'
def test_fetch_speaker_record():
speaker = schedule.Record.fetch('speaker.3471')
assert speaker.name == 'Anna Martelli Ravenscroft'
def test_event_type():
event = schedule.Record.fetch('event.33950')
assert type(event) is schedule.Event
assert repr(event) == "<Event 'There *Will* Be Bugs'>"
def test_event_repr():
event = schedule.Record.fetch('event.33950')
assert repr(event) == "<Event 'There *Will* Be Bugs'>"
event2 = schedule.Event(serial=77, kind='show')
assert repr(event2) == '<Event serial=77>'
def test_event_venue():
event = schedule.Record.fetch('event.33950')
assert event.venue_serial == 1449
assert event.venue == schedule.Record.fetch('venue.1449')
assert event.venue.name == 'Portland 251'
def test_event_speakers():
event = schedule.Record.fetch('event.33950')
assert len(event.speakers) == 2
anna, alex = [schedule.Record.fetch(f'speaker.{s}') for s in (3471, 5199)]
assert event.speakers == [anna, alex]
def test_event_no_speakers():
event = schedule.Record.fetch('event.36848')
assert event.speakers == []