pax_global_header 0000666 0000000 0000000 00000000064 14152737165 0014525 g ustar 00root root 0000000 0000000 52 comment=8569b1c7936aec7d039a19cc8e106c015f089f75
sphinxext-opengraph-0.5.1/ 0000775 0000000 0000000 00000000000 14152737165 0015543 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/.github/ 0000775 0000000 0000000 00000000000 14152737165 0017103 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/.github/workflows/ 0000775 0000000 0000000 00000000000 14152737165 0021140 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/.github/workflows/workflow.yml 0000664 0000000 0000000 00000004407 14152737165 0023542 0 ustar 00root root 0000000 0000000 name: Test and Deploy
on:
pull_request:
branches:
- main
push:
branches:
- main
create:
tags:
- '*'
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Black
run: |
pip install black
black --check --exclude /docs --diff .
test-extension:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.6', '3.7', '3.8', '3.9', 'pypy3']
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
set -xe
python -VV
python -m site
python -m pip install --upgrade pip setuptools wheel
python -m pip install -r dev-requirements.txt
- name: Install Package
run: |
python -m pip install .
- name: Run Tests for ${{ matrix.python-version }}
run: |
python -m pytest -vv
build-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v2
- name: Install dependencies
run: |
pip install -r docs/requirements.txt
- name: Build documentation
run: |
cd docs
make html
pypi-release:
needs: test-extension
runs-on: ubuntu-latest
if: contains(github.ref, 'refs/tags/') && github.repository_owner == 'wpilibsuite'
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.7'
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r ./dev-requirements.txt
- name: Build PyPI Wheel
run: |
python setup.py sdist
python setup.py bdist_wheel
- name: Publish a Python distribution to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.pypi_password }}
sphinxext-opengraph-0.5.1/.gitignore 0000664 0000000 0000000 00000011673 14152737165 0017543 0 ustar 00root root 0000000 0000000
# Created by https://www.toptal.com/developers/gitignore/api/windows,linux,python,pycharm,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,linux,python,pycharm,visualstudiocode
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### PyCharm ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### PyCharm Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
.idea/**/sonarlint/
# SonarQube Plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/
# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
docs/build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/windows,linux,python,pycharm,visualstudiocode sphinxext-opengraph-0.5.1/.readthedocs.yml 0000664 0000000 0000000 00000000331 14152737165 0020626 0 ustar 00root root 0000000 0000000 version: 2
python:
version: 3
install:
- method: pip
path: .
extra_requirements:
- rtd
- requirements: docs/requirements.txt
sphinx:
builder: html
fail_on_warning: true
sphinxext-opengraph-0.5.1/LICENSE.md 0000664 0000000 0000000 00000002705 14152737165 0017153 0 ustar 00root root 0000000 0000000 Copyright (c) 2020 FIRST
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.
* Neither the name of the FIRST nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY FIRST AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST 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. sphinxext-opengraph-0.5.1/README.md 0000664 0000000 0000000 00000004447 14152737165 0017033 0 ustar 00root root 0000000 0000000 # sphinxext-opengraph

[](https://github.com/psf/black)
Sphinx extension to generate OpenGraph metadata (https://ogp.me/)
## Installation
`python -m pip install sphinxext-opengraph`
## Usage
Just add `sphinxext.opengraph` to your extensions list in your `conf.py`
```python
extensions = [
"sphinxext.opengraph",
]
```
## Options
These values are placed in the conf.py of your sphinx project.
Users hosting documentation on Read The Docs *do not* need to set any of the following unless custom configuration is wanted. The extension will automatically retrieve your site url.
* `ogp_site_url`
* This config option is very important, set it to the URL the site is being hosted on.
* `ogp_description_length`
* Configure the amount of characters taken from a page. The default of 200 is probably good for most people. If something other than a number is used, it defaults back to 200.
* `ogp_site_name`
* This is not required. Name of the site. This is displayed above the title.
* `ogp_image`
* This is not required. Link to image to show.
* `ogp_image_alt`
* This is not required. Alt text for image. Defaults to using `ogp_site_name` or the document's title as alt text, if available. Set to `False` if you want to turn off alt text completely.
* `ogp_use_first_image`
* This is not required. Set to True to use each page's first image, if available. If set to True but no image is found, Sphinx will use `ogp_image` instead.
* `ogp_type`
* This sets the ogp type attribute, for more information on the types available please take a look at https://ogp.me/#types. By default it is set to `website`, which should be fine for most use cases.
* `ogp_custom_meta_tags`
* This is not required. List of custom html snippets to insert.
## Example Config
### Simple Config
```python
ogp_site_url = "http://example.org/"
ogp_image = "http://example.org/image.png"
```
### Advanced Config
```python
ogp_site_url = "http://example.org/"
ogp_image = "http://example.org/image.png"
ogp_description_length = 300
ogp_type = "article"
ogp_custom_meta_tags = [
'',
]
```
sphinxext-opengraph-0.5.1/dev-requirements.txt 0000664 0000000 0000000 00000000113 14152737165 0021576 0 ustar 00root root 0000000 0000000 sphinx
wheel==0.34.2
pytest==5.4.3
beautifulsoup4==4.9.1
setuptools==47.3.1 sphinxext-opengraph-0.5.1/docs/ 0000775 0000000 0000000 00000000000 14152737165 0016473 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/docs/Makefile 0000664 0000000 0000000 00000001176 14152737165 0020140 0 ustar 00root root 0000000 0000000 # Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
sphinxext-opengraph-0.5.1/docs/make.bat 0000664 0000000 0000000 00000001374 14152737165 0020105 0 ustar 00root root 0000000 0000000 @ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd
sphinxext-opengraph-0.5.1/docs/requirements.txt 0000664 0000000 0000000 00000000070 14152737165 0021754 0 ustar 00root root 0000000 0000000 myst-parser==0.15.2
furo==2021.11.12.1
sphinx==4.2.0
./
sphinxext-opengraph-0.5.1/docs/source/ 0000775 0000000 0000000 00000000000 14152737165 0017773 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/docs/source/conf.py 0000664 0000000 0000000 00000003202 14152737165 0021267 0 ustar 00root root 0000000 0000000 # Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath("../.."))
# -- Project information -----------------------------------------------------
project = "sphinxext-opengraph"
copyright = "2020, FIRST"
author = "WPILib"
# The full version, including alpha/beta/rc tags
release = "1.0"
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"myst_parser",
"sphinxext.opengraph",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = "furo"
sphinxext-opengraph-0.5.1/docs/source/index.md 0000664 0000000 0000000 00000000063 14152737165 0021423 0 ustar 00root root 0000000 0000000 ```{include} ../../README.md
:relative-images:
```
sphinxext-opengraph-0.5.1/setup.py 0000664 0000000 0000000 00000003254 14152737165 0017261 0 ustar 00root root 0000000 0000000 import subprocess
import setuptools
# This will fail if something happens or if not in a git repository.
# This is intentional.
try:
ret = subprocess.run(
"git describe --tags --abbrev=0",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
shell=True,
)
version = ret.stdout.decode("utf-8").strip()
except:
version = "main"
with open("README.md", "r", encoding="utf-8") as readme:
long_description = readme.read()
setuptools.setup(
name="sphinxext-opengraph",
version=version,
author="Itay Ziv",
author_email="itay220204@gmail.com",
description="Sphinx Extension to enable OGP support",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/wpilibsuite/sphinxext-opengraph",
install_requires=["sphinx>=2.0"],
packages=["sphinxext/opengraph"],
classifiers=[
"Development Status :: 5 - Production/Stable",
"Environment :: Plugins",
"Environment :: Web Environment",
"Framework :: Sphinx :: Extension",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python",
"Topic :: Documentation :: Sphinx",
"Topic :: Documentation",
"Topic :: Software Development :: Documentation",
"Topic :: Text Processing",
"Topic :: Utilities",
],
python_requires=">=3.6",
)
sphinxext-opengraph-0.5.1/sphinxext/ 0000775 0000000 0000000 00000000000 14152737165 0017575 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/sphinxext/opengraph/ 0000775 0000000 0000000 00000000000 14152737165 0021560 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/sphinxext/opengraph/__init__.py 0000664 0000000 0000000 00000011275 14152737165 0023677 0 ustar 00root root 0000000 0000000 from typing import Any, Dict
from urllib.parse import urljoin, urlparse, urlunparse
from pathlib import Path
import docutils.nodes as nodes
from sphinx.application import Sphinx
from .descriptionparser import get_description
from .titleparser import get_title
import os
DEFAULT_DESCRIPTION_LENGTH = 200
# A selection from https://www.iana.org/assignments/media-types/media-types.xhtml#image
IMAGE_MIME_TYPES = {
"gif": "image/gif",
"apng": "image/apng",
"webp": "image/webp",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"png": "image/png",
"bmp": "image/bmp",
"heic": "image/heic",
"heif": "image/heif",
"tiff": "image/tiff",
}
def make_tag(property: str, content: str) -> str:
return f'\n '
def get_tags(
app: Sphinx,
context: Dict[str, Any],
doctree: nodes.document,
config: Dict[str, Any],
) -> str:
# Set length of description
try:
desc_len = int(config["ogp_description_length"])
except ValueError:
desc_len = DEFAULT_DESCRIPTION_LENGTH
# Get the title and parse any html in it
title = get_title(context["title"], skip_html_tags=False)
title_excluding_html = get_title(context["title"], skip_html_tags=True)
# Parse/walk doctree for metadata (tag/description)
description = get_description(doctree, desc_len, [title, title_excluding_html])
tags = "\n "
# title tag
tags += make_tag("og:title", title)
# type tag
tags += make_tag("og:type", config["ogp_type"])
if os.getenv("READTHEDOCS") and config["ogp_site_url"] is None:
# readthedocs uses html_baseurl for sphinx > 1.8
parse_result = urlparse(config["html_baseurl"])
if config["html_baseurl"] is None:
raise EnvironmentError("ReadTheDocs did not provide a valid canonical URL!")
# Grab root url from canonical url
config["ogp_site_url"] = urlunparse(
(
parse_result.scheme,
parse_result.netloc,
parse_result.path,
"",
"",
"",
)
)
# url tag
# Get the URL of the specific page
page_url = urljoin(
config["ogp_site_url"], context["pagename"] + context["file_suffix"]
)
tags += make_tag("og:url", page_url)
# site name tag
site_name = config["ogp_site_name"]
if site_name:
tags += make_tag("og:site_name", site_name)
# description tag
if description:
tags += make_tag("og:description", description)
# image tag
# Get basic values from config
image_url = config["ogp_image"]
ogp_use_first_image = config["ogp_use_first_image"]
ogp_image_alt = config["ogp_image_alt"]
if ogp_use_first_image:
first_image = doctree.next_node(nodes.image)
if (
first_image
and Path(first_image.get("uri", "")).suffix[1:].lower() in IMAGE_MIME_TYPES
):
image_url = first_image["uri"]
ogp_image_alt = first_image.get("alt", None)
if image_url:
image_url_parsed = urlparse(image_url)
if not image_url_parsed.scheme:
# Relative image path detected. Make absolute.
image_url = urljoin(config["ogp_site_url"], image_url_parsed.path)
tags += make_tag("og:image", image_url)
# Add image alt text (either provided by config or from site_name)
if isinstance(ogp_image_alt, str):
tags += make_tag("og:image:alt", ogp_image_alt)
elif ogp_image_alt is None and site_name:
tags += make_tag("og:image:alt", site_name)
elif ogp_image_alt is None and title:
tags += make_tag("og:image:alt", title)
# custom tags
tags += "\n".join(config["ogp_custom_meta_tags"])
return tags
def html_page_context(
app: Sphinx,
pagename: str,
templatename: str,
context: Dict[str, Any],
doctree: nodes.document,
) -> None:
if doctree:
context["metatags"] += get_tags(app, context, doctree, app.config)
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_config_value("ogp_site_url", None, "html")
app.add_config_value("ogp_description_length", DEFAULT_DESCRIPTION_LENGTH, "html")
app.add_config_value("ogp_image", None, "html")
app.add_config_value("ogp_image_alt", None, "html")
app.add_config_value("ogp_use_first_image", False, "html")
app.add_config_value("ogp_type", "website", "html")
app.add_config_value("ogp_site_name", None, "html")
app.add_config_value("ogp_custom_meta_tags", [], "html")
app.connect("html-page-context", html_page_context)
return {
"parallel_read_safe": True,
"parallel_write_safe": True,
}
sphinxext-opengraph-0.5.1/sphinxext/opengraph/descriptionparser.py 0000664 0000000 0000000 00000007635 14152737165 0025705 0 ustar 00root root 0000000 0000000 import string
from typing import Iterable
import docutils.nodes as nodes
class DescriptionParser(nodes.NodeVisitor):
"""
Finds the title and creates a description from a doctree
"""
def __init__(
self,
desc_len: int,
known_titles: Iterable[str] = None,
document: nodes.document = None,
):
# Hack to prevent requirement for the doctree to be passed in.
# It's only used by doctree.walk(...) to print debug messages.
if document == None:
class document_cls:
class reporter:
@staticmethod
def debug(*args, **kwaargs):
pass
document = document_cls()
if known_titles == None:
known_titles = []
super().__init__(document)
self.description = ""
self.desc_len = desc_len
self.list_level = 0
self.known_titles = known_titles
self.first_title_found = False
# Exceptions can't be raised from dispatch_departure()
# This is used to loop the stop call back to the next dispatch_visit()
self.stop = False
def dispatch_visit(self, node: nodes.Element) -> None:
if self.stop:
raise nodes.StopTraversal
# Skip comments
if isinstance(node, nodes.Invisible):
raise nodes.SkipNode
# Skip all admonitions
if isinstance(node, nodes.Admonition):
raise nodes.SkipNode
# Mark start of nested lists
if isinstance(node, nodes.Sequential):
self.list_level += 1
if self.list_level > 1:
self.description += "-"
# Skip the first title if it's the title of the page
if not self.first_title_found and isinstance(node, nodes.title):
self.first_title_found = True
if node.astext() in self.known_titles:
raise nodes.SkipNode
if isinstance(node, nodes.raw) or isinstance(node.parent, nodes.literal_block):
raise nodes.SkipNode
# Only include leaf nodes in the description
if len(node.children) == 0:
text = node.astext().replace("\r", "").replace("\n", " ").strip()
# Remove double spaces
while text.find(" ") != -1:
text = text.replace(" ", " ")
# Put a space between elements if one does not already exist.
if (
len(self.description) > 0
and len(text) > 0
and self.description[-1] not in string.whitespace
and text[0] not in string.whitespace + string.punctuation
):
self.description += " "
self.description += text
def dispatch_departure(self, node: nodes.Element) -> None:
# Separate title from text
if isinstance(node, nodes.title):
self.description += ":"
# Separate list elements
if isinstance(node, nodes.Part):
self.description += ","
# Separate end of list from text
if isinstance(node, nodes.Sequential):
if self.description[-1] == ",":
self.description = self.description[:-1]
self.description += "."
self.list_level -= 1
# Check for length
if len(self.description) > self.desc_len:
self.description = self.description[: self.desc_len]
if self.desc_len >= 3:
self.description = self.description[:-3] + "..."
self.stop = True
def get_description(
doctree: nodes.document,
description_length: int,
known_titles: Iterable[str] = None,
document: nodes.document = None,
):
mcv = DescriptionParser(description_length, known_titles, document)
doctree.walkabout(mcv)
# Parse quotation so they won't break html tags if smart quotes are disabled
return mcv.description.replace('"', """)
sphinxext-opengraph-0.5.1/sphinxext/opengraph/titleparser.py 0000664 0000000 0000000 00000001453 14152737165 0024473 0 ustar 00root root 0000000 0000000 from html.parser import HTMLParser
class HTMLTextParser(HTMLParser):
"""
Parse HTML into text
"""
def __init__(self):
super().__init__()
# All text found
self.text = ""
# Only text outside of html tags
self.text_outside_tags = ""
self.level = 0
def handle_starttag(self, tag, attrs) -> None:
self.level += 1
def handle_endtag(self, tag) -> None:
self.level -= 1
def handle_data(self, data) -> None:
self.text += data
if self.level == 0:
self.text_outside_tags += data
def get_title(title: str, skip_html_tags: bool = False):
htp = HTMLTextParser()
htp.feed(title)
htp.close()
if skip_html_tags:
return htp.text_outside_tags
else:
return htp.text
sphinxext-opengraph-0.5.1/tests/ 0000775 0000000 0000000 00000000000 14152737165 0016705 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/tests/conftest.py 0000664 0000000 0000000 00000002302 14152737165 0021101 0 ustar 00root root 0000000 0000000 import pytest
from bs4 import BeautifulSoup
from sphinx.testing.path import path
from sphinx.application import Sphinx
pytest_plugins = "sphinx.testing.fixtures"
@pytest.fixture(scope="session")
def rootdir():
return path(__file__).parent.abspath() / "roots"
@pytest.fixture()
def content(app):
app.build()
yield app
def _meta_tags(content, subdir=None):
if subdir is None:
c = (content.outdir / "index.html").read_text()
else:
c = (content.outdir / subdir / "index.html").read_text()
return BeautifulSoup(c, "html.parser").find_all("meta")
def _og_meta_tags(content):
return [
tag for tag in _meta_tags(content) if tag.get("property", "").startswith("og:")
]
@pytest.fixture()
def meta_tags(content):
return _meta_tags(content)
@pytest.fixture()
def og_meta_tags(content):
return [
tag for tag in _meta_tags(content) if tag.get("property", "").startswith("og:")
]
@pytest.fixture()
def og_meta_tags_sub(content):
return [
tag
for tag in _meta_tags(content, "sub")
if tag.get("property", "").startswith("og:")
]
def pytest_configure(config):
config.addinivalue_line("markers", "sphinx")
sphinxext-opengraph-0.5.1/tests/roots/ 0000775 0000000 0000000 00000000000 14152737165 0020053 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/tests/roots/test-custom-tags/ 0000775 0000000 0000000 00000000000 14152737165 0023276 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/tests/roots/test-custom-tags/conf.py 0000664 0000000 0000000 00000000357 14152737165 0024602 0 ustar 00root root 0000000 0000000 extensions = ["sphinxext.opengraph"]
master_doc = "index"
exclude_patterns = ["_build"]
html_theme = "basic"
ogp_site_url = "http://example.org/"
ogp_custom_meta_tags = [
'',
]
sphinxext-opengraph-0.5.1/tests/roots/test-custom-tags/index.rst 0000664 0000000 0000000 00000000372 14152737165 0025141 0 ustar 00root root 0000000 0000000 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse at lorem ornare, fringilla massa nec, venenatis mi. Donec erat sapien, tincidunt nec rhoncus nec, scelerisque id diam. Orci varius natoque penatibus et magnis dis parturient mauris. sphinxext-opengraph-0.5.1/tests/roots/test-description-length/ 0000775 0000000 0000000 00000000000 14152737165 0024632 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/tests/roots/test-description-length/conf.py 0000664 0000000 0000000 00000000261 14152737165 0026130 0 ustar 00root root 0000000 0000000 extensions = ["sphinxext.opengraph"]
master_doc = "index"
exclude_patterns = ["_build"]
html_theme = "basic"
ogp_site_url = "http://example.org/"
ogp_description_length = 50
sphinxext-opengraph-0.5.1/tests/roots/test-description-length/index.rst 0000664 0000000 0000000 00000000372 14152737165 0026475 0 ustar 00root root 0000000 0000000 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse at lorem ornare, fringilla massa nec, venenatis mi. Donec erat sapien, tincidunt nec rhoncus nec, scelerisque id diam. Orci varius natoque penatibus et magnis dis parturient mauris. sphinxext-opengraph-0.5.1/tests/roots/test-double-spacing/ 0000775 0000000 0000000 00000000000 14152737165 0023724 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/tests/roots/test-double-spacing/conf.py 0000664 0000000 0000000 00000000225 14152737165 0025222 0 ustar 00root root 0000000 0000000 extensions = ["sphinxext.opengraph"]
master_doc = "index"
exclude_patterns = ["_build"]
html_theme = "basic"
ogp_site_url = "http://example.org/"
sphinxext-opengraph-0.5.1/tests/roots/test-double-spacing/index.rst 0000664 0000000 0000000 00000000050 14152737165 0025560 0 ustar 00root root 0000000 0000000 Example sentence 1. Example sentence 2. sphinxext-opengraph-0.5.1/tests/roots/test-first-image-no-image/ 0000775 0000000 0000000 00000000000 14152737165 0024731 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/tests/roots/test-first-image-no-image/conf.py 0000664 0000000 0000000 00000000426 14152737165 0026232 0 ustar 00root root 0000000 0000000 extensions = ["sphinxext.opengraph"]
master_doc = "index"
exclude_patterns = ["_build"]
html_theme = "basic"
ogp_site_name = "Example's Docs!"
ogp_site_url = "http://example.org/"
ogp_image = "http://example.org/image33.png"
ogp_image_alt = "TEST"
ogp_use_first_image = True
sphinxext-opengraph-0.5.1/tests/roots/test-first-image-no-image/index.rst 0000664 0000000 0000000 00000000012 14152737165 0026563 0 ustar 00root root 0000000 0000000 Title Only sphinxext-opengraph-0.5.1/tests/roots/test-first-image/ 0000775 0000000 0000000 00000000000 14152737165 0023237 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/tests/roots/test-first-image/conf.py 0000664 0000000 0000000 00000000426 14152737165 0024540 0 ustar 00root root 0000000 0000000 extensions = ["sphinxext.opengraph"]
master_doc = "index"
exclude_patterns = ["_build"]
html_theme = "basic"
ogp_site_name = "Example's Docs!"
ogp_site_url = "http://example.org/"
ogp_image = "http://example.org/image33.png"
ogp_image_alt = "TEST"
ogp_use_first_image = True
sphinxext-opengraph-0.5.1/tests/roots/test-first-image/index.rst 0000664 0000000 0000000 00000000105 14152737165 0025074 0 ustar 00root root 0000000 0000000 .. image:: http://example.org/image2.png
:alt: Test image alt text sphinxext-opengraph-0.5.1/tests/roots/test-image-rel-paths/ 0000775 0000000 0000000 00000000000 14152737165 0024007 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/tests/roots/test-image-rel-paths/conf.py 0000664 0000000 0000000 00000000322 14152737165 0025303 0 ustar 00root root 0000000 0000000 extensions = ["sphinxext.opengraph"]
master_doc = "index"
exclude_patterns = ["_build"]
html_theme = "basic"
ogp_site_name = "Example's Docs!"
ogp_site_url = "http://example.org/"
ogp_use_first_image = True
sphinxext-opengraph-0.5.1/tests/roots/test-image-rel-paths/img/ 0000775 0000000 0000000 00000000000 14152737165 0024563 5 ustar 00root root 0000000 0000000 sphinxext-opengraph-0.5.1/tests/roots/test-image-rel-paths/img/sample.jpg 0000664 0000000 0000000 00000020271 14152737165 0026550 0 ustar 00root root 0000000 0000000 JFIF C
C "
} !1AQa"q2#BR$3br
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
w !1AQaq"2B #3Rbr
$4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? C !) ^ AJմ\0àYlGge:,ֲ I!9s }3 ? G f_ԥJ2u?Z^50'
0#!9s }3 '?oOGO ?u W
W ο9j >QP ?u W
W ο9j >QP ?u W
W ο9j >QP ?u W
W ο9j >QP ?u W
W ο9j >QP ?u W
W ο9j >QP ?u W
W ο9j >QP ?u W
W ο9j >QP ?u W
W ο9j >QP ?u W
W ο9j >QP ?y CS ?j,f^`veXmbmX$Wv7Q٪Q^&:^X#Sdqf>i+ N^3 } .O
9 ux=4>o~ G 肊(り((((((((((;Q(?l( ux3=5J+־94Q?(l0ӟGW K0x(>8( ( ( ( ( ( ( ( ( ( ^ c R?oGW? T{11k 0 N^3 } .O
9 ux=4>c~ G 肊(り((((((((((;Q(?l( ux3=5J+־94Q?(l0ӟGW K0x(>8( 9KWE%LtҢ
vϻ;#2r䲧 hهⶁa[~x!]YwVPQ$è<"} ! i߇_Qd˭[>Xi5]&xCopWpK(1ay_JxG|~ɾ։c$wq,Ŕ]YjJ<+<}TOy[}ٮ1jefwM}; G^^
iwE}cu.`"2#Z5;?o%v#v>cs|d.`em>߲6;c1); 0~?㿏I"kxĖq*4.[c8*ifX֕ugϡ(ta8ۋ}tk7& >/j oGψ$Y^hΣ*AY[j.p <