pax_global_header00006660000000000000000000000064134107232540014513gustar00rootroot0000000000000052 comment=d039c3714276232543ee3d0e06d2a96a3960e61d sphinx-issues-1.2.0/000077500000000000000000000000001341072325400143355ustar00rootroot00000000000000sphinx-issues-1.2.0/.gitignore000066400000000000000000000006011341072325400163220ustar00rootroot00000000000000*.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # Complexity output/*.html output/*/index.html # Sphinx docs/_build README.html sphinx-issues-1.2.0/.pre-commit-config.yaml000066400000000000000000000005311341072325400206150ustar00rootroot00000000000000repos: - repo: https://github.com/ambv/black rev: 18.9b0 hooks: - id: black language_version: python3.6 - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.0.0 hooks: - id: flake8 - repo: https://github.com/asottile/blacken-docs rev: v0.3.0 hooks: - id: blacken-docs additional_dependencies: [black==18.9b0] sphinx-issues-1.2.0/.travis.yml000066400000000000000000000014331341072325400164470ustar00rootroot00000000000000language: python sudo: false cache: pip install: travis_retry pip install -U tox script: tox jobs: fast_finish: true include: - { python: '3.6', env: TOXENV=lint } - { python: '2.7', env: TOXENV=py27 } - { python: '3.5', env: TOXENV=py35 } - { python: '3.6', env: TOXENV=py36 } - { python: '3.7', env: TOXENV=py37, dist: xenial, sudo: true } - stage: PyPI Release if: tag IS present python: "3.6" env: [] install: skip script: skip deploy: provider: pypi user: sloria on: tags: true distributions: sdist bdist_wheel password: secure: D0c2PYyI06+N5/inLaPHkEaM/GVgKVPCBDm2asmQvCTs14ory9KK17cnS+tOmrTNyMzw2tYSvD1Ar5a7MQAfcJ+p2bOnr/UCLqzt98H2LlE/2NJdzQtI3FtNCkhRVx20LK85G8ZWaHCecGIkgGmbIDZ56u1Aj+G16z0PqEz5i7s= sphinx-issues-1.2.0/CONTRIBUTING.md000066400000000000000000000010751341072325400165710ustar00rootroot00000000000000# Contributing ## Setting up for development * Create and activate a new virtual environment * `pip install -e '.[dev]'` * (Optional but recommended) If you're using a Python 3.6 virtual environment, install the pre-commit hooks, which will format and lint your git staged files: ``` # The pre-commit CLI was installed above pre-commit install ``` * To run tests: ``` pytest ``` * To run syntax checks: ``` tox -e lint ``` * (Optional) To run tests on Python 2.7, 3.5, 3.6, and 3.7 virtual environments (must have each interpreter installed): ``` tox ``` sphinx-issues-1.2.0/LICENSE000066400000000000000000000020341341072325400153410ustar00rootroot00000000000000Copyright 2018 Steven Loria Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sphinx-issues-1.2.0/MANIFEST.in000066400000000000000000000000261341072325400160710ustar00rootroot00000000000000include *.rst LICENSE sphinx-issues-1.2.0/NOTICE000066400000000000000000000026421341072325400152450ustar00rootroot00000000000000sphinx-issues includes code adapted from other libraries. Their licenses are included here. releases License ================ Copyright (c) 2014, Jeff Forcier All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. sphinx-issues-1.2.0/README.rst000066400000000000000000000072061341072325400160310ustar00rootroot00000000000000============= sphinx-issues ============= .. image:: https://travis-ci.org/sloria/sphinx-issues.svg?branch=master :target: https://travis-ci.org/sloria/sphinx-issues A Sphinx extension for linking to your project's issue tracker. Includes roles for linking to issues, pull requests, user profiles, with built-in support for GitHub (though this works with other services). Example ******* For an example usage, check out `marshmallow's changelog `_, which makes use of the roles in this library. Installation and Configuration ****************************** .. code-block:: console pip install sphinx-issues Add ``sphinx_issues`` to ``extensions`` in your ``conf.py``. If your project is on GitHub, add the ``issues_github_path`` config variable. Otherwise, use ``issues_uri`` and ``issues_pr_uri``. .. code-block:: python # docs/conf.py # ... extensions = [ # ... "sphinx_issues" ] # Github repo issues_github_path = "sloria/marshmallow" # equivalent to issues_uri = "https://github.com/sloria/marshmallow/issues/{issue}" issues_pr_uri = "https://github.com/sloria/marshmallow/pull/{pr}" issues_commit_uri = "https://github.com/sloria/marshmallow/commit/{commit}" Usage ***** Use the ``:issue:`` and ``:pr:`` roles in your docs like so: .. code-block:: rst See issue :issue:`42` See issues :issue:`12,13` See :issue:`sloria/konch#45`. See PR :pr:`58` Use the ``:user:`` role in your docs to link to user profiles (Github by default, but can be configured via the ``issues_user_uri`` config variable). .. code-block:: rst Thanks to :user:`bitprophet` for the idea! You can also use explicit names if you want to use a different name than the github user name: .. code-block:: rst This change is due to :user:`Andreas Mueller `. Use the ``:commit:`` role to link to commits. .. code-block:: rst Fixed in :commit:`6bb9124d5e9dbb2f7b52864c3d8af7feb1b69403`. Use the ``:cve:`` role to link to CVEs on https://cve.mitre.org. .. code-block:: rst :cve:`CVE-2018-17175` - Addresses possible vulnerability when... Credits ******* Credit goes to Jeff Forcier for his work on the `releases `_ extension, which is a full-featured solution for generating changelogs. I just needed a quick way to reference Github issues in my docs, so I yoinked the bits that I needed. License ******* MIT licensed. See the bundled `LICENSE `_ file for more details. Changelog ********* 1.2.0 (2018-12-26) ------------------ - Add ``:commit:`` role for linking to commits. - Add support for linking to external repos. - Test against Python 3.7. 1.1.0 (2018-09-18) ------------------ - Add ``:cve:`` role for linking to CVEs on https://cve.mitre.org. 1.0.0 (2018-07-14) ------------------ - Add ``:pr:`` role. Thanks @jnotham for the suggestion. - Drop support for Python 3.4. 0.4.0 (2017-11-25) ------------------ - Raise ``ValueError`` if neither ``issues_uri`` nor ``issues_github_path`` is set. Thanks @jnothman for the PR. - Drop support for Python 2.6 and 3.3. 0.3.1 (2017-01-16) ------------------ - ``setup`` returns metadata, preventing warnings about parallel reads and writes. Thanks @jfinkels for reporting. 0.3.0 (2016-10-20) ------------------ - Support anchor text for ``:user:`` role. Thanks @jnothman for the suggestion and thanks @amueller for the PR. 0.2.0 (2014-12-22) ------------------ - Add ``:user:`` role for linking to Github user profiles. 0.1.0 (2014-12-21) ------------------ - Initial release. sphinx-issues-1.2.0/setup.cfg000066400000000000000000000004431341072325400161570ustar00rootroot00000000000000[metadata] # This includes the license file in the wheel. license_file = LICENSE [bdist_wheel] universal = 1 [flake8] ignore = E203, E266, E501, W503, E302, W504 max-line-length = 100 max-complexity = 18 select = B,C,E,F,W,T4,B9 exclude = .git,.ropeproject,.tox,build,env,venv,__pycache__ sphinx-issues-1.2.0/setup.py000077500000000000000000000037261341072325400160620ustar00rootroot00000000000000# -*- coding: utf-8 -*- import re from setuptools import setup INSTALL_REQUIRES = ["sphinx"] EXTRAS_REQUIRE = { "tests": ["pytest", 'mock; python_version < "3.0"'], "lint": [ "flake8==3.6.0", 'flake8-bugbear==18.8.0; python_version >= "3.5"', "pre-commit==1.13.0", ], } EXTRAS_REQUIRE["dev"] = EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["lint"] + ["tox"] def find_version(fname): """Attempts to find the version number in the file names fname. Raises RuntimeError if not found. """ version = "" with open(fname, "r") as fp: reg = re.compile(r'__version__ = [\'"]([^\'"]*)[\'"]') for line in fp: m = reg.match(line) if m: version = m.group(1) break if not version: raise RuntimeError("Cannot find version information") return version def read(fname): with open(fname) as fp: content = fp.read() return content setup( name="sphinx-issues", version=find_version("sphinx_issues.py"), description="A Sphinx extension for linking to your project's " "issue tracker", long_description=read("README.rst"), install_requires=INSTALL_REQUIRES, extras_require=EXTRAS_REQUIRE, author="Steven Loria", author_email="sloria1@gmail.com", url="https://github.com/sloria/sphinx-issues", license="MIT", keywords="sphinx issues github", classifiers=[ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Documentation", ], py_modules=["sphinx_issues"], project_urls={"Issues": "https://github.com/sloria/sphinx-issues/issues"}, ) sphinx-issues-1.2.0/sphinx_issues.py000066400000000000000000000156411341072325400176220ustar00rootroot00000000000000# -*- coding: utf-8 -*- """A Sphinx extension for linking to your project's issue tracker.""" import re from docutils import nodes, utils from sphinx.util.nodes import split_explicit_title __version__ = "1.2.0" __author__ = "Steven Loria" __license__ = "MIT" def user_role(name, rawtext, text, lineno, inliner, options=None, content=None): """Sphinx role for linking to a user profile. Defaults to linking to Github profiles, but the profile URIS can be configured via the ``issues_user_uri`` config value. Examples: :: :user:`sloria` Anchor text also works: :: :user:`Steven Loria ` """ options = options or {} content = content or [] has_explicit_title, title, target = split_explicit_title(text) target = utils.unescape(target).strip() title = utils.unescape(title).strip() config = inliner.document.settings.env.app.config if config.issues_user_uri: ref = config.issues_user_uri.format(user=target) else: ref = "https://github.com/{0}".format(target) if has_explicit_title: text = title else: text = "@{0}".format(target) link = nodes.reference(text=text, refuri=ref, **options) return [link], [] def cve_role(name, rawtext, text, lineno, inliner, options=None, content=None): """Sphinx role for linking to a CVE on https://cve.mitre.org. Examples: :: :cve:`CVE-2018-17175` """ options = options or {} content = content or [] has_explicit_title, title, target = split_explicit_title(text) target = utils.unescape(target).strip() title = utils.unescape(title).strip() ref = "https://cve.mitre.org/cgi-bin/cvename.cgi?name={0}".format(target) text = title if has_explicit_title else target link = nodes.reference(text=text, refuri=ref, **options) return [link], [] class IssueRole(object): EXTERNAL_REPO_REGEX = re.compile(r"^(\w+)/(.+)([#@])([\w]+)$") def __init__( self, uri_config_option, format_kwarg, github_uri_template, format_text=None ): self.uri_config_option = uri_config_option self.format_kwarg = format_kwarg self.github_uri_template = github_uri_template self.format_text = format_text or self.default_format_text @staticmethod def default_format_text(issue_no): return "#{0}".format(issue_no) def make_node(self, name, issue_no, config, options=None): name_map = {"pr": "pull", "issue": "issues", "commit": "commit"} options = options or {} repo_match = self.EXTERNAL_REPO_REGEX.match(issue_no) if repo_match: # External repo username, repo, symbol, issue = repo_match.groups() if name not in name_map: raise ValueError( "External repo linking not supported for :{}:".format(name) ) path = name_map.get(name) ref = "https://github.com/{issues_github_path}/{path}/{n}".format( issues_github_path="{}/{}".format(username, repo), path=path, n=issue ) formatted_issue = self.format_text(issue).lstrip("#") text = "{username}/{repo}{symbol}{formatted_issue}".format(**locals()) link = nodes.reference(text=text, refuri=ref, **options) return link if issue_no not in ("-", "0"): uri_template = getattr(config, self.uri_config_option, None) if uri_template: ref = uri_template.format(**{self.format_kwarg: issue_no}) elif config.issues_github_path: ref = self.github_uri_template.format( issues_github_path=config.issues_github_path, n=issue_no ) else: raise ValueError( "Neither {} nor issues_github_path " "is set".format(self.uri_config_option) ) issue_text = self.format_text(issue_no) link = nodes.reference(text=issue_text, refuri=ref, **options) else: link = None return link def __call__( self, name, rawtext, text, lineno, inliner, options=None, content=None ): options = options or {} content = content or [] issue_nos = [each.strip() for each in utils.unescape(text).split(",")] config = inliner.document.settings.env.app.config ret = [] for i, issue_no in enumerate(issue_nos): node = self.make_node(name, issue_no, config, options=options) ret.append(node) if i != len(issue_nos) - 1: sep = nodes.raw(text=", ", format="html") ret.append(sep) return ret, [] """Sphinx role for linking to an issue. Must have `issues_uri` or `issues_github_path` configured in ``conf.py``. Examples: :: :issue:`123` :issue:`42,45` :issue:`sloria/konch#123` """ issue_role = IssueRole( uri_config_option="issues_uri", format_kwarg="issue", github_uri_template="https://github.com/{issues_github_path}/issues/{n}", ) """Sphinx role for linking to a pull request. Must have `issues_pr_uri` or `issues_github_path` configured in ``conf.py``. Examples: :: :pr:`123` :pr:`42,45` :pr:`sloria/konch#43` """ pr_role = IssueRole( uri_config_option="issues_pr_uri", format_kwarg="pr", github_uri_template="https://github.com/{issues_github_path}/pull/{n}", ) def format_commit_text(sha): return sha[:7] """Sphinx role for linking to a commit. Must have `issues_pr_uri` or `issues_github_path` configured in ``conf.py``. Examples: :: :commit:`123abc456def` :commit:`sloria/konch@123abc456def` """ commit_role = IssueRole( uri_config_option="issues_commit_uri", format_kwarg="commit", github_uri_template="https://github.com/{issues_github_path}/commit/{n}", format_text=format_commit_text, ) def setup(app): # Format template for issues URI # e.g. 'https://github.com/sloria/marshmallow/issues/{issue} app.add_config_value("issues_uri", default=None, rebuild="html") # Format template for PR URI # e.g. 'https://github.com/sloria/marshmallow/pull/{issue} app.add_config_value("issues_pr_uri", default=None, rebuild="html") # Format template for commit URI # e.g. 'https://github.com/sloria/marshmallow/commits/{commit} app.add_config_value("issues_commit_uri", default=None, rebuild="html") # Shortcut for Github, e.g. 'sloria/marshmallow' app.add_config_value("issues_github_path", default=None, rebuild="html") # Format template for user profile URI # e.g. 'https://github.com/{user}' app.add_config_value("issues_user_uri", default=None, rebuild="html") app.add_role("issue", issue_role) app.add_role("pr", pr_role) app.add_role("user", user_role) app.add_role("commit", commit_role) app.add_role("cve", cve_role) return { "version": __version__, "parallel_read_safe": True, "parallel_write_safe": True, } sphinx-issues-1.2.0/test_sphinx_issues.py000066400000000000000000000077111341072325400206600ustar00rootroot00000000000000# -*- coding: utf-8 -*- from tempfile import mkdtemp from shutil import rmtree try: from unittest.mock import Mock except ImportError: from mock import Mock from sphinx.application import Sphinx from sphinx_issues import ( issue_role, user_role, pr_role, cve_role, commit_role, setup as issues_setup, ) import pytest @pytest.yield_fixture( params=[ # Parametrize config {"issues_github_path": "marshmallow-code/marshmallow"}, { "issues_uri": "https://github.com/marshmallow-code/marshmallow/issues/{issue}", "issues_pr_uri": "https://github.com/marshmallow-code/marshmallow/pull/{pr}", "issues_commit_uri": "https://github.com/marshmallow-code/marshmallow/commit/{commit}", }, ] ) def app(request): src, doctree, confdir, outdir = [mkdtemp() for _ in range(4)] Sphinx._log = lambda self, message, wfile, nonl=False: None app = Sphinx( srcdir=src, confdir=None, outdir=outdir, doctreedir=doctree, buildername="html" ) issues_setup(app) # Stitch together as the sphinx app init() usually does w/ real conf files app.config._raw_config = request.param try: app.config.init_values() except TypeError: app.config.init_values(lambda x: x) yield app [rmtree(x) for x in (src, doctree, confdir, outdir)] @pytest.fixture() def inliner(app): return Mock(document=Mock(settings=Mock(env=Mock(app=app)))) @pytest.mark.parametrize( ("role", "role_name", "text", "expected_text", "expected_url"), [ ( issue_role, "issue", "42", "#42", "https://github.com/marshmallow-code/marshmallow/issues/42", ), ( pr_role, "pr", "42", "#42", "https://github.com/marshmallow-code/marshmallow/pull/42", ), (user_role, "user", "sloria", "@sloria", "https://github.com/sloria"), ( user_role, "user", "Steven Loria ", "Steven Loria", "https://github.com/sloria", ), ( cve_role, "cve", "CVE-2018-17175", "CVE-2018-17175", "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-17175", ), ( commit_role, "commit", "123abc456def", "123abc4", "https://github.com/marshmallow-code/marshmallow/commit/123abc456def", ), # External issue ( issue_role, "issue", "sloria/webargs#42", "sloria/webargs#42", "https://github.com/sloria/webargs/issues/42", ), # External PR ( pr_role, "pr", "sloria/webargs#42", "sloria/webargs#42", "https://github.com/sloria/webargs/pull/42", ), # External commit ( commit_role, "commit", "sloria/webargs@abc123def456", "sloria/webargs@abc123d", "https://github.com/sloria/webargs/commit/abc123def456", ), ], ) def test_roles(inliner, role, role_name, text, expected_text, expected_url): result = role(role_name, rawtext="", text=text, lineno=None, inliner=inliner) link = result[0][0] assert link.astext() == expected_text assert link.attributes["refuri"] == expected_url def test_issue_role_multiple(inliner): result = issue_role( name=None, rawtext="", text="42,43", inliner=inliner, lineno=None ) link1 = result[0][0] assert link1.astext() == "#42" issue_url = "https://github.com/marshmallow-code/marshmallow/issues/" assert link1.attributes["refuri"] == issue_url + "42" sep = result[0][1] assert sep.astext() == ", " link2 = result[0][2] assert link2.astext() == "#43" assert link2.attributes["refuri"] == issue_url + "43" sphinx-issues-1.2.0/tox.ini000066400000000000000000000005141341072325400156500ustar00rootroot00000000000000[tox] envlist = lint,py27,py35,py36,py37 [testenv] extras = tests commands = pytest {posargs} [testenv:lint] extras = lint commands = pre-commit run --all-files --show-diff-on-failure ; Below tasks are for development only (not run in CI) [testenv:watch-readme] deps = restview skip_install = true commands = restview README.rst