class Attachment(RemoteObject): # Attachment data. id = fields.Field() attacher = fields.Object('User') creation_time = Datetime(DATETIME_FORMAT_WITH_SECONDS) last_change_time = Datetime(DATETIME_FORMAT_WITH_SECONDS) description = fields.Field() bug_id = fields.Field() bug_ref = fields.Field() # File data. file_name = fields.Field() size = fields.Field() content_type = fields.Field() # Attachment metadata. flags = fields.List(fields.Object('Flag')) is_obsolete = StringBoolean() is_private = StringBoolean() is_patch = StringBoolean() # Used for submitting changes. token = fields.Field() ref = fields.Field() # Only with attachmentdata=1 data = fields.Field() encoding = fields.Field() def __repr__(self): return '<Attachment %s: "%s">' % (self.id, self.description) def __hash__(self): return self.id
class Committee(OpenStateObject): id = fields.Field() state = fields.Field() chamber = fields.Field() committee = fields.Field() subcommittee = fields.Field() members = fields.List(fields.Object(CommitteeMember)) sources = fields.List(fields.Object(Source)) @classmethod def get(cls, id): """ Get a committee. :param id: the committee's Open State ID (e.g. CAC000005) """ func = 'committees/%s' % id return super(Committee, cls).get(func) @classmethod def search(cls, **kwargs): """ Search comittees. Use keyword argmunents to filter by committee fields. For example, ``openstates.Committee.search(state='ca')``. """ return ListOf(cls).get('committees', kwargs).entries
class Legislator(OpenStateObject): id = fields.Field() leg_id = fields.Field() full_name = fields.Field() first_name = fields.Field() last_name = fields.Field() middle_name = fields.Field() suffixes = fields.Field() votesmart_id = fields.Field() nimsp_id = fields.Field() transparencydata_id = fields.Field() active = fields.Field() chamber = fields.Field() district = fields.Field() state = fields.Field() party = fields.Field() created_at = OpenStateDatetime() updated_at = OpenStateDatetime() roles = fields.List(fields.Object(Role)) sources = fields.List(fields.Object(Source)) # Deprecated nimsp_candidate_id = fields.Field() @classmethod def get(cls, id): """ Get a specific legislator. :param id: the legislator's Open State ID (e.g. 'TXL000139') """ func = 'legislators/%s' % id return super(Legislator, cls).get(func) @classmethod def search(cls, **kwargs): """ Search legislators. Use keyword arguments to filter by legislators fields. For example, `openstates.Legislator.search(last_name='Alesi')`. """ return ListOf(cls).get('legislators', kwargs).entries @classmethod def geo(cls, lat, long): """ Get all state legislators for a given lat/long pair :param lat: the latitude :param long: the longitude """ func = 'legislators/geo' params = dict(lat=lat, long=long) return ListOf(cls).get(func, params).entries def __str__(self): return self.full_name
class Changeset(RemoteObject): changer = fields.Object('User') changes = fields.List(fields.Object('Change')) change_time = Datetime(DATETIME_FORMAT_WITH_SECONDS) def __repr__(self): return '<Changeset by %s on %s>' % ( self.changer, self.change_time.strftime(DATETIME_FORMAT))
class Event(OpenStateObject): id = fields.Field() state = fields.Field() description = fields.Field() when = OpenStateDatetime() end = OpenStateDatetime() location = fields.Field() type = fields.Field() session = fields.Field() participants = fields.List(fields.Object(EventParticipant)) sources = fields.List(fields.Object(Source)) @classmethod def search(cls, **kwargs): return ListOf(cls).get('events', kwargs).entries
class Comment(GitHubRemoteObject): """A GitHub issue comment. `GET /repos/:user/:repo/issues/comments/:id` { "url": "https://api.github.com/repos/octocat/Hello-World/issues/comments/1", "body": "Me too", "user": { "login": "******", "id": 1, "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "somehexcode", "url": "https://api.github.com/users/octocat" }, "created_at": "2011-04-14T16:00:49Z", "updated_at": "2011-04-14T16:00:49Z" } """ id = fields.Field() url = fields.Field() body = fields.Field() user = fields.Object(User) created_at = fields.Field() updated_at = fields.Field() def __unicode__(self): return u"<Comment %s>" % self.id
class UserList(ListObject): entries = fields.List(fields.Object(User)) def __getitem__(self, key): return self.entries.__getitem__(key) @classmethod def get_friends(cls, http=None, **kwargs): return cls.get_related("friends", http=http, **kwargs) @classmethod def get_followers(cls, http=None, **kwargs): return cls.get_related("followers", http=http, **kwargs) @classmethod def get_related(cls, relation, http=None, **kwargs): url = '/statuses/%s' % relation if 'id' in kwargs: url += '/%s.json' % quote_plus(kwargs['id']) else: url += '.json' query = urlencode( filter(lambda x: x in ('screen_name', 'user_id', 'page'), kwargs)) url = urlunsplit((None, None, url, query, None)) return cls.get(urljoin(Twitter.endpoint, url), http=http)
class Labels(GitHubRemoteListObject): entries = fields.List(fields.Object(Label)) def __getitem__(self, key): return self.entries.__getitem__(key) @classmethod def by_repository(cls, user_name, repo_name, **kwargs): """Get labels by repository. `GET /repos/:user/:repo/labels` """ url = '/repos/%s/%s/labels' % (user_name, repo_name) return cls.get(urljoin(GitHub.endpoint, url), **kwargs) @classmethod def get_or_create_in_repository(cls, user_name, repo_name, label_name): labels = cls.by_repository(user_name, repo_name, per_page=100, all_pages=True) for label in labels: if label.name == label_name: return label label = Label() label.name = label_name labels.post(label) return label
class Game(Bombject): id = fields.Field() name = fields.Field() api_detail_url = fields.Field() site_detail_url = fields.Field() summary = fields.Field(api_name='deck') description = fields.Field() image = fields.Object(Image) published = fields.Datetime(dateformat='%Y-%m-%d %H:%M:%S', api_name='date_added') updated = fields.Datetime(dateformat='%Y-%m-%d %H:%M:%S', api_name='date_last_updated') characters = fields.Field() concepts = fields.Field() developers = fields.Field() platforms = fields.Field() publishers = fields.Field() @classmethod def get(cls, url, **kwargs): res = GameResult.get(url) res = res.filter() return res.results[0]
class Status(RemoteObject): """A Twitter update. Statuses can be fetched from ``http://twitter.com/statuses/show/<id>.json``. """ created_at = fields.Field() id = fields.Field() text = fields.Field() source = fields.Field() truncated = fields.Field() in_reply_to_status_id = fields.Field() in_reply_to_user_id = fields.Field() in_reply_to_screen_name = fields.Field() favorited = fields.Field() user = fields.Object(User) @classmethod def get_status(cls, id, http=None): return cls.get(urljoin(Twitter.endpoint, "/statuses/show/%d.json" % int(id)), http=http) def __unicode__(self): return u"%s: %s" % (self.user.screen_name, self.text)
class Vote(OpenStateObject): date = OpenStateDatetime() chamber = fields.Field() committee = fields.Field() motion = fields.Field() yes_count = fields.Field() no_count = fields.Field() other_count = fields.Field() passed = fields.Field() type = fields.Field() yes_votes = fields.List(fields.Object(SpecificVote)) no_votes = fields.List(fields.Object(SpecificVote)) other_votes = fields.List(fields.Object(SpecificVote)) def __str__(self): return "Vote on '%s'" % self.motion
class User(RemoteObject): """A Twitter account. A User can be retrieved from ``http://twitter.com/users/show.json`` with the appropriate ``id``, ``user_id``, or ``screen_name`` parameter. """ id = fields.Field() name = fields.Field() screen_name = fields.Field() location = fields.Field() description = fields.Field() profile_image_url = fields.Field() protected = fields.Field() followers_count = fields.Field() status = fields.Object('Status') @classmethod def get_user(cls, http=None, **kwargs): url = '/users/show' if 'id' in kwargs: url += '/%s.json' % quote_plus(kwargs['id']) else: url += '.json' query = urlencode( filter(lambda x: x in ('screen_name', 'user_id'), kwargs)) url = urlunsplit((None, None, url, query, None)) return cls.get(urljoin(Twitter.endpoint, url), http=http)
class Issues(GitHubRemoteListObject): entries = fields.List(fields.Object(Issue)) @classmethod def by_repository(cls, user_name, repo_name, state='open', **kwargs): """Get issues by repository. `GET /repos/:user/:repo/issues` """ url = '/repos/%s/%s/issues?state=%s' % (user_name, repo_name, state) return cls.get(urljoin(GitHub.endpoint, url), **kwargs) @classmethod def by_repository_all(cls, user_name, repo_name, **kwargs): """Get all issues by repository (open and closed).""" open_issues = cls.by_repository(user_name, repo_name, state='open', **kwargs) closed_issues = cls.by_repository(user_name, repo_name, state='closed', **kwargs) open_issues.entries.extend(closed_issues.entries) return open_issues
class Flag(RemoteObject): id = fields.Field() name = fields.Field() setter = fields.Object('User') status = fields.Field() requestee = fields.Object('User') type_id = fields.Field() def __repr__(self): return '<Flag "%s">' % self.name def __str__(self): return self.name def __hash__(self): return self.id
class Event(GitHubRemoteObject): """A GitHub event. `GET /events` { "type": "Event", "public": true, "payload": { }, "repo": { "id": 3, "name": "octocat/Hello-World", "url": "https://api.github.com/repos/octocat/Hello-World" }, "actor": { "login": "******", "id": 1, "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "somehexcode", "url": "https://api.github.com/users/octocat" }, "org": { "login": "******", "id": 1, "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "somehexcode", "url": "https://api.github.com/users/octocat" }, "created_at": "2011-09-06T17:26:27Z" } """ id = fields.Field() type = fields.Field() public = fields.Field() payload = fields.Field() repo = fields.Field() actor = fields.Object(User) org = fields.Object(User) created_at = fields.Field() def __unicode__(self): return u"<Event %s>" % self.id
class DirectMessage(RemoteObject): """A Twitter direct message. The authenticated user's most recent direct messages are at ``http://twitter.com/direct_messages.json``. """ id = fields.Field() sender_id = fields.Field() text = fields.Field() recipient_id = fields.Field() created_at = fields.Field() sender_screen_name = fields.Field() recipient_screen_name = fields.Field() sender = fields.Object(User) recipient = fields.Object(User) def __unicode__(self): return u"%s: %s" % (self.sender.screen_name, self.text)
class Milestones(GitHubRemoteListObject): entries = fields.List(fields.Object(Milestone)) def __getitem__(self, key): return self.entries.__getitem__(key) @classmethod def by_repository(cls, user_name, repo_name, state='open', **kwargs): """Get milestones by repository. `GET /repos/:user/:repo/milestones` """ url = '/repos/%s/%s/milestones?state=%s' % (user_name, repo_name, state) return cls.get(urljoin(GitHub.endpoint, url), **kwargs) @classmethod def by_repository_all(cls, user_name, repo_name, state='open', **kwargs): """Get all milestones by repository (open and closed).""" open_milestones = cls.by_repository(user_name, repo_name, state='open', **kwargs) closed_milestones = cls.by_repository(user_name, repo_name, state='closed', **kwargs) open_milestones.entries.extend(closed_milestones.entries) return open_milestones @classmethod def get_or_create_in_repository(cls, user_name, repo_name, milestone_title): if milestone_title is None: return None milestones = cls.by_repository_all(user_name, repo_name, per_page=100, all_pages=True) for milestone in milestones: if milestone.title == milestone_title: return milestone milestone = Milestone() milestone.title = milestone_title milestones.post(milestone) return milestone
class ViewResult(CouchObject, ListObject): total_rows = fields.Field() offset = fields.Field() entries = fields.List(fields.Object(ListItem), api_name='rows') def filter(self, **kwargs): for k, v in kwargs.iteritems(): if isinstance(v, list) or isinstance(v, dict) or isinstance( v, bool): kwargs[k] = json.dumps(v) return super(ViewResult, self).filter(**kwargs)
class Collaborators(GitHubRemoteListObject): entries = fields.List(fields.Object(Collaborator)) @classmethod def by_repository(cls, user_name, repo_name, **kwargs): """Get collaborators by repository. `GET /repos/:user/:repo/collaborators` """ url = '/repos/%s/%s/collaborators' % (user_name, repo_name) return cls.get(urljoin(GitHub.endpoint, url), **kwargs)
class GameResult(Bombject): status_code = fields.Field() error = fields.Field() total = fields.Field(api_name='number_of_total_results') count = fields.Field(api_name='number_of_page_results') limit = fields.Field() offset = fields.Field() results = fields.List(fields.Object(Game)) def update_from_dict(self, data): if not isinstance(data['results'], list): data = dict(data) data['results'] = [data['results']] super(GameResult, self).update_from_dict(data)
class Events(GitHubRemoteListObject): entries = fields.List(fields.Object(Event)) def __getitem__(self, key): return self.entries.__getitem__(key) @classmethod def by_repository(cls, repo_user, repo_name, **kwargs): """Get events by repository. `GET /repos/:user/:repo/events` """ url = '/repos/%s/%s/events' % (repo_user, repo_name) return cls.get(urljoin(GitHub.endpoint, url), **kwargs)
class Comment(RemoteObject): id = fields.Field() creator = fields.Object('User') creation_time = Datetime(DATETIME_FORMAT_WITH_SECONDS) text = fields.Field() is_private = StringBoolean() def __repr__(self): return '<Comment by %s on %s>' % ( self.creator, self.creation_time.strftime(DATETIME_FORMAT)) def __str__(self): return self.text def __hash__(self): return self.id
class Timeline(ListObject): entries = fields.List(fields.Object(Status)) def __getitem__(self, key): return self.entries.__getitem__(key) @classmethod def public(cls, http=None): return cls.get(urljoin(Twitter.endpoint, '/statuses/public_timeline.json'), http=http) @classmethod def friends(cls, http=None, **kwargs): query = urlencode( filter(lambda x: x in ('since_id', 'max_id', 'count', 'page'), kwargs)) url = urlunsplit( (None, None, '/statuses/friends_timeline.json', query, None)) return cls.get(urljoin(Twitter.endpoint, url), http=http) @classmethod def user(cls, http=None, **kwargs): url = '/statuses/user_timeline' if 'id' in kwargs: url += '/%s.json' % quote_plus(kwargs['id']) else: url += '.json' query = urlencode( filter( lambda x: x in ('screen_name', 'user_id', 'since_id', 'max_id', 'page'), kwargs)) url = urlunsplit((None, None, url, query, None)) return cls.get(urljoin(Twitter.endpoint, url), http=http) @classmethod def mentions(cls, http=None, **kwargs): query = urlencode( filter(lambda x: x in ('since_id', 'max_id', 'page'), kwargs)) url = urlunsplit((None, None, '/statuses/mentions.json', query, None)) return cls.get(urljoin(Twitter.endpoint, url), http=http)
def __new__(cls, name, bases=None, attr=None): """Creates a new `PageObject` subclass. If `bases` and `attr` are specified, as in a regular subclass declaration, a new class is created as per the specified settings. If only `name` is specified, that value is used as a reference to a `RemoteObject` class to which the new `PageObject` class is bound. The `name` parameter can be either a name or a `RemoteObject` class, as when declaring a `remoteobjects.fields.Object` field. """ direct = attr is None if direct: # Don't bother making a new subclass if we already made one for # this target. if name in cls._subclasses: return cls._subclasses[name] entryclass = name if callable(entryclass): name = cls.__name__ + entryclass.__name__ else: name = cls.__name__ + entryclass bases = (cls._basemodule, ) attr = { 'entries': fields.List(fields.Object(entryclass)), } newcls = super(PageOf, cls).__new__(cls, name, bases, attr) # Save the result for later direct invocations. if direct: cls._subclasses[entryclass] = newcls newcls.__module__ = cls._modulename setattr(sys.modules[cls._modulename], name, newcls) elif cls._basemodule is None: cls._basemodule = newcls return newcls
class DirectMessageList(ListObject): entries = fields.List(fields.Object(DirectMessage)) def __getitem__(self, key): return self.entries.__getitem__(key) @classmethod def get_messages(cls, http=None, **kwargs): url = '/direct_messages.json' query = urlencode(filter(lambda x: x in ('since_id', 'page'), kwargs)) url = urlunsplit((None, None, url, query, None)) return cls.get(urljoin(Twitter.endpoint, url), http=http) @classmethod def get_sent_messages(cls, http=None, **kwargs): url = '/direct_messages/sent.json' query = urlencode(filter(lambda x: x in ('since_id', 'page'), kwargs)) url = urlunsplit((None, None, url, query, None)) return cls.get(urljoin(Twitter.endpoint, url), http=http)
class Bill(OpenStateObject): title = fields.Field() state = fields.Field() session = fields.Field() chamber = fields.Field() bill_id = fields.Field() created_at = OpenStateDatetime() updated_at = OpenStateDatetime() alternate_titles = fields.List(fields.Field()) actions = fields.List(fields.Object(Action)) sponsors = fields.List(fields.Object(Sponsor)) votes = fields.List(fields.Object(Vote)) versions = fields.List(fields.Object(Version)) documents = fields.List(fields.Object(Document)) sources = fields.List(fields.Object(Source)) @classmethod def get(cls, state, session, chamber, bill_id): """ Get a specific bill. :param state: the two-letter abbreviation of the originating state :param session: the session identifier for the bill (see the state's metadata for legal values) :param chamber: which legislative chamber the bill originated in ('upper' or 'lower') :param bill_id: the bill's ID as assigned by the state """ func = "bills/%s/%s/%s/%s" % (state, session, chamber, bill_id) return super(Bill, cls).get(func) @classmethod def search(cls, query=None, **kwargs): """ Search bills. :param query: a query string which will be used to search bill titles Any additional keyword arguments will be used to further filter the results. """ if query: kwargs['q'] = query func = 'bills' return ListOf(cls).get(func, kwargs).entries def __str__(self): return '%s: %s' % (self.bill_id, self.title)
class Milestone(GitHubRemoteObject): """A GitHub milestone. `GET /repos/:user/:repo/milestones/:number` { "url": "https://api.github.com/repos/octocat/Hello-World/milestones/1", "number": 1, "state": "open", "title": "v1.0", "description": "", "creator": { "login": "******", "id": 1, "avatar_url": "https://github.com/images/error/octocat_happy.gif", "gravatar_id": "somehexcode", "url": "https://api.github.com/users/octocat" }, "open_issues": 4, "closed_issues": 8, "created_at": "2011-04-10T20:09:31Z", "due_on": null } """ url = fields.Field() number = fields.Field() state = fields.Field() title = fields.Field() description = fields.Field() creator = fields.Object(User) open_issues = fields.Field() closed_issues = fields.Field() created_at = fields.Field() due_on = fields.Field() def __unicode__(self): return u"<Milestone %s>" % self.title
class Comments(GitHubRemoteListObject): entries = fields.List(fields.Object(Comment)) def __getitem__(self, key): return self.entries.__getitem__(key) @classmethod def by_issue(cls, issue, **kwargs): """Get comments by issue. `GET /repos/:user/:repo/issues/:number/comments` """ # Don't request the list of comments if we know there should be 0. if issue.comments == 0: comments = cls(entries=[]) comments._location = '%s/comments' % issue.url return comments url = '%s/comments' % issue.url return cls.get(url, **kwargs)
class State(OpenStateObject): name = fields.Field() abbreviation = fields.Field() legislature_name = fields.Field() upper_chamber_name = fields.Field() lower_chamber_name = fields.Field() upper_chamber_term = fields.Field() lower_chamber_term = fields.Field() upper_chamber_title = fields.Field() lower_chamber_title = fields.Field() terms = fields.List(fields.Object(Term)) @classmethod def get(cls, abbrev): """ Get metadata about a state. :param abbrev: the state's two-letter abbreviation. """ return super(State, cls).get('metadata/%s' % abbrev) def __str__(self): return self.name
class Bug(RemoteObject): id = fields.Field() summary = fields.Field() assigned_to = fields.Object('User') creator = fields.Object('User') target_milestone = fields.Field() attachments = fields.List(fields.Object('Attachment')) comments = fields.List(fields.Object('Comment')) history = fields.List(fields.Object('Changeset')) keywords = fields.List(fields.Object('Keyword')) status = fields.Field() resolution = fields.Field() # TODO: These are Mozilla specific and should be generalized cf_blocking_20 = fields.Field() cf_blocking_fennec = fields.Field() cf_crash_signature = fields.Field() creation_time = Datetime(DATETIME_FORMAT_WITH_SECONDS) flags = fields.List(fields.Object('Flag')) blocks = fields.List(fields.Field()) depends_on = fields.List(fields.Field()) url = fields.Field() cc = fields.List(fields.Object('User')) keywords = fields.List(fields.Field()) whiteboard = fields.Field() op_sys = fields.Field() platform = fields.Field() priority = fields.Field() product = fields.Field() qa_contact = fields.Object('User') severity = fields.Field() see_also = fields.List(fields.Field()) version = fields.Field() alias = fields.Field() classification = fields.Field() component = fields.Field() is_cc_accessible = StringBoolean() is_everconfirmed = StringBoolean() is_creator_accessible = StringBoolean() last_change_time = Datetime(DATETIME_FORMAT_WITH_SECONDS) ref = fields.Field() # Needed for submitting changes. token = fields.Field(api_name='update_token') # Time tracking. actual_time = fields.Field() deadline = Datetime(DATETIME_FORMAT_WITH_SECONDS) estimated_time = fields.Field() # groups = fields.Field() # unimplemented percentage_complete = fields.Field() remaining_time = fields.Field() work_time = fields.Field() def __repr__(self): return '<Bug %s: "%s">' % (self.id, self.summary) def __str__(self): return "[Bug %s] - %s" % (self.id, self.summary) def __hash__(self): return self.id