From 695a6b0bb7afdb3fa1013bdfecb2fc7dc7a09f61 Mon Sep 17 00:00:00 2001 From: Kurt McKee Date: Fri, 1 Dec 2023 08:10:42 -0600 Subject: [PATCH 1/3] Add a ReadTheDocs configuration file and a docs test environment --- .gitignore | 1 + .readthedocs.yaml | 14 ++++++++++++++ doc/requirements.txt | 1 + tox.ini | 10 +++++++++- 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 .readthedocs.yaml create mode 100644 doc/requirements.txt diff --git a/.gitignore b/.gitignore index 8fe10f2..61f7a75 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ MANIFEST # Hidden files. .* +!.readthedocs.yaml !.gitignore diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..40aafd3 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,14 @@ +version: 2 + +build: + os: 'ubuntu-22.04' + tools: + python: '3.12' + +sphinx: + configuration: 'doc/source/conf.py' + fail_on_warning: true + +python: + install: + - requirements: 'doc/requirements.txt' diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 0000000..6fc994d --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1 @@ +Sphinx==7.2.6 diff --git a/tox.ini b/tox.ini index 89f20bd..7d7a17c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,14 @@ [tox] -envlist = py38, py39, py310, py311, py312, pypy3 +envlist = + py{38, 39, 310, 311, 312} + pypy3 + docs isolated_build = True [testenv] commands = python -m unittest {posargs} + +[testenv:docs] +base_path = py312 +deps = -rdoc/requirements.txt +commands = sphinx-build -aWEnqb html doc/source doc/build From 903027cb11631dc3aeb961ce085de7783493695d Mon Sep 17 00:00:00 2001 From: Kurt McKee Date: Fri, 1 Dec 2023 08:13:58 -0600 Subject: [PATCH 2/3] Resolve issues identified by the docs tests Most issues boil down to "bad reference or typo". Some were rendering differences between Sphinx 7.2 and the ancient Sphinx 1.8 version ReadTheDocs defaults to when there isn't a `.readthedocs.yaml` file. --- doc/source/api.rst | 1 + doc/source/conf.py | 14 +++++++------- doc/source/index.rst | 1 + pathspec/gitignore.py | 9 +++++---- pathspec/pathspec.py | 14 +++++++------- pathspec/pattern.py | 4 ++-- pathspec/util.py | 26 +++++++++++++------------- 7 files changed, 36 insertions(+), 33 deletions(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index 0fb44b8..c62961b 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1,3 +1,4 @@ +:tocdepth: 2 API === diff --git a/doc/source/conf.py b/doc/source/conf.py index e8c0b53..3e5ef46 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -24,15 +24,15 @@ # -- General configuration ------------------------------------------------ -# If your documentation needs a minimal Sphinx version, state it here. -# -needs_sphinx = '1.2' - # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode'] +# The autodoc extension doesn't understand the `Self` typehint. +# To avoid documentation build errors, autodoc typehints must be disabled. +autodoc_typehints = "none" + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -64,7 +64,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -102,7 +102,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +# html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -165,4 +165,4 @@ ] # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} diff --git a/doc/source/index.rst b/doc/source/index.rst index 8437bec..6649eab 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -9,6 +9,7 @@ Welcome to pathspec's documentation! .. toctree:: :caption: Contents: + :maxdepth: 2 readme api diff --git a/pathspec/gitignore.py b/pathspec/gitignore.py index a939225..fd79223 100644 --- a/pathspec/gitignore.py +++ b/pathspec/gitignore.py @@ -32,14 +32,14 @@ class GitIgnoreSpec(PathSpec): """ - The :class:`GitIgnoreSpec` class extends :class:`PathSpec` to + The :class:`GitIgnoreSpec` class extends :class:`pathspec.pathspec.PathSpec` to replicate *.gitignore* behavior. """ def __eq__(self, other: object) -> bool: """ - Tests the equality of this gitignore-spec with *other* - (:class:`GitIgnoreSpec`) by comparing their :attr:`~PathSpec.patterns` + Tests the equality of this gitignore-spec with *other* (:class:`GitIgnoreSpec`) + by comparing their :attr:`~pathspec.pattern.Pattern` attributes. A non-:class:`GitIgnoreSpec` will not compare equal. """ if isinstance(other, GitIgnoreSpec): @@ -66,7 +66,8 @@ def from_lines( *pattern_factory* can be :data:`None`, the name of a registered pattern factory (:class:`str`), or a :class:`~collections.abc.Callable` used to compile patterns. The callable must accept an uncompiled - pattern (:class:`str`) and return the compiled pattern (:class:`.Pattern`). + pattern (:class:`str`) and return the compiled pattern + (:class:`pathspec.pattern.Pattern`). Default is :data:`None` for :class:`.GitWildMatchPattern`). Returns the :class:`GitIgnoreSpec` instance. diff --git a/pathspec/pathspec.py b/pathspec/pathspec.py index 93f2f60..9153baa 100644 --- a/pathspec/pathspec.py +++ b/pathspec/pathspec.py @@ -137,7 +137,7 @@ def match_entries( """ Matches the entries to this path-spec. - *entries* (:class:`~collections.abc.Iterable` of :class:`~util.TreeEntry`) + *entries* (:class:`~collections.abc.Iterable` of :class:`~pathspec.util.TreeEntry`) contains the entries to be matched against :attr:`self.patterns `. *separators* (:class:`~collections.abc.Collection` of :class:`str`; or @@ -150,7 +150,7 @@ def match_entries( :data:`False`. Returns the matched entries (:class:`~collections.abc.Iterator` of - :class:`~util.TreeEntry`). + :class:`~pathspec.util.TreeEntry`). """ if not _is_iterable(entries): raise TypeError(f"entries:{entries!r} is not an iterable.") @@ -179,7 +179,7 @@ def match_file( """ Matches the file to this path-spec. - *file* (:class:`str` or :class:`os.PathLike[str]`) is the file path to be + *file* (:class:`str` or :class:`os.PathLike`) is the file path to be matched against :attr:`self.patterns `. *separators* (:class:`~collections.abc.Collection` of :class:`str`) @@ -202,7 +202,7 @@ def match_files( Matches the files to this path-spec. *files* (:class:`~collections.abc.Iterable` of :class:`str` or - :class:`os.PathLike[str]`) contains the file paths to be matched against + :class:`os.PathLike`) contains the file paths to be matched against :attr:`self.patterns `. *separators* (:class:`~collections.abc.Collection` of :class:`str`; or @@ -215,7 +215,7 @@ def match_files( :data:`False`. Returns the matched files (:class:`~collections.abc.Iterator` of - :class:`str` or :class:`os.PathLike[str]`). + :class:`str` or :class:`os.PathLike`). """ if not _is_iterable(files): raise TypeError(f"files:{files!r} is not an iterable.") @@ -243,7 +243,7 @@ def match_tree_entries( Walks the specified root path for all files and matches them to this path-spec. - *root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory to + *root* (:class:`str` or :class:`os.PathLike`) is the root directory to search. *on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally @@ -277,7 +277,7 @@ def match_tree_files( Walks the specified root path for all files and matches them to this path-spec. - *root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory to + *root* (:class:`str` or :class:`os.PathLike`) is the root directory to search for files. *on_error* (:class:`~collections.abc.Callable` or :data:`None`) optionally diff --git a/pathspec/pattern.py b/pathspec/pattern.py index 5222ec0..8f20e73 100644 --- a/pathspec/pattern.py +++ b/pathspec/pattern.py @@ -51,7 +51,7 @@ def match(self, files: Iterable[str]) -> Iterator[str]: *files* (:class:`~collections.abc.Iterable` of :class:`str`) contains each file relative to the root directory (e.g., - :data:`"relative/path/to/file"`). + ``"relative/path/to/file"``). Returns an :class:`~collections.abc.Iterable` yielding each matched file path (:class:`str`). @@ -160,7 +160,7 @@ def match_file(self, file: str) -> Optional['RegexMatchResult']: *file* (:class:`str`) contains each file relative to the root directory (e.g., "relative/path/to/file"). - Returns the match result (:class:`RegexMatchResult`) if *file* + Returns the match result (:class:`.RegexMatchResult`) if *file* matched; otherwise, :data:`None`. """ if self.include is not None: diff --git a/pathspec/util.py b/pathspec/util.py index 969e3bc..9408f25 100644 --- a/pathspec/util.py +++ b/pathspec/util.py @@ -62,7 +62,7 @@ def append_dir_sep(path: pathlib.Path) -> str: files on the file-system by relying on the presence of a trailing path separator. - *path* (:class:`pathlib.path`) is the path to use. + *path* (:class:`pathlib.Path`) is the path to use. Returns the path (:class:`str`). """ @@ -88,7 +88,7 @@ def detailed_match_files( *files* (:class:`~collections.abc.Iterable` of :class:`str`) contains the normalized file paths to be matched against *patterns*. - *all_matches* (:class:`boot` or :data:`None`) is whether to return all + *all_matches* (:class:`bool` or :data:`None`) is whether to return all matches patterns (:data:`True`), or only the last matched pattern (:data:`False`). Default is :data:`None` for :data:`False`. @@ -154,7 +154,7 @@ def iter_tree_entries( """ Walks the specified directory for all files and directories. - *root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory to + *root* (:class:`str` or :class:`os.PathLike`) is the root directory to search. *on_error* (:class:`~collections.abc.Callable` or :data:`None`) @@ -270,7 +270,7 @@ def iter_tree_files( """ Walks the specified directory for all files. - *root* (:class:`str` or :class:`os.PathLike[str]`) is the root directory to + *root* (:class:`str` or :class:`os.PathLike`) is the root directory to search for files. *on_error* (:class:`~collections.abc.Callable` or :data:`None`) @@ -376,16 +376,16 @@ def normalize_file( ) -> str: """ Normalizes the file path to use the POSIX path separator (i.e., - :data:`'/'`), and make the paths relative (remove leading :data:`'/'`). + ``"/"``), and make the paths relative (remove leading ``"/"``). - *file* (:class:`str` or :class:`os.PathLike[str]`) is the file path. + *file* (:class:`str` or :class:`os.PathLike`) is the file path. *separators* (:class:`~collections.abc.Collection` of :class:`str`; or - :data:`None`) optionally contains the path separators to normalize. - This does not need to include the POSIX path separator (:data:`'/'`), - but including it will not affect the results. Default is :data:`None` - for :data:`NORMALIZE_PATH_SEPS`. To prevent normalization, pass an - empty container (e.g., an empty tuple :data:`()`). + ``None``) optionally contains the path separators to normalize. + This does not need to include the POSIX path separator (``"/"``), + but including it will not affect the results. Default is ``None`` + for ``NORMALIZE_PATH_SEPS``. To prevent normalization, pass an + empty container (e.g., an empty tuple ``()``). Returns the normalized file path (:class:`str`). """ @@ -421,7 +421,7 @@ def normalize_files( Normalizes the file paths to use the POSIX path separator. *files* (:class:`~collections.abc.Iterable` of :class:`str` or - :class:`os.PathLike[str]`) contains the file paths to be normalized. + :class:`os.PathLike`) contains the file paths to be normalized. *separators* (:class:`~collections.abc.Collection` of :class:`str`; or :data:`None`) optionally contains the path separators to normalize. @@ -429,7 +429,7 @@ def normalize_files( Returns a :class:`dict` mapping each normalized file path (:class:`str`) to the original file paths (:class:`list` of :class:`str` or - :class:`os.PathLike[str]`). + :class:`os.PathLike`). """ warnings.warn(( "util.normalize_files() is deprecated. Use util.normalize_file() " From 51b0c01dfe4b0082c5f8dbc17296239ebad89fa1 Mon Sep 17 00:00:00 2001 From: Kurt McKee Date: Fri, 1 Dec 2023 08:17:31 -0600 Subject: [PATCH 3/3] Test doc builds in CI --- .github/workflows/ci.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 43f3f97..b2e2a39 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -32,3 +32,22 @@ jobs: - name: Run tests run: python -m tox -e py -- --verbose + + docs: + # Test documentation builds. + # This environment mirrors the ReadTheDocs build environment. + name: Docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v4 + with: + python-version: "3.12" + + - name: Install tox + run: python -m pip install tox + + - name: Run tests + run: python -m tox -e docs