""" 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): try: return getattr(self.__data, name) except AttributeError: return FrozenJSON(self.__data[name]) # <4> def __dir__(self): return self.__data.keys() # end::EXPLORE2[]