From 8972834a85a17ebbeb326a9d4493725d53913e33 Mon Sep 17 00:00:00 2001 From: Alejandro Gómez Date: Thu, 26 Apr 2012 21:00:13 +0200 Subject: Labels and Milestones services added --- pygithub3/requests/issues/milestones.py | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 pygithub3/requests/issues/milestones.py (limited to 'pygithub3/requests/issues/milestones.py') diff --git a/pygithub3/requests/issues/milestones.py b/pygithub3/requests/issues/milestones.py new file mode 100644 index 0000000..355c3b0 --- /dev/null +++ b/pygithub3/requests/issues/milestones.py @@ -0,0 +1,38 @@ +# -*- encoding: utf-8 -*- + +from pygithub3.requests.base import Request +from pygithub3.resources.issues import Milestone + + +class List(Request): + uri = 'repos/{user}/{repo}/milestones' + resource = Milestone + + +class Get(Request): + uri = 'repos/{user}/{repo}/milestones/{number}' + resource = Milestone + + +class Create(Request): + uri = 'repos/{user}/{repo}/milestones' + resource = Milestone + body_schema = { + 'schema': ('title', 'state', 'description', 'due_on'), + 'required': ('title',) + } + + +class Update(Request): + + uri = 'repos/{user}/{repo}/milestones/{number}' + resource = Milestone + body_schema = { + 'schema': ('title', 'state', 'description', 'due_on'), + 'required': ('title',) + } + + +class Delete(Request): + uri = 'repos/{user}/{repo}/milestones/{number}' + resource = Milestone -- cgit v1.2.3-59-g8ed1b From ce110c8e4cd23d5cdd33a855119f924d54cbd399 Mon Sep 17 00:00:00 2001 From: David Medina Date: Sat, 16 Jun 2012 12:32:43 +0200 Subject: issues.milestones service Also fix doc in issues.labels --- pygithub3/requests/issues/milestones.py | 14 ++--- pygithub3/services/issues/labels.py | 7 ++- pygithub3/services/issues/milestones.py | 107 ++++++++++++++++---------------- 3 files changed, 66 insertions(+), 62 deletions(-) (limited to 'pygithub3/requests/issues/milestones.py') diff --git a/pygithub3/requests/issues/milestones.py b/pygithub3/requests/issues/milestones.py index 355c3b0..f695e1f 100644 --- a/pygithub3/requests/issues/milestones.py +++ b/pygithub3/requests/issues/milestones.py @@ -1,6 +1,6 @@ # -*- encoding: utf-8 -*- -from pygithub3.requests.base import Request +from pygithub3.requests.base import Request, ValidationError from pygithub3.resources.issues import Milestone @@ -22,15 +22,15 @@ class Create(Request): 'required': ('title',) } + def clean_body(self): # Test if API normalize it + state = self.body.get('state', '') + if state.lower() not in ('open', 'closed'): + raise ValidationError("'state' must be 'open' or 'closed'") -class Update(Request): + +class Update(Create): uri = 'repos/{user}/{repo}/milestones/{number}' - resource = Milestone - body_schema = { - 'schema': ('title', 'state', 'description', 'due_on'), - 'required': ('title',) - } class Delete(Request): diff --git a/pygithub3/services/issues/labels.py b/pygithub3/services/issues/labels.py index a20e48e..931a6b4 100644 --- a/pygithub3/services/issues/labels.py +++ b/pygithub3/services/issues/labels.py @@ -142,8 +142,8 @@ class Labels(Service): name=label) return self._delete(request) - def replace_all(self, number, labels, user=None, repo=None): - """ Replace all labels of a issue + def replace_all(self, number, user=None, repo=None, *labels): + """ Replace all labels for a issue :param int number: Issue number :param list labels: New labels @@ -151,6 +151,9 @@ class Labels(Service): :param str repo: Repo name :returns: A :doc:`result` + .. note:: + If labels weren't especified, it'd remove all labels from the issue + .. note:: Remember :ref:`config precedence` """ diff --git a/pygithub3/services/issues/milestones.py b/pygithub3/services/issues/milestones.py index 851e9f2..fa0f95d 100644 --- a/pygithub3/services/issues/milestones.py +++ b/pygithub3/services/issues/milestones.py @@ -1,105 +1,106 @@ #!/usr/bin/env python # -*- encoding: utf-8 -*- +from datetime import datetime + from pygithub3.services.base import Service +from pygithub3.resources.base import GITHUB_DATE_FORMAT class Milestones(Service): - """ Consume `Milestones API + """ Consume `Milestones API `_ """ - def list(self, user, repo): + def list(self, user=None, repo=None, state='open', sort='due_date', + direction='desc'): """ List milestones for a repo :param str user: Username :param str repo: Repo name + :param str state: 'open' or 'closed' + :param str sort: 'due_date' or 'completeness' + :param str direction: 'asc' or 'desc' :returns: A :doc:`result` + + .. note:: + Remember :ref:`config precedence` """ - request = self.request_builder('issues.milestones.list', - user=user, - repo=repo) - return self._get_result(request) + request = self.make_request('issues.milestones.list', user=user, + repo=repo) + return self._get_result(request, state=state, sort=sort, + direction=direction) - def get(self, user, repo, number): + def get(self, number, user=None, repo=None): """ Get a single milestone + :param int number: Milestone number :param str user: Username :param str repo: Repo name - :param int number: Milestone number + + .. note:: + Remember :ref:`config precedence` """ - request = self.request_builder('issues.milestones.get', user=user, + request = self.make_request('issues.milestones.get', user=user, repo=repo, number=number) return self._get(request) - def create(self, - user, - repo, - title, - state=None, - description=None, - due_on=None): + def _normalize_due_on(self, data): + """ If ``due_on`` comes as ``datetime``, it'll normalize it """ + try: + due_on = datetime.strptime(data.get('due_on'), GITHUB_DATE_FORMAT) + data.update({'due_on': due_on}) + except: + pass + + def create(self, data, user=None, repo=None): """ Create a milestone + :param dict data: Input. See `github milestones doc`_ :param str user: Username :param str repo: Repo name - :param str title: Milestone title - :param str state: Milestone state - :param str description: Milestone description - :param date due_on: Milestone due date .. warning:: You must be authenticated + + .. note:: + Remember :ref:`config precedence` """ - request = self.request_builder('issues.milestones.create', - user=user, - repo=repo, - body={'title': title, - 'state': state, - 'due_on': due_on}) + self._normalize_due_on(data) + request = self.make_request('issues.milestones.create', user=user, + repo=repo, body=data) return self._post(request) - def update(self, - user, - repo, - number, - title, - state=None, - description=None, - due_on=None): + def update(self, number, data, user=None, repo=None): """ Update a milestone + :param int number: Milestone number + :param dict data: Input. See `github milestones doc`_ :param str user: Username :param str repo: Repo name - :param int number: Milestone number - :param str title: Milestone title - :param str state: Milestone state - :param str description: Milestone description - :param date due_on: Milestone due date .. warning:: You must be authenticated + + .. note:: + Remember :ref:`config precedence` """ - request = self.request_builder('issues.milestones.update', - user=user, - repo=repo, - number=number, - body={'title': title, - 'state': state, - 'description': description, - 'due_on': due_on, }) + self._normalize_due_on(data) + request = self.make_request('issues.milestones.update', user=user, + repo=repo, number=number, body=data) return self._patch(request) - def delete(self, user, repo, number): + def delete(self, number, user=None, repo=None): """ Delete a milestone + :param int number: Milestone number :param str user: Username :param str repo: Repo name - :param int number: Milestone number .. warning:: You must be authenticated + + .. note:: + Remember :ref:`config precedence` """ - request = self.request_builder('issues.milestones.delete', - user=user, - repo=repo, - number=number) + request = self.make_request('issues.milestones.delete', user=user, + repo=repo, number=number) self._delete(request) -- cgit v1.2.3-59-g8ed1b From e383e91973bdbf0b6b77c739249225e3a85b9f24 Mon Sep 17 00:00:00 2001 From: David Medina Date: Sat, 16 Jun 2012 13:38:24 +0200 Subject: Tests on services.issues working Also fix some bugs --- pygithub3/requests/base.py | 4 +- pygithub3/requests/issues/milestones.py | 3 +- pygithub3/services/issues/__init__.py | 4 +- pygithub3/services/issues/comments.py | 4 +- pygithub3/services/issues/events.py | 2 +- pygithub3/services/issues/labels.py | 6 +- pygithub3/tests/services/test_issues.py | 99 +++++++++++++++------------------ 7 files changed, 58 insertions(+), 64 deletions(-) (limited to 'pygithub3/requests/issues/milestones.py') diff --git a/pygithub3/requests/base.py b/pygithub3/requests/base.py index c4fe5cc..6088bae 100644 --- a/pygithub3/requests/base.py +++ b/pygithub3/requests/base.py @@ -27,8 +27,8 @@ class Body(object): def parse(self): """ Parse body with schema-required rules """ if not hasattr(self.content, 'items'): - raise ValidationError("'%s' needs a content dictionary" - % self.__class__.__name__) + raise ValidationError("It needs a content dictionary (%s)" % ( + self.content, )) parsed = dict([(key, self.content[key]) for key in self.schema if key in self.content]) for attr_required in self.required: diff --git a/pygithub3/requests/issues/milestones.py b/pygithub3/requests/issues/milestones.py index f695e1f..4093c7e 100644 --- a/pygithub3/requests/issues/milestones.py +++ b/pygithub3/requests/issues/milestones.py @@ -24,8 +24,9 @@ class Create(Request): def clean_body(self): # Test if API normalize it state = self.body.get('state', '') - if state.lower() not in ('open', 'closed'): + if state and state.lower() not in ('open', 'closed'): raise ValidationError("'state' must be 'open' or 'closed'") + return self.body class Update(Create): diff --git a/pygithub3/services/issues/__init__.py b/pygithub3/services/issues/__init__.py index f17ee91..7851e6f 100644 --- a/pygithub3/services/issues/__init__.py +++ b/pygithub3/services/issues/__init__.py @@ -35,7 +35,7 @@ class Issue(Service, MimeTypeMixin): """ params = dict(filter=filter, state=state, labels=labels, sort=sort, direction=direction) - self._normalize_data('since', params) + self._normalize_date('since', params) request = self.request_builder('issues.list') return self._get_result(request, **params) @@ -60,7 +60,7 @@ class Issue(Service, MimeTypeMixin): """ params = dict(milestone=milestone, state=state, assignee=assignee, mentioned=mentioned, labels=labels, sort=sort, direction=direction) - self._normalize_data('since', params) + self._normalize_date('since', params) request = self.make_request('issues.list_by_repo', user=user, repo=repo) return self._get_result(request, **params) diff --git a/pygithub3/services/issues/comments.py b/pygithub3/services/issues/comments.py index 2b976a8..54d4287 100644 --- a/pygithub3/services/issues/comments.py +++ b/pygithub3/services/issues/comments.py @@ -68,7 +68,7 @@ class Comments(Service, MimeTypeMixin): .. note:: Remember :ref:`config precedence` """ - request = self.request_builder('issues.comments.edit', user=user, + request = self.make_request('issues.comments.edit', user=user, repo=repo, id=id, body={'body': message}) return self._patch(request) @@ -85,6 +85,6 @@ class Comments(Service, MimeTypeMixin): .. note:: Remember :ref:`config precedence` """ - request = self.request_builder('issues.comments.delete', user=user, + request = self.make_request('issues.comments.delete', user=user, repo=repo, id=id) self._delete(request) diff --git a/pygithub3/services/issues/events.py b/pygithub3/services/issues/events.py index 3fd94e3..92bb332 100644 --- a/pygithub3/services/issues/events.py +++ b/pygithub3/services/issues/events.py @@ -26,7 +26,7 @@ class Events(Service): :param str repo: Repo name :returns: A :doc:`result` """ - request = self.request_builder('issues.events.list_by_repo', + request = self.make_request('issues.events.list_by_repo', user=user, repo=repo) return self._get_result(request) diff --git a/pygithub3/services/issues/labels.py b/pygithub3/services/issues/labels.py index 931a6b4..d1119d3 100644 --- a/pygithub3/services/issues/labels.py +++ b/pygithub3/services/issues/labels.py @@ -102,7 +102,7 @@ class Labels(Service): repo=repo, number=number) return self._get(request) - def add_to_issue(self, number, user=None, repo=None, *labels): + def add_to_issue(self, number, labels, user=None, repo=None): """ Add labels to issue :param int number: Issue number @@ -142,7 +142,7 @@ class Labels(Service): name=label) return self._delete(request) - def replace_all(self, number, user=None, repo=None, *labels): + def replace_all(self, number, labels, user=None, repo=None): """ Replace all labels for a issue :param int number: Issue number @@ -161,7 +161,7 @@ class Labels(Service): user=user, repo=repo, number=number, - body=labels,) + body=map(str, labels)) return self._put(request) def remove_all(self, number, user=None, repo=None): diff --git a/pygithub3/tests/services/test_issues.py b/pygithub3/tests/services/test_issues.py index 4672bdb..2d42405 100644 --- a/pygithub3/tests/services/test_issues.py +++ b/pygithub3/tests/services/test_issues.py @@ -7,7 +7,8 @@ from mock import patch, Mock from pygithub3.exceptions import ValidationError from pygithub3.tests.utils.core import TestCase from pygithub3.resources.base import json -from pygithub3.services.issues import Issue, Comments, Events, Labels, Milestones +from pygithub3.services.issues import (Issue, Comments, Events, Labels, + Milestones) from pygithub3.tests.utils.base import (mock_response, mock_response_result, mock_json) from pygithub3.tests.utils.services import _ @@ -20,7 +21,7 @@ json.loads = Mock(side_effect=mock_json) class TestIssuesService(TestCase): def setUp(self): - self.isu = Issue() + self.isu = Issue(user='octocat', repo='Hello-World') def test_LIST_without_user(self, request_method): request_method.return_value = mock_response_result() @@ -29,27 +30,25 @@ class TestIssuesService(TestCase): def test_LIST_by_repo(self, request_method): request_method.return_value = mock_response_result() - self.isu.list_by_repo('octocat', 'Hello-World').all() + self.isu.list_by_repo().all() self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/issues'))) def test_GET(self, request_method): request_method.return_value = mock_response() - self.isu.get('octocat', 'Hello-World', 1) + self.isu.get(1) self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/issues/1'))) def test_CREATE(self, request_method): request_method.return_value = mock_response('post') - self.isu.create('octocat', 'Hello-World', - dict(title='My issue', body='Fix this issue')) + self.isu.create(dict(title='My issue', body='Fix this issue')) self.assertEqual(request_method.call_args[0], ('post', _('repos/octocat/Hello-World/issues'))) def test_UPDATE(self, request_method): request_method.return_value = mock_response('patch') - self.isu.update('octocat', 'Hello-World', 1, - {'body': 'edited'}) + self.isu.update(1, {'body': 'edited'}) self.assertEqual(request_method.call_args[0], ('patch', _('repos/octocat/Hello-World/issues/1'))) @@ -58,35 +57,35 @@ class TestIssuesService(TestCase): class TestCommentService(TestCase): def setUp(self): - self.cs = Comments() + self.cs = Comments(user='octocat', repo='Hello-World') def test_LIST(self, request_method): request_method.return_value = mock_response_result() - self.cs.list('octocat', 'Hello-World', 1).all() + self.cs.list(1).all() self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/issues/1/comments'))) def test_GET(self, request_method): request_method.return_value = mock_response() - self.cs.get('octocat', 'Hello-World', 1) + self.cs.get(1) self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/issues/comments/1'))) def test_CREATE(self, request_method): request_method.return_value = mock_response('post') - self.cs.create('octocat', 'Hello-World', 1, 'comment') + self.cs.create(1, 'comment') self.assertEqual(request_method.call_args[0], ('post', _('repos/octocat/Hello-World/issues/1/comments'))) def test_UPDATE(self, request_method): request_method.return_value = mock_response('patch') - self.cs.update('octocat', 'Hello-World', 1, 'new comment') + self.cs.update(1, 'new comment') self.assertEqual(request_method.call_args[0], ('patch', _('repos/octocat/Hello-World/issues/comments/1'))) def test_DELETE(self, request_method): request_method.return_value = mock_response('delete') - self.cs.delete('octocat', 'Hello-World', 1) + self.cs.delete(1) self.assertEqual(request_method.call_args[0], ('delete', _('repos/octocat/Hello-World/issues/comments/1'))) @@ -95,23 +94,23 @@ class TestCommentService(TestCase): class TestEventsService(TestCase): def setUp(self): - self.ev = Events() + self.ev = Events(user='octocat', repo='Hello-World') def test_LIST_by_issue(self, request_method): request_method.return_value = mock_response_result() - self.ev.list_by_issue('octocat', 'Hello-World', 1).all() + self.ev.list_by_issue(1).all() self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/issues/1/events'))) def test_LIST_by_repo(self, request_method): request_method.return_value = mock_response_result() - self.ev.list_by_repo('octocat', 'Hello-World').all() + self.ev.list_by_repo().all() self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/issues/events'))) def test_GET(self, request_method): request_method.return_value = mock_response() - self.ev.get('octocat', 'Hello-World', 1) + self.ev.get(1) self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/issues/events/1'))) @@ -120,121 +119,115 @@ class TestEventsService(TestCase): class TestLabelsService(TestCase): def setUp(self): - self.lb = Labels() + self.lb = Labels(user='octocat', repo='Hello-World') def test_GET(self, request_method): request_method.return_value = mock_response() - self.lb.get('octocat', 'Hello-World', 'bug') + self.lb.get('bug') self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/labels/bug'))) def test_CREATE(self, request_method): request_method.return_value = mock_response('post') - self.lb.create('octocat', 'Hello-World', 'bug', 'FF0000') + self.lb.create(dict(name='bug', color='FF0000')) self.assertEqual(request_method.call_args[0], ('post', _('repos/octocat/Hello-World/labels'))) def test_CREATE_with_invalid_color(self, request_method): request_method.return_value = mock_response('post') # invalid color - with self.assertRaises(ValidationError): - args={'user': 'octocat', - 'repo': 'Hello-world', - 'name': 'bug', - 'color': 'FF00',} - self.lb.create(**args) + with self.assertRaises(ValidationError): + args={'name': 'bug', 'color': 'FF00'} + self.lb.create(args) def test_UPDATE(self, request_method): request_method.return_value = mock_response('patch') - self.lb.update('octocat', 'Hello-World', 'bug', 'critical', 'FF0000') + self.lb.update('bug', dict(name='critical', color='FF0000')) self.assertEqual(request_method.call_args[0], ('patch', _('repos/octocat/Hello-World/labels/bug'))) def test_UPDATE_with_invalid_color(self, request_method): request_method.return_value = mock_response('post') # invalid color - with self.assertRaises(ValidationError): - args={'user': 'octocat', - 'repo': 'Hello-world', - 'name': 'bug', - 'new_name': 'critical', + with self.assertRaises(ValidationError): + args={'name': 'critical', 'color': 'FF00',} - self.lb.update(**args) + self.lb.update('bug', args) def test_DELETE(self, request_method): request_method.return_value = mock_response('delete') - self.lb.delete('octocat', 'Hello-World', 'bug') + self.lb.delete('bug') self.assertEqual(request_method.call_args[0], ('delete', _('repos/octocat/Hello-World/labels/bug'))) - def test_LIST_by_repo(self, request_method): - request_method.return_value = mock_response() - self.lb.list_by_repo('octocat', 'Hello-World') - self.assertEqual(request_method.call_args[0], - ('get', _('repos/octocat/Hello-World/labels'))) - def test_LIST_by_issue(self, request_method): request_method.return_value = mock_response() - self.lb.list_by_issue('octocat', 'Hello-World', 1) + self.lb.list_by_issue(1) self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/issues/1/labels'))) def test_ADD_to_issue(self, request_method): request_method.return_value = mock_response('post') - self.lb.add_to_issue('octocat', 'Hello-World', 1, ['bug', 'critical']) + self.lb.add_to_issue(1, ('bug', 'critical')) self.assertEqual(request_method.call_args[0], ('post', _('repos/octocat/Hello-World/issues/1/labels'))) def test_REMOVE_from_issue(self, request_method): request_method.return_value = mock_response('delete') - self.lb.remove_from_issue('octocat', 'Hello-World', 1, 'bug') + self.lb.remove_from_issue(1, 'bug') self.assertEqual(request_method.call_args[0], ('delete', _('repos/octocat/Hello-World/issues/1/labels/bug'))) def test_REPLACE_all(self, request_method): - self.lb.replace_all('octocat', 'Hello-World', 1, ['bug', 'critical']) + self.lb.replace_all(1, ['bug', 'critical']) self.assertEqual(request_method.call_args[0], ('put', _('repos/octocat/Hello-World/issues/1/labels'))) def test_REMOVE_all(self, request_method): request_method.return_value = mock_response('delete') - self.lb.remove_all('octocat', 'Hello-World', 1) + self.lb.remove_all(1) self.assertEqual(request_method.call_args[0], ('delete', _('repos/octocat/Hello-World/issues/1/labels'))) - + + def test_LIST_by_milestone(self, request_method): + request_method.return_value = mock_response_result() + self.lb.list_by_milestone(1).all() + self.assertEqual(request_method.call_args[0], + ('get', _('repos/octocat/Hello-World/milestones/1/labels'))) + @patch.object(requests.sessions.Session, 'request') class TestMilestonesService(TestCase): def setUp(self): - self.mi = Milestones() + self.mi = Milestones(user='octocat', repo='Hello-World') def test_LIST_by_repo(self, request_method): request_method.return_value = mock_response_result() - self.mi.list('octocat', 'Hello-World').all() + self.mi.list().all() self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/milestones'))) def test_GET(self, request_method): request_method.return_value = mock_response() - self.mi.get('octocat', 'Hello-World', 1) + self.mi.get(1) self.assertEqual(request_method.call_args[0], ('get', _('repos/octocat/Hello-World/milestones/1'))) def test_CREATE(self, request_method): request_method.return_value = mock_response('post') - self.mi.create('octocat', 'Hello-World', 'title') + self.mi.create(dict(title='test')) self.assertEqual(request_method.call_args[0], ('post', _('repos/octocat/Hello-World/milestones'))) def test_UPDATE(self, request_method): request_method.return_value = mock_response('patch') - self.mi.update('octocat', 'Hello-World', 1, 'critical') + self.mi.update(1, dict(title='test')) self.assertEqual(request_method.call_args[0], ('patch', _('repos/octocat/Hello-World/milestones/1'))) def test_DELETE(self, request_method): request_method.return_value = mock_response('delete') - self.mi.delete('octocat', 'Hello-World', 1) + self.mi.delete(1) self.assertEqual(request_method.call_args[0], ('delete', _('repos/octocat/Hello-World/milestones/1'))) -- cgit v1.2.3-59-g8ed1b