Skip to content

Commit b2fd54b

Browse files
committed
Move everything from "core" into __init__.py and rearrange docs.
1 parent 5685319 commit b2fd54b

File tree

13 files changed

+241
-212
lines changed

13 files changed

+241
-212
lines changed

doc-source/api/extension.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
===========================================
2-
:mod:`~seed_intersphinx_mapping.extension`
3-
===========================================
1+
==================================================================================
2+
:mod:`seed_intersphinx_mapping.extension <seed_intersphinx_mapping.extension>`
3+
==================================================================================
44

55
.. automodule:: seed_intersphinx_mapping.extension
66
:undoc-members:

doc-source/api/index.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
============
2+
Public API
3+
============
4+
5+
In addition to the Sphinx extension ``seed_intersphinx_mapping`` provides a public API.
6+
7+
.. toctree::
8+
:maxdepth: 3
9+
:caption: modules
10+
:glob:
11+
12+
seed_intersphinx_mapping
13+
*
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
=====================================================
2-
:mod:`~seed_intersphinx_mapping.requirements_parsers`
3-
=====================================================
1+
==========================================================================================================
2+
:mod:`seed_intersphinx_mapping.requirements_parsers <seed_intersphinx_mapping.requirements_parsers>`
3+
==========================================================================================================
44

55
.. automodule:: seed_intersphinx_mapping.requirements_parsers
66
:undoc-members:
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
=======================================
2-
:mod:`~seed_intersphinx_mapping.core`
2+
:mod:`seed_intersphinx_mapping`
33
=======================================
44

5-
.. automodule:: seed_intersphinx_mapping.core
5+
.. automodule:: seed_intersphinx_mapping
66
:undoc-members:

doc-source/contributing.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
Overview
2-
---------
1+
==============
2+
Contributing
3+
==============
34

45
.. This file based on https://github.com/PyGithub/PyGithub/blob/master/CONTRIBUTING.md
56

doc-source/index.rst

Lines changed: 3 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -158,85 +158,6 @@ This avoids having to manually compile (and keep updated) a mapping like:
158158
.. _core metadata: https://packaging.python.org/specifications/core-metadata
159159
.. _pull request: https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests
160160

161-
Installation
162-
---------------
163-
164-
.. start installation
165-
166-
.. installation:: seed_intersphinx_mapping
167-
:pypi:
168-
:github:
169-
:anaconda:
170-
:conda-channels: conda-forge, domdfcoding
171-
172-
.. end installation
173-
174-
175-
.. extensions:: seed_intersphinx_mapping
176-
177-
Configuration
178-
-----------------
179-
180-
.. confval:: pkg_requirements_source
181-
182-
The requirements source. This may be one of:
183-
184-
* A list of directories (relative to :confval:`repository_root`)
185-
in which to search for ``requirements.txt`` files.
186-
Any files found will be used to compile the list of requirements.
187-
188-
* The string ``'requirements'``.
189-
The list of requirements will be determined from the ``requirements.txt`` file
190-
in the directory given by the :confval:`repository_root` option.
191-
192-
* The string ``'pyproject'`` (or ``'pyproject.toml'``).
193-
The list will be parsed from the ``[project.dependencies]`` table of the
194-
``pyproject.toml`` file in the :confval:`repository_root`.
195-
196-
.. seealso:: :pep:`621` -- Storing project metadata in pyproject.toml
197-
198-
* The string ``'flit'``.
199-
The list will be parsed from the ``[tool.flit.metadata.requires]`` table of the
200-
``pyproject.toml`` file in the :confval:`repository_root`.
201-
202-
203-
.. confval:: repository_root
204-
205-
The path to the repository root, relative to the Sphinx source directory.
206-
207-
E.g., for this repository structure:
208-
209-
::
210-
211-
.
212-
├── LICENSE
213-
├── README.rst
214-
├── doc-source # <- this is the Sphinx source directory
215-
│ ├── index.rst
216-
│ └── conf.py
217-
├── requirements.txt # <- this is the file containing the requirements
218-
├── seed_intersphinx_mapping
219-
│ └── __init__.py
220-
├── setup.py
221-
├── tests
222-
└── tox.ini
223-
224-
the value would be ``..``, which is the default.
225-
226-
227-
Caching
228-
--------
229-
230-
``seed_intersphinx_mapping`` caches the documentation URLs for PyPI packages.
231-
The cache can be cleared as follows:
232-
233-
.. prompt:: bash
234-
235-
python3 -m seed_intersphinx_mapping
236-
237-
.. TODO:: automatic cache clearing, perhaps using ``intersphinx_cache_limit``
238-
239-
240161
Contents
241162
--------
242163

@@ -247,15 +168,11 @@ Contents
247168

248169
.. toctree::
249170
:maxdepth: 3
250-
:caption: API Reference
171+
:caption: Documentation
251172
:glob:
252173

253-
api/*
254-
255-
.. toctree::
256-
:maxdepth: 3
257-
:caption: Contributing
258-
174+
usage
175+
api/index
259176
contributing
260177
Source
261178

doc-source/usage.rst

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
=======
2+
Usage
3+
=======
4+
5+
Installation
6+
---------------
7+
8+
.. start installation
9+
10+
.. installation:: seed_intersphinx_mapping
11+
:pypi:
12+
:github:
13+
:anaconda:
14+
:conda-channels: conda-forge, domdfcoding
15+
16+
.. end installation
17+
18+
19+
.. extensions:: seed_intersphinx_mapping
20+
21+
22+
Configuration
23+
-----------------
24+
25+
.. confval:: pkg_requirements_source
26+
27+
The requirements source. This may be one of:
28+
29+
* A list of directories (relative to :confval:`repository_root`)
30+
in which to search for ``requirements.txt`` files.
31+
Any files found will be used to compile the list of requirements.
32+
33+
* The string ``'requirements'``.
34+
The list of requirements will be determined from the ``requirements.txt`` file
35+
in the directory given by the :confval:`repository_root` option.
36+
37+
* The string ``'pyproject'`` (or ``'pyproject.toml'``).
38+
The list will be parsed from the ``[project.dependencies]`` table of the
39+
``pyproject.toml`` file in the :confval:`repository_root`.
40+
41+
.. seealso:: :pep:`621` -- Storing project metadata in pyproject.toml
42+
43+
* The string ``'flit'``.
44+
The list will be parsed from the ``[tool.flit.metadata.requires]`` table of the
45+
``pyproject.toml`` file in the :confval:`repository_root`.
46+
47+
48+
.. confval:: repository_root
49+
50+
The path to the repository root, relative to the Sphinx source directory.
51+
52+
E.g., for this repository structure:
53+
54+
::
55+
56+
.
57+
├── LICENSE
58+
├── README.rst
59+
├── doc-source # <- this is the Sphinx source directory
60+
│ ├── index.rst
61+
│ └── conf.py
62+
├── requirements.txt # <- this is the file containing the requirements
63+
├── seed_intersphinx_mapping
64+
│ └── __init__.py
65+
├── setup.py
66+
├── tests
67+
└── tox.ini
68+
69+
the value would be ``..``, which is the default.
70+
71+
72+
Caching
73+
--------
74+
75+
``seed_intersphinx_mapping`` caches the documentation URLs for PyPI packages.
76+
The cache can be cleared as follows:
77+
78+
.. prompt:: bash
79+
80+
python3 -m seed_intersphinx_mapping
81+
82+
.. TODO:: automatic cache clearing, perhaps using ``intersphinx_cache_limit``

repo_helper.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ short_desc: "Populate the Sphinx 'intersphinx_mapping' dictionary from the proje
1414
sphinx_html_theme: furo
1515
docs_fail_on_warning: true
1616
use_whey: true
17+
standalone_contrib_guide: true
1718

1819
conda_channels:
1920
- conda-forge

seed_intersphinx_mapping/__init__.py

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
# __init__.py
44
"""
55
Populate the Sphinx 'intersphinx_mapping' dictionary from the project's requirements.
6+
7+
.. versionchanged:: 0.5.0
8+
9+
The functions formerly in ``seed_intersphinx_mapping.core`` can now be found here.
610
"""
711
#
8-
# Copyright © 2020 Dominic Davis-Foster <[email protected]>
12+
# Copyright © 2020-2021 Dominic Davis-Foster <[email protected]>
913
#
1014
# Permission is hereby granted, free of charge, to any person obtaining a copy
1115
# of this software and associated documentation files (the "Software"), to deal
@@ -26,14 +30,126 @@
2630
# OR OTHER DEALINGS IN THE SOFTWARE.
2731
#
2832

33+
# stdlib
34+
import functools
35+
import json
36+
from typing import Dict, Optional, Tuple, Union
37+
38+
# 3rd party
39+
import requests
40+
from cawdrey.utils import search_dict
41+
from domdf_python_tools.compat import importlib_resources
42+
from domdf_python_tools.utils import stderr_writer
43+
from packaging.requirements import Requirement
44+
from shippinglabel import get_project_links
45+
2946
# this package
3047
from seed_intersphinx_mapping.cache import cache
31-
from seed_intersphinx_mapping.core import get_sphinx_doc_url, seed_intersphinx_mapping
3248
from seed_intersphinx_mapping.extension import setup
3349

3450
__author__: str = "Dominic Davis-Foster"
3551
__copyright__: str = "2020 Dominic Davis-Foster"
36-
3752
__license__: str = "MIT License"
3853
__version__: str = "0.4.1"
3954
__email__: str = "[email protected]"
55+
56+
__all__ = ["get_sphinx_doc_url", "fallback_mapping", "seed_intersphinx_mapping"]
57+
58+
59+
@cache
60+
def get_sphinx_doc_url(pypi_name: str) -> str:
61+
"""
62+
Returns the URL to the given project's Sphinx documentation.
63+
64+
Not all projects include this URL in their distributions and therefore it may not be possible to determine it from PyPI.
65+
66+
Responses are cached to prevent overloading the PyPI server.
67+
The cache can be cleared as follows:
68+
69+
.. prompt:: bash
70+
71+
python3 -m seed_intersphinx_mapping
72+
73+
.. TODO:: automatic cache clearing, perhaps using ``intersphinx_cache_limit``
74+
75+
:param pypi_name: The name of the project on PyPI
76+
77+
:returns: The URL of the project's Sphinx documentation.
78+
79+
:raises: | :exc:`ValueError` if the url could not be determined.
80+
| :exc:`packaging.requirements.InvalidRequirement` if the project could not be found on PyPI.
81+
82+
.. versionchanged:: 0.4.0
83+
84+
Now raises a :exc:`packaging.requirements.InvalidRequirement` rather than a
85+
:exc:`apeye.slumber_url.exceptions.HttpNotFoundError` if the project could not be found on PyPI.
86+
"""
87+
88+
docs_dict = search_dict(get_project_links(pypi_name), r"^[dD]oc(s|umentation)")
89+
90+
if docs_dict:
91+
92+
# Follow redirects to get actual URL
93+
r = requests.head(list(docs_dict.values())[0], allow_redirects=True, timeout=10)
94+
if r.status_code != 200: # pragma: no cover
95+
raise ValueError(f"Documentation URL not found: HTTP Status {r.status_code}.")
96+
97+
docs_url = r.url
98+
99+
if docs_url.endswith('/'):
100+
objects_inv_url = f"{docs_url}objects.inv"
101+
else: # pragma: no cover
102+
objects_inv_url = f"{docs_url}/objects.inv"
103+
104+
r = requests.head(objects_inv_url)
105+
if r.status_code != 200:
106+
raise ValueError(f"objects.inv not found at url {objects_inv_url}: HTTP Status {r.status_code}.")
107+
108+
return docs_url
109+
110+
raise ValueError("Documentation URL not found in data from PyPI.")
111+
112+
113+
@functools.lru_cache()
114+
def fallback_mapping() -> Dict[str, str]:
115+
"""
116+
Returns the fallback mapping for projects that do not provide a link to their documentation on PyPI.
117+
118+
The mapping is loaded from JSON data on demand, and consists of ``project_name: url`` pairs.
119+
"""
120+
121+
return json.loads(importlib_resources.read_text("seed_intersphinx_mapping", "fallback_mapping.json"))
122+
123+
124+
def seed_intersphinx_mapping(*requirements: Union[Requirement, str]) -> Dict[str, Tuple[str, Optional[str]]]:
125+
r"""
126+
Returns an intersphinx mapping dictionary for the project's requirements.
127+
128+
:param \*requirements: The requirements to find the documentation for.
129+
130+
.. versionchanged:: 0.4.0
131+
132+
Now takes the requirements as arguments rather than
133+
a directory to read the ``requirements.txt`` file from.
134+
"""
135+
136+
intersphinx_mapping: Dict[str, Tuple[str, Optional[str]]] = {}
137+
138+
for requirement in requirements:
139+
if isinstance(requirement, Requirement):
140+
project_name = requirement.name
141+
else:
142+
project_name = str(requirement)
143+
144+
try:
145+
doc_url = get_sphinx_doc_url(project_name)
146+
intersphinx_mapping[project_name] = (doc_url, None)
147+
except (ValueError, requests.exceptions.ConnectionError, requests.exceptions.Timeout):
148+
# Couldn't get it from PyPI, trying fallback mapping
149+
if project_name in fallback_mapping():
150+
doc_url = fallback_mapping()[project_name]
151+
intersphinx_mapping[project_name] = (doc_url, None)
152+
else:
153+
stderr_writer(f"WARNING: Unable to determine documentation url for project {project_name}")
154+
155+
return intersphinx_mapping

0 commit comments

Comments
 (0)