diff --git a/.github/workflows/basic-ci.yml b/.github/workflows/basic-ci.yml index bcb29d3..f112fbc 100644 --- a/.github/workflows/basic-ci.yml +++ b/.github/workflows/basic-ci.yml @@ -1,35 +1,18 @@ -# This workflow will install Python dependencies, run tests and lint with a variety of Python versions on multiple platforms. -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions - name: Python lint and test on: - push: - branches: [ main ] - pull_request: - branches: [ main ] + - push jobs: - format: + format: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.8'] - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install black - - name: Run black - run: | - python -m black --check --diff . + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.8" + - uses: pre-commit/action@v3.0.0 test: runs-on: ${{ matrix.os }} @@ -38,9 +21,9 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ['3.7', '3.8', '3.9', '3.10'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..40c0649 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,12 @@ +repos: + - repo: "https://github.com/psf/black" + rev: 22.3.0 + hooks: + - id: black + stages: [commit] + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: "v0.0.217" + hooks: + - id: ruff + stages: [commit] + args: ["--force-exclude"] \ No newline at end of file diff --git a/README.md b/README.md index 4508aec..cc62d8b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # sphinx-favicon +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Black badge](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) +[![PyPI](https://img.shields.io/pypi/v/sphinx-favicon?logo=python&logoColor=white)](https://pypi.org/project/sphinx-favicon/) +![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/tcmetzger/sphinx-favicon/basic-ci.yml?logo=github&logoColor=white) + **A Sphinx extension to add custom favicons** With sphinx-favicon, you can add custom favicons to your Sphinx html @@ -200,5 +205,10 @@ To contribute to this extension, please open an issue or make a pull request to the repository on GitHub. Additional dependencies for development are listed in the file -`dev-requirements.txt` in the repository. Use ``pytest -vv`` to run tests. All -Python code should be formatted with [Black](https://github.com/psf/black). +`dev-requirements.txt` in the repository. Use ``pytest -vv`` to run tests. + +Please install `pre-commit` Python package and run the following command before commiting your modifications: + +``` +pre-commit install +``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 9ac9b91..3097b5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,3 +4,15 @@ requires = [ "wheel", ] build-backend = "setuptools.build_meta" + +[tool.ruff] +fix = true +select = ["E", "F", "W", "I", "D", "RUF"] +ignore = ["E501"] # line too long | Black take care of it +exclude = ["setup.py", "tests/roots/*"] + +[tool.ruff.flake8-quotes] +docstring-quotes = "double" + +[tool.ruff.pydocstyle] +convention = "google" diff --git a/setup.py b/setup.py index e559992..b908cbe 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,3 @@ -# See https://setuptools.pypa.io/en/latest/userguide/quickstart.html#development-mode - import setuptools setuptools.setup() diff --git a/sphinx_favicon/__init__.py b/sphinx_favicon/__init__.py index 9f1834f..c8dd7d1 100644 --- a/sphinx_favicon/__init__.py +++ b/sphinx_favicon/__init__.py @@ -1,3 +1,12 @@ +"""Sphinx extension to add custom favicons. + +With sphinx-favicon, you can add custom favicons to your Sphinx html documentation quickly and easily. + +You can define favicons directly in your conf.py, with different rel attributes such as "icon" or "apple-touch-icon" and any favicon size. + +The sphinx-favicon extension gives you more flexibility than the standard favicon.ico supported by Sphinx. It provides a quick and easy way to add the most important favicon formats for different browsers and devices. +""" + from typing import Any, Callable, Dict, List, Optional, Union import docutils.nodes as nodes @@ -37,10 +46,10 @@ def generate_meta(favicon: Dict[str, str]) -> str: SVG, or PNG files) Args: - favicon (Dict[str, str]): Favicon data + favicon: Favicon data Returns: - str: Favicon meta tag + Favicon meta tag """ rel = favicon.get("rel", "icon") href = favicon["href"] @@ -66,10 +75,17 @@ def generate_meta(favicon: Dict[str, str]) -> str: def _static_to_href(pathto: Callable, favicon: Dict[str, str]) -> Dict[str, str]: - """If a ``static-file`` is provided, returns a modified version of the icon - attributes replacing ``static-file`` with the correct ``href``. + """Replace static ref to fully qualified href. + If a ``static-file`` is provided, returns a modified version of the icon attributes replacing ``static-file`` with the correct ``href``. If both ``static-file`` and ``href`` are provided, ``href`` will be ignored. + + Args: + pathto: Sphinx helper_ function to handle relative URLs + favicon: The favicon description as set in the conf.py file + + Returns: + The favicon with a fully qualified href """ if FILE_FIELD in favicon: attrs = favicon.copy() @@ -84,14 +100,14 @@ def create_favicons_meta(pathto: Callable, favicons: FaviconsDef) -> Optional[st """Create ```` elements for favicons defined in configuration. Args: - pathto (Callable): Sphinx helper_ function to handle relative URLs - favicons (FaviconsDef): Favicon data from configuration. - Can be a single dict or a list of dicts. + pathto: Sphinx helper_ function to handle relative URLs + favicons: Favicon data from configuration. Can be a single dict or a list of dicts. Returns: - str: ```` elements for all favicons. + ```` elements for all favicons. - .. _helper: https://www.sphinx-doc.org/en/master/templating.html#patht + See Also: + https://www.sphinx-doc.org/en/master/templating.html#path """ meta_favicons = "" @@ -112,10 +128,8 @@ def create_favicons_meta(pathto: Callable, favicons: FaviconsDef) -> Optional[st meta_favicons += generate_meta(attrs) + "\n" else: logger.warning( - """ - Invalid config value for favicon extension. Custom favicons will not - be included in build. - """ + "Invalid config value for favicon extension." + "Custom favicons will notbe included in build." ) return None @@ -129,7 +143,15 @@ def html_page_context( context: Dict[str, Any], doctree: nodes.document, ) -> None: + """Update the html page context by adding the favicons. + Args: + app: The sphinx application + pagename: the name of the page as string + templatename: the name of the template as string + context: the html context dictionnary + doctree: the docutils document tree + """ if doctree and app.config["favicons"]: pathto: Callable = context["pathto"] # should exist in a HTML context favicons_meta = create_favicons_meta(pathto, app.config["favicons"]) @@ -137,6 +159,14 @@ def html_page_context( def setup(app: Sphinx) -> Dict[str, Any]: + """Add custom configuration to shinx app. + + Args: + app: the Sphinx application + + Returns: + the 2 parralel parameters set to ``True`` + """ app.add_config_value("favicons", None, "html") app.connect("html-page-context", html_page_context) diff --git a/tests/conftest.py b/tests/conftest.py index 3459ea1..521d99f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,30 +1,33 @@ -import os +"""Configuration fixtures of the tests.""" + 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(): + """The root directory.""" return path(__file__).parent.abspath() / "roots" @pytest.fixture() def content(app): + """The app build content.""" app.build() yield app def _link_tags(content, page): + """Link tags in a page content.""" c = (content.outdir / page).read_text() return BeautifulSoup(c, "html.parser").find_all("link") def _favicon_tags(content, page="index.html"): + """Favicon tags in the index.html page.""" return [ tag for tag in _link_tags(content, page) @@ -34,18 +37,22 @@ def _favicon_tags(content, page="index.html"): @pytest.fixture() def link_tags(content): + """Link tags in index.html page.""" return _link_tags(content, "index.html") @pytest.fixture() def favicon_tags(content): + """Favicon tags in index.html page.""" return _favicon_tags(content) @pytest.fixture() def favicon_tags_for_nested(content): + """Favicon tags in nested/page.html page.""" return _favicon_tags(content, "nested/page.html") def pytest_configure(config): + """Add markers config to pytest.""" config.addinivalue_line("markers", "sphinx") diff --git a/tests/test_options.py b/tests/test_options.py index fa5b65d..8c6bad1 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -1,3 +1,5 @@ +"""Test suit for the sphinx-favicon extention.""" + from itertools import chain from pathlib import Path @@ -6,7 +8,11 @@ @pytest.mark.sphinx("html", testroot="list_of_three_dicts") def test_list_of_three_dicts(favicon_tags): + """Run tests on a list of 3 dicts. + Args: + favicon_tags: Favicon tags in index.html page. + """ # this test should have 3 favicons assert len(favicon_tags) == 3 @@ -29,7 +35,11 @@ def test_list_of_three_dicts(favicon_tags): @pytest.mark.sphinx("html", testroot="list_of_three_dicts_automated_values") def test_list_of_three_dicts_automated_values(favicon_tags): + """Run tests on a list of 3 dicts with automated values. + Args: + favicon_tags: Favicon tags in index.html page. + """ # this test should have 3 favicons assert len(favicon_tags) == 3 @@ -52,7 +62,11 @@ def test_list_of_three_dicts_automated_values(favicon_tags): @pytest.mark.sphinx("html", testroot="single_dict") def test_single_dict(favicon_tags): + """Run tests on a single dict. + Args: + favicon_tags: Favicon tags in index.html page. + """ # this test should have 1 favicon assert len(favicon_tags) == 1 @@ -68,7 +82,11 @@ def test_single_dict(favicon_tags): @pytest.mark.sphinx("html", testroot="list_of_urls") def test_list_of_urls(favicon_tags): + """Run tests on a list of urls. + Args: + favicon_tags: Favicon tags in index.html page. + """ # this test should have 3 favicons assert len(favicon_tags) == 3 @@ -89,7 +107,13 @@ def test_list_of_urls(favicon_tags): @pytest.mark.sphinx("html", testroot="static_files") def test_static_files(app, favicon_tags, favicon_tags_for_nested): + """Run tests using static files. + Args: + app: the Sphinx application + favicon_tags: Favicon tags in index.html page. + favicon_tags_for_nested: Favicon tags in nested/page.html page. + """ # this test should have 2 favicons assert len(favicon_tags) == 2 @@ -114,7 +138,13 @@ def test_static_files(app, favicon_tags, favicon_tags_for_nested): @pytest.mark.sphinx("html", testroot="href_and_static") def test_href_and_static(app, favicon_tags, favicon_tags_for_nested): + """Run tests on a mix of static files and complete urls. + Args: + app: the Sphinx application + favicon_tags: Favicon tags in index.html page. + favicon_tags_for_nested: Favicon tags in nested/page.html page. + """ # this test should have 3 favicons assert len(favicon_tags) == 2