diff --git a/.gitignore b/.gitignore index ea2d6d3..241d83f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,17 @@ -.DS_Store -.coverage -.noseids -.ropeproject/ -.tox/ -*.py[co] -*~ -*.sqlite -*.sqlite-journal -settings_local.py -local_settings.py +*.egg-info/ + .*.sw[po] +*.py[co] + +build/ dist/ -*.egg-info doc/.build/ -build/ -locale/ +.ropeproject/ +.tox/ + +ChangeLog pip-log.txt + +.DS_Store +.coverage +.noseids diff --git a/.ucopy.cfg b/.ucopy.cfg new file mode 100644 index 0000000..530185a --- /dev/null +++ b/.ucopy.cfg @@ -0,0 +1,21 @@ +[repo] +name = python-github2 +license-from = bsd-3 +vcs = git + +[files] +ignore-from = git +ignore-glob = COPYING, README.rst, .keep, test/data/github.com,api* + +[patch] +unicode = python + +[author-override] +Ask Solem = +Chris Vale = +Claudio B. = +Daniel Greenfeld = +Donald von Stufft = +Michael Basnight = +Sameer Al-Sakran = +Stéphane Angel = diff --git a/AUTHORS b/AUTHORS index 99f5070..5e14ae3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,31 +1,38 @@ -Ask Solem -Mark Paschal -Donald von Stufft -Maximillian Dornseif +python-github2 was written by: + +Ask Solem + +with contributions from the following people: + +Adam Vandenberg Asheesh Laroia -Rick Harris -Cody Soyland -Fernando Perez -Evan Broder -Scott Torborg -Claudio B. +Barthelemy Dagenais Chris Vale -Adam Vandenberg -Kenneth Reitz +Christopher MacGown +Claudio B. +Cody Soyland Daniel Greenfeld +Donald von Stufft +Evan Broder +Fernando Perez +Ionuț Arțăriși +James Rowe +Jens Ohlig Jeremy Dunck Jonas Obrist -Sameer Al-Sakran -Vincent Driessen -James Rowe Josh Weinberg -Barthelemy Dagenais -Surajram Kumarave -broderboy -Patryk Zawadzki +Justin Quick +Kenneth Reitz +Mark Paschal +Maximillian Dornseif Michael Basnight -Christopher MacGown +Patryk Zawadzki +Rick Harris Rok Garbas -Ionuț Arțăriși +Sameer Al-Sakran +Scott Torborg Stéphane Angel +Surajram Kumaravel +Vincent Driessen +broderboy modocache diff --git a/MANIFEST.in b/MANIFEST.in index ac52cc3..e77f35d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,6 @@ recursive-include examples * + +include ChangeLog include NEWS.rst include README.rst include AUTHORS diff --git a/NEWS.rst b/NEWS.rst index e7092fe..eaa874c 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -6,6 +6,12 @@ look at the `git repository`_ for the full project history. .. _git repository: https://github.com/ask/python-github2/ +0.6.2 - 2012-06-11 +------------------ + +* Updated dependencies to handle recent ``python-dateutil`` releases +* Fixed ``simplejson`` dependencies for Python 2.4 + 0.6.1 - 2012-02-28 ------------------ diff --git a/README.rst b/README.rst index 3e6ab34..a91633f 100644 --- a/README.rst +++ b/README.rst @@ -1,30 +1,29 @@ ================================================================================ -github2 - Github API v2 library for Python. +github2 - GitHub API v2 library for Python. ================================================================================ :Authors: Ask Solem (askh@opera.com) -:Version: 0.6.1 +:Version: 0.6.2 .. warning:: - GitHub are planning to `switch off API v2`_ on 2012-05-01, you should - be looking to replace ``github2`` as soon as possible. + GitHub have marked API v2 as deprecated, you should be looking to replace + your usage of ``github2`` in the near future. Both remoteobjects_ and micromodels_ provide easy-to-use functionality for creating bindings to remote APIs, and should significantly reduce the amount of work needed in moving away from GitHub's API v2. This is a Python library implementing all of the features available in version 2 -of the `Github API`_. +of the `GitHub API`_. See the ``doc/`` directory for installation instructions and usage information. If you prefer you can also read the `documentation online`_. -.. _switch off API v2: https://github.com/blog/1090-github-api-moving-on .. _remoteobjects: https://github.com/saymedia/remoteobjects .. _micromodels: https://github.com/j4mie/micromodels -.. _Github API: http://develop.github.com/ +.. _GitHub API: http://develop.github.com/ .. _documentation online: http://packages.python.org/github2 License diff --git a/doc/.templates/layout.html b/doc/.templates/layout.html index 3560b06..b251a03 100644 --- a/doc/.templates/layout.html +++ b/doc/.templates/layout.html @@ -1,3 +1,10 @@ +{# + Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. +#} {% extends "!layout.html" %} {% block extrahead %} diff --git a/doc/api/client.rst b/doc/api/client.rst index b11eaa8..1cf0ea9 100644 --- a/doc/api/client.rst +++ b/doc/api/client.rst @@ -1,3 +1,11 @@ +.. Copyright (C) 2011-2012 James Rowe + Michael Basnight + modocache + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.client Creating a client diff --git a/doc/api/commit.rst b/doc/api/commit.rst index e4a69bf..ffca1a2 100644 --- a/doc/api/commit.rst +++ b/doc/api/commit.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.commits Commit diff --git a/doc/api/core.rst b/doc/api/core.rst index 9b9e297..1e26d09 100644 --- a/doc/api/core.rst +++ b/doc/api/core.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.core Core diff --git a/doc/api/index.rst b/doc/api/index.rst index cbe2c5c..36fa3a0 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + API documentation ================= diff --git a/doc/api/issues.rst b/doc/api/issues.rst index 6ba740c..1f2dcfb 100644 --- a/doc/api/issues.rst +++ b/doc/api/issues.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.issues Issues diff --git a/doc/api/network.rst b/doc/api/network.rst index f07baa9..1d7312d 100644 --- a/doc/api/network.rst +++ b/doc/api/network.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. currentmodule:: github2.client Network diff --git a/doc/api/object.rst b/doc/api/object.rst index 79842c7..106b685 100644 --- a/doc/api/object.rst +++ b/doc/api/object.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. currentmodule:: github2.client Object diff --git a/doc/api/organizations.rst b/doc/api/organizations.rst index fc46950..b4fb0f6 100644 --- a/doc/api/organizations.rst +++ b/doc/api/organizations.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.organizations Organizations diff --git a/doc/api/pull_requests.rst b/doc/api/pull_requests.rst index 140a824..ee6f518 100644 --- a/doc/api/pull_requests.rst +++ b/doc/api/pull_requests.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.pull_requests Pull requests diff --git a/doc/api/repos.rst b/doc/api/repos.rst index 4f777ee..1d96337 100644 --- a/doc/api/repos.rst +++ b/doc/api/repos.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.repositories Repository diff --git a/doc/api/request.rst b/doc/api/request.rst index 0dd71f2..b3ffc49 100644 --- a/doc/api/request.rst +++ b/doc/api/request.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.request Requests diff --git a/doc/api/teams.rst b/doc/api/teams.rst index dc2102b..4e72746 100644 --- a/doc/api/teams.rst +++ b/doc/api/teams.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.teams Teams diff --git a/doc/api/users.rst b/doc/api/users.rst index 052092a..d9ac95d 100644 --- a/doc/api/users.rst +++ b/doc/api/users.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + .. module:: github2.users Users diff --git a/doc/bugs.rst b/doc/bugs.rst index 6105987..1c838a1 100644 --- a/doc/bugs.rst +++ b/doc/bugs.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + Reporting bugs ============== diff --git a/doc/conf.py b/doc/conf.py index ea950db..d74babe 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -229,7 +229,7 @@ [u'Ask Solem'], 1) ] -autoclass_content = "init" +autoclass_content = "class" autodoc_default_flags = ['members', ] intersphinx_mapping = { diff --git a/doc/contributing.rst b/doc/contributing.rst index 8c3b47a..d307ba3 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -1,12 +1,18 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + Contributing ============ Patches for :mod:`github2` are most welcome! Forks on GitHub_ and patches attached to issues are both great ways to -contribute. If you're comfortable with ``git`` using a fork hosted on GitHub is -probably the simpler solution, both for the package maintainers and you as a -contributor. +contribute. If you're comfortable with ``git`` then using a fork hosted on +GitHub is probably the simpler solution, both for the :mod:`github2` maintainers +and for you as a contributor. Following the simple guidelines below makes it easier to review and integrate your changes: diff --git a/doc/index.rst b/doc/index.rst index 55814bf..963e6a2 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,7 +1,8 @@ -.. python-github2 documentation master file, created by - sphinx-quickstart on Mon Apr 11 16:16:25 2011. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. .. If you prefer you can also read the pre-built documentation at @@ -10,19 +11,18 @@ .. module:: github2 :synopsis: GitHub API v2 library for Python -``github2`` - Github API v2 library for Python +``github2`` - GitHub API v2 library for Python ============================================== .. warning:: - GitHub are planning to `switch off API v2`_ on 2012-05-01, you should - be looking to replace ``github2`` as soon as possible. + GitHub have marked API v2 as deprecated, you should be looking to replace + your usage of ``github2`` in the near future. Both remoteobjects_ and micromodels_ provide easy-to-use functionality for creating bindings to remote APIs, and should significantly reduce the amount of work needed in moving away from GitHub's API v2. -.. _switch off API v2: https://github.com/blog/1090-github-api-moving-on .. _remoteobjects: https://github.com/saymedia/remoteobjects .. _micromodels: https://github.com/j4mie/micromodels @@ -31,15 +31,15 @@ :class: sidebar This is a Python library implementing all of the features available in version 2 -of the `Github API`_. +of the `GitHub API`_. -You should read the developer documentation for the `Github API`_ first. +You should read the developer documentation for the `GitHub API`_ first. :Git repository: https://github.com/ask/python-github2/ :Issue tracker: https://github.com/ask/python-github2/issues/ :Contributors: https://github.com/ask/python-github2/contributors/ -.. _Github API: http://develop.github.com/ +.. _GitHub API: http://develop.github.com/ Contents -------- diff --git a/doc/install.rst b/doc/install.rst index 8d309ee..7eb1aa6 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -1,3 +1,10 @@ +.. Copyright (C) 2011-2012 James Rowe + Michael Basnight + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + Installation ------------ @@ -26,5 +33,6 @@ handling [#]_. :pypi:`simplejson` is also required when using :mod:`github2` with Python 2.4 or 2.5. If you install via :pypi:`pip` or :pypi:`easy_install ` the dependencies should be installed automatically for you. -.. [#] You must use :pypi:`python-dateutil` 1.x when working with Python 2.x, - the latest 2.x releases are for Python 3.x installations only. +.. [#] You must use :pypi:`python-dateutil` 1.x when working with Python 2.5 or + earlier, the latest 2.x releases are for Python 2.6 and newer + installations only. diff --git a/doc/license.rst b/doc/license.rst index 7e1c1b4..316b2ae 100644 --- a/doc/license.rst +++ b/doc/license.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + License ======= diff --git a/doc/problems.rst b/doc/problems.rst index 5fabddf..31d3052 100644 --- a/doc/problems.rst +++ b/doc/problems.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + Solving problems ================ diff --git a/doc/quickstart.rst b/doc/quickstart.rst index bb41f5e..ff54b29 100644 --- a/doc/quickstart.rst +++ b/doc/quickstart.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2011-2012 James Rowe + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + Quickstart ========== @@ -7,6 +13,7 @@ package. Create an unauthenticated client object:: + >>> from github2.client import Github >>> github = Github() .. note:: @@ -22,6 +29,7 @@ Read the description of the ``python-github2`` project:: >>> repo = github.repos.show("ask/python-github2") >>> repo.description + u'github client in python, with issues support.' We can take advantage of Python's :func:`dir` to explore the package a little more:: diff --git a/doc/release.rst b/doc/release.rst index b7baf79..745d419 100644 --- a/doc/release.rst +++ b/doc/release.rst @@ -1,3 +1,9 @@ +.. Copyright (C) 2012 James Rowe + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + Release HOWTO ============= diff --git a/doc/wild.rst b/doc/wild.rst index 8a49b96..07bd653 100644 --- a/doc/wild.rst +++ b/doc/wild.rst @@ -1,3 +1,10 @@ +.. Copyright (C) 2011-2012 James Rowe + Stéphane Angel + + This file is part of python-github2, and is licensed under the 3-clause BSD + License. See the LICENSE file in the top distribution directory for the full + license text. + In the wild ----------- diff --git a/examples/friend-or-follow.py b/examples/friend-or-follow.py index ccef96a..7b87edc 100644 --- a/examples/friend-or-follow.py +++ b/examples/friend-or-follow.py @@ -1,3 +1,8 @@ +# Copyright (C) 2010-2012 Ask Solem +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + import sys import optparse from subprocess import Popen, PIPE @@ -10,10 +15,10 @@ OPTION_LIST = ( optparse.make_option('-t', '--api-token', default=None, action="store", dest="api_token", type="str", - help="Github API token. Default is to find this from git config"), + help="GitHub API token. Default is to find this from git config"), optparse.make_option('-u', '--api-user', default=None, action="store", dest="api_user", type="str", - help="Github Username. Default is to find this from git config"), + help="GitHub Username. Default is to find this from git config"), ) BY_LOWER = lambda value: value.lower() diff --git a/extra/requirements-doc.txt b/extra/requirements-doc.txt new file mode 100644 index 0000000..709ee46 --- /dev/null +++ b/extra/requirements-doc.txt @@ -0,0 +1,4 @@ +-r requirements.txt +cloud_sptheme>=1.2 +sphinx>=1.1 +sphinxcontrib-cheeseshop diff --git a/extra/requirements-py25.txt b/extra/requirements-py25.txt new file mode 100644 index 0000000..45bfac5 --- /dev/null +++ b/extra/requirements-py25.txt @@ -0,0 +1,3 @@ +httplib2 >= 0.7.0 +python-dateutil < 2.0, >= 2.1 +simplejson >= 2.0.9 diff --git a/extra/requirements-test.txt b/extra/requirements-test.txt new file mode 100644 index 0000000..d271169 --- /dev/null +++ b/extra/requirements-test.txt @@ -0,0 +1,4 @@ +-r requirements.txt +coverage>=3.5 +mock>=0.7.1 +nose>=1.1.2 diff --git a/extra/requirements.txt b/extra/requirements.txt new file mode 100644 index 0000000..5115300 --- /dev/null +++ b/extra/requirements.txt @@ -0,0 +1,2 @@ +httplib2 >= 0.7.0 +python-dateutil < 2.0 diff --git a/github2/__init__.py b/github2/__init__.py index 30d323e..f098fc2 100644 --- a/github2/__init__.py +++ b/github2/__init__.py @@ -1,4 +1,10 @@ -"Github API v2 library for Python" +"GitHub API v2 library for Python." +# Copyright (C) 2009-2012 Ask Solem +# James Rowe +# Maximillian Dornseif +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. from github2 import _version diff --git a/github2/_version.py b/github2/_version.py index 0269a27..6e26b1f 100644 --- a/github2/_version.py +++ b/github2/_version.py @@ -1,9 +1,9 @@ -# This is github2 version 0.6.1 (2012-02-28) +# This is github2 version 0.6.2 (2012-06-11) # pylint: disable=C0103, C0111, C0121, W0622 -dotted = "0.6.1" -libtool = "6:21" -hex = 0x000601 -date = "2012-02-28" -tuple = (0, 6, 1) -web = "github2/0.6.1" +dotted = "0.6.2" +libtool = "6:22" +hex = 0x000602 +date = "2012-06-11" +tuple = (0, 6, 2) +web = "github2/0.6.2" diff --git a/github2/bin/__init__.py b/github2/bin/__init__.py index 792d600..6c5b974 100644 --- a/github2/bin/__init__.py +++ b/github2/bin/__init__.py @@ -1 +1,5 @@ # +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. diff --git a/github2/bin/manage_collaborators.py b/github2/bin/manage_collaborators.py index 3efafee..b63ab6c 100755 --- a/github2/bin/manage_collaborators.py +++ b/github2/bin/manage_collaborators.py @@ -8,8 +8,11 @@ """ # Created by Maximillian Dornseif on 2009-12-31 for HUDORA. -# Copyright (c) 2009 HUDORA. All rights reserved. -# BSD licensed +# Copyright (C) 2009-2012 James Rowe +# Maximillian Dornseif +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. import logging import sys @@ -24,9 +27,11 @@ def print_(text): - """Python 2 & 3 compatible print function + """Python 2 & 3 compatible print function. - We support <2.6, so can't use __future__.print_function""" + We support <2.6, so can't use __future__.print_function + + """ if PY3K: print(text) else: @@ -34,7 +39,7 @@ def print_(text): def parse_commandline(): - """Parse the comandline and return parsed options.""" + """Parse the command line and return parsed options.""" parser = OptionParser() parser.description = __doc__ @@ -73,7 +78,7 @@ def parse_commandline(): def main(): - """This implements the actual program functionality""" + """Implement the actual program functionality.""" options, args = parse_commandline() diff --git a/github2/bin/search_repos.py b/github2/bin/search_repos.py index c52be46..1023e2c 100755 --- a/github2/bin/search_repos.py +++ b/github2/bin/search_repos.py @@ -1,6 +1,10 @@ #! /usr/bin/env python # coding: utf-8 """github_search_repos - search for repositories on GitHub""" +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. import logging @@ -17,9 +21,11 @@ def print_(text): - """Python 2 & 3 compatible print function + """Python 2 & 3 compatible print function. - We support <2.6, so can't use __future__.print_function""" + We support <2.6, so can't use __future__.print_function + + """ if PY3K: print(text) else: @@ -27,7 +33,7 @@ def print_(text): def parse_commandline(): - """Parse the comandline and return parsed options.""" + """Parse the command line and return parsed options.""" parser = OptionParser() parser.description = __doc__ @@ -46,7 +52,7 @@ def parse_commandline(): def main(): - """This implements the actual program functionality""" + """Implement the actual program functionality.""" return_value = 0 options, term = parse_commandline() diff --git a/github2/client.py b/github2/client.py index c585f3b..d0a3f2b 100644 --- a/github2/client.py +++ b/github2/client.py @@ -1,3 +1,18 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2009-2012 Ask Solem +# Christopher MacGown +# Evan Broder +# James Rowe +# Jeremy Dunck +# Michael Basnight +# Patryk Zawadzki +# Surajram Kumaravel +# Vincent Driessen +# modocache +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from github2.request import GithubRequest from github2.issues import Issues from github2.repositories import Repositories @@ -10,12 +25,12 @@ class Github(object): + """Interface to GitHub's API v2.""" + def __init__(self, username=None, api_token=None, requests_per_second=None, access_token=None, cache=None, proxy_host=None, proxy_port=8080, github_url=None): - """ - An interface to GitHub's API: - http://develop.github.com/ + """Setup GitHub API object. .. versionadded:: 0.2.0 The ``requests_per_second`` parameter @@ -42,6 +57,7 @@ def __init__(self, username=None, api_token=None, requests_per_second=None, default to 8080 if a proxy_host is set and no port is set). :param str github_url: the hostname to connect to, for GitHub Enterprise support + """ self.request = GithubRequest(username=username, api_token=api_token, @@ -59,59 +75,65 @@ def __init__(self, username=None, api_token=None, requests_per_second=None, self.pull_requests = PullRequests(self.request) def project_for_user_repo(self, user, repo): - """Return Github identifier for a user's repository + """Return GitHub identifier for a user's repository. :param str user: repository owner :param str repo: repository name + """ return "/".join([user, repo]) def get_all_blobs(self, project, tree_sha): - """Get a list of all blobs for a specific tree + """Get a list of all blobs for a specific tree. .. versionadded:: 0.3.0 :param str project: GitHub project :param str tree_sha: object ID of tree + """ blobs = self.request.get("blob/all", project, tree_sha) return blobs.get("blobs") def get_blob_info(self, project, tree_sha, path): - """Get the blob for a file within a specific tree + """Get the blob for a file within a specific tree. :param str project: GitHub project :param str tree_sha: object ID of tree :param str path: path within tree to fetch blob for + """ blob = self.request.get("blob/show", project, tree_sha, path) return blob.get("blob") def get_tree(self, project, tree_sha): - """Get tree information for a specifc tree + """Get tree information for a specific tree. :param str project: GitHub project :param str tree_sha: object ID of tree + """ tree = self.request.get("tree/show", project, tree_sha) return tree.get("tree", []) def get_network_meta(self, project): - """Get Github metadata associated with a project + """Get GitHub metadata associated with a project. :param str project: GitHub project + """ return self.request.raw_request("/".join([self.request.github_url, project, "network_meta"]), {}) def get_network_data(self, project, nethash, start=None, end=None): - """Get chunk of Github network data + """Get chunk of GitHub network data. :param str project: GitHub project - :param str nethash: identifier provided by ``get_network_meta`` + :param str nethash: identifier provided by :meth:`get_network_meta` :param int start: optional start point for data :param int stop: optional end point for data + """ data = {"nethash": nethash} if start: diff --git a/github2/commits.py b/github2/commits.py index 8910937..40e6a8e 100644 --- a/github2/commits.py +++ b/github2/commits.py @@ -1,8 +1,20 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2009-2012 Ask Solem +# James Rowe +# Stéphane Angel +# Vincent Driessen +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from github2.core import (BaseData, GithubCommand, Attribute, DateAttribute, repr_string) class Commit(BaseData): + + """Commit container.""" + message = Attribute("Commit message.") parents = Attribute("List of parents for this commit.") url = Attribute("Canonical URL for this commit.") @@ -25,10 +37,13 @@ def __repr__(self): class Commits(GithubCommand): + + """GitHub API commits functionality.""" + domain = "commits" def list(self, project, branch="master", file=None, page=1): - """List commits on a project + """List commits on a project. .. warning:: Not all projects use ``master`` as their default branch, you can @@ -39,15 +54,17 @@ def list(self, project, branch="master", file=None, page=1): :param str branch: branch name, or ``master`` if not given :param str file: optional file filter :param int page: optional page number + """ return self.get_values("list", project, branch, file, filter="commits", datatype=Commit, page=page) def show(self, project, sha): - """Get a specific commit + """Get a specific commit. :param str project: project name :param str sha: commit id + """ return self.get_value("show", project, sha, filter="commit", datatype=Commit) diff --git a/github2/core.py b/github2/core.py index 856a489..86d4788 100644 --- a/github2/core.py +++ b/github2/core.py @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2009-2012 Ask Solem +# Fernando Perez +# James Rowe +# Mark Paschal +# Patryk Zawadzki +# Sameer Al-Sakran +# Stéphane Angel +# Vincent Driessen +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + import logging import sys @@ -27,9 +40,10 @@ def string_to_datetime(string): - """Convert a string to Python datetime + """Convert a string to Python datetime. :param str github_date: date string to parse + """ parsed = parser.parse(string) if NAIVE: @@ -38,9 +52,10 @@ def string_to_datetime(string): def _handle_naive_datetimes(f): - """Decorator to make datetime arguments use GitHub timezone + """Decorator to make datetime arguments use GitHub timezone. :param func f: Function to wrap + """ def wrapper(datetime_): if not datetime_.tzinfo: @@ -59,18 +74,20 @@ def wrapper(datetime_): @_handle_naive_datetimes def datetime_to_ghdate(datetime_): - """Convert Python datetime to Github date string + """Convert Python datetime to GitHub date string. :param datetime datetime_: datetime object to convert + """ return datetime_.strftime(GITHUB_DATE_FORMAT) @_handle_naive_datetimes def datetime_to_commitdate(datetime_): - """Convert Python datetime to Github date string + """Convert Python datetime to GitHub date string. :param datetime datetime_: datetime object to convert + """ date_without_tz = datetime_.strftime(COMMIT_DATE_FORMAT) utcoffset = GITHUB_TZ.utcoffset(datetime_) @@ -80,7 +97,7 @@ def datetime_to_commitdate(datetime_): def datetime_to_isodate(datetime_): - """Convert Python datetime to Github date string + """Convert Python datetime to GitHub date string. :param str datetime_: datetime object to convert @@ -94,16 +111,18 @@ def datetime_to_isodate(datetime_): class AuthError(Exception): - """Requires authentication""" + + """Requires authentication.""" def requires_auth(f): - """Decorate to check a function call for authentication + """Decorate to check a function call for authentication. Sets a ``requires_auth`` attribute on functions, for use in introspection. :param func f: Function to wrap :raises AuthError: If function called without an authenticated session + """ # When Python 2.4 support is dropped move straight to functools.wraps, # don't pass go and don't collect $200. @@ -122,12 +141,13 @@ def wrapper(self, *args, **kwargs): def enhanced_by_auth(f): - """Decorator to mark a function as enhanced by authentication + """Decorator to mark a function as enhanced by authentication. Sets a ``enhanced_by_auth`` attribute on functions, for use in introspection. :param func f: Function to wrap + """ f.enhanced_by_auth = True f.__doc__ += """\n.. note:: This call is enhanced with authentication""" @@ -136,15 +156,18 @@ def enhanced_by_auth(f): class GithubCommand(object): + """Main API binding interface.""" + def __init__(self, request): - """Main API binding interface + """Setup command object. :param github2.request.GithubRequest request: HTTP request handler + """ self.request = request def make_request(self, command, *args, **kwargs): - """Make an API request + """Make an API request. Various options are supported if they exist in ``kwargs``: @@ -154,6 +177,7 @@ def make_request(self, command, *args, **kwargs): data * The value of a ``page`` argument will be used to fetch a specific page of results, default of 1 is assumed if not given + """ filter = kwargs.get("filter") post_data = kwargs.get("post_data") or {} @@ -177,10 +201,11 @@ def make_request(self, command, *args, **kwargs): return response def get_value(self, *args, **kwargs): - """Process a single-value response from the API + """Process a single-value response from the API. If a ``datatype`` parameter is given it defines the :class:`BaseData`-derived class we should build from the provided data + """ datatype = kwargs.pop("datatype", None) value = self.make_request(*args, **kwargs) @@ -196,9 +221,10 @@ def get_value(self, *args, **kwargs): return value def get_values(self, *args, **kwargs): - """Process a multi-value response from the API + """Process a multi-value response from the API. :see: :meth:`get_value` + """ datatype = kwargs.pop("datatype", None) values = self.make_request(*args, **kwargs) @@ -216,10 +242,11 @@ def get_values(self, *args, **kwargs): def doc_generator(docstring, attributes): - """Utility function to augment BaseDataType docstring + """Utility function to augment BaseDataType docstring. :param str docstring: docstring to augment :param dict attributes: attributes to add to docstring + """ docstring = docstring or "" @@ -232,10 +259,14 @@ def bullet(title, text): class Attribute(object): + + """Generic object attribute for use with :class:`BaseData`.""" + def __init__(self, help): - """Generic object attribute for use with :class:`BaseData` + """Setup Attribute object. :param str help: Attribute description + """ self.help = help @@ -246,6 +277,9 @@ def to_python(self, value): class DateAttribute(Attribute): + + """Date handling attribute for use with :class:`BaseData`.""" + format = "github" converter_for_format = { "github": datetime_to_ghdate, @@ -255,10 +289,11 @@ class DateAttribute(Attribute): } def __init__(self, *args, **kwargs): - """Date handling attribute for use with :class:`BaseData` + """Setup DateAttribute object. :param str format: The date format to support, see :data:`convertor_for_format` for supported options + """ self.format = kwargs.pop("format", self.format) super(DateAttribute, self).__init__(*args, **kwargs) @@ -312,43 +347,47 @@ def iterate(self): # Ugly base class definition for Python 2 and 3 compatibility, where metaclass # syntax is incompatible class BaseData(BaseDataType('BaseData', (object, ), {})): - """Wrapper for API responses + + """Wrapper for API responses. .. warning:: Supports subscript attribute access purely for backwards compatibility, you shouldn't rely on that functionality in new code + """ + def __getitem__(self, key): - """Access objects's attribute using subscript notation + """Access objects's attribute using subscript notation. This is here purely to maintain compatibility when switching ``dict`` responses to ``BaseData`` derived objects. + """ LOGGER.warning("Subscript access on %r is deprecated, use object " - "attributes" % self.__class__.__name__, - DeprecationWarning) + "attributes" % self.__class__.__name__) if not key in self._meta.keys(): raise KeyError(key) return getattr(self, key) def __setitem__(self, key, value): - """Update object's attribute using subscript notation + """Update object's attribute using subscript notation. :see: :meth:`BaseData.__getitem__` + """ LOGGER.warning("Subscript access on %r is deprecated, use object " - "attributes" % self.__class__.__name__, - DeprecationWarning) + "attributes" % self.__class__.__name__) if not key in self._meta.keys(): raise KeyError(key) setattr(self, key, value) def repr_string(string): - """Shorten string for use in repr() output + """Shorten string for use in repr() output. :param str string: string to operate on :return: string, with maximum length of 20 characters + """ if len(string) > 20: string = string[:17] + '...' diff --git a/github2/issues.py b/github2/issues.py index 851f813..fa87098 100644 --- a/github2/issues.py +++ b/github2/issues.py @@ -1,3 +1,13 @@ +# Copyright (C) 2009-2012 Adam Vandenberg +# Ask Solem +# Barthelemy Dagenais +# Fernando Perez +# James Rowe +# Scott Torborg +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + try: from urllib.parse import quote_plus # For Python 3 except ImportError: @@ -8,6 +18,9 @@ class Issue(BaseData): + + """Issue container.""" + position = Attribute("The position of this issue in a list.") number = Attribute("The issue number (unique for project).") votes = Attribute("Number of votes for this issue.") @@ -28,6 +41,9 @@ def __repr__(self): class Comment(BaseData): + + """Comment container.""" + created_at = DateAttribute("The date this comment was created.") updated_at = DateAttribute("The date when this comment was last updated.") body = Attribute("The full text of this comment.") @@ -39,6 +55,9 @@ def __repr__(self): class Issues(GithubCommand): + + """GitHub API issues functionality.""" + domain = "issues" def search(self, project, term, state="open"): @@ -48,7 +67,8 @@ def search(self, project, term, state="open"): :param str project: GitHub project :param str term: term to search issues for - :param str state: can be either ``open`` or ``closed``. + :param str state: can be either ``open`` or ``closed`` + """ return self.get_values("search", project, state, quote_plus(term), filter="issues", datatype=Issue) @@ -57,7 +77,8 @@ def list(self, project, state="open"): """Get all issues for project with given state. :param str project: GitHub project - :param str state: can be either ``open`` or ``closed``. + :param str state: can be either ``open`` or ``closed`` + """ return self.get_values("list", project, state, filter="issues", datatype=Issue) @@ -68,7 +89,8 @@ def list_by_label(self, project, label): .. versionadded:: 0.3.0 :param str project: GitHub project - :param str label: a string representing a label (e.g., ``bug``). + :param str label: a string representing a label (e.g., ``bug``) + """ return self.get_values("list", project, "label", label, filter="issues", datatype=Issue) @@ -79,6 +101,7 @@ def list_labels(self, project): .. versionadded:: 0.3.0 :param str project: GitHub project + """ return self.get_values("labels", project, filter="labels") @@ -86,7 +109,8 @@ def show(self, project, number): """Get all the data for issue by issue-number. :param str project: GitHub project - :param int number: issue number in the Github database + :param int number: issue number in the GitHub database + """ return self.get_value("show", project, str(number), filter="issue", datatype=Issue) @@ -98,6 +122,7 @@ def open(self, project, title, body): :param str project: GitHub project :param str title: title for issue :param str body: body for issue + """ issue_data = {"title": title, "body": body} return self.get_value("open", project, post_data=issue_data, @@ -105,36 +130,39 @@ def open(self, project, title, body): @requires_auth def close(self, project, number): - """Close an issue + """Close an issue. :param str project: GitHub project - :param int number: issue number in the Github database + :param int number: issue number in the GitHub database + """ return self.get_value("close", project, str(number), filter="issue", datatype=Issue, method="POST") @requires_auth def reopen(self, project, number): - """Reopen a closed issue + """Reopen a closed issue. .. versionadded:: 0.3.0 :param str project: GitHub project - :param int number: issue number in the Github database + :param int number: issue number in the GitHub database + """ return self.get_value("reopen", project, str(number), filter="issue", datatype=Issue, method="POST") @requires_auth def edit(self, project, number, title, body): - """Edit an existing issue + """Edit an existing issue. .. versionadded:: 0.3.0 :param str project: GitHub project - :param int number: issue number in the Github database + :param int number: issue number in the GitHub database :param str title: title for issue :param str body: body for issue + """ issue_data = {"title": title, "body": body} return self.get_value("edit", project, str(number), @@ -143,22 +171,24 @@ def edit(self, project, number, title, body): @requires_auth def add_label(self, project, number, label): - """Add a label to an issue + """Add a label to an issue. :param str project: GitHub project - :param int number: issue number in the Github database + :param int number: issue number in the GitHub database :param str label: label to attach to issue + """ return self.get_values("label/add", project, label, str(number), filter="labels", method="POST") @requires_auth def remove_label(self, project, number, label): - """Remove an existing label from an issue + """Remove an existing label from an issue. :param str project: GitHub project - :param int number: issue number in the Github database + :param int number: issue number in the GitHub database :param str label: label to remove from issue + """ return self.get_values("label/remove", project, label, str(number), filter="labels", method="POST") @@ -168,8 +198,9 @@ def comment(self, project, number, comment): """Comment on an issue. :param str project: GitHub project - :param int number: issue number in the Github database + :param int number: issue number in the GitHub database :param str comment: comment to attach to issue + """ comment_data = {'comment': comment} return self.get_value("comment", project, str(number), @@ -180,7 +211,7 @@ def comments(self, project, number): """View comments on an issue. :param str project: GitHub project - :param int number: issue number in the Github database + """ return self.get_values("comments", project, str(number), filter="comments", datatype=Comment) diff --git a/github2/organizations.py b/github2/organizations.py index 38eac83..d11f9c4 100644 --- a/github2/organizations.py +++ b/github2/organizations.py @@ -1,3 +1,10 @@ +# Copyright (C) 2011-2012 James Rowe +# Patryk Zawadzki +# Rok Garbas +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from github2.core import (BaseData, GithubCommand, Attribute, DateAttribute, requires_auth) from github2.repositories import Repository @@ -6,7 +13,13 @@ class Organization(BaseData): - """.. versionadded:: 0.4.0""" + + """Organization container. + + .. versionadded:: 0.4.0 + + """ + id = Attribute("The organization id.") name = Attribute("The full name of the organization.") blog = Attribute("The organization's blog.") @@ -35,65 +48,77 @@ def __repr__(self): class Organizations(GithubCommand): - """.. versionadded:: 0.4.0""" + + """GitHub API organizations functionality. + + .. versionadded:: 0.4.0 + + """ + domain = "organizations" def show(self, organization): - """Get information on organization + """Get information on organization. :param str organization: organization to show + """ return self.get_value(organization, filter="organization", datatype=Organization) def list(self): - """Get list of all of your organizations""" + """Get list of all of your organizations.""" return self.get_values('', filter="organizations", datatype=Organization) def repositories(self, organization=''): - """Get list of all repositories in an organization + """Get list of all repositories in an organization. If organization is not given, or is empty, then this will list repositories for all organizations the authenticated user belongs to. :param: str organization: organization to list repositories for + """ return self.get_values(organization, 'repositories', filter="repositories", datatype=Repository) def public_repositories(self, organization): - """Get list of public repositories in an organization + """Get list of public repositories in an organization. :param str organization: organization to list public repositories for + """ return self.get_values(organization, 'public_repositories', filter="repositories", datatype=Repository) def public_members(self, organization): - """Get list of public members in an organization + """Get list of public members in an organization. :param str organization: organization to list members for + """ return self.get_values(organization, 'public_members', filter="users", datatype=User) def teams(self, organization): - """Get list of teams in an organization + """Get list of teams in an organization. :param str organization: organization to list teams for + """ return self.get_values(organization, 'teams', filter="teams", datatype=Team) @requires_auth def add_team(self, organization, name, permission='pull', projects=None): - """Add a team to an organization + """Add a team to an organization. :param str organization: organization to add team to :param str team: name of team to add :param str permission: permissions for team(push, pull or admin) :param list projects: optional GitHub projects for this team + """ team_data = {'team[name]': name, 'team[permission]': permission} if projects: diff --git a/github2/pull_requests.py b/github2/pull_requests.py index b75d62e..d4ea6e9 100644 --- a/github2/pull_requests.py +++ b/github2/pull_requests.py @@ -1,12 +1,24 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2012 Christopher MacGown +# Ionuț Arțăriși +# James Rowe +# Stéphane Angel +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from github2.core import (BaseData, GithubCommand, Attribute, DateAttribute, repr_string) class PullRequest(BaseData): - """Pull request encapsulation + + """Pull request container. .. versionadded:: 0.5.0 + """ + state = Attribute("The pull request state") base = Attribute("The base repo") head = Attribute("The head of the pull request") @@ -40,25 +52,29 @@ def __repr__(self): class PullRequests(GithubCommand): - """Operations on pull requests + + """GitHub API pull request functionality. .. versionadded:: 0.5.0 + """ + domain = "pulls" def create(self, project, base, head, title=None, body=None, issue=None): - """Create a new pull request + """Create a new pull request. Pull requests can be created from scratch, or attached to an existing issue. If an ``issue`` parameter is supplied the pull request is attached to that issue, else a new pull request is created. - :param str project: the Github project to send the pull request to + :param str project: the GitHub project to send the pull request to :param str base: branch changes should be pulled into :param str head: branch of the changes to be pulled :param str title: title for pull request :param str body: optional body for pull request :param str issue: existing issue to attach pull request to + """ post_data = {"base": base, "head": head} if issue: @@ -76,20 +92,22 @@ def create(self, project, base, head, title=None, body=None, issue=None): filter="pull", datatype=PullRequest) def show(self, project, number): - """Show a single pull request + """Show a single pull request. + + :param str project: GitHub project + :param int number: pull request number in the GitHub database - :param str project: Github project - :param int number: pull request number in the Github database """ return self.get_value(project, str(number), filter="pull", datatype=PullRequest) def list(self, project, state="open", page=1): - """List all pull requests for a project + """List all pull requests for a project. - :param str project: Github project + :param str project: GitHub project :param str state: can be either ``open`` or ``closed`` :param int page: optional page number + """ return self.get_values(project, state, filter="pulls", datatype=PullRequest, page=page) diff --git a/github2/repositories.py b/github2/repositories.py index 89f8e57..bb84bcf 100644 --- a/github2/repositories.py +++ b/github2/repositories.py @@ -1,3 +1,20 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2009-2012 Ask Solem +# Claudio B. +# Daniel Greenfeld +# James Rowe +# Jens Ohlig +# Jeremy Dunck +# Jonas Obrist +# Kenneth Reitz +# Mark Paschal +# Maximillian Dornseif +# Sameer Al-Sakran +# Stéphane Angel +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from github2.core import (BaseData, GithubCommand, Attribute, DateAttribute, requires_auth) @@ -5,6 +22,9 @@ class Repository(BaseData): + + """Repository container.""" + name = Attribute("Name of repository.") description = Attribute("Repository description.") forks = Attribute("Number of forks of this repository.") @@ -35,6 +55,8 @@ def __repr__(self): class Repositories(GithubCommand): + """GitHub API repository functionality.""" + domain = "repos" def search(self, query): @@ -44,6 +66,7 @@ def search(self, query): Returns at most 100 repositories :param str query: term to search issues for + """ return self.get_values("search", query, filter="repositories", datatype=Repository) @@ -52,6 +75,7 @@ def show(self, project): """Get repository object for project. :param str project: GitHub project + """ return self.get_value("show", project, filter="repository", datatype=Repository) @@ -61,6 +85,7 @@ def pushable(self): """Return a list of repos you can push to that are not your own. .. versionadded:: 0.3.0 + """ return self.get_values("pushable", filter="repositories", datatype=Repository) @@ -68,13 +93,14 @@ def pushable(self): def list(self, user=None, page=1): """Return a list of all repositories for a user. - .. deprecated: 0.4.0 + .. deprecated:: 0.4.0 Previous releases would attempt to display repositories for the logged-in user when ``user`` wasn't supplied. This functionality is brittle and will be removed in a future release! - :param str user: Github user name to list repositories for + :param str user: GitHub user name to list repositories for :param int page: optional page number + """ user = user or self.request.username return self.get_values("show", user, filter="repositories", @@ -82,39 +108,43 @@ def list(self, user=None, page=1): @requires_auth def watch(self, project): - """Watch a project + """Watch a project. :param str project: GitHub project + """ return self.get_value("watch", project, filter='repository', datatype=Repository) @requires_auth def unwatch(self, project): - """Unwatch a project + """Unwatch a project. :param str project: GitHub project + """ return self.get_value("unwatch", project, filter='repository', datatype=Repository) @requires_auth def fork(self, project): - """Fork a project + """Fork a project. :param str project: GitHub project + """ return self.get_value("fork", project, filter="repository", datatype=Repository) @requires_auth def create(self, project, description=None, homepage=None, public=True): - """Create a repository + """Create a repository. :param str project: new project name :param str description: optional project description :param str homepage: optional project homepage :param bool public: whether to make a public project + """ repo_data = {"name": project, "description": description, "homepage": homepage, "public": str(int(public))} @@ -123,9 +153,10 @@ def create(self, project, description=None, homepage=None, public=True): @requires_auth def delete(self, project): - """Delete a repository + """Delete a repository. :param str project: project name to delete + """ # Two-step delete mechanism. We must echo the delete_token value back # to GitHub to actually delete a repository @@ -134,99 +165,111 @@ def delete(self, project): @requires_auth def set_private(self, project): - """Mark repository as private + """Mark repository as private. :param str project: project name to set as private + """ return self.make_request("set/private", project) @requires_auth def set_public(self, project): - """Mark repository as public + """Mark repository as public. :param str project: project name to set as public + """ return self.make_request("set/public", project) def list_collaborators(self, project): - """Lists all the collaborators in a project + """List all the collaborators in a project. :param str project: GitHub project + """ return self.get_values("show", project, "collaborators", filter="collaborators") @requires_auth def add_collaborator(self, project, username): - """Adds an add_collaborator to a repo + """Add an add_collaborator to a repo. + + :param str project: GitHub project + :param str username: GitHub user to add as collaborator - :param str project: Github project - :param str username: Github user to add as collaborator """ return self.make_request("collaborators", project, "add", username, method="POST") @requires_auth def remove_collaborator(self, project, username): - """Removes an add_collaborator from a repo + """Remove a collaborator from a repo. + + :param str project: GitHub project + :param str username: GitHub user to add as collaborator - :param str project: Github project - :param str username: Github user to add as collaborator """ return self.make_request("collaborators", project, "remove", username, method="POST") def network(self, project): - """Get network data for project + """Get network data for project. + + :param str project: GitHub project - :param str project: Github project """ return self.get_values("show", project, "network", filter="network", datatype=Repository) def languages(self, project): - """Get programming language data for project + """Get programming language data for project. + + :param str project: GitHub project - :param str project: Github project """ return self.get_values("show", project, "languages", filter="languages") def tags(self, project): - """Get tags for project + """Get tags for project. + + :param str project: GitHub project - :param str project: Github project """ return self.get_values("show", project, "tags", filter="tags") def branches(self, project): - """Get branch names for project + """Get branch names for project. + + :param str project: GitHub project - :param str project: Github project """ return self.get_values("show", project, "branches", filter="branches") def watchers(self, project): - """Get list of watchers for project + """Get list of watchers for project. + + :param str project: GitHub project - :param str project: Github project """ return self.get_values("show", project, "watchers", filter="watchers") def watching(self, for_user=None, page=None): - """Lists all the repos a user is watching + """List all the repos a user is watching. - :param str for_user: optional Github user name to list repositories for + :param str for_user: optional GitHub user name to list repositories for :param int page: optional page number + """ for_user = for_user or self.request.username return self.get_values("watched", for_user, filter="repositories", datatype=Repository, page=page) def list_contributors(self, project): - """Lists all the contributors in a project + """List all the contributors in a project. + + :param str project: GitHub project - :param str project: Github project """ return self.get_values("show", project, "contributors", filter="contributors", datatype=User) diff --git a/github2/request.py b/github2/request.py index 9aea264..5961471 100644 --- a/github2/request.py +++ b/github2/request.py @@ -1,3 +1,24 @@ +# Copyright (C) 2009-2012 Adam Vandenberg +# Asheesh Laroia +# Ask Solem +# Chris Vale +# Daniel Greenfeld +# Evan Broder +# James Rowe +# Jeremy Dunck +# Josh Weinberg +# Mark Paschal +# Maximillian Dornseif +# Michael Basnight +# Patryk Zawadzki +# Rick Harris +# Sameer Al-Sakran +# Vincent Driessen +# modocache +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + import datetime import logging import re @@ -38,8 +59,12 @@ #: Logger for requests module LOGGER = logging.getLogger('github2.request') +# Fetch actual path for httplib2's default cert bundle, for distributions that +# symlink their system certs +_HTTPLIB2_BUNDLE = path.realpath(path.dirname(httplib2.CA_CERTS)) #: Whether github2 is using the system's certificates for SSL connections -SYSTEM_CERTS = not httplib2.CA_CERTS.startswith(path.dirname(httplib2.__file__)) +SYSTEM_CERTS = not _HTTPLIB2_BUNDLE.startswith(path.dirname(httplib2.__file__)) +CA_CERTS = None #: Whether github2 is using the cert's from the file given in $CURL_CA_BUNDLE CURL_CERTS = False if not SYSTEM_CERTS and sys.platform.startswith('linux'): @@ -67,10 +92,11 @@ def charset_from_headers(headers): - """Parse charset from headers + """Parse charset from headers. :param httplib2.Response headers: Request headers :return: Defined encoding, or default to ASCII + """ match = re.search("charset=([^ ;]+)", headers.get('content-type', "")) if match: @@ -81,17 +107,21 @@ def charset_from_headers(headers): class GithubError(Exception): - """An error occurred when making a request to the Github API.""" + + """An error occurred when making a request to the GitHub API.""" class HttpError(RuntimeError): - """A HTTP error occured when making a request to the Github API.""" + + """A HTTP error occurred when making a request to the GitHub API.""" + def __init__(self, message, content, code): - """Create a HttpError exception + """Create a HttpError exception. :param str message: Exception string :param str content: Full content of HTTP request :param int code: HTTP status code + """ self.args = (message, content, code) self.message = message @@ -106,6 +136,13 @@ def __init__(self, message, content, code): class GithubRequest(object): + + """Make an API request. + + :see: :class:`github2.client.Github` + + """ + url_format = "%(github_url)s/api/%(api_version)s/%(api_format)s" api_version = "v2" api_format = "json" @@ -115,10 +152,6 @@ def __init__(self, username=None, api_token=None, url_prefix=None, requests_per_second=None, access_token=None, cache=None, proxy_host=None, proxy_port=None, github_url=None): - """Make an API request. - - :see: :class:`github2.client.Github` - """ self.username = username self.api_token = api_token self.access_token = access_token diff --git a/github2/teams.py b/github2/teams.py index b46116f..ca423c9 100644 --- a/github2/teams.py +++ b/github2/teams.py @@ -1,10 +1,22 @@ +# Copyright (C) 2011-2012 James Rowe +# Patryk Zawadzki +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from github2.core import BaseData, GithubCommand, Attribute, requires_auth from github2.repositories import Repository from github2.users import User class Team(BaseData): - """.. versionadded:: 0.4.0""" + + """Team container. + + .. versionadded:: 0.4.0 + + """ + id = Attribute("The team id") name = Attribute("Name of the team") permission = Attribute("Permissions of the team") @@ -14,49 +26,60 @@ def __repr__(self): class Teams(GithubCommand): - """.. versionadded:: 0.4.0""" + + """GitHub API teams functionality. + + .. versionadded:: 0.4.0 + + """ + domain = "teams" def show(self, team_id): - """Get information on team_id + """Get information on team_id. :param int team_id: team to get information for + """ return self.get_value(str(team_id), filter="team", datatype=Team) def members(self, team_id): - """Get list of all team members + """Get list of all team members. :param int team_id: team to get information for + """ return self.get_values(str(team_id), "members", filter="users", datatype=User) @requires_auth def add_member(self, team_id, username): - """Add a new member to a team + """Add a new member to a team. :param int team_id: team to add new member to :param str username: GitHub username to add to team + """ return self.get_values(str(team_id), 'members', method='POST', post_data={'name': username}, filter='users', datatype=User) def repositories(self, team_id): - """Get list of all team repositories + """Get list of all team repositories. :param int team_id: team to get information for + """ return self.get_values(str(team_id), "repositories", filter="repositories", datatype=Repository) @requires_auth def add_project(self, team_id, project): - """Add a project to a team + """Add a project to a team. :param int team_id: team to add repository to :param str project: GitHub project + """ if isinstance(project, Repository): project = project.project @@ -66,10 +89,11 @@ def add_project(self, team_id, project): @requires_auth def remove_project(self, team_id, project): - """Remove a project to a team + """Remove a project to a team. :param int team_id: team to remove project from :param str project: GitHub project + """ if isinstance(project, Repository): project = project.project diff --git a/github2/users.py b/github2/users.py index ad40fc1..805fed4 100644 --- a/github2/users.py +++ b/github2/users.py @@ -1,3 +1,12 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2009-2012 Ask Solem +# James Rowe +# Sameer Al-Sakran +# Stéphane Angel +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + try: from urllib.parse import quote_plus # For Python 3 except ImportError: @@ -8,6 +17,9 @@ class Key(BaseData): + + """SSH key container.""" + id = Attribute('The key id') key = Attribute('The SSH key data') title = Attribute('The title for the SSH key') @@ -17,6 +29,9 @@ def __repr__(self): class User(BaseData): + + """GitHub user container.""" + id = Attribute("The user id") login = Attribute("The login username") name = Attribute("The users full name") @@ -41,9 +56,11 @@ class User(BaseData): format="user") def is_authenticated(self): - """Test for user authentication + """Test for user authentication. - :return bool: ``True`` if user is authenticated""" + :return bool: ``True`` if user is authenticated + + """ return self.plan is not None def __repr__(self): @@ -51,78 +68,88 @@ def __repr__(self): class Users(GithubCommand): + + """GitHub API user functionality.""" + domain = "user" def search(self, query): - """Search for users + """Search for users. .. warning: Returns at most 100 users :param str query: term to search for + """ return self.get_values("search", quote_plus(query), filter="users", datatype=User) def search_by_email(self, query): - """Search for users by email address + """Search for users by email address. :param str query: email to search for + """ return self.get_value("email", query, filter="user", datatype=User) @enhanced_by_auth def show(self, username): - """Get information on Github user + """Get information on GitHub user. if ``username`` is ``None`` or an empty string information for the currently authenticated user is returned. - :param str username: Github user name + """ return self.get_value("show", username, filter="user", datatype=User) def followers(self, username): - """Get list of Github user's followers + """Get list of GitHub user's followers. + + :param str username: GitHub user name - :param str username: Github user name """ return self.get_values("show", username, "followers", filter="users") def following(self, username): - """Get list of users a Github user is following + """Get list of users a GitHub user is following. + + :param str username: GitHub user name - :param str username: Github user name """ return self.get_values("show", username, "following", filter="users") @requires_auth def follow(self, other_user): - """Follow a Github user + """Follow a GitHub user. + + :param str other_user: GitHub user name - :param str other_user: Github user name """ return self.get_values("follow", other_user, method="POST") @requires_auth def unfollow(self, other_user): - """Unfollow a Github user + """Unfollow a GitHub user. + + :param str other_user: GitHub user name - :param str other_user: Github user name """ return self.get_values("unfollow", other_user, method="POST") @requires_auth def list_keys(self): - """Get list of SSH keys for the authenticated user""" + """Get list of SSH keys for the authenticated user.""" return self.get_values('keys', filter='public_keys', datatype=Key) @requires_auth def add_key(self, key, title=''): - """Add a SSH key for the authenticated user + """Add a SSH key for the authenticated user. :param str key: SSH key identifier :param str title: Optional title for the SSH key + """ return self.get_values("key/add", post_data={'key': key, 'title': title}, @@ -131,9 +158,10 @@ def add_key(self, key, title=''): @requires_auth def remove_key(self, key_id): - """Remove a SSH key for the authenticated user + """Remove a SSH key for the authenticated user. :param int key_id: SSH key's GitHub identifier + """ return self.get_values('key/remove', post_data={'id': str(key_id)}, filter='public_keys', datatype=Key) diff --git a/setup.py b/setup.py index 8613f1f..b72d775 100755 --- a/setup.py +++ b/setup.py @@ -1,5 +1,15 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# Copyright (C) 2009-2012 Ask Solem +# Cody Soyland +# Donald von Stufft +# James Rowe +# Maximillian Dornseif +# Michael Basnight +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + import codecs import sys @@ -9,14 +19,22 @@ install_requires = ['httplib2 >= 0.7.0', ] -# simplejson is included in the standard library since Python 2.6 as json. -if sys.version_info[:2] < (2, 6): + +# simplejson is included in the standard library since Python 2.6 as json +if sys.version_info < (2, 5): + # 2.1 drops support for 2.4 + install_requires.append('simplejson >= 2.0.9, < 2.1') +elif sys.version_info[:2] < (2, 6): install_requires.append('simplejson >= 2.0.9') -if sys.version_info >= (3,): - install_requires.append('python-dateutil >= 2.0') -else: +# dateutil supports python 2.x in dateutil-1, python 3.x in dateutil-2.0 and +# python 2.6+ in dateutil-2.1. Exciting… +if sys.version_info[:2] <= (2, 5): install_requires.append('python-dateutil < 2.0') +elif sys.version_info < (3, ): + install_requires.append('python-dateutil < 2.0, >= 2.1') +else: + install_requires.append('python-dateutil > 2.0') long_description = (codecs.open('README.rst', "r", "utf-8").read() + "\n" + codecs.open('NEWS.rst', "r", "utf-8").read()) diff --git a/tests/test_charset_header.py b/tests/test_charset_header.py index 40aff70..2786673 100644 --- a/tests/test_charset_header.py +++ b/tests/test_charset_header.py @@ -1,13 +1,18 @@ -from nose.tools import assert_equals +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + +from nose.tools import eq_ from github2.request import charset_from_headers def no_match_test(): d = {} - assert_equals("ascii", charset_from_headers(d)) + eq_("ascii", charset_from_headers(d)) def utf_test(): d = {'content-type': 'application/json; charset=utf-8'} - assert_equals("utf-8", charset_from_headers(d)) + eq_("utf-8", charset_from_headers(d)) diff --git a/tests/test_commits.py b/tests/test_commits.py index 5d4ee8e..b27fbd3 100644 --- a/tests/test_commits.py +++ b/tests/test_commits.py @@ -1,71 +1,71 @@ +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from datetime import datetime -from nose.tools import assert_equals +from nose.tools import eq_ import utils class CommitProperties(utils.HttpMockTestCase): - """Test commit property handling""" + + """Test commit property handling.""" + commit_id = '1c83cde9b5a7c396a01af1007fb7b88765b9ae45' def test_commit(self): commit = self.client.commits.show('ask/python-github2', self.commit_id) - assert_equals(commit.message, - 'Added cache support to manage_collaborators.') - assert_equals(commit.parents, - [{"id": '7d1c855d2f44a55e4b90b40017be697cf70cb4a0'}]) - assert_equals(commit.url, - '/ask/python-github2/commit/%s' % self.commit_id) - assert_equals(commit.author['login'], 'JNRowe') - assert_equals(commit.id, self.commit_id) - assert_equals(commit.committed_date, - datetime(2011, 6, 6, 16, 13, 50)) - assert_equals(commit.authored_date, datetime(2011, 6, 6, 16, 13, 50)) - assert_equals(commit.tree, 'f48fcc1a0b8ea97f3147dc42cf7cdb6683493e94') - assert_equals(commit.committer['login'], 'JNRowe') - assert_equals(commit.added, None) - assert_equals(commit.removed, None) - assert_equals(commit.modified[0]['filename'], - 'github2/bin/manage_collaborators.py') + eq_(commit.message, 'Added cache support to manage_collaborators.') + eq_(commit.parents, + [{"id": '7d1c855d2f44a55e4b90b40017be697cf70cb4a0'}]) + eq_(commit.url, '/ask/python-github2/commit/%s' % self.commit_id) + eq_(commit.author['login'], 'JNRowe') + eq_(commit.id, self.commit_id) + eq_(commit.committed_date, datetime(2011, 6, 6, 16, 13, 50)) + eq_(commit.authored_date, datetime(2011, 6, 6, 16, 13, 50)) + eq_(commit.tree, 'f48fcc1a0b8ea97f3147dc42cf7cdb6683493e94') + eq_(commit.committer['login'], 'JNRowe') + eq_(commit.added, None) + eq_(commit.removed, None) + eq_(commit.modified[0]['filename'], + 'github2/bin/manage_collaborators.py') def test_repr(self): commit = self.client.commits.show('ask/python-github2', self.commit_id) - assert_equals(repr(commit), - '' % self.commit_id[:8]) + eq_(repr(commit), + '' % self.commit_id[:8]) class CommitsQueries(utils.HttpMockTestCase): + """Test commit querying""" def test_list(self): commits = self.client.commits.list('JNRowe/misc-overlay') - assert_equals(len(commits), 35) - assert_equals(commits[0].id, - '4de0834d58b37ef3020c49df43c95649217a2def') + eq_(len(commits), 35) + eq_(commits[0].id, '4de0834d58b37ef3020c49df43c95649217a2def') def test_list_with_page(self): commits = self.client.commits.list('JNRowe/jnrowe-misc', page=2) - assert_equals(len(commits), 35) - assert_equals(commits[0].id, - '1f5ad2c3206bafc4aca9e6ce50f5c605befdb3d6') + eq_(len(commits), 35) + eq_(commits[0].id, '1f5ad2c3206bafc4aca9e6ce50f5c605befdb3d6') def test_list_with_branch(self): commits = self.client.commits.list('JNRowe/misc-overlay', 'gh-pages') - assert_equals(len(commits), 35) - assert_equals(commits[0].id, - '025148bdaa6fb6bdac9c3522d481fadf1c0a456f') + eq_(len(commits), 35) + eq_(commits[0].id, '025148bdaa6fb6bdac9c3522d481fadf1c0a456f') def test_list_with_file(self): commits = self.client.commits.list('JNRowe/misc-overlay', file='Makefile') - assert_equals(len(commits), 35) - assert_equals(commits[0].id, - 'fc12b924d34dc38c8ce76d27a866221faa88cb72') + eq_(len(commits), 35) + eq_(commits[0].id, 'fc12b924d34dc38c8ce76d27a866221faa88cb72') def test_list_with_branch_and_file(self): commits = self.client.commits.list('JNRowe/misc-overlay', 'gh-pages', 'packages/dev-python.html') - assert_equals(len(commits), 35) - assert_equals(commits[0].id, - '025148bdaa6fb6bdac9c3522d481fadf1c0a456f') + eq_(len(commits), 35) + eq_(commits[0].id, '025148bdaa6fb6bdac9c3522d481fadf1c0a456f') diff --git a/tests/test_date_handling.py b/tests/test_date_handling.py index fabc8d5..b696a74 100644 --- a/tests/test_date_handling.py +++ b/tests/test_date_handling.py @@ -1,8 +1,12 @@ # -*- coding: utf-8 -*- +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. from datetime import datetime as dt -from nose.tools import assert_equals +from nose.tools import eq_ from github2.core import (datetime_to_ghdate, datetime_to_commitdate, datetime_to_isodate, string_to_datetime) @@ -12,154 +16,138 @@ # naïve datetime objects used in the current code base def test_ghdate_to_datetime(): - assert_equals(string_to_datetime('2011/05/22 00:24:15 -0700'), - dt(2011, 5, 22, 0, 24, 15)) - - assert_equals(string_to_datetime('2009/04/18 13:04:09 -0700'), - dt(2009, 4, 18, 13, 4, 9)) - #assert_equals(string_to_datetime('2009/11/12 21:15:17 -0800'), - # dt(2009, 11, 12, 21, 15, 17)) - #assert_equals(string_to_datetime('2009/11/12 21:16:20 -0800'), - # dt(2009, 11, 12, 21, 16, 20)) - assert_equals(string_to_datetime('2010/04/17 17:24:29 -0700'), - dt(2010, 4, 17, 17, 24, 29)) - assert_equals(string_to_datetime('2010/05/18 06:10:36 -0700'), - dt(2010, 5, 18, 6, 10, 36)) - assert_equals(string_to_datetime('2010/05/25 21:59:37 -0700'), - dt(2010, 5, 25, 21, 59, 37)) - assert_equals(string_to_datetime('2010/05/26 17:08:41 -0700'), - dt(2010, 5, 26, 17, 8, 41)) - assert_equals(string_to_datetime('2010/06/20 06:13:37 -0700'), - dt(2010, 6, 20, 6, 13, 37)) - assert_equals(string_to_datetime('2010/07/28 12:56:51 -0700'), - dt(2010, 7, 28, 12, 56, 51)) - assert_equals(string_to_datetime('2010/09/20 21:32:49 -0700'), - dt(2010, 9, 20, 21, 32, 49)) + eq_(string_to_datetime('2011/05/22 00:24:15 -0700'), + dt(2011, 5, 22, 0, 24, 15)) + + eq_(string_to_datetime('2009/04/18 13:04:09 -0700'), + dt(2009, 4, 18, 13, 4, 9)) + #eq_(string_to_datetime('2009/11/12 21:15:17 -0800'), + # dt(2009, 11, 12, 21, 15, 17)) + #eq_(string_to_datetime('2009/11/12 21:16:20 -0800'), + # dt(2009, 11, 12, 21, 16, 20)) + eq_(string_to_datetime('2010/04/17 17:24:29 -0700'), + dt(2010, 4, 17, 17, 24, 29)) + eq_(string_to_datetime('2010/05/18 06:10:36 -0700'), + dt(2010, 5, 18, 6, 10, 36)) + eq_(string_to_datetime('2010/05/25 21:59:37 -0700'), + dt(2010, 5, 25, 21, 59, 37)) + eq_(string_to_datetime('2010/05/26 17:08:41 -0700'), + dt(2010, 5, 26, 17, 8, 41)) + eq_(string_to_datetime('2010/06/20 06:13:37 -0700'), + dt(2010, 6, 20, 6, 13, 37)) + eq_(string_to_datetime('2010/07/28 12:56:51 -0700'), + dt(2010, 7, 28, 12, 56, 51)) + eq_(string_to_datetime('2010/09/20 21:32:49 -0700'), + dt(2010, 9, 20, 21, 32, 49)) def test_datetime_to_ghdate(): - assert_equals(datetime_to_ghdate(dt(2011, 5, 22, 0, 24, 15)), - '2011/05/22 00:24:15 -0700') - - assert_equals(datetime_to_ghdate(dt(2009, 4, 18, 20, 4, 9)), - '2009/04/18 20:04:09 -0700') - #assert_equals(datetime_to_ghdate(dt(2009, 11, 13, 4, 15, 17)), - # '2009/11/13 04:15:17 -0800') - #assert_equals(datetime_to_ghdate(dt(2009, 11, 13, 4, 16, 20)), - # '2009/11/13 04:16:20 -0800') - assert_equals(datetime_to_ghdate(dt(2010, 4, 18, 0, 24, 29)), - '2010/04/18 00:24:29 -0700') - assert_equals(datetime_to_ghdate(dt(2010, 5, 18, 13, 10, 36)), - '2010/05/18 13:10:36 -0700') - assert_equals(datetime_to_ghdate(dt(2010, 5, 26, 5, 59, 37)), - '2010/05/26 05:59:37 -0700') - assert_equals(datetime_to_ghdate(dt(2010, 5, 27, 0, 8, 41)), - '2010/05/27 00:08:41 -0700') - assert_equals(datetime_to_ghdate(dt(2010, 6, 20, 13, 13, 37)), - '2010/06/20 13:13:37 -0700') - assert_equals(datetime_to_ghdate(dt(2010, 7, 28, 19, 56, 51)), - '2010/07/28 19:56:51 -0700') - assert_equals(datetime_to_ghdate(dt(2010, 9, 21, 4, 32, 49)), - '2010/09/21 04:32:49 -0700') + eq_(datetime_to_ghdate(dt(2011, 5, 22, 0, 24, 15)), + '2011/05/22 00:24:15 -0700') + + eq_(datetime_to_ghdate(dt(2009, 4, 18, 20, 4, 9)), + '2009/04/18 20:04:09 -0700') + #eq_(datetime_to_ghdate(dt(2009, 11, 13, 4, 15, 17)), + # '2009/11/13 04:15:17 -0800') + #eq_(datetime_to_ghdate(dt(2009, 11, 13, 4, 16, 20)), + # '2009/11/13 04:16:20 -0800') + eq_(datetime_to_ghdate(dt(2010, 4, 18, 0, 24, 29)), + '2010/04/18 00:24:29 -0700') + eq_(datetime_to_ghdate(dt(2010, 5, 18, 13, 10, 36)), + '2010/05/18 13:10:36 -0700') + eq_(datetime_to_ghdate(dt(2010, 5, 26, 5, 59, 37)), + '2010/05/26 05:59:37 -0700') + eq_(datetime_to_ghdate(dt(2010, 5, 27, 0, 8, 41)), + '2010/05/27 00:08:41 -0700') + eq_(datetime_to_ghdate(dt(2010, 6, 20, 13, 13, 37)), + '2010/06/20 13:13:37 -0700') + eq_(datetime_to_ghdate(dt(2010, 7, 28, 19, 56, 51)), + '2010/07/28 19:56:51 -0700') + eq_(datetime_to_ghdate(dt(2010, 9, 21, 4, 32, 49)), + '2010/09/21 04:32:49 -0700') def test_commitdate_to_datetime(): - assert_equals(string_to_datetime('2011-05-22T00:24:15-07:00'), - dt(2011, 5, 22, 0, 24, 15)) - - assert_equals(string_to_datetime('2011-04-09T10:07:30-07:00'), - dt(2011, 4, 9, 10, 7, 30)) - #assert_equals(string_to_datetime('2011-02-19T07:16:11-08:00'), - # dt(2011, 2, 19, 7, 16, 11)) - #assert_equals(string_to_datetime('2010-12-21T12:34:27-08:00'), - # dt(2010, 12, 21, 12, 34, 27)) - assert_equals(string_to_datetime('2011-04-09T10:20:05-07:00'), - dt(2011, 4, 9, 10, 20, 5)) - assert_equals(string_to_datetime('2011-04-09T10:05:58-07:00'), - dt(2011, 4, 9, 10, 5, 58)) - assert_equals(string_to_datetime('2011-04-09T09:53:00-07:00'), - dt(2011, 4, 9, 9, 53, 0)) - assert_equals(string_to_datetime('2011-04-09T10:00:21-07:00'), - dt(2011, 4, 9, 10, 0, 21)) - #assert_equals(string_to_datetime('2010-12-16T15:10:59-08:00'), - # dt(2010, 12, 16, 15, 10, 59)) - assert_equals(string_to_datetime('2011-04-09T09:53:00-07:00'), - dt(2011, 4, 9, 9, 53, 0)) - assert_equals(string_to_datetime('2011-04-09T09:53:00-07:00'), - dt(2011, 4, 9, 9, 53, 0)) + eq_(string_to_datetime('2011-05-22T00:24:15-07:00'), + dt(2011, 5, 22, 0, 24, 15)) + + eq_(string_to_datetime('2011-04-09T10:07:30-07:00'), + dt(2011, 4, 9, 10, 7, 30)) + #eq_(string_to_datetime('2011-02-19T07:16:11-08:00'), + # dt(2011, 2, 19, 7, 16, 11)) + #eq_(string_to_datetime('2010-12-21T12:34:27-08:00'), + # dt(2010, 12, 21, 12, 34, 27)) + eq_(string_to_datetime('2011-04-09T10:20:05-07:00'), + dt(2011, 4, 9, 10, 20, 5)) + eq_(string_to_datetime('2011-04-09T10:05:58-07:00'), + dt(2011, 4, 9, 10, 5, 58)) + eq_(string_to_datetime('2011-04-09T09:53:00-07:00'), + dt(2011, 4, 9, 9, 53, 0)) + eq_(string_to_datetime('2011-04-09T10:00:21-07:00'), + dt(2011, 4, 9, 10, 0, 21)) + #eq_(string_to_datetime('2010-12-16T15:10:59-08:00'), + # dt(2010, 12, 16, 15, 10, 59)) + eq_(string_to_datetime('2011-04-09T09:53:00-07:00'), + dt(2011, 4, 9, 9, 53, 0)) + eq_(string_to_datetime('2011-04-09T09:53:00-07:00'), + dt(2011, 4, 9, 9, 53, 0)) def test_datetime_to_commitdate(): - assert_equals(datetime_to_commitdate(dt(2011, 5, 22, 0, 24, 15)), - '2011-05-22T00:24:15-07:00') - - assert_equals(datetime_to_commitdate(dt(2011, 4, 9, 10, 7, 30)), - '2011-04-09T10:07:30-07:00') - #assert_equals(datetime_to_commitdate(dt(2011, 2, 19, 7, 16, 11)), - # '2011-02-19T07:16:11-08:00') - #assert_equals(datetime_to_commitdate(dt(2010, 12, 21, 12, 34, 27)), - # '2010-12-21T12:34:27-08:00') - assert_equals(datetime_to_commitdate(dt(2011, 4, 9, 10, 20, 5)), - '2011-04-09T10:20:05-07:00') - assert_equals(datetime_to_commitdate(dt(2011, 4, 9, 10, 5, 58)), - '2011-04-09T10:05:58-07:00') - assert_equals(datetime_to_commitdate(dt(2011, 4, 9, 9, 53, 0)), - '2011-04-09T09:53:00-07:00') - assert_equals(datetime_to_commitdate(dt(2011, 4, 9, 10, 0, 21)), - '2011-04-09T10:00:21-07:00') - #assert_equals(datetime_to_commitdate(dt(2010, 12, 16, 15, 10, 59)), - # '2010-12-16T15:10:59-08:00') - assert_equals(datetime_to_commitdate(dt(2011, 4, 9, 9, 53, 0)), - '2011-04-09T09:53:00-07:00') - assert_equals(datetime_to_commitdate(dt(2011, 4, 9, 9, 53, 0)), - '2011-04-09T09:53:00-07:00') + eq_(datetime_to_commitdate(dt(2011, 5, 22, 0, 24, 15)), + '2011-05-22T00:24:15-07:00') + + eq_(datetime_to_commitdate(dt(2011, 4, 9, 10, 7, 30)), + '2011-04-09T10:07:30-07:00') + #eq_(datetime_to_commitdate(dt(2011, 2, 19, 7, 16, 11)), + # '2011-02-19T07:16:11-08:00') + #eq_(datetime_to_commitdate(dt(2010, 12, 21, 12, 34, 27)), + # '2010-12-21T12:34:27-08:00') + eq_(datetime_to_commitdate(dt(2011, 4, 9, 10, 20, 5)), + '2011-04-09T10:20:05-07:00') + eq_(datetime_to_commitdate(dt(2011, 4, 9, 10, 5, 58)), + '2011-04-09T10:05:58-07:00') + eq_(datetime_to_commitdate(dt(2011, 4, 9, 9, 53, 0)), + '2011-04-09T09:53:00-07:00') + eq_(datetime_to_commitdate(dt(2011, 4, 9, 10, 0, 21)), + '2011-04-09T10:00:21-07:00') + #eq_(datetime_to_commitdate(dt(2010, 12, 16, 15, 10, 59)), + # '2010-12-16T15:10:59-08:00') + eq_(datetime_to_commitdate(dt(2011, 4, 9, 9, 53, 0)), + '2011-04-09T09:53:00-07:00') + eq_(datetime_to_commitdate(dt(2011, 4, 9, 9, 53, 0)), + '2011-04-09T09:53:00-07:00') def test_isodate_to_datetime(): - assert_equals(string_to_datetime('2011-05-22T00:24:15Z'), - dt(2011, 5, 22, 0, 24, 15)) - assert_equals(string_to_datetime('2011-04-09T10:07:30Z'), - dt(2011, 4, 9, 10, 7, 30)) - assert_equals(string_to_datetime('2011-02-19T07:16:11Z'), - dt(2011, 2, 19, 7, 16, 11)) - assert_equals(string_to_datetime('2010-12-21T12:34:27Z'), - dt(2010, 12, 21, 12, 34, 27)) - assert_equals(string_to_datetime('2011-04-09T10:20:05Z'), - dt(2011, 4, 9, 10, 20, 5)) - assert_equals(string_to_datetime('2011-04-09T10:05:58Z'), - dt(2011, 4, 9, 10, 5, 58)) - assert_equals(string_to_datetime('2011-04-09T09:53:00Z'), - dt(2011, 4, 9, 9, 53, 0)) - assert_equals(string_to_datetime('2011-04-09T10:00:21Z'), - dt(2011, 4, 9, 10, 0, 21)) - assert_equals(string_to_datetime('2010-12-16T15:10:59Z'), - dt(2010, 12, 16, 15, 10, 59)) - assert_equals(string_to_datetime('2011-04-09T09:53:00Z'), - dt(2011, 4, 9, 9, 53, 0)) - assert_equals(string_to_datetime('2011-04-09T09:53:00Z'), - dt(2011, 4, 9, 9, 53, 0)) + eq_(string_to_datetime('2011-05-22T00:24:15Z'), dt(2011, 5, 22, 0, 24, 15)) + eq_(string_to_datetime('2011-04-09T10:07:30Z'), dt(2011, 4, 9, 10, 7, 30)) + eq_(string_to_datetime('2011-02-19T07:16:11Z'), dt(2011, 2, 19, 7, 16, 11)) + eq_(string_to_datetime('2010-12-21T12:34:27Z'), + dt(2010, 12, 21, 12, 34, 27)) + eq_(string_to_datetime('2011-04-09T10:20:05Z'), dt(2011, 4, 9, 10, 20, 5)) + eq_(string_to_datetime('2011-04-09T10:05:58Z'), dt(2011, 4, 9, 10, 5, 58)) + eq_(string_to_datetime('2011-04-09T09:53:00Z'), dt(2011, 4, 9, 9, 53, 0)) + eq_(string_to_datetime('2011-04-09T10:00:21Z'), dt(2011, 4, 9, 10, 0, 21)) + eq_(string_to_datetime('2010-12-16T15:10:59Z'), + dt(2010, 12, 16, 15, 10, 59)) + eq_(string_to_datetime('2011-04-09T09:53:00Z'), dt(2011, 4, 9, 9, 53, 0)) + eq_(string_to_datetime('2011-04-09T09:53:00Z'), dt(2011, 4, 9, 9, 53, 0)) def test_datetime_to_isodate(): - assert_equals(datetime_to_isodate(dt(2011, 5, 22, 0, 24, 15)), - '2011-05-22T00:24:15Z') - assert_equals(datetime_to_isodate(dt(2011, 4, 9, 10, 7, 30)), - '2011-04-09T10:07:30Z') - assert_equals(datetime_to_isodate(dt(2011, 2, 19, 7, 16, 11)), - '2011-02-19T07:16:11Z') - assert_equals(datetime_to_isodate(dt(2010, 12, 21, 12, 34, 27)), - '2010-12-21T12:34:27Z') - assert_equals(datetime_to_isodate(dt(2011, 4, 9, 10, 20, 5)), - '2011-04-09T10:20:05Z') - assert_equals(datetime_to_isodate(dt(2011, 4, 9, 10, 5, 58)), - '2011-04-09T10:05:58Z') - assert_equals(datetime_to_isodate(dt(2011, 4, 9, 9, 53, 0)), - '2011-04-09T09:53:00Z') - assert_equals(datetime_to_isodate(dt(2011, 4, 9, 10, 0, 21)), - '2011-04-09T10:00:21Z') - assert_equals(datetime_to_isodate(dt(2010, 12, 16, 15, 10, 59)), - '2010-12-16T15:10:59Z') - assert_equals(datetime_to_isodate(dt(2011, 4, 9, 9, 53, 0)), - '2011-04-09T09:53:00Z') - assert_equals(datetime_to_isodate(dt(2011, 4, 9, 9, 53, 0)), - '2011-04-09T09:53:00Z') + eq_(datetime_to_isodate(dt(2011, 5, 22, 0, 24, 15)), + '2011-05-22T00:24:15Z') + eq_(datetime_to_isodate(dt(2011, 4, 9, 10, 7, 30)), '2011-04-09T10:07:30Z') + eq_(datetime_to_isodate(dt(2011, 2, 19, 7, 16, 11)), + '2011-02-19T07:16:11Z') + eq_(datetime_to_isodate(dt(2010, 12, 21, 12, 34, 27)), + '2010-12-21T12:34:27Z') + eq_(datetime_to_isodate(dt(2011, 4, 9, 10, 20, 5)), '2011-04-09T10:20:05Z') + eq_(datetime_to_isodate(dt(2011, 4, 9, 10, 5, 58)), '2011-04-09T10:05:58Z') + eq_(datetime_to_isodate(dt(2011, 4, 9, 9, 53, 0)), '2011-04-09T09:53:00Z') + eq_(datetime_to_isodate(dt(2011, 4, 9, 10, 0, 21)), '2011-04-09T10:00:21Z') + eq_(datetime_to_isodate(dt(2010, 12, 16, 15, 10, 59)), + '2010-12-16T15:10:59Z') + eq_(datetime_to_isodate(dt(2011, 4, 9, 9, 53, 0)), '2011-04-09T09:53:00Z') + eq_(datetime_to_isodate(dt(2011, 4, 9, 9, 53, 0)), '2011-04-09T09:53:00Z') diff --git a/tests/test_issues.py b/tests/test_issues.py index dfd693e..67cbff7 100644 --- a/tests/test_issues.py +++ b/tests/test_issues.py @@ -1,6 +1,11 @@ +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from datetime import datetime -from nose.tools import assert_equals +from nose.tools import eq_ import utils @@ -8,70 +13,70 @@ class Issue(utils.HttpMockTestCase): def test_properties(self): issue = self.client.issues.show('ask/python-github2', 24) - assert_equals(issue.position, 24.0) - assert_equals(issue.number, 24) - assert_equals(issue.votes, 0) - assert_equals(len(issue.body), 164) - assert_equals(issue.title, 'Pagination support for commits.') - assert_equals(issue.user, 'svetlyak40wt') - assert_equals(issue.state, 'open') - assert_equals(issue.labels, []) - assert_equals(issue.created_at, datetime(2010, 12, 8, 23, 50, 26)) - assert_equals(issue.closed_at, None) - assert_equals(issue.updated_at, datetime(2011, 1, 4, 16, 26, 7)) - assert_equals(issue.diff_url, - 'https://github.com/ask/python-github2/pull/24.diff') - assert_equals(issue.patch_url, - 'https://github.com/ask/python-github2/pull/24.patch') - assert_equals(issue.pull_request_url, - 'https://github.com/ask/python-github2/pull/24') + eq_(issue.position, 24.0) + eq_(issue.number, 24) + eq_(issue.votes, 0) + eq_(len(issue.body), 164) + eq_(issue.title, 'Pagination support for commits.') + eq_(issue.user, 'svetlyak40wt') + eq_(issue.state, 'open') + eq_(issue.labels, []) + eq_(issue.created_at, datetime(2010, 12, 8, 23, 50, 26)) + eq_(issue.closed_at, None) + eq_(issue.updated_at, datetime(2011, 1, 4, 16, 26, 7)) + eq_(issue.diff_url, + 'https://github.com/ask/python-github2/pull/24.diff') + eq_(issue.patch_url, + 'https://github.com/ask/python-github2/pull/24.patch') + eq_(issue.pull_request_url, + 'https://github.com/ask/python-github2/pull/24') def test_issue_repr(self): issue = self.client.issues.show('ask/python-github2', 24) - assert_equals(repr(issue), - '') + eq_(repr(issue), '') class Comment(utils.HttpMockTestCase): def test_properties(self): comments = self.client.issues.comments('ask/python-github2', 24) comment = comments[0] - assert_equals(comment.created_at, datetime(2010, 12, 9, 22, 37, 26)) - assert_equals(comment.updated_at, datetime(2010, 12, 9, 22, 37, 26)) - assert_equals(len(comment.body), 267) - assert_equals(comment.id, 601871) - assert_equals(comment.user, 'nvie') + eq_(comment.created_at, datetime(2010, 12, 9, 22, 37, 26)) + eq_(comment.updated_at, datetime(2010, 12, 9, 22, 37, 26)) + eq_(len(comment.body), 267) + eq_(comment.id, 601871) + eq_(comment.user, 'nvie') def test_comment_repr(self): comments = self.client.issues.comments('ask/python-github2', 24) - assert_equals(repr(comments[1]), - '') + eq_(repr(comments[1]), '') class IssueQueries(utils.HttpMockTestCase): - """Test issue querying""" + + """Test issue querying.""" + def test_search(self): issues = self.client.issues.search('ask/python-github2', 'timezone', 'closed') - assert_equals(len(issues), 2) - assert_equals(issues[1].number, 39) + eq_(len(issues), 2) + eq_(issues[1].number, 39) def test_list(self): issues = self.client.issues.list('ask/python-github2') - assert_equals(len(issues), 4) - assert_equals(issues[-1].number, 58) + eq_(len(issues), 4) + eq_(issues[-1].number, 58) def test_list_with_state(self): issues = self.client.issues.list('ask/python-github2', "closed") - assert_equals(len(issues), 55) - assert_equals(issues[0].number, 59) + eq_(len(issues), 55) + eq_(issues[0].number, 59) def test_issue_labels(self): labels = self.client.issues.list_labels('JNRowe/misc-overlay') - assert_equals(len(labels), 4) - assert_equals(labels[0], 'feature') + eq_(len(labels), 4) + eq_(labels[0], 'feature') def test_list_by_label(self): issues = self.client.issues.list_by_label('JNRowe/misc-overlay', 'bug') - assert_equals(len(issues), 30) - assert_equals(issues[-1].number, 328) + eq_(len(issues), 30) + eq_(issues[-1].number, 328) diff --git a/tests/test_organizations.py b/tests/test_organizations.py index 9f4e56b..e2ddc77 100644 --- a/tests/test_organizations.py +++ b/tests/test_organizations.py @@ -1,6 +1,11 @@ +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from datetime import datetime -from nose.tools import (assert_equals, assert_true) +from nose.tools import (eq_, ok_) import utils @@ -8,57 +13,54 @@ class OrganizationProperties(utils.HttpMockTestCase): def test_properties(self): organization = self.client.organizations.show('github') - assert_equals(organization.id, 9919) - assert_equals(organization.name, 'GitHub') - assert_equals(organization.blog, 'https://github.com/about') - assert_equals(organization.location, 'San Francisco, CA') - assert_equals(organization.gravatar_id, - '61024896f291303615bcd4f7a0dcfb74') - assert_equals(organization.login, 'github') - assert_equals(organization.email, 'support@github.com') - assert_equals(organization.company, None) - assert_equals(organization.created_at, - datetime(2008, 5, 10, 21, 37, 31)) - assert_equals(organization.following_count, 0) - assert_equals(organization.followers_count, 591) - assert_equals(organization.public_gist_count, 0) - assert_equals(organization.public_repo_count, 31) - assert_equals(organization.permission, None) - assert_equals(organization.plan, None) + eq_(organization.id, 9919) + eq_(organization.name, 'GitHub') + eq_(organization.blog, 'https://github.com/about') + eq_(organization.location, 'San Francisco, CA') + eq_(organization.gravatar_id, '61024896f291303615bcd4f7a0dcfb74') + eq_(organization.login, 'github') + eq_(organization.email, 'support@github.com') + eq_(organization.company, None) + eq_(organization.created_at, datetime(2008, 5, 10, 21, 37, 31)) + eq_(organization.following_count, 0) + eq_(organization.followers_count, 591) + eq_(organization.public_gist_count, 0) + eq_(organization.public_repo_count, 31) + eq_(organization.permission, None) + eq_(organization.plan, None) def test_is_authenticated(self): organization = self.client.organizations.show('github') - assert_true(organization.is_authenticated() is False) + ok_(organization.is_authenticated() is False) organization = self.client.organizations.show('fake_org_with_auth') - assert_true(organization.is_authenticated() is True) + ok_(organization.is_authenticated() is True) class Organization(utils.HttpMockTestCase): def test_repr(self): organization = self.client.organizations.show('github') - assert_equals(repr(organization), - '') + eq_(repr(organization), '') class OrganizationQueries(utils.HttpMockTestCase): """Test organisation querying""" def test_public_repositories(self): repos = self.client.organizations.public_repositories('github') - assert_equals(len(repos), 31) - assert_equals(repos[2].name, 'hubahuba') + eq_(len(repos), 31) + eq_(repos[2].name, 'hubahuba') def test_public_members(self): members = self.client.organizations.public_members('github') - assert_equals(len(members), 35) - assert_equals(members[2].name, 'Ben Burkert') + eq_(len(members), 35) + eq_(members[2].name, 'Ben Burkert') class OrganizationsEdits(utils.HttpMockAuthenticatedTestCase): def test_add_team(self): team = self.client.organizations.add_team('JNRowe-test-org', 'test_pull', 'pull') - assert_equals(team.name, 'team_pull') - assert_equals(team.permission, 'pull') + eq_(team.name, 'team_pull') + eq_(team.permission, 'pull') def test_add_team_with_repos(self): projects = ['JNRowe-test-org/test1', 'JNRowe-test-org/test2'] @@ -67,5 +69,4 @@ def test_add_team_with_repos(self): projects) team_repos = self.client.teams.repositories(team.id) - assert_equals(['/'.join([x.organization, x.name]) for x in team_repos], - projects) + eq_(['/'.join([x.organization, x.name]) for x in team_repos], projects) diff --git a/tests/test_pull_requests.py b/tests/test_pull_requests.py index 50197ce..efe486c 100644 --- a/tests/test_pull_requests.py +++ b/tests/test_pull_requests.py @@ -1,6 +1,11 @@ +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + from datetime import datetime -from nose.tools import assert_equals +from nose.tools import eq_ import utils @@ -8,55 +13,48 @@ class PullRequest(utils.HttpMockTestCase): def test_properties(self): pull_request = self.client.pull_requests.show('ask/python-github2', 39) - assert_equals(pull_request.state, 'closed') - assert_equals(pull_request.base['sha'], + eq_(pull_request.state, 'closed') + eq_(pull_request.base['sha'], '0786a96c80afad7bbd0747df590f649eaa46ca04') - assert_equals(pull_request.head['sha'], + eq_(pull_request.head['sha'], '5438e41d9c390f53089ed3fa0842831fafc73d8e') - assert_equals(pull_request.issue_user['login'], 'JNRowe') - assert_equals(pull_request.user['login'], 'JNRowe') - assert_equals(pull_request.title, 'Datetime timezone handling.') - assert_equals(len(pull_request.body), 1442) - assert_equals(pull_request.position, 39.0) - assert_equals(pull_request.number, 39.0) - assert_equals(pull_request.votes, 0) - assert_equals(pull_request.comments, 4) - assert_equals(pull_request.diff_url, - 'https://github.com/ask/python-github2/pull/39.diff') - assert_equals(pull_request.patch_url, - 'https://github.com/ask/python-github2/pull/39.patch') - assert_equals(pull_request.labels, []) - assert_equals(pull_request.html_url, - 'https://github.com/ask/python-github2/pull/39') - assert_equals(pull_request.issue_created_at, - datetime(2011, 4, 18, 15, 25, 47)) - assert_equals(pull_request.issue_updated_at, - datetime(2011, 6, 23, 9, 33, 57)) - assert_equals(pull_request.created_at, - datetime(2011, 6, 20, 16, 51, 24)) - assert_equals(pull_request.updated_at, - datetime(2011, 6, 23, 9, 28, 42)) - assert_equals(pull_request.closed_at, - datetime(2011, 6, 23, 9, 33, 57)) - assert_equals(len(pull_request.discussion), 13) - assert_equals(pull_request.mergeable, True) + eq_(pull_request.issue_user['login'], 'JNRowe') + eq_(pull_request.user['login'], 'JNRowe') + eq_(pull_request.title, 'Datetime timezone handling.') + eq_(len(pull_request.body), 1442) + eq_(pull_request.position, 39.0) + eq_(pull_request.number, 39.0) + eq_(pull_request.votes, 0) + eq_(pull_request.comments, 4) + eq_(pull_request.diff_url, + 'https://github.com/ask/python-github2/pull/39.diff') + eq_(pull_request.patch_url, + 'https://github.com/ask/python-github2/pull/39.patch') + eq_(pull_request.labels, []) + eq_(pull_request.html_url, + 'https://github.com/ask/python-github2/pull/39') + eq_(pull_request.issue_created_at, datetime(2011, 4, 18, 15, 25, 47)) + eq_(pull_request.issue_updated_at, datetime(2011, 6, 23, 9, 33, 57)) + eq_(pull_request.created_at, datetime(2011, 6, 20, 16, 51, 24)) + eq_(pull_request.updated_at, datetime(2011, 6, 23, 9, 28, 42)) + eq_(pull_request.closed_at, datetime(2011, 6, 23, 9, 33, 57)) + eq_(len(pull_request.discussion), 13) + eq_(pull_request.mergeable, True) def test_repr(self): pull_request = self.client.pull_requests.show('ask/python-github2', 39) - assert_equals(repr(pull_request), - '') + eq_(repr(pull_request), '') class PullRequestQueries(utils.HttpMockTestCase): """Test pull request querying""" def test_list(self): pull_requests = self.client.pull_requests.list('ask/python-github2') - assert_equals(len(pull_requests), 1) - assert_equals(pull_requests[0].title, - 'Pagination support for commits.') + eq_(len(pull_requests), 1) + eq_(pull_requests[0].title, 'Pagination support for commits.') def test_list_with_page(self): pull_requests = self.client.pull_requests.list('robbyrussell/oh-my-zsh', page=2) - assert_equals(len(pull_requests), 52) - assert_equals(pull_requests[1].title, 'Added my own custom theme') + eq_(len(pull_requests), 52) + eq_(pull_requests[1].title, 'Added my own custom theme') diff --git a/tests/test_regression.py b/tests/test_regression.py index a2b235c..b5fee60 100644 --- a/tests/test_regression.py +++ b/tests/test_regression.py @@ -1,23 +1,22 @@ +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + import httplib2 -from nose.tools import assert_equals +from nose.tools import eq_ from github2.client import Github -import utils - def test_issue_50(): - """Erroneous init of ``Http`` with proxy setup + """Erroneous init of ``Http`` with proxy setup. See https://github.com/ask/python-github2/pull/50 """ - utils.set_http_mock() - client = Github(proxy_host="my.proxy.com", proxy_port=9000) - setup_args = client.request._http.called_with - assert_equals(type(setup_args['proxy_info']), httplib2.ProxyInfo) - assert_equals(setup_args['proxy_info'].proxy_host, 'my.proxy.com') - assert_equals(setup_args['proxy_info'].proxy_port, 9000) - - utils.unset_http_mock() + proxy_info = client.request._http.proxy_info + eq_(type(proxy_info), httplib2.ProxyInfo) + eq_(proxy_info.proxy_host, 'my.proxy.com') + eq_(proxy_info.proxy_port, 9000) diff --git a/tests/test_repositories.py b/tests/test_repositories.py index 63f39c0..8abbc30 100644 --- a/tests/test_repositories.py +++ b/tests/test_repositories.py @@ -1,6 +1,13 @@ +# coding: utf-8 +# Copyright (C) 2011-2012 James Rowe +# Stéphane Angel +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + import datetime -from nose.tools import assert_equals +from nose.tools import eq_ import utils @@ -8,111 +15,108 @@ class Repo(utils.HttpMockTestCase): def test_repr(self): repo = self.client.repos.show('JNRowe/misc-overlay') - assert_equals(repr(repo), '') + eq_(repr(repo), '') class RepoProperties(utils.HttpMockTestCase): - """Test repository property handling""" + + """Test repository property handling.""" + def test_repo(self): repo = self.client.repos.show('JNRowe/misc-overlay') - assert_equals(repo.name, 'misc-overlay') - assert_equals(repo.description, - 'Gentoo overlay -- miscellaneous packages') - assert_equals(repo.url, 'https://github.com/JNRowe/misc-overlay') - assert_equals(repo.owner, 'JNRowe') - assert_equals(repo.homepage, 'http://jnrowe.github.com/misc-overlay/') + eq_(repo.name, 'misc-overlay') + eq_(repo.description, 'Gentoo overlay -- miscellaneous packages') + eq_(repo.url, 'https://github.com/JNRowe/misc-overlay') + eq_(repo.owner, 'JNRowe') + eq_(repo.homepage, 'http://jnrowe.github.com/misc-overlay/') - assert_equals(repo.project, 'JNRowe/misc-overlay') + eq_(repo.project, 'JNRowe/misc-overlay') def test_meta(self): repo = self.client.repos.show('JNRowe/misc-overlay') - assert_equals(repo.forks, 0) - assert_equals(repo.watchers, 5) - assert_equals(repo.private, False) - assert_equals(repo.fork, False) - assert_equals(repo.master_branch, None) - assert_equals(repo.integration_branch, None) - assert_equals(repo.open_issues, 13) - assert_equals(repo.created_at, - datetime.datetime(2009, 5, 2, 7, 32, 50)) - assert_equals(repo.pushed_at, - datetime.datetime(2011, 8, 11, 11, 46, 23)) - assert_equals(repo.has_downloads, True) - assert_equals(repo.has_wiki, True) - assert_equals(repo.has_issues, True) - assert_equals(repo.language, 'Python') + eq_(repo.forks, 0) + eq_(repo.watchers, 5) + eq_(repo.private, False) + eq_(repo.fork, False) + eq_(repo.master_branch, None) + eq_(repo.integration_branch, None) + eq_(repo.open_issues, 13) + eq_(repo.created_at, datetime.datetime(2009, 5, 2, 7, 32, 50)) + eq_(repo.pushed_at, datetime.datetime(2011, 8, 11, 11, 46, 23)) + eq_(repo.has_downloads, True) + eq_(repo.has_wiki, True) + eq_(repo.has_issues, True) + eq_(repo.language, 'Python') def test_fork_properties(self): repo = self.client.repos.show('JNRowe/python-github2') - assert_equals(repo.forks, 0) - assert_equals(repo.fork, True) - assert_equals(repo.parent, 'ask/python-github2') - assert_equals(repo.source, 'ask/python-github2') + eq_(repo.forks, 0) + eq_(repo.fork, True) + eq_(repo.parent, 'ask/python-github2') + eq_(repo.source, 'ask/python-github2') class RepoQueries(utils.HttpMockTestCase): """Test repository querying""" def test_search(self): repos = self.client.repos.search('surfraw') - assert_equals(len(repos), 8) - assert_equals(repos[0].owner, 'JNRowe') + eq_(len(repos), 8) + eq_(repos[0].owner, 'JNRowe') def test_list(self): repos = self.client.repos.list('JNRowe') - assert_equals(len(repos), 48) - assert_equals(repos[0].name, 'bfm') + eq_(len(repos), 48) + eq_(repos[0].name, 'bfm') def test_list_with_page(self): repos = self.client.repos.list('tekkub', page=2) - assert_equals(len(repos), 37) - assert_equals(repos[0].name, 'OhSnap') + eq_(len(repos), 37) + eq_(repos[0].name, 'OhSnap') def test_watching(self): repos = self.client.repos.watching('JNRowe') - assert_equals(len(repos), 90) - assert_equals(repos[0].name, 'nerdtree') + eq_(len(repos), 90) + eq_(repos[0].name, 'nerdtree') def test_watching_with_page(self): repos = self.client.repos.watching('tekkub', page=2) - assert_equals(len(repos), 39) - assert_equals(repos[0].name, 'Buffoon') + eq_(len(repos), 39) + eq_(repos[0].name, 'Buffoon') def test_contributors(self): contributors = self.client.repos.list_contributors('ask/python-github2') - assert_equals(len(contributors), 29) - assert_equals(contributors[1].name, 'Ask Solem Hoel') + eq_(len(contributors), 29) + eq_(contributors[1].name, 'Ask Solem Hoel') def test_list_collaborators(self): collaborators = self.client.repos.list_collaborators('ask/python-github2') - assert_equals(len(collaborators), 4) - assert_equals(collaborators[2], 'JNRowe') + eq_(len(collaborators), 4) + eq_(collaborators[2], 'JNRowe') def test_languages(self): languages = self.client.repos.languages('JNRowe/misc-overlay') - assert_equals(len(languages), 2) - assert_equals(languages['Python'], 11194) + eq_(len(languages), 2) + eq_(languages['Python'], 11194) def test_tags(self): tags = self.client.repos.tags('ask/python-github2') - assert_equals(len(tags), 7) - assert_equals(tags['0.4.1'], - '96b0a41dd249c521323700bc11a0a721a7c9e642') + eq_(len(tags), 7) + eq_(tags['0.4.1'], '96b0a41dd249c521323700bc11a0a721a7c9e642') def test_branches(self): branches = self.client.repos.branches('ask/python-github2') - assert_equals(len(branches), 1) - assert_equals(branches['master'], - '1c83cde9b5a7c396a01af1007fb7b88765b9ae45') + eq_(len(branches), 1) + eq_(branches['master'], '1c83cde9b5a7c396a01af1007fb7b88765b9ae45') def test_watchers(self): watchers = self.client.repos.watchers('ask/python-github2') - assert_equals(len(watchers), 143) - assert_equals(watchers[0], 'ask') + eq_(len(watchers), 143) + eq_(watchers[0], 'ask') class AuthenticatedRepoQueries(utils.HttpMockAuthenticatedTestCase): def test_pushable(self): repos = self.client.repos.pushable() - assert_equals(len(repos), 1) - assert_equals(repos[0].name, 'python-github2') + eq_(len(repos), 1) + eq_(repos[0].name, 'python-github2') diff --git a/tests/test_request.py b/tests/test_request.py index 7c7f93b..529de26 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -1,3 +1,8 @@ +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + import unittest try: @@ -30,7 +35,9 @@ def assert_params_contain(first, second): class TestAuthEncode(unittest.TestCase): - """Test processing of authentication data""" + + """Test processing of authentication data.""" + def setUp(self): self.r = request.GithubRequest() diff --git a/tests/test_teams.py b/tests/test_teams.py index 85689aa..cd18166 100644 --- a/tests/test_teams.py +++ b/tests/test_teams.py @@ -1,4 +1,9 @@ -from nose.tools import assert_equals +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + +from nose.tools import eq_ import utils @@ -6,4 +11,4 @@ class TeamEdits(utils.HttpMockAuthenticatedTestCase): def test_add_member(self): users = self.client.teams.add_member(121990, 'JNRowe') - assert_equals(users[0].login, 'JNRowe') + eq_(users[0].login, 'JNRowe') diff --git a/tests/test_tz_aware_date_handling.py b/tests/test_tz_aware_date_handling.py index 5789593..c2b152f 100644 --- a/tests/test_tz_aware_date_handling.py +++ b/tests/test_tz_aware_date_handling.py @@ -1,9 +1,13 @@ # -*- coding: utf-8 -*- +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. from datetime import datetime as dt from dateutil.tz import tzutc -from nose.tools import assert_equals +from nose.tools import eq_ from github2 import core from github2.core import (datetime_to_ghdate, datetime_to_commitdate, @@ -11,168 +15,169 @@ def setup_module(): - """Enable timezone-aware datetime handling for this module's tests""" + """Enable timezone-aware datetime handling for this module's tests.""" core.NAIVE = False def teardown_module(): - """Disable timezone-aware datetime handling when tests have completed""" + """Disable timezone-aware datetime handling when tests have completed.""" core.NAIVE = True def dt_utz(year, month, day, hour, minute, second): - """Produce a UTC-anchored datetime object + """Produce a UTC-anchored datetime object. :see: :class:`datetime.datetime` + """ return dt(year, month, day, hour, minute, second, tzinfo=tzutc()) def test_ghdate_to_datetime(): - assert_equals(string_to_datetime('2011/05/22 00:24:15 -0700'), - dt_utz(2011, 5, 22, 7, 24, 15)) - assert_equals(string_to_datetime('2009/04/18 13:04:09 -0700'), - dt_utz(2009, 4, 18, 20, 4, 9)) - assert_equals(string_to_datetime('2009/11/12 21:15:17 -0800'), - dt_utz(2009, 11, 13, 5, 15, 17)) - assert_equals(string_to_datetime('2009/11/12 21:16:20 -0800'), - dt_utz(2009, 11, 13, 5, 16, 20)) - assert_equals(string_to_datetime('2010/04/17 17:24:29 -0700'), - dt_utz(2010, 4, 18, 0, 24, 29)) - assert_equals(string_to_datetime('2010/05/18 06:10:36 -0700'), - dt_utz(2010, 5, 18, 13, 10, 36)) - assert_equals(string_to_datetime('2010/05/25 21:59:37 -0700'), - dt_utz(2010, 5, 26, 4, 59, 37)) - assert_equals(string_to_datetime('2010/05/26 17:08:41 -0700'), - dt_utz(2010, 5, 27, 0, 8, 41)) - assert_equals(string_to_datetime('2010/06/20 06:13:37 -0700'), - dt_utz(2010, 6, 20, 13, 13, 37)) - assert_equals(string_to_datetime('2010/07/28 12:56:51 -0700'), - dt_utz(2010, 7, 28, 19, 56, 51)) - assert_equals(string_to_datetime('2010/09/20 21:32:49 -0700'), - dt_utz(2010, 9, 21, 4, 32, 49)) + eq_(string_to_datetime('2011/05/22 00:24:15 -0700'), + dt_utz(2011, 5, 22, 7, 24, 15)) + eq_(string_to_datetime('2009/04/18 13:04:09 -0700'), + dt_utz(2009, 4, 18, 20, 4, 9)) + eq_(string_to_datetime('2009/11/12 21:15:17 -0800'), + dt_utz(2009, 11, 13, 5, 15, 17)) + eq_(string_to_datetime('2009/11/12 21:16:20 -0800'), + dt_utz(2009, 11, 13, 5, 16, 20)) + eq_(string_to_datetime('2010/04/17 17:24:29 -0700'), + dt_utz(2010, 4, 18, 0, 24, 29)) + eq_(string_to_datetime('2010/05/18 06:10:36 -0700'), + dt_utz(2010, 5, 18, 13, 10, 36)) + eq_(string_to_datetime('2010/05/25 21:59:37 -0700'), + dt_utz(2010, 5, 26, 4, 59, 37)) + eq_(string_to_datetime('2010/05/26 17:08:41 -0700'), + dt_utz(2010, 5, 27, 0, 8, 41)) + eq_(string_to_datetime('2010/06/20 06:13:37 -0700'), + dt_utz(2010, 6, 20, 13, 13, 37)) + eq_(string_to_datetime('2010/07/28 12:56:51 -0700'), + dt_utz(2010, 7, 28, 19, 56, 51)) + eq_(string_to_datetime('2010/09/20 21:32:49 -0700'), + dt_utz(2010, 9, 21, 4, 32, 49)) def test_datetime_to_ghdate(): - assert_equals(datetime_to_ghdate(dt_utz(2011, 5, 22, 7, 24, 15)), - '2011/05/22 00:24:15 -0700') - assert_equals(datetime_to_ghdate(dt_utz(2009, 4, 18, 20, 4, 9)), - '2009/04/18 13:04:09 -0700') - assert_equals(datetime_to_ghdate(dt_utz(2009, 11, 13, 4, 15, 17)), - '2009/11/12 20:15:17 -0800') - assert_equals(datetime_to_ghdate(dt_utz(2009, 11, 13, 4, 16, 20)), - '2009/11/12 20:16:20 -0800') - assert_equals(datetime_to_ghdate(dt_utz(2010, 4, 18, 0, 24, 29)), - '2010/04/17 17:24:29 -0700') - assert_equals(datetime_to_ghdate(dt_utz(2010, 5, 18, 13, 10, 36)), - '2010/05/18 06:10:36 -0700') - assert_equals(datetime_to_ghdate(dt_utz(2010, 5, 26, 5, 59, 37)), - '2010/05/25 22:59:37 -0700') - assert_equals(datetime_to_ghdate(dt_utz(2010, 5, 27, 0, 8, 41)), - '2010/05/26 17:08:41 -0700') - assert_equals(datetime_to_ghdate(dt_utz(2010, 6, 20, 13, 13, 37)), - '2010/06/20 06:13:37 -0700') - assert_equals(datetime_to_ghdate(dt_utz(2010, 7, 28, 19, 56, 51)), - '2010/07/28 12:56:51 -0700') - assert_equals(datetime_to_ghdate(dt_utz(2010, 9, 21, 4, 32, 49)), - '2010/09/20 21:32:49 -0700') + eq_(datetime_to_ghdate(dt_utz(2011, 5, 22, 7, 24, 15)), + '2011/05/22 00:24:15 -0700') + eq_(datetime_to_ghdate(dt_utz(2009, 4, 18, 20, 4, 9)), + '2009/04/18 13:04:09 -0700') + eq_(datetime_to_ghdate(dt_utz(2009, 11, 13, 4, 15, 17)), + '2009/11/12 20:15:17 -0800') + eq_(datetime_to_ghdate(dt_utz(2009, 11, 13, 4, 16, 20)), + '2009/11/12 20:16:20 -0800') + eq_(datetime_to_ghdate(dt_utz(2010, 4, 18, 0, 24, 29)), + '2010/04/17 17:24:29 -0700') + eq_(datetime_to_ghdate(dt_utz(2010, 5, 18, 13, 10, 36)), + '2010/05/18 06:10:36 -0700') + eq_(datetime_to_ghdate(dt_utz(2010, 5, 26, 5, 59, 37)), + '2010/05/25 22:59:37 -0700') + eq_(datetime_to_ghdate(dt_utz(2010, 5, 27, 0, 8, 41)), + '2010/05/26 17:08:41 -0700') + eq_(datetime_to_ghdate(dt_utz(2010, 6, 20, 13, 13, 37)), + '2010/06/20 06:13:37 -0700') + eq_(datetime_to_ghdate(dt_utz(2010, 7, 28, 19, 56, 51)), + '2010/07/28 12:56:51 -0700') + eq_(datetime_to_ghdate(dt_utz(2010, 9, 21, 4, 32, 49)), + '2010/09/20 21:32:49 -0700') def test_commitdate_to_datetime(): - assert_equals(string_to_datetime('2011-05-22T00:24:15-07:00'), - dt_utz(2011, 5, 22, 7, 24, 15)) - assert_equals(string_to_datetime('2011-04-09T10:07:30-07:00'), - dt_utz(2011, 4, 9, 17, 7, 30)) - assert_equals(string_to_datetime('2011-02-19T07:16:11-08:00'), - dt_utz(2011, 2, 19, 15, 16, 11)) - assert_equals(string_to_datetime('2010-12-21T12:34:27-08:00'), - dt_utz(2010, 12, 21, 20, 34, 27)) - assert_equals(string_to_datetime('2011-04-09T10:20:05-07:00'), - dt_utz(2011, 4, 9, 17, 20, 5)) - assert_equals(string_to_datetime('2011-04-09T10:05:58-07:00'), - dt_utz(2011, 4, 9, 17, 5, 58)) - assert_equals(string_to_datetime('2011-04-09T09:53:00-07:00'), - dt_utz(2011, 4, 9, 16, 53, 0)) - assert_equals(string_to_datetime('2011-04-09T10:00:21-07:00'), - dt_utz(2011, 4, 9, 17, 0, 21)) - assert_equals(string_to_datetime('2010-12-16T15:10:59-08:00'), - dt_utz(2010, 12, 16, 23, 10, 59)) - assert_equals(string_to_datetime('2011-04-09T09:53:00-07:00'), - dt_utz(2011, 4, 9, 16, 53, 0)) - assert_equals(string_to_datetime('2011-04-09T09:53:00-07:00'), - dt_utz(2011, 4, 9, 16, 53, 0)) + eq_(string_to_datetime('2011-05-22T00:24:15-07:00'), + dt_utz(2011, 5, 22, 7, 24, 15)) + eq_(string_to_datetime('2011-04-09T10:07:30-07:00'), + dt_utz(2011, 4, 9, 17, 7, 30)) + eq_(string_to_datetime('2011-02-19T07:16:11-08:00'), + dt_utz(2011, 2, 19, 15, 16, 11)) + eq_(string_to_datetime('2010-12-21T12:34:27-08:00'), + dt_utz(2010, 12, 21, 20, 34, 27)) + eq_(string_to_datetime('2011-04-09T10:20:05-07:00'), + dt_utz(2011, 4, 9, 17, 20, 5)) + eq_(string_to_datetime('2011-04-09T10:05:58-07:00'), + dt_utz(2011, 4, 9, 17, 5, 58)) + eq_(string_to_datetime('2011-04-09T09:53:00-07:00'), + dt_utz(2011, 4, 9, 16, 53, 0)) + eq_(string_to_datetime('2011-04-09T10:00:21-07:00'), + dt_utz(2011, 4, 9, 17, 0, 21)) + eq_(string_to_datetime('2010-12-16T15:10:59-08:00'), + dt_utz(2010, 12, 16, 23, 10, 59)) + eq_(string_to_datetime('2011-04-09T09:53:00-07:00'), + dt_utz(2011, 4, 9, 16, 53, 0)) + eq_(string_to_datetime('2011-04-09T09:53:00-07:00'), + dt_utz(2011, 4, 9, 16, 53, 0)) def test_datetime_to_commitdate(): - assert_equals(datetime_to_commitdate(dt_utz(2011, 5, 22, 7, 24, 15)), - '2011-05-22T00:24:15-07:00') - assert_equals(datetime_to_commitdate(dt_utz(2011, 4, 9, 17, 7, 30)), - '2011-04-09T10:07:30-07:00') - assert_equals(datetime_to_commitdate(dt_utz(2011, 2, 19, 15, 16, 11)), - '2011-02-19T07:16:11-08:00') - assert_equals(datetime_to_commitdate(dt_utz(2010, 12, 21, 20, 34, 27)), - '2010-12-21T12:34:27-08:00') - assert_equals(datetime_to_commitdate(dt_utz(2011, 4, 9, 17, 20, 5)), - '2011-04-09T10:20:05-07:00') - assert_equals(datetime_to_commitdate(dt_utz(2011, 4, 9, 17, 5, 58)), - '2011-04-09T10:05:58-07:00') - assert_equals(datetime_to_commitdate(dt_utz(2011, 4, 9, 16, 53, 0)), - '2011-04-09T09:53:00-07:00') - assert_equals(datetime_to_commitdate(dt_utz(2011, 4, 9, 17, 0, 21)), - '2011-04-09T10:00:21-07:00') - assert_equals(datetime_to_commitdate(dt_utz(2010, 12, 16, 23, 10, 59)), - '2010-12-16T15:10:59-08:00') - assert_equals(datetime_to_commitdate(dt_utz(2011, 4, 9, 16, 53, 0)), - '2011-04-09T09:53:00-07:00') - assert_equals(datetime_to_commitdate(dt_utz(2011, 4, 9, 16, 53, 0)), - '2011-04-09T09:53:00-07:00') + eq_(datetime_to_commitdate(dt_utz(2011, 5, 22, 7, 24, 15)), + '2011-05-22T00:24:15-07:00') + eq_(datetime_to_commitdate(dt_utz(2011, 4, 9, 17, 7, 30)), + '2011-04-09T10:07:30-07:00') + eq_(datetime_to_commitdate(dt_utz(2011, 2, 19, 15, 16, 11)), + '2011-02-19T07:16:11-08:00') + eq_(datetime_to_commitdate(dt_utz(2010, 12, 21, 20, 34, 27)), + '2010-12-21T12:34:27-08:00') + eq_(datetime_to_commitdate(dt_utz(2011, 4, 9, 17, 20, 5)), + '2011-04-09T10:20:05-07:00') + eq_(datetime_to_commitdate(dt_utz(2011, 4, 9, 17, 5, 58)), + '2011-04-09T10:05:58-07:00') + eq_(datetime_to_commitdate(dt_utz(2011, 4, 9, 16, 53, 0)), + '2011-04-09T09:53:00-07:00') + eq_(datetime_to_commitdate(dt_utz(2011, 4, 9, 17, 0, 21)), + '2011-04-09T10:00:21-07:00') + eq_(datetime_to_commitdate(dt_utz(2010, 12, 16, 23, 10, 59)), + '2010-12-16T15:10:59-08:00') + eq_(datetime_to_commitdate(dt_utz(2011, 4, 9, 16, 53, 0)), + '2011-04-09T09:53:00-07:00') + eq_(datetime_to_commitdate(dt_utz(2011, 4, 9, 16, 53, 0)), + '2011-04-09T09:53:00-07:00') def test_isodate_to_datetime(): - assert_equals(string_to_datetime('2011-05-22T00:24:15Z'), - dt_utz(2011, 5, 22, 0, 24, 15)) - assert_equals(string_to_datetime('2011-04-09T10:07:30Z'), - dt_utz(2011, 4, 9, 10, 7, 30)) - assert_equals(string_to_datetime('2011-02-19T07:16:11Z'), - dt_utz(2011, 2, 19, 7, 16, 11)) - assert_equals(string_to_datetime('2010-12-21T12:34:27Z'), - dt_utz(2010, 12, 21, 12, 34, 27)) - assert_equals(string_to_datetime('2011-04-09T10:20:05Z'), - dt_utz(2011, 4, 9, 10, 20, 5)) - assert_equals(string_to_datetime('2011-04-09T10:05:58Z'), - dt_utz(2011, 4, 9, 10, 5, 58)) - assert_equals(string_to_datetime('2011-04-09T09:53:00Z'), - dt_utz(2011, 4, 9, 9, 53, 0)) - assert_equals(string_to_datetime('2011-04-09T10:00:21Z'), - dt_utz(2011, 4, 9, 10, 0, 21)) - assert_equals(string_to_datetime('2010-12-16T15:10:59Z'), - dt_utz(2010, 12, 16, 15, 10, 59)) - assert_equals(string_to_datetime('2011-04-09T09:53:00Z'), - dt_utz(2011, 4, 9, 9, 53, 0)) - assert_equals(string_to_datetime('2011-04-09T09:53:00Z'), - dt_utz(2011, 4, 9, 9, 53, 0)) + eq_(string_to_datetime('2011-05-22T00:24:15Z'), + dt_utz(2011, 5, 22, 0, 24, 15)) + eq_(string_to_datetime('2011-04-09T10:07:30Z'), + dt_utz(2011, 4, 9, 10, 7, 30)) + eq_(string_to_datetime('2011-02-19T07:16:11Z'), + dt_utz(2011, 2, 19, 7, 16, 11)) + eq_(string_to_datetime('2010-12-21T12:34:27Z'), + dt_utz(2010, 12, 21, 12, 34, 27)) + eq_(string_to_datetime('2011-04-09T10:20:05Z'), + dt_utz(2011, 4, 9, 10, 20, 5)) + eq_(string_to_datetime('2011-04-09T10:05:58Z'), + dt_utz(2011, 4, 9, 10, 5, 58)) + eq_(string_to_datetime('2011-04-09T09:53:00Z'), + dt_utz(2011, 4, 9, 9, 53, 0)) + eq_(string_to_datetime('2011-04-09T10:00:21Z'), + dt_utz(2011, 4, 9, 10, 0, 21)) + eq_(string_to_datetime('2010-12-16T15:10:59Z'), + dt_utz(2010, 12, 16, 15, 10, 59)) + eq_(string_to_datetime('2011-04-09T09:53:00Z'), + dt_utz(2011, 4, 9, 9, 53, 0)) + eq_(string_to_datetime('2011-04-09T09:53:00Z'), + dt_utz(2011, 4, 9, 9, 53, 0)) def test_datetime_to_isodate(): - assert_equals(datetime_to_isodate(dt_utz(2011, 5, 22, 0, 24, 15)), - '2011-05-22T00:24:15Z') - assert_equals(datetime_to_isodate(dt_utz(2011, 4, 9, 10, 7, 30)), - '2011-04-09T10:07:30Z') - assert_equals(datetime_to_isodate(dt_utz(2011, 2, 19, 7, 16, 11)), - '2011-02-19T07:16:11Z') - assert_equals(datetime_to_isodate(dt_utz(2010, 12, 21, 12, 34, 27)), - '2010-12-21T12:34:27Z') - assert_equals(datetime_to_isodate(dt_utz(2011, 4, 9, 10, 20, 5)), - '2011-04-09T10:20:05Z') - assert_equals(datetime_to_isodate(dt_utz(2011, 4, 9, 10, 5, 58)), - '2011-04-09T10:05:58Z') - assert_equals(datetime_to_isodate(dt_utz(2011, 4, 9, 9, 53, 0)), - '2011-04-09T09:53:00Z') - assert_equals(datetime_to_isodate(dt_utz(2011, 4, 9, 10, 0, 21)), - '2011-04-09T10:00:21Z') - assert_equals(datetime_to_isodate(dt_utz(2010, 12, 16, 15, 10, 59)), - '2010-12-16T15:10:59Z') - assert_equals(datetime_to_isodate(dt_utz(2011, 4, 9, 9, 53, 0)), - '2011-04-09T09:53:00Z') - assert_equals(datetime_to_isodate(dt_utz(2011, 4, 9, 9, 53, 0)), - '2011-04-09T09:53:00Z') + eq_(datetime_to_isodate(dt_utz(2011, 5, 22, 0, 24, 15)), + '2011-05-22T00:24:15Z') + eq_(datetime_to_isodate(dt_utz(2011, 4, 9, 10, 7, 30)), + '2011-04-09T10:07:30Z') + eq_(datetime_to_isodate(dt_utz(2011, 2, 19, 7, 16, 11)), + '2011-02-19T07:16:11Z') + eq_(datetime_to_isodate(dt_utz(2010, 12, 21, 12, 34, 27)), + '2010-12-21T12:34:27Z') + eq_(datetime_to_isodate(dt_utz(2011, 4, 9, 10, 20, 5)), + '2011-04-09T10:20:05Z') + eq_(datetime_to_isodate(dt_utz(2011, 4, 9, 10, 5, 58)), + '2011-04-09T10:05:58Z') + eq_(datetime_to_isodate(dt_utz(2011, 4, 9, 9, 53, 0)), + '2011-04-09T09:53:00Z') + eq_(datetime_to_isodate(dt_utz(2011, 4, 9, 10, 0, 21)), + '2011-04-09T10:00:21Z') + eq_(datetime_to_isodate(dt_utz(2010, 12, 16, 15, 10, 59)), + '2010-12-16T15:10:59Z') + eq_(datetime_to_isodate(dt_utz(2011, 4, 9, 9, 53, 0)), + '2011-04-09T09:53:00Z') + eq_(datetime_to_isodate(dt_utz(2011, 4, 9, 9, 53, 0)), + '2011-04-09T09:53:00Z') diff --git a/tests/test_unit.py b/tests/test_unit.py index 7cd3113..104256d 100644 --- a/tests/test_unit.py +++ b/tests/test_unit.py @@ -1,11 +1,18 @@ # -*- coding: utf-8 -*- +# Copyright (C) 2010-2012 Adam Vandenberg +# James Rowe +# Jeremy Dunck +# modocache +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. -import datetime import unittest -from nose.tools import (assert_equals, assert_true) +from mock import patch +from nose.tools import (eq_, ok_, raises) -from github2.core import repr_string +from github2.core import (AuthError, repr_string, requires_auth) from github2.issues import Issue from github2.client import Github @@ -13,71 +20,97 @@ class ReprTests(unittest.TestCase): + """__repr__ must return strings, not unicode objects.""" def test_issue(self): """Issues can have non-ASCII characters in the title.""" title = 'abcdé' i = Issue(title=title) - assert_equals(str, type(repr(i))) + eq_(str, type(repr(i))) class HostSetting(unittest.TestCase): def test_default_host(self): client = Github() - assert_equals(client.request.github_url, 'https://github.com') + eq_(client.request.github_url, 'https://github.com') def test_non_standard_host(self): client = Github(github_url="http://your-github-enterprise-url.com/") - assert_equals(client.request.github_url, - 'http://your-github-enterprise-url.com/') + eq_(client.request.github_url, + 'http://your-github-enterprise-url.com/') class RateLimits(utils.HttpMockTestCase): - """Test API rate-limitting""" - def test_delays(self): - """Test call delay is at least one second""" + + """Test API rate-limiting.""" + + @patch('github2.request.time.sleep') + def test_delays(self, sleep): + """Test calls in quick succession are delayed.""" client = Github(requests_per_second=.5) client.users.show('defunkt') - start = datetime.datetime.utcnow() client.users.show('mojombo') - end = datetime.datetime.utcnow() - - delta = end - start - delta_seconds = delta.days * 24 * 60 * 60 + delta.seconds - assert_true(delta_seconds >= 2, - "Expected .5 reqs per second to require a 2 second delay " - "between calls.") + # 0.5 requests per second, means a two second delay + sleep.assert_called_once_with(2.0) class BaseDataIter(utils.HttpMockTestCase): - """Test iter availability of objects""" + + """Test iter availability of objects.""" + def test_iter(self): commit_id = '1c83cde9b5a7c396a01af1007fb7b88765b9ae45' commit = self.client.commits.show('ask/python-github2', commit_id) - assert_true('__iter__' in dir(commit)) + ok_('__iter__' in dir(commit)) class BaseDataDict(utils.HttpMockTestCase): - """Test __getitem__ availability on objects""" + + """Test dict compatibility on objects.""" + def test_getitem(self): user = self.client.users.show('defunkt') - assert_equals(user['blog'], user.blog) - assert_equals(user['company'], user.company) - assert_equals(user['email'], user.email) - assert_equals(user['location'], user.location) - assert_equals(user['login'], user.login) - assert_equals(user['name'], user.name) + eq_(user['blog'], user.blog) + eq_(user['company'], user.company) + eq_(user['email'], user.email) + eq_(user['location'], user.location) + eq_(user['login'], user.login) + eq_(user['name'], user.name) + + @raises(KeyError) + def test_getitem_failure(self): + user = self.client.users.show('defunkt') + ok_(user['invalid_key']) + + def test_setitem(self): + user = self.client.users.show('defunkt') + user['blog'] = 'http://example.com' + eq_(user['blog'], 'http://example.com') + + @raises(KeyError) + def test_setitem_failure(self): + user = self.client.users.show('defunkt') + user['invalid_key'] = 'test' def test_project_for_user_repo(): client = Github() - assert_equals(client.project_for_user_repo('JNRowe', 'misc-overlay'), + eq_(client.project_for_user_repo('JNRowe', 'misc-overlay'), 'JNRowe/misc-overlay') def test_repr_string(): - assert_equals(repr_string('test'), 'test') - assert_equals(repr_string('abcdefghijklmnopqrst'), 'abcdefghijklmnopqrst') - assert_equals(repr_string('abcdefghijklmnopqrstu'), 'abcdefghijklmnopq...') + eq_(repr_string('test'), 'test') + eq_(repr_string('abcdefghijklmnopqrst'), 'abcdefghijklmnopqrst') + eq_(repr_string('abcdefghijklmnopqrstu'), 'abcdefghijklmnopq...') + + +class RequiresAuth(utils.HttpMockTestCase): + @raises(AuthError) + def test_no_auth(self): + f = lambda: None + f.__doc__ = 'test func' + wrapped = requires_auth(f) + wrapped(self.client) diff --git a/tests/test_user.py b/tests/test_user.py index aff6ad5..c2fab11 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -1,58 +1,66 @@ +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + import datetime -from nose.tools import (assert_equals, assert_false, assert_true) +from nose.tools import (eq_, assert_false, ok_) import utils class UserProperties(utils.HttpMockTestCase): - """Test user property handling""" + + """Test user property handling.""" + def test_user(self): user = self.client.users.show('defunkt') - assert_equals(user.blog, 'http://chriswanstrath.com/') - assert_equals(user.company, 'GitHub') - assert_equals(user.email, 'chris@wanstrath.com') - assert_equals(user.location, 'San Francisco') - assert_equals(user.login, 'defunkt') - assert_equals(user.name, 'Chris Wanstrath') + eq_(user.blog, 'http://chriswanstrath.com/') + eq_(user.company, 'GitHub') + eq_(user.email, 'chris@wanstrath.com') + eq_(user.location, 'San Francisco') + eq_(user.login, 'defunkt') + eq_(user.name, 'Chris Wanstrath') def test_meta(self): user = self.client.users.show('defunkt') - assert_equals(user.created_at, - datetime.datetime(2007, 10, 19, 22, 24, 19)) - assert_equals(user.followers_count, 3402) - assert_equals(user.following_count, 212) - assert_equals(user.gravatar_id, 'b8dbb1987e8e5318584865f880036796') - assert_equals(user.id, 2) - assert_equals(user.public_gist_count, 278) - assert_equals(user.public_repo_count, 93) + eq_(user.created_at, datetime.datetime(2007, 10, 19, 22, 24, 19)) + eq_(user.followers_count, 3402) + eq_(user.following_count, 212) + eq_(user.gravatar_id, 'b8dbb1987e8e5318584865f880036796') + eq_(user.id, 2) + eq_(user.public_gist_count, 278) + eq_(user.public_repo_count, 93) def test_followers(self): - assert_equals(len(self.client.users.followers('defunkt')), 3402) + eq_(len(self.client.users.followers('defunkt')), 3402) def test_following(self): - assert_equals(len(self.client.users.following('defunkt')), 212) + eq_(len(self.client.users.following('defunkt')), 212) def test_is_not_authenticated(self): user = self.client.users.show('defunkt') - assert_true(user.is_authenticated() is False) + ok_(user.is_authenticated() is False) class UserQueries(utils.HttpMockTestCase): - """Test user querying """ + + """Test user querying.""" + def test_search(self): - assert_equals(repr(self.client.users.search('James Rowe')), - '[, ]') + eq_(repr(self.client.users.search('James Rowe')), + '[, ]') def test_search_by_email(self): user = self.client.users.search_by_email('jnrowe@gmail.com') - assert_equals(repr(user), '') + eq_(repr(user), '') class AuthenticatedUserMethods(utils.HttpMockAuthenticatedTestCase): def test_follow(self): result = self.client.users.follow('defunkt') - assert_true('defunkt' in result['users']) + ok_('defunkt' in result['users']) def test_unfollow(self): result = self.client.users.unfollow('defunkt') @@ -60,25 +68,25 @@ def test_unfollow(self): def test_is_authenticated(self): user = self.client.users.show('') - assert_true(user.is_authenticated() is True) + ok_(user.is_authenticated() is True) def test_list_keys(self): keys = self.client.users.list_keys() - assert_equals(keys[0].id, 1337) + eq_(keys[0].id, 1337) class AuthenticatedUserProperties(utils.HttpMockAuthenticatedTestCase): def test_private_data(self): user = self.client.users.show('') - assert_equals(user.total_private_repo_count, 0) - assert_equals(user.collaborators, 0) - assert_equals(user.disk_usage, 66069) - assert_equals(user.owned_private_repo_count, 0) - assert_equals(user.private_gist_count, 7) + eq_(user.total_private_repo_count, 0) + eq_(user.collaborators, 0) + eq_(user.disk_usage, 66069) + eq_(user.owned_private_repo_count, 0) + eq_(user.private_gist_count, 7) def test_plan_data(self): user = self.client.users.show('') - assert_equals(user.plan['name'], "free") - assert_equals(user.plan['collaborators'], 0) - assert_equals(user.plan['space'], 307200) - assert_equals(user.plan['private_repos'], 0) + eq_(user.plan['name'], "free") + eq_(user.plan['collaborators'], 0) + eq_(user.plan['space'], 307200) + eq_(user.plan['private_repos'], 0) diff --git a/tests/utils.py b/tests/utils.py index 78fb8c4..313836e 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,3 +1,8 @@ +# Copyright (C) 2011-2012 James Rowe +# +# This file is part of python-github2, and is made available under the 3-clause +# BSD license. See LICENSE for the full details. + import os import sys import unittest @@ -6,6 +11,8 @@ import httplib2 +from mock import Mock + from github2.client import Github from github2.request import charset_from_headers @@ -14,85 +21,62 @@ bytes = lambda x, enc: x -HTTP_DATA_DIR = "tests/data/" +ORIG_REQUEST_METHOD = httplib2.Http.request -ORIG_HTTP_OBJECT = httplib2.Http +def request_mock(uri, method='GET', body=None, headers=None, + redirections=5, connection_type=None): + """Http mock side effect that returns saved entries. -class HttpMock(object): - """Simple Http mock that returns saved entries + Implementation tests should never span network boundaries. - Implementation tests should never span network boundaries """ - def __init__(self, cache=None, timeout=None, proxy_info=None, - ca_certs=None): - """Create a mock httplib.Http object - - .. attribute: called_with - - ``locals()`` during ``__init__``, for testing call spec - """ - self.called_with = locals() - - def request(self, uri, method='GET', body=None, headers=None, - redirections=5, connection_type=None): - file = os.path.join(HTTP_DATA_DIR, httplib2.safename(uri)) - if os.path.exists(file): - response = message_from_file(open(file)) - headers = httplib2.Response(response) - body = bytes(response.get_payload(), charset_from_headers(headers)) - return (headers, body) - else: - return (httplib2.Response({"status": "404"}), - "Resource %r unavailable from test data store" % file) + file = os.path.join("tests/data", httplib2.safename(uri)) + if os.path.exists(file): + response = message_from_file(open(file)) + headers = httplib2.Response(response) + body = bytes(response.get_payload(), charset_from_headers(headers)) + return (headers, body) + else: + return (httplib2.Response({"status": "404"}), + "Resource %r unavailable from test data store" % file) class HttpMockTestCase(unittest.TestCase): def setUp(self): - """Prepare test fixtures + """Prepare test fixtures. `httplib2.Http` is patched to return cached entries via :class:`HttpMock`. :attr:`client` is an unauthenticated :obj:`Github` object for easy use in tests. + """ - httplib2.Http = HttpMock + httplib2.Http.request = Mock(spec_set=httplib2.Http.request, + side_effect=request_mock) self.client = Github() def tearDown(self): - """Remove test fixtures + """Remove test fixtures. `httplib2.Http` is returned to its original state. + """ - httplib2.Http = ORIG_HTTP_OBJECT + httplib2.Http.request = ORIG_REQUEST_METHOD class HttpMockAuthenticatedTestCase(HttpMockTestCase): def setUp(self): - """Prepare test fixtures + """Prepare test fixtures. :see: :class:`HttpMockTestCase` :attr:`client` is an authenticated :obj:`Github` object for easy use in tests. + """ - httplib2.Http = HttpMock + httplib2.Http.request = Mock(spec_set=httplib2.Http.request, + side_effect=request_mock) self.client = Github(access_token='xxx') - - -def set_http_mock(): - """Function to enable ``Http`` mock - - This is useful in simple `nose`-compliant test functions - """ - httplib2.Http = HttpMock - - -def unset_http_mock(): - """Function to disable ``Http`` mock - - :see: :func:`set_http_mock` - """ - httplib2.Http = ORIG_HTTP_OBJECT diff --git a/tox.ini b/tox.ini index 531bac9..ffb9775 100644 --- a/tox.ini +++ b/tox.ini @@ -6,8 +6,28 @@ envlist = py24, py25, py26, py27, py31, py32, rst, sphinx deps = nose coverage + mock commands = nosetests {posargs:-vv} tests +# When tox 1.4 is released use substitution to remove all the duplication. +[testenv:py24] +deps = + nose + coverage + mock + unittest2 +[testenv:py25] +deps = + nose + coverage + mock + unittest2 +[testenv:py26] +deps = + nose + coverage + mock + unittest2 [testenv:rst] deps = docutils