diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..0faea60 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +github: chfw +patreon: chfw diff --git a/.github/workflows/moban-update.yml b/.github/workflows/moban-update.yml new file mode 100644 index 0000000..ef8e30a --- /dev/null +++ b/.github/workflows/moban-update.yml @@ -0,0 +1,27 @@ +on: [push] + +jobs: + run_moban: + runs-on: ubuntu-latest + name: synchronize templates via moban + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.7' + - name: check changes + run: | + pip install moban gitfs2 pypifs + moban + git status + git diff --exit-code + - name: Auto-commit + if: failure() + uses: docker://cdssnc/auto-commit-github-action + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: This is an auto-commit diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml new file mode 100644 index 0000000..9e7ec42 --- /dev/null +++ b/.github/workflows/pythonpublish.yml @@ -0,0 +1,26 @@ +name: Upload Python Package + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python setup.py sdist bdist_wheel + twine upload dist/* diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000..d2e943a --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,12 @@ +[settings] +line_length=79 +# Ignore generated files +skip=setup.py, moban/__init__.py +known_third_party=crayons, requests, mock, nose +indent=' ' +multi_line_output=3 +length_sort=1 +include_trailing_comma=true +default_section=FIRSTPARTY +no_lines_before=LOCALFOLDER +sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER diff --git a/.moban.d/CUSTOM_README.rst.jj2 b/.moban.d/CUSTOM_README.rst.jj2 index d48c254..1dcf765 100644 --- a/.moban.d/CUSTOM_README.rst.jj2 +++ b/.moban.d/CUSTOM_README.rst.jj2 @@ -4,14 +4,8 @@ {%endblock%} {%block features%} -:: - - A long long time ago, ancient developers do not have the command to do a github - release. They relied on mouse clicks and web user interface to do their releases. - Until 2017, they got a specialized command, **{{command_line_interface}}** and realized release management - is no long a manual job. -**{{name}}** {{description}}. +It's understood that you may use github cli, however **{{name}}** {{description}}. .. image:: https://github.com/{{organisation}}/{{name}}/raw/master/images/cli.png :width: 600px @@ -59,6 +53,21 @@ Command Line gs gease v0.0.2 "second great release" + +:: +contributors list the contributors of a repo. version 0.0.4 + +Usage: contributors user/org repo + +Where: + user/org is the your github username or orgnisation name + repo is the repository name + +Examples: + + contributors pyexcel pyexcel-io + + License ================================================================================ diff --git a/.moban.d/tests/requirements.txt.jj2 b/.moban.d/tests/requirements.txt.jj2 deleted file mode 100644 index 895f5ee..0000000 --- a/.moban.d/tests/requirements.txt.jj2 +++ /dev/null @@ -1,7 +0,0 @@ -nose -codecov -coverage -flake8 -mock -{%block extras %} -{%endblock%} diff --git a/.moban.yml b/.moban.yml index 7d1d452..4455185 100644 --- a/.moban.yml +++ b/.moban.yml @@ -1,6 +1,7 @@ configuration: template_dir: - - "setupmobans/templates" + - "git://github.com/moremoban/pypi-mobans.git?submodule=true&brach=dev!/templates" + - "git://github.com/moremoban/pypi-mobans.git?submodule=true&brach=dev!/statics" - ".moban.d" configuration: gease.yml targets: @@ -10,3 +11,10 @@ targets: - "tests/requirements.txt": "tests/requirements.txt.jj2" - test.sh: test.script.jj2 - 'gease/_version.py': 'version.py.jj2' + - ".github/workflows/pythonpublish.yml": "pythonpublish.yml" + - output: CHANGELOG.rst + configuration: changelog.yml + template: CHANGELOG.rst.jj2 + - Makefile: Makefile.jj2 + - format.sh: format.sh.jj2 + - lint.sh: lint.script.jj2 diff --git a/.travis.yml b/.travis.yml index 9130de1..7296944 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,7 @@ notifications: email: false python: - 3.6 - - 3.5 - - 3.4 - - 3.3 - - 2.7 - - pypy + - 3.7 before_install: - pip install -r tests/requirements.txt script: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c786f94..a6f8fbb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,26 +1,31 @@ Change log -=========== +================================================================================ -v0.0.3 - 25.11.2017 +0.0.4 - 21.08.2020 -------------------------------------------------------------------------------- -added -******************************************************************************** +**Added** -#. `issue 1`_, release repos of the +#. get contributors of a github repo + +0.0.3 - 25.11.2017 +-------------------------------------------------------------------------------- + +**Added** + +#. `#1 `_: release repos of the organisation that you belong to. -v0.0.2 - 15.10.2017 +0.0.2 - 15.10.2017 -------------------------------------------------------------------------------- -updated -******************************************************************************** +**Added** #. quit with -1 if github responds with error - -v0.0.1 - 13.10.2017 +0.0.1 - 13.10.2017 -------------------------------------------------------------------------------- -First release. Make a release from command line +**Added** +#. First release. diff --git a/Makefile b/Makefile index 26d9b68..d7e640e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,19 @@ all: test -test: +test: lint bash test.sh -document: - bash document.sh +install_test: + pip install -r tests/requirements.txt + +git-diff-check: + git diff --exit-code + +lint: + bash lint.sh + +format: + bash format.sh + +git-diff-check: + git diff --exit-code diff --git a/README.rst b/README.rst index e8bad94..c46d822 100644 --- a/README.rst +++ b/README.rst @@ -2,21 +2,23 @@ gease - gITHUB RELease ================================================================================ -.. image:: https://api.travis-ci.org/moremoban/gease.svg?branch=master +.. image:: https://api.travis-ci.org/moremoban/gease.svg :target: http://travis-ci.org/moremoban/gease -.. image:: https://codecov.io/gh/moremoban/gease/branch/master/graph/badge.svg - :target: https://codecov.io/gh/moremoban/gease +.. image:: https://codecov.io/github/moremoban/gease/coverage.png + :target: https://codecov.io/github/moremoban/gease +.. image:: https://badge.fury.io/py/gease.svg + :target: https://pypi.org/project/gease +.. image:: https://pepy.tech/badge/gease/month + :target: https://pepy.tech/project/gease/month + +.. image:: https://img.shields.io/github/stars/moremoban/gease.svg?style=social&maxAge=3600&label=Star + :target: https://github.com/moremoban/gease/stargazers -:: - A long long time ago, ancient developers do not have the command to do a github - release. They relied on mouse clicks and web user interface to do their releases. - Until 2017, they got a specialized command, **gs** and realized release management - is no long a manual job. -**gease** simply makes a git release using github api v3. +It's understood that you may use github cli, however **gease** simply makes a git release using github api v3. .. image:: https://github.com/moremoban/gease/raw/master/images/cli.png :width: 600px @@ -81,8 +83,22 @@ Command Line gs gease v0.0.2 "second great release" + +:: +contributors list the contributors of a repo. version 0.0.4 + +Usage: contributors user/org repo + +Where: + user/org is the your github username or orgnisation name + repo is the repository name + +Examples: + + contributors pyexcel pyexcel-io + + License ================================================================================ MIT - diff --git a/changelog.yml b/changelog.yml new file mode 100644 index 0000000..6de97ea --- /dev/null +++ b/changelog.yml @@ -0,0 +1,27 @@ +name: gease +organisation: moremoban +releases: + - changes: + - action: Added + details: + - get contributors of a github repo + date: 21.08.2020 + version: 0.0.4 + - changes: + - action: Added + details: + - "`#1`: release repos of the organisation that you belong to." + date: 25.11.2017 + version: 0.0.3 + - changes: + - action: Added + details: + - quit with -1 if github responds with error + date: 15.10.2017 + version: 0.0.2 + - changes: + - action: Added + details: + - First release. + date: 13.10.2017 + version: 0.0.1 diff --git a/format.sh b/format.sh new file mode 100644 index 0000000..063d1ef --- /dev/null +++ b/format.sh @@ -0,0 +1,3 @@ +isort $(find gease -name "*.py"|xargs echo) $(find tests -name "*.py"|xargs echo) +black -l 79 gease +black -l 79 tests diff --git a/gease.yml b/gease.yml index b4b0307..cfa82c6 100644 --- a/gease.yml +++ b/gease.yml @@ -4,12 +4,15 @@ organisation: "moremoban" author: "C. W." contact: "wangc_2011@hotmail.com" company: "Onni Software Ltd." -version: "0.0.3" -current_version: 0.0.3 -release: "0.0.3" -copyright_year: 2017 -command_line_interface: "gs" +version: "0.0.4" +current_version: 0.0.4 +release: "0.0.4" +copyright_year: 2017-2020 +command_line_interface: gease entry_point: "gease.main:main" +entry_points: + console_scripts: + - "contributors = gease.contributors:main" include_doctest: true nodocs: true license: MIT diff --git a/gease/__init__.py b/gease/__init__.py index c961145..cfc0cdd 100644 --- a/gease/__init__.py +++ b/gease/__init__.py @@ -1,3 +1,2 @@ # flake8: noqa -from gease._version import __version__ -from gease._version import __author__ +from gease._version import __author__, __version__ diff --git a/gease/_version.py b/gease/_version.py index deee25d..e86918d 100644 --- a/gease/_version.py +++ b/gease/_version.py @@ -1,3 +1,3 @@ -__version__ = '0.0.3' +__version__ = '0.0.4' __author__ = 'C. W.' __description__ = 'simply makes a git release using github api v3' diff --git a/gease/constants.py b/gease/constants.py index d4613ad..65b1cc8 100644 --- a/gease/constants.py +++ b/gease/constants.py @@ -1,6 +1,6 @@ -DEFAULT_GEASE_FILE_NAME = '.gease' +DEFAULT_GEASE_FILE_NAME = ".gease" DEFAULT_RELEASE_MESSAGE = "A new release via gease." -NOT_ENOUGH_ARGS = 'Not enough arguments' -KEY_GEASE_USER = 'user' -KEY_GEASE_TOKEN = 'personal_access_token' -MESSAGE_FMT_RELEASED = 'Release is created at: %s' +NOT_ENOUGH_ARGS = "Not enough arguments" +KEY_GEASE_USER = "user" +KEY_GEASE_TOKEN = "personal_access_token" +MESSAGE_FMT_RELEASED = "Release is created at: %s" diff --git a/gease/contributors.py b/gease/contributors.py new file mode 100644 index 0000000..b39b32e --- /dev/null +++ b/gease/contributors.py @@ -0,0 +1,104 @@ +""" + contributors + ~~~~~~ + get a list of contributors + + :copyright: (c) 2020 by Onni Software Ltd. + :license: MIT License, see LICENSE for more details + +""" +import sys + +import crayons + +import gease.utils as utils +import gease.constants as constants +import gease.exceptions as exceptions +from gease.rest import Api +from gease._version import __version__ +from gease.uritemplate import UriTemplate + +HELP = """%s. version %s + +Usage: %s + +Where: + user/org is the your github username or orgnisation name + repo is the repository name + +Examples: + + contributors pyexcel pyexcel-io +""" % ( + crayons.yellow("contributors list the contributors of a repo"), + crayons.magenta(__version__, bold=True), + crayons.yellow("contributors user/org repo", bold=True), +) +REPO_URL = "https://api.github.com/repos{/owner}{/repo}/contributors" + + +class EndPoint(object): + """ + Github authenticated user's repo endpoint + """ + + def __init__(self, owner, repo): + self.__template = UriTemplate(REPO_URL) + self.__template.owner = owner + self.__template.repo = repo + self.__client = Api.get_api() + + @property + def url(self): + return str(self.__template) + + def get_all_contributors(self): + json_reply = self.__client.get(self.url) + print(json_reply) + contributors = [] + for user in json_reply: + user_details = self.__client.get(user["url"]) + contributors.append( + {"name": user_details["name"], "url": user["url"]} + ) + return contributors + + +def main(): + if len(sys.argv) < 3: + if len(sys.argv) == 2: + error(constants.NOT_ENOUGH_ARGS) + print(HELP) + sys.exit(-1) + + user = sys.argv[1] + repo = sys.argv[2] + try: + repo = EndPoint(user, repo) + message = repo.get_all_contributors() + print(message) + except exceptions.RepoNotFoundError: + fatal("%s does not exist!" % repo) + except exceptions.AbnormalGithubResponse as e: + fatal(str(e)) + except exceptions.NoGeaseConfigFound as e: + fatal(str(e)) + except KeyError as e: + fatal("Key %s is not found" % str(e)) + + +def get_default_user(): + return utils.get_info(constants.KEY_GEASE_USER) + + +def error(message): + print("Error: %s" % crayons.red(message)) + + +def fatal(message): + error(message) + sys.exit(-1) + + +if __name__ == "__main__": + main() diff --git a/gease/main.py b/gease/main.py index 119daf0..fa24446 100644 --- a/gease/main.py +++ b/gease/main.py @@ -8,15 +8,15 @@ :license: MIT License, see LICENSE for more details """ - import sys + import crayons -from gease._version import __version__, __description__ -from gease.release import EndPoint import gease.utils as utils import gease.constants as constants import gease.exceptions as exceptions +from gease.release import EndPoint +from gease._version import __version__, __description__ HELP = """%s. version %s @@ -32,9 +32,9 @@ gs gease v0.0.1 first great release gs gease v0.0.2 "second great release" """ % ( - crayons.yellow('gease ' + __description__), + crayons.yellow("gease " + __description__), crayons.magenta(__version__, bold=True), - crayons.yellow('gs repo tag [release message]', bold=True), + crayons.yellow("gs repo tag [release message]", bold=True), ) @@ -72,7 +72,7 @@ def get_default_user(): def error(message): - print('Error: %s' % crayons.red(message)) + print("Error: %s" % crayons.red(message)) def fatal(message): @@ -80,5 +80,5 @@ def fatal(message): sys.exit(-1) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/gease/orgs.py b/gease/orgs.py index 5b5adc2..da6b083 100644 --- a/gease/orgs.py +++ b/gease/orgs.py @@ -9,7 +9,8 @@ """ from gease.rest import Api -REPO_URL = 'https://api.github.com/user/orgs' + +REPO_URL = "https://api.github.com/user/orgs" class EndPoint(object): diff --git a/gease/release.py b/gease/release.py index 2aee418..ee5c393 100644 --- a/gease/release.py +++ b/gease/release.py @@ -9,16 +9,15 @@ """ -from gease.rest import Api +import gease.exceptions as exceptions from gease.orgs import EndPoint as Orgs from gease.repo import EndPoint as Repo +from gease.rest import Api from gease.uritemplate import UriTemplate -import gease.exceptions as exceptions - -RELEASE_URL = 'https://api.github.com/repos{/owner}{/repo}/releases' -KEY_HTML_URL = 'html_url' -MESSAGE_MISSING_KEY = 'No %s in github repsonse' % KEY_HTML_URL +RELEASE_URL = "https://api.github.com/repos{/owner}{/repo}/releases" +KEY_HTML_URL = "html_url" +MESSAGE_MISSING_KEY = "No %s in github repsonse" % KEY_HTML_URL class EndPoint(object): @@ -28,6 +27,7 @@ class EndPoint(object): More documentation is available at https://developer.github.com/v3/repos/releases/ """ + def __init__(self, owner, repo): self.__template = UriTemplate(RELEASE_URL) self.__template.owner = owner @@ -56,13 +56,14 @@ def publish(self, **kwargs): return self.republish(**kwargs) except exceptions.RepoNotFoundError: raise exceptions.AbnormalGithubResponse( - self.__template.repo + " does not exist!") + self.__template.repo + " does not exist!" + ) except KeyError: - raise exceptions.AbnormalGithubResponse( - MESSAGE_MISSING_KEY) + raise exceptions.AbnormalGithubResponse(MESSAGE_MISSING_KEY) except exceptions.ReleaseExistException: raise exceptions.AbnormalGithubResponse( - "Release or tag %s exists" % kwargs['tag_name']) + "Release or tag %s exists" % kwargs["tag_name"] + ) except exceptions.UnhandledException as e: raise exceptions.AbnormalGithubResponse(str(e)) @@ -80,8 +81,8 @@ def republish(self, **kwargs): def which_org_has(repo): orgs = Orgs() for org_info in orgs.get_all_organisations(): - org_repo = Repo(org_info['repos_url']) + org_repo = Repo(org_info["repos_url"]) for arepo in org_repo.get_all_repos(): - if repo == arepo['name']: - return org_info['login'] + if repo == arepo["name"]: + return org_info["login"] return None diff --git a/gease/repo.py b/gease/repo.py index 74ed69d..d87d21a 100644 --- a/gease/repo.py +++ b/gease/repo.py @@ -9,7 +9,8 @@ """ from gease.rest import Api -REPO_URL = 'https://api.github.com/user/repos' + +REPO_URL = "https://api.github.com/user/repos" class EndPoint(object): diff --git a/gease/rest.py b/gease/rest.py index 3dbb31d..13e15f0 100644 --- a/gease/rest.py +++ b/gease/rest.py @@ -20,12 +20,14 @@ class Api(object): """ A session holder so that each request shares the same token """ + __instance = None def __init__(self, personal_access_token): self.__session = requests.Session() - self.__session.headers.update({ - 'Authorization': 'token %s' % personal_access_token}) + self.__session.headers.update( + {"Authorization": "token %s" % personal_access_token} + ) def create(self, url, data): """ @@ -38,13 +40,15 @@ def create(self, url, data): raise exceptions.ReleaseExistException() elif r.status_code == 401: response = r.json() - message = '%s. Please check your gease file' % response['message'] + message = "%s. Please check your gease file" % response["message"] raise exceptions.AbnormalGithubResponse(message) elif r.status_code == 404: raise exceptions.RepoNotFoundError() else: - message = 'Github responded with HTTP %s, %s ' % ( - r.status_code, r.text) + message = "Github responded with HTTP %s, %s " % ( + r.status_code, + r.text, + ) raise exceptions.UnhandledException(message) def get(self, url): diff --git a/gease/uritemplate.py b/gease/uritemplate.py index f164e06..bdde7e2 100644 --- a/gease/uritemplate.py +++ b/gease/uritemplate.py @@ -42,6 +42,7 @@ class UriTemplate(object): False """ + def __init__(self, url_template_string): self.__s = url_template_string self.__variables = extract_variables(self.__s) @@ -72,14 +73,14 @@ def __get_dict(self): a_new_dict = {} for v in self.__variables: if self.__dict__[v]: - a_new_dict['/' + v] = '/' + self.__dict__[v] + a_new_dict["/" + v] = "/" + self.__dict__[v] else: - a_new_dict['/' + v] = '{/' + v + '}' + a_new_dict["/" + v] = "{/" + v + "}" return a_new_dict def extract_variables(url_template_string): - results = re.findall('\{/([^}]+)\}', url_template_string) + results = re.findall("\{/([^}]+)\}", url_template_string) return results diff --git a/gease/utils.py b/gease/utils.py index 98a39d9..2b916f3 100644 --- a/gease/utils.py +++ b/gease/utils.py @@ -1,8 +1,9 @@ import os import json -import gease.exceptions as exceptions import gease.constants as constants +import gease.exceptions as exceptions + try: FileNotFoundError except NameError: @@ -13,13 +14,11 @@ def get_info(key): """ Find geasefile from user's home folder """ - home_dir = os.path.expanduser('~') - geasefile = os.path.join(home_dir, - constants.DEFAULT_GEASE_FILE_NAME) + home_dir = os.path.expanduser("~") + geasefile = os.path.join(home_dir, constants.DEFAULT_GEASE_FILE_NAME) try: - with open(geasefile, 'r') as config: + with open(geasefile, "r") as config: gease = json.load(config) return gease[key] except FileNotFoundError: - raise exceptions.NoGeaseConfigFound( - 'Cannot find %s' % geasefile) + raise exceptions.NoGeaseConfigFound("Cannot find %s" % geasefile) diff --git a/lint.sh b/lint.sh new file mode 100644 index 0000000..6907d07 --- /dev/null +++ b/lint.sh @@ -0,0 +1,3 @@ +pip install flake8 +flake8 . --exclude=.moban.d,docs,setup.py --builtins=unicode,xrange,long +python setup.py checkdocs diff --git a/setup.py b/setup.py index afe9d79..11d630d 100644 --- a/setup.py +++ b/setup.py @@ -1,63 +1,87 @@ -# Template by setupmobans +#!/usr/bin/env python3 + +""" +Template by pypi-mobans +""" + import os import sys import codecs +import locale +import platform from shutil import rmtree -from setuptools import setup, find_packages, Command + +from setuptools import Command, setup, find_packages + PY2 = sys.version_info[0] == 2 PY26 = PY2 and sys.version_info[1] < 7 - -NAME = 'gease' -AUTHOR = 'C. W.' -VERSION = '0.0.3' -EMAIL = 'wangc_2011@hotmail.com' -LICENSE = 'MIT' +PY33 = sys.version_info < (3, 4) + +# Work around mbcs bug in distutils. +# http://bugs.python.org/issue10945 +# This work around is only if a project supports Python < 3.4 + +# Work around for locale not being set +try: + lc = locale.getlocale() + pf = platform.system() + if pf != "Windows" and lc == (None, None): + locale.setlocale(locale.LC_ALL, "C.UTF-8") +except (ValueError, UnicodeError, locale.Error): + locale.setlocale(locale.LC_ALL, "en_US.UTF-8") + +NAME = "gease" +AUTHOR = "C. W." +VERSION = "0.0.4" +EMAIL = "wangc_2011@hotmail.com" +LICENSE = "MIT" ENTRY_POINTS = { - 'console_scripts': [ - 'gs = gease.main:main' - ] + "console_scripts": [ + "gease = gease.main:main", + "contributors = gease.contributors:main", + ], } DESCRIPTION = ( - 'simply makes a git release using github api v3' + - '' + "simply makes a git release using github api v3" ) -URL = 'https://github.com/moremoban/gease' -DOWNLOAD_URL = '%s/archive/0.0.3.tar.gz' % URL -FILES = ['README.rst', 'CHANGELOG.rst'] +URL = "https://github.com/moremoban/gease" +DOWNLOAD_URL = "%s/archive/0.0.4.tar.gz" % URL +FILES = ["README.rst", "CHANGELOG.rst"] KEYWORDS = [ - 'python' + "python", ] CLASSIFIERS = [ - 'Topic :: Office/Business', - 'Topic :: Utilities', - 'Topic :: Software Development :: Libraries', - 'Programming Language :: Python', - 'Intended Audience :: Developers', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', + "Topic :: Software Development :: Libraries", + "Programming Language :: Python", + "Intended Audience :: Developers", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + ] + INSTALL_REQUIRES = [ - 'crayons', - 'requests', + "crayons", + "requests", ] +SETUP_COMMANDS = {} - -PACKAGES = find_packages(exclude=['ez_setup', 'examples', 'tests']) +PACKAGES = find_packages(exclude=["ez_setup", "examples", "tests", "tests.*"]) EXTRAS_REQUIRE = { } # You do not need to read beyond this line -PUBLISH_COMMAND = '{0} setup.py sdist bdist_wheel upload -r pypi'.format( - sys.executable) -GS_COMMAND = ('gs gease v0.0.3 ' + - "Find 0.0.3 in changelog for more details") -NO_GS_MESSAGE = ('Automatic github release is disabled. ' + - 'Please install gease to enable it.') +PUBLISH_COMMAND = "{0} setup.py sdist bdist_wheel upload -r pypi".format(sys.executable) +GS_COMMAND = ("gs gease v0.0.4 " + + "Find 0.0.4 in changelog for more details") +NO_GS_MESSAGE = ("Automatic github release is disabled. " + + "Please install gease to enable it.") UPLOAD_FAILED_MSG = ( 'Upload failed. please run "%s" yourself.' % PUBLISH_COMMAND) HERE = os.path.abspath(os.path.dirname(__file__)) @@ -66,13 +90,13 @@ class PublishCommand(Command): """Support setup.py upload.""" - description = 'Build and publish the package on github and pypi' + description = "Build and publish the package on github and pypi" user_options = [] @staticmethod def status(s): """Prints things in bold.""" - print('\033[1m{0}\033[0m'.format(s)) + print("\033[1m{0}\033[0m".format(s)) def initialize_options(self): pass @@ -82,12 +106,14 @@ def finalize_options(self): def run(self): try: - self.status('Removing previous builds...') - rmtree(os.path.join(HERE, 'dist')) + self.status("Removing previous builds...") + rmtree(os.path.join(HERE, "dist")) + rmtree(os.path.join(HERE, "build")) + rmtree(os.path.join(HERE, "gease.egg-info")) except OSError: pass - self.status('Building Source and Wheel (universal) distribution...') + self.status("Building Source and Wheel (universal) distribution...") run_status = True if has_gease(): run_status = os.system(GS_COMMAND) == 0 @@ -95,11 +121,16 @@ def run(self): self.status(NO_GS_MESSAGE) if run_status: if os.system(PUBLISH_COMMAND) != 0: - self.status(UPLOAD_FAILED_MSG % PUBLISH_COMMAND) + self.status(UPLOAD_FAILED_MSG) sys.exit() +SETUP_COMMANDS.update({ + "publish": PublishCommand +}) + + def has_gease(): """ test if github release command is installed @@ -124,7 +155,8 @@ def read_files(*files): def read(afile): """Read a file into setup""" - with codecs.open(afile, 'r', 'utf-8') as opened_file: + the_relative_file = os.path.join(HERE, afile) + with codecs.open(the_relative_file, "r", "utf-8") as opened_file: content = filter_out_test_code(opened_file) content = "".join(list(content)) return content @@ -133,11 +165,11 @@ def read(afile): def filter_out_test_code(file_handle): found_test_code = False for line in file_handle.readlines(): - if line.startswith('.. testcode:'): + if line.startswith(".. testcode:"): found_test_code = True continue if found_test_code is True: - if line.startswith(' '): + if line.startswith(" "): continue else: empty_line = line.strip() @@ -147,15 +179,16 @@ def filter_out_test_code(file_handle): found_test_code = False yield line else: - for keyword in ['|version|', '|today|']: + for keyword in ["|version|", "|today|"]: if keyword in line: break else: yield line -if __name__ == '__main__': +if __name__ == "__main__": setup( + test_suite="tests", name=NAME, author=AUTHOR, version=VERSION, @@ -167,14 +200,12 @@ def filter_out_test_code(file_handle): license=LICENSE, keywords=KEYWORDS, extras_require=EXTRAS_REQUIRE, - tests_require=['nose'], + tests_require=["nose"], install_requires=INSTALL_REQUIRES, packages=PACKAGES, include_package_data=True, zip_safe=False, entry_points=ENTRY_POINTS, classifiers=CLASSIFIERS, - cmdclass={ - 'publish': PublishCommand, - } + cmdclass=SETUP_COMMANDS ) diff --git a/test.sh b/test.sh index a851940..8b28874 100644 --- a/test.sh +++ b/test.sh @@ -1,2 +1,2 @@ pip freeze -nosetests --with-coverage --cover-package gease --cover-package tests --with-doctest --doctest-extension=.rst README.rst tests gease && flake8 . --exclude=.moban.d --builtins=unicode,xrange,long +nosetests --with-coverage --cover-package gease --cover-package tests tests --with-doctest --doctest-extension=.rst README.rst gease diff --git a/tests/requirements.txt b/tests/requirements.txt index c445df5..0c3a80f 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,5 +1,10 @@ nose -mock +mock;python_version<"3" codecov coverage flake8 +black +isort +collective.checkdocs +pygments +moban diff --git a/tests/test_api.py b/tests/test_api.py index 959f8ee..0ff4389 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,29 +1,29 @@ +from mock import MagicMock, patch from nose.tools import raises -from gease.rest import Api -from gease.exceptions import ReleaseExistException -from gease.exceptions import AbnormalGithubResponse -from gease.exceptions import RepoNotFoundError -from mock import patch, MagicMock +from gease.rest import Api +from gease.exceptions import ( + RepoNotFoundError, + ReleaseExistException, + AbnormalGithubResponse, +) SAMPLE_422_ERROR = { - 'errors': [ - {'code': 'already_exists', - 'field': 'tag_name', - 'resource': 'Release'} + "errors": [ + {"code": "already_exists", "field": "tag_name", "resource": "Release"} ], - 'documentation_url': 'https://.../#create-a-release', - 'message': 'Validation Failed' + "documentation_url": "https://.../#create-a-release", + "message": "Validation Failed", } WRONG_CREDENTIALS = { "message": "Bad credentials", - "documentation_url": "https://developer.github.com/v3" + "documentation_url": "https://developer.github.com/v3", } class TestApi: def setUp(self): - self.patcher = patch('gease.rest.requests.Session') + self.patcher = patch("gease.rest.requests.Session") self.fake_session = self.patcher.start() def tearDown(self): @@ -33,13 +33,12 @@ def test_create(self): self.fake_session.return_value = MagicMock( post=MagicMock( return_value=MagicMock( - status_code=201, - json=MagicMock(return_value={}) + status_code=201, json=MagicMock(return_value={}) ) ) ) - api = Api('test') - api.create('http://localhost/', 'cool') + api = Api("test") + api.create("http://localhost/", "cool") @raises(ReleaseExistException) def test_existing_release(self): @@ -47,12 +46,12 @@ def test_existing_release(self): post=MagicMock( return_value=MagicMock( status_code=422, - json=MagicMock(return_value=SAMPLE_422_ERROR) + json=MagicMock(return_value=SAMPLE_422_ERROR), ) ) ) - api = Api('test') - api.create('http://localhost/', 'cool') + api = Api("test") + api.create("http://localhost/", "cool") @raises(AbnormalGithubResponse) def test_wrong_credentials(self): @@ -60,12 +59,12 @@ def test_wrong_credentials(self): post=MagicMock( return_value=MagicMock( status_code=401, - json=MagicMock(return_value=WRONG_CREDENTIALS) + json=MagicMock(return_value=WRONG_CREDENTIALS), ) ) ) - api = Api('test') - api.create('http://localhost/', 'cool') + api = Api("test") + api.create("http://localhost/", "cool") @raises(RepoNotFoundError) def test_404(self): @@ -73,22 +72,21 @@ def test_404(self): post=MagicMock( return_value=MagicMock( status_code=404, - json=MagicMock(return_value=WRONG_CREDENTIALS) + json=MagicMock(return_value=WRONG_CREDENTIALS), ) ) ) - api = Api('test') - api.create('http://localhost/', 'cool') + api = Api("test") + api.create("http://localhost/", "cool") @raises(Exception) def test_unknown_error(self): self.fake_session.return_value = MagicMock( post=MagicMock( return_value=MagicMock( - status_code=400, - json=MagicMock(return_value={}) + status_code=400, json=MagicMock(return_value={}) ) ) ) - api = Api('test') - api.create('http://localhost/', 'cool') + api = Api("test") + api.create("http://localhost/", "cool") diff --git a/tests/test_contributors.py b/tests/test_contributors.py new file mode 100644 index 0000000..7069225 --- /dev/null +++ b/tests/test_contributors.py @@ -0,0 +1,49 @@ +from mock import MagicMock, patch +from nose.tools import eq_, raises + +import gease.exceptions as exceptions +from gease.contributors import EndPoint + + +class TestPublish: + @patch("gease.contributors.Api.get_api") + def test_all_contributors(self, fake_api): + sample_reply = [ + { + "login": "howdy", + "id": 4280312, + "node_id": "MDQ6VXNlcjQyODAzMTI=", + "avatar_url": "https://avatars0.githubusercontent.com/u/4280312?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/howdy", + "html_url": "https://github.com/howdy", + "followers_url": "https://api.github.com/users/howdy/followers", + "following_url": "https://api.github.com/users/howdy/following{/other_user}", + "gists_url": "https://api.github.com/users/howdy/gists{/gist_id}", + "starred_url": "https://api.github.com/users/howdy/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/howdy/subscriptions", + "organizations_url": "https://api.github.com/users/howdy/orgs", + "repos_url": "https://api.github.com/users/howdy/repos", + "events_url": "https://api.github.com/users/howdy/events{/privacy}", + "received_events_url": "https://api.github.com/users/howdy/received_events", + "type": "User", + "site_admin": False, + "contributions": 259, + } + ] + fake_api.return_value = MagicMock( + get=MagicMock(side_effect=[sample_reply, {"name": "hello world"}]) + ) + + repo = EndPoint("test", "repo") + contributors = repo.get_all_contributors() + + eq_( + contributors, + [ + { + "name": "hello world", + "url": "https://api.github.com/users/howdy", + } + ], + ) diff --git a/tests/test_main.py b/tests/test_main.py index bb65adc..c8d0e36 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,24 +1,24 @@ import os import sys + import mock -from gease.main import main -from gease.constants import DEFAULT_RELEASE_MESSAGE -from gease.main import fatal -import gease.exceptions as exceptions from nose.tools import raises -TEST_TAG = 'tag' -SHORT_ARGS = ['gs', 'repo', TEST_TAG] +import gease.exceptions as exceptions +from gease.main import main, fatal +from gease.constants import DEFAULT_RELEASE_MESSAGE +TEST_TAG = "tag" +SHORT_ARGS = ["gs", "repo", TEST_TAG] -class TestMain: +class TestMain: def setUp(self): - self.patcher = mock.patch('gease.utils.os.path.expanduser') + self.patcher = mock.patch("gease.utils.os.path.expanduser") self.fake_expand = self.patcher.start() - self.fake_expand.return_value = os.path.join('tests', 'fixtures') + self.fake_expand.return_value = os.path.join("tests", "fixtures") - self.patcher2 = mock.patch('gease.main.EndPoint') + self.patcher2 = mock.patch("gease.main.EndPoint") self.fake_release = self.patcher2.start() def tearDown(self): @@ -28,76 +28,79 @@ def tearDown(self): @raises(SystemExit) def test_key_error_in_main(self): self.fake_expand.return_value = os.path.join( - 'tests', 'fixtures', 'malformed') - with mock.patch.object(sys, 'argv', SHORT_ARGS): + "tests", "fixtures", "malformed" + ) + with mock.patch.object(sys, "argv", SHORT_ARGS): main() @raises(SystemExit) def test_no_gease_file_in_main(self): - self.fake_expand.return_value = os.path.join('tests') - with mock.patch.object(sys, 'argv', SHORT_ARGS): + self.fake_expand.return_value = os.path.join("tests") + with mock.patch.object(sys, "argv", SHORT_ARGS): main() def test_good_commands(self): create_method = mock.MagicMock( - return_value='http://localhost/tag/testurl') + return_value="http://localhost/tag/testurl" + ) self.fake_release.return_value = mock.MagicMock(publish=create_method) - with mock.patch.object(sys, 'argv', SHORT_ARGS): + with mock.patch.object(sys, "argv", SHORT_ARGS): main() create_method.assert_called_with( - tag_name=TEST_TAG, - name=TEST_TAG, - body=DEFAULT_RELEASE_MESSAGE) + tag_name=TEST_TAG, name=TEST_TAG, body=DEFAULT_RELEASE_MESSAGE + ) def test_custom_release_message(self): - release_message = ['hello', 'world', 'you', 'see', 'it'] + release_message = ["hello", "world", "you", "see", "it"] create_method = mock.MagicMock( - return_value='http://localhost/tag/testurl') + return_value="http://localhost/tag/testurl" + ) self.fake_release.return_value = mock.MagicMock(publish=create_method) - with mock.patch.object(sys, 'argv', SHORT_ARGS + release_message): + with mock.patch.object(sys, "argv", SHORT_ARGS + release_message): main() create_method.assert_called_with( tag_name=TEST_TAG, name=TEST_TAG, - body=' '.join(release_message)) + body=" ".join(release_message), + ) def test_quoted_release_message(self): - release_message = 'hello world you see it' + release_message = "hello world you see it" create_method = mock.MagicMock( - return_value='http://localhost/tag/testurl') + return_value="http://localhost/tag/testurl" + ) self.fake_release.return_value = mock.MagicMock(publish=create_method) - with mock.patch.object(sys, 'argv', SHORT_ARGS + [release_message]): + with mock.patch.object(sys, "argv", SHORT_ARGS + [release_message]): main() create_method.assert_called_with( - tag_name=TEST_TAG, - name=TEST_TAG, - body=release_message) + tag_name=TEST_TAG, name=TEST_TAG, body=release_message + ) @raises(SystemExit) def test_error_response(self): create_method = mock.MagicMock( - side_effect=exceptions.AbnormalGithubResponse) + side_effect=exceptions.AbnormalGithubResponse + ) self.fake_release.return_value = mock.MagicMock(publish=create_method) - with mock.patch.object(sys, 'argv', SHORT_ARGS): + with mock.patch.object(sys, "argv", SHORT_ARGS): main() create_method.assert_called_with( - tag_name=TEST_TAG, - name=TEST_TAG, - body=DEFAULT_RELEASE_MESSAGE) + tag_name=TEST_TAG, name=TEST_TAG, body=DEFAULT_RELEASE_MESSAGE + ) @raises(SystemExit) def test_no_args(): - with mock.patch.object(sys, 'argv', []): + with mock.patch.object(sys, "argv", []): main() @raises(SystemExit) def test_insufficent_args(): - with mock.patch.object(sys, 'argv', SHORT_ARGS[:2]): + with mock.patch.object(sys, "argv", SHORT_ARGS[:2]): main() @raises(SystemExit) def test_fatal_message(): - fatal('message and we quit') + fatal("message and we quit") diff --git a/tests/test_misc.py b/tests/test_misc.py index 495dfdc..e0d4fe2 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1,24 +1,24 @@ -from mock import patch, MagicMock +from mock import MagicMock, patch +from nose.tools import eq_ + from gease.orgs import EndPoint as Org from gease.repo import EndPoint as Repo -from nose.tools import eq_ -class TestOrgEndPoint(): +class TestOrgEndPoint: def setUp(self): - self.patcher = patch('gease.orgs.Api') + self.patcher = patch("gease.orgs.Api") self.fake_api_singleton = self.patcher.start() self.get = MagicMock() self.fake_api_singleton.get_api = MagicMock( - return_value=MagicMock( - get=self.get - )) + return_value=MagicMock(get=self.get) + ) def tearDown(self): self.patcher.stop() def test_orgs(self): - test_return = 'hei' + test_return = "hei" self.get.return_value = test_return org = Org() @@ -26,21 +26,20 @@ def test_orgs(self): eq_(test_return, response) -class TestRepoEndPoint(): +class TestRepoEndPoint: def setUp(self): - self.patcher = patch('gease.repo.Api') + self.patcher = patch("gease.repo.Api") self.fake_api_singleton = self.patcher.start() self.get = MagicMock() self.fake_api_singleton.get_api = MagicMock( - return_value=MagicMock( - get=self.get - )) + return_value=MagicMock(get=self.get) + ) def tearDown(self): self.patcher.stop() def test_repo(self): - test_return = 'hei' + test_return = "hei" self.get.return_value = test_return repo = Repo() diff --git a/tests/test_release.py b/tests/test_release.py index a31c96b..a24ec24 100644 --- a/tests/test_release.py +++ b/tests/test_release.py @@ -1,19 +1,19 @@ -from nose.tools import raises, eq_ -from gease.release import EndPoint -from mock import patch, MagicMock +from mock import MagicMock, patch +from nose.tools import eq_, raises + import gease.exceptions as exceptions +from gease.release import EndPoint class TestPublish: - def setUp(self): - self.patcher = patch('gease.release.Api') + self.patcher = patch("gease.release.Api") self.fake_api_singleton = self.patcher.start() self.fake_api = MagicMock() self.fake_api_singleton.get_api = self.fake_api - self.patcher2 = patch('gease.rest.get_token') + self.patcher2 = patch("gease.rest.get_token") self.fake_token = self.patcher2.start() - self.fake_token.return_value = 'token' + self.fake_token.return_value = "token" def tearDown(self): self.patcher2.stop() @@ -21,64 +21,52 @@ def tearDown(self): def test_create_release(self): self.fake_api.return_value = MagicMock( - create=MagicMock( - return_value={'html_url': 'aurl'} - ) + create=MagicMock(return_value={"html_url": "aurl"}) ) - release = EndPoint('owner', 'repo') - release.publish(hello='world') + release = EndPoint("owner", "repo") + release.publish(hello="world") @raises(exceptions.AbnormalGithubResponse) def test_unknown_error(self): self.fake_api.return_value = MagicMock( - create=MagicMock( - return_value={} - ) - ) - release = EndPoint('owner', 'repo') - release.publish(hello='world') + create=MagicMock(return_value={}) + ) + release = EndPoint("owner", "repo") + release.publish(hello="world") @raises(exceptions.AbnormalGithubResponse) def test_release_exist(self): self.fake_api.return_value = MagicMock( - create=MagicMock( - side_effect=exceptions.ReleaseExistException - ) - ) - release = EndPoint('owner', 'repo') - release.publish(hello='world', tag_name='existing tag') + create=MagicMock(side_effect=exceptions.ReleaseExistException) + ) + release = EndPoint("owner", "repo") + release.publish(hello="world", tag_name="existing tag") @raises(exceptions.AbnormalGithubResponse) def test_repo_not_found(self): self.fake_api.return_value = MagicMock( - create=MagicMock( - side_effect=exceptions.RepoNotFoundError - ) - ) - release = EndPoint('owner', 'repo') - release.republish = MagicMock( - side_effect=exceptions.RepoNotFoundError) - release.publish(hello='world') + create=MagicMock(side_effect=exceptions.RepoNotFoundError) + ) + release = EndPoint("owner", "repo") + release.republish = MagicMock(side_effect=exceptions.RepoNotFoundError) + release.publish(hello="world") @raises(exceptions.AbnormalGithubResponse) def test_unhandled_exception(self): self.fake_api.return_value = MagicMock( - create=MagicMock( - side_effect=exceptions.UnhandledException - ) - ) - release = EndPoint('owner', 'repo') - release.publish(hello='world') + create=MagicMock(side_effect=exceptions.UnhandledException) + ) + release = EndPoint("owner", "repo") + release.publish(hello="world") class TestRepublish: - def setUp(self): - self.patcher = patch('gease.release.Orgs') + self.patcher = patch("gease.release.Orgs") self.fake_orgs = self.patcher.start() - self.patcher2 = patch('gease.release.Repo') + self.patcher2 = patch("gease.release.Repo") self.fake_repo = self.patcher2.start() - self.patcher3 = patch('gease.release.Api') + self.patcher3 = patch("gease.release.Api") self.fake_api_singleton = self.patcher3.start() self.fake_api = MagicMock() self.fake_api_singleton.get_api = self.fake_api @@ -89,31 +77,18 @@ def tearDown(self): self.patcher.stop() def test_create_release(self): - test_url = 'special url' + test_url = "special url" self.fake_orgs.return_value = MagicMock( get_all_organisations=MagicMock( - return_value=[ - { - "repos_url": 'repo', - "login": "zhangfei" - } - ] + return_value=[{"repos_url": "repo", "login": "zhangfei"}] ) ) self.fake_repo.return_value = MagicMock( - get_all_repos=MagicMock( - return_value=[ - { - "name": "repo" - } - ])) + get_all_repos=MagicMock(return_value=[{"name": "repo"}]) + ) self.fake_api.return_value = MagicMock( - create=MagicMock( - return_value={ - 'html_url': test_url - } - ) - ) - release = EndPoint('owner', 'repo') - ret = release.republish(hello='world') + create=MagicMock(return_value={"html_url": test_url}) + ) + release = EndPoint("owner", "repo") + ret = release.republish(hello="world") eq_(ret, test_url) diff --git a/tests/test_uritemplate.py b/tests/test_uritemplate.py index a4e68fa..feeb096 100644 --- a/tests/test_uritemplate.py +++ b/tests/test_uritemplate.py @@ -1,54 +1,52 @@ from nose.tools import eq_ -from gease.uritemplate import extract_variables -from gease.uritemplate import UriTemplate -from gease.uritemplate import is_partial +from gease.uritemplate import UriTemplate, is_partial, extract_variables def test_extract_variables(): - url = '{/abc}{/dde}' + url = "{/abc}{/dde}" variables = extract_variables(url) - eq_(variables, ['abc', 'dde']) + eq_(variables, ["abc", "dde"]) def test_extract_variables_got_empty(): - url = '' + url = "" variables = extract_variables(url) eq_(variables, []) def test_uri_template_variable(): - template = UriTemplate('http://abc{/cute}') + template = UriTemplate("http://abc{/cute}") assert template.cute is None def test_uri_template_template(): - template = UriTemplate('http://abc{/cute}') - template.cute = 'world' - eq_(str(template), 'http://abc/world') + template = UriTemplate("http://abc{/cute}") + template.cute = "world" + eq_(str(template), "http://abc/world") def test_uri_template_template2(): - template = UriTemplate('http://abc{/cute}') - eq_(template(cute='world'), 'http://abc/world') + template = UriTemplate("http://abc{/cute}") + eq_(template(cute="world"), "http://abc/world") def test_uri_template_partial_apply(): - template = UriTemplate('http://abc{/cute}{/left}') - eq_(template(cute='world'), 'http://abc/world{/left}') + template = UriTemplate("http://abc{/cute}{/left}") + eq_(template(cute="world"), "http://abc/world{/left}") def test_is_partial(): - url = '{/abc}' + url = "{/abc}" assert is_partial(url) is True def test_is_partial_2(): - url = UriTemplate('{/abc}') + url = UriTemplate("{/abc}") assert url.is_partial() is True def test_get_original_template(): - original = '{/abc}' - url = UriTemplate('{/abc}') + original = "{/abc}" + url = UriTemplate("{/abc}") assert url.get_template_string() is original diff --git a/tests/test_utils.py b/tests/test_utils.py index 10e051c..5ac2463 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,33 +1,35 @@ import os + from mock import patch -from gease.utils import get_info -import gease.exceptions as exceptions -import gease.constants as constants from nose.tools import eq_, raises +import gease.constants as constants +import gease.exceptions as exceptions +from gease.utils import get_info -class TestMain: +class TestMain: def setUp(self): - self.patcher = patch('gease.utils.os.path.expanduser') + self.patcher = patch("gease.utils.os.path.expanduser") self.fake_expand = self.patcher.start() - self.fake_expand.return_value = os.path.join('tests', 'fixtures') + self.fake_expand.return_value = os.path.join("tests", "fixtures") def tearDown(self): self.patcher.stop() def test_get_token(self): - self.fake_expand.return_value = os.path.join('tests', 'fixtures') + self.fake_expand.return_value = os.path.join("tests", "fixtures") user = get_info(constants.KEY_GEASE_TOKEN) - eq_(user, 'test') + eq_(user, "test") @raises(exceptions.NoGeaseConfigFound) def test_no_gease_file(self): - self.fake_expand.return_value = os.path.join('tests') + self.fake_expand.return_value = os.path.join("tests") get_info(constants.KEY_GEASE_TOKEN) @raises(KeyError) def test_wrong_key(self): self.fake_expand.return_value = os.path.join( - 'tests', 'fixtures', 'malformed') + "tests", "fixtures", "malformed" + ) get_info(constants.KEY_GEASE_TOKEN)