diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index e6d2cf33..1968306d 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -6,7 +6,7 @@ open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: pypi/sphobjinv # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: bskinn # Replace with a single Liberapay username +liberapay: # bskinn # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username -custom: ['https://paypal.me/btskinn'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] +custom: # ['https://paypal.me/btskinn'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index f399d2ac..18ea8d83 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -10,12 +10,16 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: '3.10' + cache: 'pip' + cache-dependency-path: | + requirements-ci.txt + requirements-flake8.txt - name: Update pip & setuptools run: python -m pip install -U pip setuptools @@ -59,17 +63,21 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: ['3.6', '3.7', '3.8', '3.9'] + python: ['3.6', '3.7', '3.8', '3.9', '3.11'] if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - name: Check out repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} + cache: 'pip' + cache-dependency-path: | + requirements-ci.txt + requirements-flake8.txt - name: Update pip & setuptools run: python -m pip install -U pip setuptools diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ff92ceda..ccc2af3c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - id: check-yaml - id: check-added-large-files - repo: https://github.com/psf/black - rev: '22.1.0' + rev: '22.3.0' hooks: - id: black - repo: https://github.com/tox-dev/pyproject-fmt diff --git a/.readthedocs.yml b/.readthedocs.yml index 62541d22..c8cb0972 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,18 +5,22 @@ # Required version: 2 -# Build with sphinx -sphinx: - configuration: doc/source/conf.py - -# Build all the things -formats: all +# Build and VM configuration +build: + os: 'ubuntu-22.04' + tools: + python: '3.10' -# Python and requirements +# Python requirements python: - version: '3.8' install: - requirements: requirements-rtd.txt - method: pip path: . +# Build with sphinx +sphinx: + configuration: doc/source/conf.py + +# Build all the things +formats: all diff --git a/AUTHORS.md b/AUTHORS.md index e3b7a59e..b3dcc0ec 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,23 +1,31 @@ Credits ======= -`sphobjinv` is authored and maintained by Brian Skinn ([Blog](https://bskinn.github.io)) ([Twitter](https://twitter.com/btskinn)). +`sphobjinv` is authored and maintained by Brian Skinn +([Blog](https://bskinn.github.io)) ([Twitter](https://twitter.com/btskinn)). -The idea for the project came about as I was starting to deepen my expertise with Sphinx, and found it -hugely frustrating to debug cross-references to objects in code. I discovered the `objects.inv` files -relatively quickly, but struggled with trying to get at the actual object information. -At the time (2016), the ability to [execute `sphinx.ext.intersphinx` as a module](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#showing-all-links-of-an-intersphinx-mapping-file) -hadn't yet been documented (that happened in [2018](https://github.com/sphinx-doc/sphinx/commit/7aaba1758a4622298d15339fddd8556eb221af86)), -and a fair bit of searching didn't turn up anything promising. +The idea for the project came about as I was starting to deepen my expertise +with Sphinx, and found it hugely frustrating to debug cross-references to +objects in code. I discovered the `objects.inv` files relatively quickly, but +struggled with trying to get at the actual object information. At the time +(2016), the ability to +[execute `sphinx.ext.intersphinx` as a module](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#showing-all-links-of-an-intersphinx-mapping-file) +hadn't yet been documented (that happened in +[2018](https://github.com/sphinx-doc/sphinx/commit/7aaba1758a4622298d15339fddd8556eb221af86)), +and a fair bit of searching didn't turn up anything promising. -Once I dug into the Sphinx code to figure out how to zlib-decompress the object data, it was relatively straightforward -to put together the initial v1.0 of `sphobjinv`, which could only (de)compress `objects.inv` files to/from plaintext. -As I started to use it regularly in my own documentation work, it became clear that there would be significant advantages -from also implementing functionality to assist with object searches, especially in large documentation sets. -Also, it seemed likely that a robust API for creation/manipulation of inventory contents would be useful, in order to -assist with things like scraping a non-Sphinx website to generate an `objects.inv` for cross-referencing in other docs. -This led to the current object-oriented API of `sphobjinv` v2.x. +Once I dug into the Sphinx code to figure out how to zlib-decompress the object +data, it was relatively straightforward to put together the initial v1.0 of +`sphobjinv`, which could only (de)compress `objects.inv` files to/from +plaintext. As I started to use it regularly in my own documentation work, it +became clear that there would be significant advantages to also implement object +searches, especially in large documentation sets. Also, it seemed likely that a +robust API for creation/manipulation of inventory contents would be useful, in +order to assist with things like scraping a non-Sphinx website to generate an +`objects.inv` for cross-referencing in other docs. This led to the current +object-oriented API of `sphobjinv` v2.x. -While there are [numerous](https://github.com/bskinn/sphobjinv/issues) possible enhancements to the project, -I'm quite satisfied with its ease of use and usefulness, at least for my purposes, and thus consider it fully stable. -I'm always glad to receive feature requests and bug reports, though. \ No newline at end of file +While there are [numerous](https://github.com/bskinn/sphobjinv/issues) possible +enhancements to the project, I'm satisfied with its ease of use and usefulness, +at least for my purposes, and thus consider it fully stable. I'm always glad to +receive feature requests and bug reports, though. diff --git a/CHANGELOG.md b/CHANGELOG.md index 5752032d..9ff29552 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,110 @@ and this project strives to adhere to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +### [2.3] - 2022-11-08 + +#### Added + + * The CLI now prints the project name and version for the `objects.inv` as + part of the 'suggest' mode output. + + * The CLI now prints an inferred `intersphinx_mapping` entry for a remote + docset as part of the 'suggest' mode output, where such inference is + possible. The output from this mapping inference was added to the relevant + tests, and a couple of unit tests on some basic pieces of functionality were + written. ([#149](https://github.com/bskinn/sphobjinv/issues/149)) + + * The CLI now provides considerably more information about what is happening + with the URLs it checks when trying to retrieve a remote inventory. + ([#99](https://github.com/bskinn/sphobjinv/issues/99), plus more) + + * A new CLI option, `-p`/`--paginate`, enables paging of the results from the + `suggest` feature. ([#70](https://github.com/bskinn/sphobjinv/issues/70)) + +#### Fixed + + * The regex for parsing object lines from decompressed inventories now + correctly processes `{role}` values that contain internal colons. + + * CLI corner case where options are passed but no subparser is specified + now results in a clean error-exit, instead of an exception. + ([#239](https://github.com/bskinn/sphobjinv/issues/239)) + +#### Documentation + + * Updated doctests to reflect the new v22.1 attrs `objects.inv` used for + demonstration purposes. + + * Updated `syntax.rst` to indicate that the `{role}` in an inventory object + MAY contain a colon. + + * Added new 'CLI implementation' pages for the new modules, downstream of the + refactoring of the CLI 'convert' and 'suggest' code. + + * Revised the intro paragraph of the 'CLI usage' page to more clearly emphasize + the two CLI subcommands and the links to their respective docs pages. + + * Fixed a mistake in the CLI help info for the `--url` argument to `convert`. + +#### Tests + + * Various tests were updated to reflect the contents of the new v22.1 attrs + `objects.inv` introduced to replace the previous v17.2 inventory. + + * A modern Sphinx `objects.inv` (v6.0.0b) was added to `tests/resource` as + `objects_sphinx.inv`, and the previous v1.6.6 was renamed to + `objects_sphinx_1_6_6.inv`. + + * The 'valid objects' test cases were updated to reflect the possibility for a colon within `{role}`: + + * The colon-within-`{role}` test case was moved from 'invalid' to 'valid'. + + * The colon-within-`{domain}` test case was also moved from 'invalid' to + 'valid', but with an annotation added to indicate that it's not actually + viable---it will actually be interpreted incorrectly, with the first + portion of the colon-containing `{domain}` imported as `{domain}`, and the + remainder imported as part of `{role}`. + +#### Internal + + * Refactor CLI code to place the 'convert' and 'suggest' implementations in + their own modules. + + * Refactor CLI 'suggest' code to the main `do_suggest()` function and a + handful of sub-functions. + + * Rename the `log_print()` CLI helper function to the more-descriptive + `print_stderr()`. + + * Bump development Sphinx version to v5.3. + + * Bump flake8 version to >=5, due to the absorption of flake8-colors + colorization functionality. The flake8/tox config was updated accordingly. + + * Bump pre-commit black hook to v22.3.0. + + * Remove PyPy and Python 3.6 from Azure Pipelines test matrix. + + * Revise `__version__` retrieval in `setup.py` to use an intermediate + dictionary with `exec()`. + + * Update `setup.cfg` to use `license_files`, instead of the deprecated + `license_file`. + +#### Administrative + + * Apply CC BY 4.0 to documentation and docstrings and update project files to + reflect. + + ### [2.2.2] - 2022-03-22 +#### Changed + + * CLI 'suggest' results output now displays more information about + the total number of objects in the inventory, the search score threshold, + and the number of results falling at/above that threshold. + #### Fixed * UnicodeDecodeErrors are ignored within the vendored `fuzzywuzzy` package diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e04d4e7..95610559 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,8 +37,8 @@ Start by forking the repo and cloning locally: $ git clone https://github.com/{you}/sphobjinv ``` -Then, create a virtual environment for the project, -in whatever location you prefer. Any Python interpreter 3.6+ *should* work fine. +Then, create a virtual environment for the project, in whatever location you +prefer. Any Python interpreter 3.6+ *should* work fine. I prefer to use `virtualenv` and create in `./env`: @@ -63,14 +63,22 @@ The next step is to upgrade/install the development requirements: (sphobjinv) $ pip install -r requirements-dev.txt ``` -Then, install the pre-commit hooks: +Then, install the [`pre-commit`](https://pre-commit.com/) hooks: ``` (sphobjinv) $ pre-commit install ``` -Finally, you'll need to build the Sphinx docs, -as some of the tests interact with them: +One of the `pre-commit` hooks installed on the project is the hook from +[`black`](https://black.readthedocs.io/en/stable/). If you want to run `black` +independently from `pre-commit`, you'll need to install it separately: + +``` +(sphobjinv) $ pip install black +``` + +Finally, you'll need to build the Sphinx docs locally, as some of the tests +interact with them: ``` (sphobjinv) $ cd doc @@ -80,8 +88,8 @@ as some of the tests interact with them: ## Working with git -There's no way I can fit a whole git tutorial in here, so this -just highlights a couple of key functionalities you'll need. +There's no way I can fit a whole git tutorial in here, so this just highlights a +couple of key functionalities you'll need. First, always hack on a bugfix or feature in a new branch: @@ -89,11 +97,11 @@ First, always hack on a bugfix or feature in a new branch: $ git checkout -b description-of-change ``` -This makes it a lot simpler to get your repo fork up to date -after `main` receives further commits. +This makes it a lot simpler to get your repo fork up to date after `main` +receives further commits. -To bring your fork's `main` up to date, you first need to -add the main repo as a new git remote (one-time task): +To bring your fork's `main` up to date, you first need to add the main repo as a +new git remote (one-time task): ``` $ git remote add upstream https://github.com/bskinn/sphobjinv @@ -104,54 +112,51 @@ Then, any time you need to refresh the fork's `main`: ``` $ git fetch --all $ git checkout main -$ git merge upstream/main # (should merge without incident) -$ git push # (should push to your fork without incident) +$ git merge upstream/main # (should merge without incident) +$ git push # (should push to your fork without incident) ``` ## Tests -`sphobjinv` uses the [`pytest`](https://github.com/pytest-dev/pytest) -framework for most of its automated tests. From a properly configured -virtual environment, a simple no-arguments invocation is all -that is required: +`sphobjinv` uses the [`pytest`](https://github.com/pytest-dev/pytest) framework +for most of its automated tests. From a properly configured virtual environment, +a simple no-arguments invocation is all that is required: ``` $ pytest ``` -The test suite defaults to running only local tests, -those that do **NOT** require network access. To include -the nonlocal tests, run with the `--nonloc` flag: +The test suite defaults to running only local tests, those that do **NOT** +require network access. To include the nonlocal tests, run with the `--nonloc` +flag: ``` $ pytest --nonloc ``` -When putting together a PR, at minimum, please add/augment the test suite -as necessary to maintain 100% test coverage. To the extent possible, -please go beyond this and add tests that check potential edge cases, -bad/malformed/invalid inputs, etc. For bugfixes, add one or more -focused regression tests that cover the bug behavior being fixed. +When putting together a PR, at minimum, please add/augment the test suite as +necessary to maintain 100% test coverage. To the extent possible, please go +beyond this and add tests that check potential edge cases, bad/malformed/invalid +inputs, etc. For bugfixes, add one or more focused regression tests that cover +the bug behavior being fixed. -PRs that add [xfail tests for existing bugs](https://blog.ganssle.io/articles/2021/11/pytest-xfail.html) +PRs that add +[xfail tests for existing bugs](https://blog.ganssle.io/articles/2021/11/pytest-xfail.html) are also welcomed. -There are some situations where it may make sense to use a -`# pragma: no cover` to ignore coverage on certain line(s) of code. -Please start a discussion in the issue or PR comments before -adding such a pragma. +There are some situations where it may make sense to use a `# pragma: no cover` +to ignore coverage on certain line(s) of code. Please start a discussion in the +issue or PR comments before adding such a pragma. -Note that while [`tox`](https://github.com/tox-dev/tox/) *is* -configured for the project, it is **not** set up to be an everyday test runner. -Instead, it's used to execute a matrix of test environments -checking for the compatibility of different Python and dependency -versions. You can run it if you want, but you'll need -working versions of all of Python 3.6 through 3.11 -installed and on `PATH` as `python3.6`, `python3.7`, etc. -The nonlocal test suite is run for each `tox` environment, so -it's best to use at most two parallel sub-processes to avoid oversaturating -your network bandwidth; e.g.: +Note that while [`tox`](https://tox.wiki/en/latest/) *is* configured for the +project, it is **not** set up to be an everyday test runner. Instead, it's used +to execute an extensive matrix of test environments checking for the +compatibility of different Python and dependency versions. You can run it if you +want, but you'll need working versions of all of Python 3.6 through 3.11 +installed and on `PATH` as `python3.6`, `python3.7`, etc. The nonlocal test +suite is run for each `tox` environment, so it's best to use at most two +parallel sub-processes to avoid oversaturating your network bandwidth; e.g.: ``` $ tox -rp2 @@ -161,8 +166,8 @@ $ tox -rp2 ## Linting The project uses a number of lints, which are checked using -[`flake8`](https://gitlab.com/pycqa/flake8) in CI. -To run the lints locally, it's easiest to use `tox`: +[`flake8`](https://flake8.pycqa.org/en/latest/) in CI. To run the lints locally, +it's easiest to use `tox`: ``` $ tox -e flake8 @@ -170,15 +175,15 @@ $ tox -e flake8 In some limited circumstances, it may be necessary to add [`# noqa`](https://flake8.pycqa.org/en/stable/user/violations.html#in-line-ignoring-errors) -or [`per_file_ignores`](https://flake8.pycqa.org/en/stable/user/options.html#cmdoption-flake8-per-file-ignores) -exclusions to the `flake8` lints. -Please note these for discussion in an issue/PR comment -as soon as you think they might be needed. +or +[`per_file_ignores`](https://flake8.pycqa.org/en/stable/user/options.html#cmdoption-flake8-per-file-ignores) +exclusions to the `flake8` lints. Please note these for discussion in an +issue/PR comment as soon as you think they might be needed. -Additionally, the CI for pull requests is set up to check that all -modules, functions, classes and methods have docstrings -using the [`interrogate`](https://pypi.org/project/interrogate/) package. -There's a `tox` environment for running this check, also: +Additionally, the CI for pull requests is set up to check that all modules, +functions, classes and methods have docstrings using the +[`interrogate`](https://pypi.org/project/interrogate/) package. There's a `tox` +environment for running this check, also: ``` $ tox -e interrogate @@ -187,36 +192,33 @@ $ tox -e interrogate ## Type Hints -I'd like to [roll out typing](https://github.com/bskinn/sphobjinv/issues/132) -on the project at some point in the near future, and add -[`mypy`](https://github.com/python/mypy) checking to CI. -(This would be a great PR to put together, for anyone interested....) -For now, types on contributed code are welcomed, but optional. -Once the codebase is typed, though, they will be a required part of -any PR touching code. +I'd like to [roll out typing](https://github.com/bskinn/sphobjinv/issues/132) on +the project at some point in the near future, and add +[`mypy`](https://github.com/python/mypy) checking to CI. (This would be a great +PR to put together, for anyone interested....) For now, types on contributed +code are welcomed, but optional. Once the codebase is typed, though, they will +be a required part of any PR touching code. ## Documentation -All of the project documentation (except the README) is -generated via [Sphinx](https://github.com/sphinx-doc/sphinx), -and should be updated for (at minimum) any behavior changes -in the codebase. API changes should be documented in the -relevant docstring(s), and possibly in the prose portions -of the documentation as well. Please use the modified -[NumPy-style](https://numpydoc.readthedocs.io/en/latest/format.html) -formatting for docstrings that is already in use in the project. +All of the project documentation (except the README) is generated via +[Sphinx](https://github.com/sphinx-doc/sphinx), and should be updated for (at +minimum) any behavior changes in the codebase. API changes should be documented +in the relevant docstring(s), and possibly in the prose portions of the +documentation as well. Please use the modified +[NumPy-style](https://numpydoc.readthedocs.io/en/latest/format.html) formatting +for docstrings that is already in use in the project. A large number of reStructuredText substitutions are defined in the `rst_epilog` -setting within `conf.py`, to make the documentation source -more readable. Feel free to add more entries there. +setting within `conf.py`, to make the documentation source more readable. Feel +free to add more entries there. -To run any of the Sphinx builders, first change to the `/doc` directory -in the repository tree. In most cases, a plain `make html` invocation -is sufficient to build the docs properly, -as Sphinx does its best to detect which files were changed and -rebuild only the minimum portion of the documentation necessary. -If the docs seem not to be rendering correctly, try a clean build: +To run any of the Sphinx builders, first change to the `/doc` directory in the +repository tree. In most cases, a plain `make html` invocation is sufficient to +build the docs properly, as Sphinx does its best to detect which files were +changed and rebuild only the minimum portion of the documentation necessary. If +the docs seem not to be rendering correctly, try a clean build: ``` === Linux/Mac @@ -226,10 +228,10 @@ doc $ make clean html doc> make -Ea ``` -It's also a good idea to build the complete docs every once in a while with -its ['nitpicky' option](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-nitpicky), -in order to detect any broken cross-references, as these will fail -the [Azure CI pipeline](#continuous-integration): +It's also a good idea to build the complete docs every once in a while with its +['nitpicky' option](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-nitpicky), +in order to detect any broken cross-references, as these will fail the +[Azure CI pipeline](#continuous-integration): ``` === Linux/Mac @@ -239,51 +241,53 @@ doc $ O=-n make clean html doc> make html -Ean ``` -You can also run the doctests with `make doctest` -and the link validity checker with `make linkcheck`. +You can also run the doctests with `make doctest` and the link validity checker +with `make linkcheck`. ## Continuous Integration -Both Github Actions and Azure Pipelines are set up for the project, -and should run on any forks of the repository. +Both Github Actions and Azure Pipelines are set up for the project, and should +run on any forks of the repository. -Github Actions runs the test suite on Linux for Python 3.6 through 3.10, -as well as the `flake8` lints and the Sphinx doctests and link-validity testing, -and is configured to run on all commits. The workflow can be skipped -per-commit by including `[skip ci]` in the commit message. +Github Actions runs the test suite on Linux for Python 3.6 through 3.11, as well +as the `flake8` lints and the Sphinx doctests and link-validity testing, and is +configured to run on all commits. The workflow can be skipped per-commit by +including `[skip ci]` in the commit message. The Azure Pipelines CI runs an extensive matrix of cross-platform and -cross-Python-version tests, as well as numerous other checks. -Due to its length, it is configured to run only on release branches -and PRs to `main` or `stable`. It cannot be skipped. +cross-Python-version tests, as well as numerous other checks. Due to its length, +it is configured to run only on release branches and PRs to `main` or `stable`. +Azure Pipelines now [also obeys `[skip ci]` +directives](https://learn.microsoft.com/en-us/azure/devops/pipelines/repos/azure-repos-git?view=azure-devops&tabs=yaml#skipping-ci-for-individual-pushes). ## CHANGELOG -The project [`CHANGELOG`](https://github.com/bskinn/sphobjinv/blob/main/CHANGELOG.md) -should be updated for the majority of contributions. No tooling is in place -(e.g., [`towncrier`](https://github.com/twisted/towncrier)) for automated collation -of news items into `CHANGELOG`; -all changes should be documented manually, directly in the `CHANGELOG`. +The project +[`CHANGELOG`](https://github.com/bskinn/sphobjinv/blob/main/CHANGELOG.md) should +be updated for the majority of contributions. No tooling is in place (e.g., +[`towncrier`](https://github.com/twisted/towncrier)) for automated collation of +news items into `CHANGELOG`; all changes should be documented manually, directly +in the `CHANGELOG`. Please follow the format currently in use. Any PR that touches the project code *must* include a `CHANGELOG` entry. -Contributions that make changes just to the test suite should usually also include -a `CHANGELOG` entry, except for very minor or cosmetic changes. Other changes of note -(packaging/build tooling, test/lint tooling/plugins, tool settings, etc.) -may also warrant a `CHANGELOG` bullet, depending on the situation. -When in doubt, ask! +Contributions that make changes just to the test suite should usually also +include a `CHANGELOG` entry, except for very minor or cosmetic changes. Other +changes of note (packaging/build tooling, test/lint tooling/plugins, tool +settings, etc.) may also warrant a `CHANGELOG` bullet, depending on the +situation. When in doubt, ask! ## Issue & PR Templates -The project is configured with a PR template and a couple of -issue templates, to hopefully make it easier to provide all -the information needed to act on code contributions, bug reports, -and feature requests. If the templates don't fit the issue/PR -you want to create, though, then don't use them. +I've set up the project with a PR template and a couple of issue templates, to +hopefully make it easier to provide all the information needed to act on code +contributions, bug reports, and feature requests. If the templates don't fit the +issue/PR you want to create, though, then don't use them. ## License -All contributions will take on the MIT License of the project at large. +All code and documentation contributions will respectively take on the MIT +License and CC-BY 4.0 license of the project at large. diff --git a/LICENSE.txt b/LICENSE.txt index 7810c538..8cf98957 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,21 +1,33 @@ +The sphobjinv documentation (including docstrings) is licensed under a Creative +Commons Attribution 4.0 International License (CC-BY). + +See http://creativecommons.org/licenses/by/4.0/. + + +The sphobjinv codebase is released under the MIT License, the text of which is +included below. + + +==================================================================================== + + The MIT License (MIT) -Copyright (c) 2016-2022 Brian Skinn +Copyright (c) 2016-2022 Brian Skinn and community contributors -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: +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. +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. diff --git a/README.rst b/README.rst index 641d13da..c1803f54 100644 --- a/README.rst +++ b/README.rst @@ -33,7 +33,7 @@ sphobjinv: Manipulate and inspect Sphinx objects.inv files :target: https://github.com/psf/black .. image:: https://pepy.tech/badge/sphobjinv/month - :target: https://pepy.tech/project/sphobjinv?versions=2.1b1&versions=2.2b1&versions=2.2&versions=2.1&versions=2.0.1 + :target: https://pepy.tech/project/sphobjinv?versions=2.0.1&versions=2.1&versions=2.2.2&versions=2.3 ---- @@ -49,13 +49,23 @@ you mean, but it's pretty hit-or-miss. The best approach is to provide Sphinx with a completely specified cross-reference, and that's where ``sphobjinv`` comes in. -After a ``pip install sphobjinv``, find the documentation set you want -to cross-reference into, and pass it to ``sphobjinv suggest``. +After a ``pip install sphobjinv`` (or ``pipx install sphobjinv``), find the +documentation set you want to cross-reference into, and pass it to +``sphobjinv suggest``. For internal cross-references, locate ``objects.inv`` within ``build/html``:: $ sphobjinv suggest doc/build/html/objects.inv as_rst -st 58 + Project: sphobjinv + Version: 2.3 + + 219 objects in inventory. + + 11 results found at/above current threshold of 58. + + Cannot infer intersphinx_mapping from a local objects.inv. + Name Score --------------------------------------------------- ------- :py:property:`sphobjinv.data.SuperDataObj.as_rst` 60 @@ -76,19 +86,33 @@ The ``-s`` argument in the above shell command indicates to print the ``fuzzywuzzy`` match score along with each search result, and ``-t 50`` changes the reporting threshold for the match score. -For external references, just find the API documentation wherever it lives on the web, -and pass ``sphobjinv suggest`` a URL from within the documentation set +For external references, just find the API documentation wherever it lives on +the web, and pass ``sphobjinv suggest`` a URL from within the documentation set with the ``--url/-u`` flag. For example, say I need to know how to cross-reference the ``linspace`` function from numpy (see -`here `__):: +`here `__):: + + $ sphobjinv suggest https://numpy.org/doc/1.23/reference/index.html linspace -su + + Attempting https://numpy.org/doc/1.23/reference/index.html ... + ... no recognized inventory. + Attempting "https://numpy.org/doc/1.23/reference/index.html/objects.inv" ... + ... HTTP error: 404 Not Found. + Attempting "https://numpy.org/doc/1.23/reference/objects.inv" ... + ... HTTP error: 404 Not Found. + Attempting "https://numpy.org/doc/1.23/objects.inv" ... + ... inventory found. + + Project: NumPy + Version: 1.23 + + 8074 objects in inventory. + + 8 results found at/above current threshold of 75. - $ sphobjinv suggest https://numpy.org/doc/1.19/reference/index.html linspace -su + The intersphinx_mapping for this docset is LIKELY: - No inventory at provided URL. - Attempting "https://numpy.org/doc/1.19/reference/index.html/objects.inv" ... - Attempting "https://numpy.org/doc/1.19/reference/objects.inv" ... - Attempting "https://numpy.org/doc/1.19/objects.inv" ... - Remote inventory found. + (https://numpy.org/doc/1.23/, None) Name Score @@ -104,8 +128,8 @@ cross-reference the ``linspace`` function from numpy (see .. end shell command -**NOTE** that the results from ``sphobjinv suggest`` are printed using the longer -*block directives*, whereas cross-references must be composed using the +**NOTE** that the results from ``sphobjinv suggest`` are printed using the +longer *block directives*, whereas cross-references must be composed using the *inline directives*. Thus, the above ``linspace()`` function must be cross-referenced as ``:func:`numpy.linspace```, **not** ``:function:`numpy.linspace```. @@ -133,13 +157,13 @@ inventory creation/modification:: >>> import sphobjinv as soi >>> inv = soi.Inventory('doc/build/html/objects.inv') >>> print(inv) - + >>> inv.project 'sphobjinv' >>> inv.version - '2.2' + '2.3' >>> inv.objects[0] - DataObjStr(name='sphobjinv.cli.core', domain='py', role='module', priority='0', uri='cli/implementation/core.html#module-$', dispname='-') + DataObjStr(name='sphobjinv.cli.convert', domain='py', role='module', priority='0', uri='cli/implementation/convert.html#module-$', dispname='-') The API also enables straightforward re-export of an inventory, for subsequent use with ``intersphinx`` cross-references. @@ -161,5 +185,9 @@ and feature requests are welcomed at the Copyright (c) Brian Skinn 2016-2022 -License: The MIT License. See `LICENSE.txt `__ -for full license terms. +The ``sphobjinv`` documentation (including docstrings) is licensed under a +`Creative Commons Attribution 4.0 International License `__ +(CC-BY). The ``sphobjinv`` codebase is released under the +`MIT License `__. See +`LICENSE.txt `__ for +full license terms. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index da8b7654..893d0974 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -71,7 +71,7 @@ stages: spec: '3.10' pypy3: spec: 'pypy3' - platforms: [linux, windows] + platforms: [linux] - template: azure-coretest.yml parameters: @@ -84,7 +84,7 @@ stages: spec: '3.9' py310: spec: '3.10' - platforms: [macOs] + platforms: [windows, macOs] - stage: aux_tests @@ -203,5 +203,3 @@ stages: - script: tox -e flake8-noqa displayName: Run never-fail flake8 with noqa check - - diff --git a/conftest.py b/conftest.py index 1ed15dd3..a4e77290 100644 --- a/conftest.py +++ b/conftest.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 @@ -16,10 +16,14 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -218,7 +222,7 @@ def sphinx_version(): """ p_version = re.compile(r"(\d+)[.]?(\d+)?[.]?(\d+)?") mch = p_version.match(sphinx_version_str) - return tuple(map((lambda x: int(x) if x else 0), mch.groups())) + return tuple(int(x) if x else 0 for x in mch.groups()) @pytest.fixture() # Must be function scope since uses monkeypatch @@ -278,8 +282,8 @@ def func(inv, source_type): """ assert inv.project == "attrs" - assert inv.version == "17.2" - assert inv.count == 56 + assert inv.version == "22.1" + assert inv.count == 129 assert inv.source_type return func diff --git a/doc/source/_static/css/custom.css b/doc/source/_static/css/custom.css new file mode 100644 index 00000000..ed801b50 --- /dev/null +++ b/doc/source/_static/css/custom.css @@ -0,0 +1,47 @@ +/* Lighten the header blue color */ +div.wy-side-nav-search { + background-color: #7ebbff; +} + +/* White version text in header */ +div.version { + color: #ffffff !important; + font-weight: bolder !important; +} + +/* Blue border around the search bar */ +form.wy-form input { + border: 3px solid #6eabef !important; +} + +/* + ul.current selects only the sidebar ul. Otherwise, + toctrees in the text get colored white, too +*/ +ul.current li.toctree-l1:not(.current) a { + color: #f8f8f8 !important; +} + +/* Increase font size for code object names in navbar toctree */ +a.reference.internal code.docutils.literal.notranslate { + font-size: 85%; +} + +/* + Reduce margin at bottom of 'property' docs. + Too much vertical whitespace previously. +*/ +.rst-content dl.property { + margin-bottom: 10px !important; +} + +/* + Reduced font size in footer +*/ +footer, footer div[role=contentinfo] p, footer p.footer-license { + font-size: 13px; +} + +footer p.footer-license { + line-height: 20px; +} diff --git a/doc/source/_static/mouseover_example.png b/doc/source/_static/mouseover_example.png index 07e60cba..eef34b44 100644 Binary files a/doc/source/_static/mouseover_example.png and b/doc/source/_static/mouseover_example.png differ diff --git a/doc/source/_static/soi-logo_duo_border.png b/doc/source/_static/soi-logo_duo_border.png index a60917b9..cda86fa6 100644 Binary files a/doc/source/_static/soi-logo_duo_border.png and b/doc/source/_static/soi-logo_duo_border.png differ diff --git a/doc/source/_static/soi-logo_duo_border.xcf b/doc/source/_static/soi-logo_duo_border.xcf index 08e35189..a1e37544 100644 Binary files a/doc/source/_static/soi-logo_duo_border.xcf and b/doc/source/_static/soi-logo_duo_border.xcf differ diff --git a/doc/source/_templates/footer.html b/doc/source/_templates/footer.html new file mode 100644 index 00000000..1ee7734e --- /dev/null +++ b/doc/source/_templates/footer.html @@ -0,0 +1,21 @@ +{% extends "!footer.html" %} + +{%-block extrafooter %} + +{{ super }} + +

+ + + + + +{% endblock %} diff --git a/doc/source/api_usage.rst b/doc/source/api_usage.rst index 20d8b556..8e6e097c 100644 --- a/doc/source/api_usage.rst +++ b/doc/source/api_usage.rst @@ -17,11 +17,11 @@ Inspecting the contents of an existing inventory is handled entirely by the >>> inv = soi.Inventory('objects_attrs.inv') >>> print(inv) - + >>> inv.version - '17.2' + '22.1' >>> inv.count - 56 + 129 The location of the inventory file to import can also be provided as a :class:`pathlib.Path`, instead of as a string: @@ -38,12 +38,12 @@ a |list| in the :attr:`~sphobjinv.inventory.Inventory.objects` attribute: .. doctest:: api_inspect >>> len(inv.objects) - 56 + 129 >>> dobj = inv.objects[0] >>> dobj - DataObjStr(name='attr.Attribute', domain='py', role='class', priority='1', uri='api.html#$', dispname='-') + DataObjStr(name='attr', domain='py', role='module', priority='0', uri='index.html#module-$', dispname='-') >>> dobj.name - 'attr.Attribute' + 'attr' >>> dobj.domain 'py' >>> [d.name for d in inv.objects if 'validator' in d.uri] @@ -56,10 +56,10 @@ inventories, as |bytes|: >>> inv2 = soi.Inventory(inv.data_file()) >>> print(inv2) - + >>> inv3 = soi.Inventory(soi.compress(inv.data_file())) >>> print(inv3) - + Remote |objects.inv| files can also be retrieved via URL, with the *url* keyword argument: @@ -67,7 +67,7 @@ Remote |objects.inv| files can also be retrieved via URL, with the *url* keyword >>> inv4 = soi.Inventory(url='https://github.com/bskinn/sphobjinv/raw/main/tests/resource/objects_attrs.inv') >>> print(inv4) - + Comparing Inventories --------------------- @@ -118,10 +118,10 @@ The :class:`~sphobjinv.data.DataObjStr` instances can be edited in place: >>> inv = soi.Inventory('objects_attrs.inv') >>> inv.objects[0] - DataObjStr(name='attr.Attribute', domain='py', role='class', priority='1', uri='api.html#$', dispname='-') + DataObjStr(name='attr', domain='py', role='module', priority='0', uri='index.html#module-$', dispname='-') >>> inv.objects[0].uri = 'attribute.html' >>> inv.objects[0] - DataObjStr(name='attr.Attribute', domain='py', role='class', priority='1', uri='attribute.html', dispname='-') + DataObjStr(name='attr', domain='py', role='module', priority='0', uri='attribute.html', dispname='-') New instances can be easily created either by direct instantiation, or by :meth:`~sphobjinv.data.SuperDataObj.evolve`: @@ -130,9 +130,9 @@ New instances can be easily created either by direct instantiation, or by >>> inv.objects.append(inv.objects[0].evolve(name='attr.Generator', uri='generator.html')) >>> inv.count - 57 + 130 >>> inv.objects[-1] - DataObjStr(name='attr.Generator', domain='py', role='class', priority='1', uri='generator.html', dispname='-') + DataObjStr(name='attr.Generator', domain='py', role='module', priority='0', uri='generator.html', dispname='-') The other attributes of the :class:`~sphobjinv.inventory.Inventory` instance can also be freely modified: @@ -141,7 +141,7 @@ The other attributes of the :class:`~sphobjinv.inventory.Inventory` instance can >>> inv.project = 'not_attrs' >>> inv.version = '0.1' >>> print(inv) - + Formatting Inventory Contents @@ -156,10 +156,10 @@ the plaintext |objects.inv| format **as** |bytes| via :meth:`~sphobjinv.inventor >>> print(*inv.data_file().splitlines()[:6], sep='\n') b'# Sphinx inventory version 2' b'# Project: attrs' - b'# Version: 17.2' + b'# Version: 22.1' b'# The remainder of this file is compressed using zlib.' - b'attr.Attribute py:class 1 api.html#$ -' - b'attr.Factory py:class 1 api.html#$ -' + b'attr py:module 0 index.html#module-$ -' + b'attr.VersionInfo py:class 1 api.html#$ -' This method makes use of the :meth:`DataObjStr.data_line ` method to format each of the object information lines. @@ -171,11 +171,11 @@ If desired, the :ref:`shorthand ` used for the .. doctest:: api_formatting >>> print(*inv.data_file(expand=True).splitlines()[4:6], sep='\n') - b'attr.Attribute py:class 1 api.html#attr.Attribute attr.Attribute' - b'attr.Factory py:class 1 api.html#attr.Factory attr.Factory' + b'attr py:module 0 index.html#module-attr attr' + b'attr.VersionInfo py:class 1 api.html#attr.VersionInfo attr.VersionInfo' >>> do = inv.objects[0] >>> do.data_line(expand=True) - 'attr.Attribute py:class 1 api.html#attr.Attribute attr.Attribute' + 'attr py:module 0 index.html#module-attr attr' Exporting an Inventory @@ -202,10 +202,10 @@ To export plaintext: >>> print(*Path('objects_attrs.txt').read_text().splitlines()[:6], sep='\n') # Sphinx inventory version 2 # Project: attrs - # Version: 17.2 + # Version: 22.1 # The remainder of this file is compressed using zlib. - attr.Attribute py:class 1 api.html#$ - - attr.Factory py:class 1 api.html#$ - + attr py:module 0 index.html#module-$ - + attr.VersionInfo py:class 1 api.html#$ - For zlib-compressed: @@ -216,10 +216,10 @@ For zlib-compressed: >>> print(*Path('objects_attrs_new.inv').read_bytes().splitlines()[:4], sep='\n') b'# Sphinx inventory version 2' b'# Project: attrs' - b'# Version: 17.2' + b'# Version: 22.1' b'# The remainder of this file is compressed using zlib.' >>> print(Path('objects_attrs_new.inv').read_bytes().splitlines()[6][:10]) - b'5\xcb0\xd7\x9f>\xf3\x84\x89' + b'\xbf\x86\x8fL49\xc4\x91\xb8\x8c' For JSON: @@ -229,4 +229,3 @@ For JSON: >>> soi.writejson('objects_attrs.json', jd) >>> print(Path('objects_attrs.json').read_text()[:51]) # doctest: +SKIP {"project": "attrs", "version": "17.2", "count": 56 - diff --git a/doc/source/cli/convert.rst b/doc/source/cli/convert.rst index d0ebc57d..b979fc78 100644 --- a/doc/source/cli/convert.rst +++ b/doc/source/cli/convert.rst @@ -1,11 +1,11 @@ .. Description of convert commandline usage -Command-Line Usage: "convert" Mode -================================== +Command-Line Usage: "convert" Subcommand +======================================== .. program:: sphobjinv convert -The |cour|\ convert\ |/cour| subparser is used for all conversions of +The |cour|\ convert\ |/cour| subcommand is used for all conversions of "version 2" Sphinx inventory files among plaintext, zlib-compressed, and (unique to |soi|) JSON formats. The |soi| CLI can read and write inventory data from local files @@ -32,10 +32,10 @@ Basic file conversion to the default output filename is straightforward: >>> print(file_head('objects_attrs.txt', head=6)) # Sphinx inventory version 2 # Project: attrs - # Version: 17.2 + # Version: 22.1 # The remainder of this file is compressed using zlib. - attr.Attribute py:class 1 api.html#$ - - attr.Factory py:class 1 api.html#$ - + attr py:module 0 index.html#module-$ - + attr.VersionInfo py:class 1 api.html#$ - A different target filename can be specified, to avoid overwriting an existing file: @@ -66,7 +66,8 @@ indicated URL): >>> cli_run('sphobjinv convert plain -u https://github.com/bskinn/sphobjinv/raw/main/tests/resource/objects_attrs.inv') - Remote inventory found. + Attempting https://github.com/bskinn/sphobjinv/raw/main/tests/resource/objects_attrs.inv ... + ... inventory found. Conversion completed. 'https://github.com/b[...]ce/objects_attrs.inv' converted to '...objects.txt' (plain). @@ -75,10 +76,10 @@ indicated URL): >>> print(file_head('objects.txt', head=6)) # Sphinx inventory version 2 # Project: attrs - # Version: 17.2 + # Version: 22.1 # The remainder of this file is compressed using zlib. - attr.Attribute py:class 1 api.html#$ - - attr.Factory py:class 1 api.html#$ - + attr py:module 0 index.html#module-$ - + attr.VersionInfo py:class 1 api.html#$ - The URL provided **MUST** have the leading protocol specified (here, |cour|\ https\ ://\ |/cour|). @@ -91,11 +92,14 @@ it will automatically find and use the correct |objects.inv|: >>> cli_run('sphobjinv convert plain -ou https://docs.python.org/3/library/urllib.error.html#urllib.error.URLError') - No inventory at provided URL. + Attempting https://docs.python.org/3/library/urllib.error.html#urllib.error.URLError ... + ... no recognized inventory. Attempting "https://docs.python.org/3/library/urllib.error.html/objects.inv" ... + ... HTTP error: 404 Not Found. Attempting "https://docs.python.org/3/library/objects.inv" ... + ... HTTP error: 404 Not Found. Attempting "https://docs.python.org/3/objects.inv" ... - Remote inventory found. + ... inventory found. Conversion completed. '...objects.inv' converted to '...objects.txt' (plain). @@ -131,11 +135,11 @@ If processing of JSON files by API URL is desirable, please >>> cli_run('sphobjinv co plain objects_attrs.inv -') # Sphinx inventory version 2 # Project: attrs - # Version: 17.2 + # Version: 22.1 # The remainder of this file is compressed using zlib. - attr.Attribute py:class 1 api.html#$ - - attr.Factory py:class 1 api.html#$ - - attr.asdict py:function 1 api.html#$ - + attr py:module 0 index.html#module-$ - + attr.VersionInfo py:class 1 api.html#$ - + attr._make.Attribute py:class -1 api.html#attrs.Attribute - ... @@ -205,4 +209,3 @@ If processing of JSON files by API URL is desirable, please Contract `uri` and `dispname` fields, if possible, before writing to output; see :ref:`here `. Cannot be specified with :option:`--expand`. - diff --git a/doc/source/cli/implementation/convert.rst b/doc/source/cli/implementation/convert.rst new file mode 100644 index 00000000..cd68000b --- /dev/null +++ b/doc/source/cli/implementation/convert.rst @@ -0,0 +1,7 @@ +.. Module API page for cli/convert.py + +sphobjinv.cli.convert +===================== + +.. automodule:: sphobjinv.cli.convert + :members: diff --git a/doc/source/cli/implementation/index.rst b/doc/source/cli/implementation/index.rst index 55946645..a174e6f3 100644 --- a/doc/source/cli/implementation/index.rst +++ b/doc/source/cli/implementation/index.rst @@ -6,12 +6,14 @@ sphobjinv.cli (non-API) .. toctree:: :maxdepth: 1 + convert core load parser paths + suggest ui write - -.. .. |argparse| replace:: :mod:`argparse` \ No newline at end of file + +.. .. |argparse| replace:: :mod:`argparse` diff --git a/doc/source/cli/implementation/suggest.rst b/doc/source/cli/implementation/suggest.rst new file mode 100644 index 00000000..3424d1b5 --- /dev/null +++ b/doc/source/cli/implementation/suggest.rst @@ -0,0 +1,7 @@ +.. Module API page for cli/suggest.py + +sphobjinv.cli.suggest +===================== + +.. automodule:: sphobjinv.cli.suggest + :members: diff --git a/doc/source/cli/index.rst b/doc/source/cli/index.rst index ae6a4a22..1974dbdc 100644 --- a/doc/source/cli/index.rst +++ b/doc/source/cli/index.rst @@ -3,17 +3,23 @@ Command-Line Usage ================== -The CLI for |soi| is implemented using two subparsers, one each for the -:doc:`convert ` and :doc:`suggest ` sub-functions. -More information about the implementation of these features can be -found :doc:`here ` and in the documentation for the +The CLI for |soi| is implemented using two subcommands: + + - A :doc:`convert ` subcommand, which handles conversion of + inventories between supported formats (currently zlib-compressed, + plaintext, and JSON). + - A :doc:`suggest ` subcommand, which provides suggestions for + objects in an inventory matching a desired search term. + +More information about the underlying implementation of these subcommands can +be found :doc:`here ` and in the documentation for the :class:`~sphobjinv.inventory.Inventory` object, in particular the :meth:`~sphobjinv.inventory.Inventory.data_file` and :meth:`~sphobjinv.inventory.Inventory.suggest` methods. Some notes on these CLI docs: - * CLI examples are executed in a sandboxed directory pre-loaded with + * CLI docs examples are executed in a sandboxed directory pre-loaded with |cour|\ objects_attrs.inv\ |/cour| (from, e.g., `here `__). @@ -54,5 +60,3 @@ The options for the parent |soi| command are: "convert" Mode "suggest" Mode - - diff --git a/doc/source/cli/suggest.rst b/doc/source/cli/suggest.rst index d12a9026..21fa0a29 100644 --- a/doc/source/cli/suggest.rst +++ b/doc/source/cli/suggest.rst @@ -1,7 +1,7 @@ .. Description of suggest commandline usage -Command-Line Usage: "suggest" Mode -================================== +Command-Line Usage: "suggest" Subcommand +======================================== .. program:: sphobjinv suggest @@ -39,7 +39,7 @@ It is usually not necessary to locate the |objects.inv| file before running |soi for most Sphinx documentation sets, if you provide a URL to any page in the docs, it will automatically find and use the correct |objects.inv|: -.. command-output:: sphobjinv suggest -u https://sphobjinv.readthedocs.io/en/v2.0rc1/cmdline.html compress +.. command-output:: sphobjinv suggest -u https://sphobjinv.readthedocs.io/en/stable/cli/convert.html compress :cwd: /../../tests/resource |soi| only supports download of zlib-compressed |objects.inv| files by URL. @@ -67,7 +67,8 @@ If download of JSON files by URL is desirable, please Path (or URL, if :option:`--url` is specified) to file to be searched. If passed as ``-``, |soi| will attempt import of a plaintext or JSON - inventory from ``stdin`` (incompatible with :option:`--url`). + inventory from ``stdin``. This is incompatible with :option:`--url`, + and automatically enables :option:`--all`. .. option:: search @@ -105,6 +106,3 @@ If download of JSON files by URL is desirable, please Treat :option:`infile` as a URL for download. Cannot be used when :option:`infile` is passed as ``-``. - - - diff --git a/doc/source/conf.py b/doc/source/conf.py index a532e35f..419bc1ec 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -17,9 +17,9 @@ # -- Project information ----------------------------------------------------- -project = 'sphobjinv' -copyright = '2016-2022, Brian Skinn' -author = 'Brian Skinn' +project = "sphobjinv" +copyright = "2016-2022, Brian Skinn" +author = "Brian Skinn" # The full version for `release`, including alpha/beta/rc tags from sphobjinv import __version__ as release @@ -34,6 +34,7 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + "sphinx_rtd_theme", "sphinx.ext.autodoc", "sphinx.ext.doctest", "sphinx.ext.intersphinx", @@ -51,7 +52,7 @@ issues_github_path = "bskinn/sphobjinv" # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -122,10 +123,20 @@ .. _license_txt: https://github.com/bskinn/sphobjinv/blob/main/LICENSE.txt +.. _MIT License: https://opensource.org/licenses/MIT + +.. |CC BY 4.0| replace:: CC BY 4.0 International License + +.. _CC BY 4.0: http://creativecommons.org/licenses/by/4.0/ + .. |fuzzywuzzy| replace:: ``fuzzywuzzy`` .. _fuzzywuzzy: https://github.com/seatgeek/fuzzywuzzy +.. |pipx| replace:: ``pipx`` + +.. _pipx: https://pypa.github.io/pipx/ + .. |python-Levenshtein| replace:: ``python-Levenshtein`` .. _python-Levenshtein: https://pypi.org/project/python-Levenshtein @@ -154,7 +165,7 @@ .. |soi| raw:: html - sphobjinv + sphobjinv .. |stdin| replace:: |cour|\ stdin\ |/cour| @@ -308,12 +319,12 @@ def file_head(fn, *, head=None): # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # 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"] # Output file basename htmlhelp_basename = "sphobjinv" @@ -321,3 +332,8 @@ def file_head(fn, *, head=None): # Location of the favicon and logo images html_favicon = "_static/soi-logo.png" html_logo = "_static/soi-logo_duo_border.png" + +# Adding custom CSS +html_css_files = [ + "css/custom.css", +] diff --git a/doc/source/customfile.rst b/doc/source/customfile.rst index 390ec5c1..24871e43 100644 --- a/doc/source/customfile.rst +++ b/doc/source/customfile.rst @@ -71,10 +71,10 @@ can be found at the GitHub repo The `role` values here must be the **full** role names ("`block directives`"), described as the "directives" in the `Sphinx documentation for - domains `__, + domains `__, and not the abbreviated forms ("`inline directives`") `used when constructing cross-references - `__. + `__. Thus, for example, a :class:`~sphobjinv.data.DataObjStr` corresponding to a method on a class should be constructed with @@ -148,8 +148,8 @@ can be found at the GitHub repo # Django puts its objects.inv file in a non-standard location 'django': ('https://docs.djangoproject.com/en/dev/', 'https://docs.djangoproject.com/en/dev/_objects/'), - # Drawing the Sphinx objects.inv from a local copy, but referring to the 1.7 web docs - 'sphinx': ('https://www.sphinx-doc.org/en/1.7/', '/path/to/local/objects.inv'), + # Drawing the Sphinx objects.inv from a local copy, but referring to the current web docs + 'sphinx': ('https://www.sphinx-doc.org/en/master/', '/path/to/local/objects.inv'), } .. MAKE SURE TO UPDATE THESE TWO STEP REFERENCES IF NUMBERING CHANGES!! diff --git a/doc/source/index.rst b/doc/source/index.rst index cea37fcf..678d1b7f 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -11,7 +11,7 @@ Welcome to sphobjinv! When documentation is built using, e.g., Sphinx's :obj:`~sphinx.builders.html.StandaloneHTMLBuilder`, an inventory of the named objects in the documentation set `is dumped -`__ +`__ to a file called |objects.inv| in the html build directory. (One common location is, |cour|\ doc/build/html\ |/cour|, though the exact location will vary depending on the details of how Sphinx is configured.) This file is read by |isphx| when @@ -41,6 +41,10 @@ Install |soi| via |cour|\ pip\ |/cour|:: $ pip install sphobjinv +Or, if you only plan to use the |soi| CLI, another option is |pipx|_:: + + $ pipx install sphobjinv + Alternatively, |soi| is packaged with `multiple POSIX distributions `__ and package managers, including: @@ -59,7 +63,7 @@ and package managers, including: * OpenEuler: ``python-sphobjinv`` - * openSUSE: ``python-sphobjinv`` (`info `__) + * openSUSE: ``python-sphobjinv`` (`info `__) * Parabola: ``python-sphobjinv`` (`info `__) @@ -99,13 +103,4 @@ The project source repository is on GitHub: `bskinn/sphobjinv Indices and Tables ------------------ -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - - -.. raw:: html - - Logo adapted from freely-available image at - https://heypik.com/images/hand-drawn-cartoon-color-tourist-attraction-sphinx_8ZU4501.html - (retrieved July 2019; now defunct). +:ref:`genindex` --- :ref:`modindex` --- :ref:`search` diff --git a/doc/source/syntax.rst b/doc/source/syntax.rst index 65d9601a..1bb62e49 100644 --- a/doc/source/syntax.rst +++ b/doc/source/syntax.rst @@ -3,26 +3,31 @@ Sphinx objects.inv v2 Syntax ============================ -After decompression, "version 2" Sphinx |objects.inv| files -follow a syntax that, to the best of this author's ability to determine, -is not included in the Sphinx documentation. The below -syntax is believed to be accurate as of Jan 2022 (Sphinx v4.4.0). +After decompression, "version 2" Sphinx |objects.inv| files follow a syntax +that, to the best of this author's ability to determine, is not included in the +Sphinx documentation. The below syntax is believed to be accurate as of Nov 2022 +(Sphinx v6.0.0b2). It is based on inspection of |objects.inv| files "in the +wild" and of the Sphinx inventory object `parsing regex`_. Based upon a quick ``git diff`` of the `Sphinx repository `__, it is thought to be valid for all Sphinx versions >=1.0b1 that make use of this "version 2" |objects.inv| format. -**NOTE** that the previous version of the syntax presented here has been -shown to be inaccurate (see :issue:`181`), in that it *is* -permitted for the |{name}|_ field to contain whitespace. -The descriptions below have been updated to reflect this and to provide -more detailed information on the constraints governing each field -of an |objects.inv| data line. +**NOTE** that previous versions of the syntax presented here have been +shown to be inaccurate: + + * It *is* permitted for the |{name}|_ field to contain whitespace (see :issue:`181`). + + * It *is* permitted for the |{role}|_ field to contain a colon (see :issue:`256`). + +The descriptions below have been updated to reflect this and to provide more +detailed information on the constraints governing each field of an |objects.inv| +data line. ---- **The first line** `must be exactly -`__: +`__: .. code-block:: none @@ -31,7 +36,7 @@ of an |objects.inv| data line. ---- **The second and third lines** `must obey -`__ +`__ the template: .. code-block:: none @@ -51,7 +56,7 @@ the |isphx| cross-references: ---- **The fourth line** `must contain -`__ +`__ the string ``zlib`` somewhere within it, but for consistency it should be exactly: .. code-block:: none @@ -62,7 +67,7 @@ the string ``zlib`` somewhere within it, but for consistency it should be exactl **All remaining lines** of the file are the objects data, each laid out in the `following syntax -`__: +`__: .. code-block:: none @@ -106,16 +111,19 @@ the string ``zlib`` somewhere within it, but for consistency it should be exactl ``{role}`` The Sphinx role used when cross-referencing the object (falls between the - second and third colons; or, between the first and second colons if + second and third/last colons; or, between the first and second/last colons if using the |defdom|_). + Note that the role MAY contain a colon, as occurs with the + |rst-directive-option|_ directive in the Sphinx docs. + **Constraints** * **MUST** have nonzero length * **MUST** match a role defined in the domain referenced by ``{domain}`` - * **MUST NOT** contain whitespace or a colon + * **MUST NOT** contain whitespace * **RECOMMENDED** to consist of only ASCII word characters (``a-z``, ``A-Z``, ``0-9``, and ``_``) @@ -124,7 +132,7 @@ the string ``zlib`` somewhere within it, but for consistency it should be exactl ``{priority}`` Flag for `placement in search results - `__. Most will be ``1`` (standard priority) or + `__. Most will be ``1`` (standard priority) or ``-1`` (omit from results) for documentation built by Sphinx. To note, as of Jan 2022 this value is **not** used by ``intersphinx``; @@ -208,11 +216,11 @@ size of the inventory file: `__," the portion following the ``#`` symbol) and the tail of the anchor is identical to |{name}|_, that tail is `replaced - `__ + `__ with ``$``. |br| |br| #. If |{dispname}|_ is identical to |{name}|_, it is `stored - `__ + `__ as ``-``. Thus, a standard |isphx| reference to this method would take the form: @@ -262,11 +270,11 @@ as in :obj:`This is join! `: .. |prio_js_search| replace:: here -.. _prio_js_search: https://github.com/sphinx-doc/sphinx/blob/241577f65eea94a08944bf096bd704b495282373/sphinx/themes/basic/static/searchtools.js#L26-L43 +.. _prio_js_search: https://github.com/sphinx-doc/sphinx/blob/2f60b44999d7e610d932529784f082fc1c6af989/sphinx/themes/basic/static/searchtools.js#L28-L47 .. |prio_py_search| replace:: here -.. _prio_py_search: https://github.com/sphinx-doc/sphinx/blob/241577f65eea94a08944bf096bd704b495282373/sphinx/search/__init__.py#L332 +.. _prio_py_search: https://github.com/sphinx-doc/sphinx/blob/2f60b44999d7e610d932529784f082fc1c6af989/sphinx/search/__init__.py#L332-L333 .. |sphinx_uri_issue| replace:: sphinx-doc/sphinx#7096 @@ -283,3 +291,9 @@ as in :obj:`This is join! `: .. |{uri}| replace:: ``{uri}`` .. |{dispname}| replace:: ``{dispname}`` + +.. |rst-directive-option| replace:: ``:rst:directive:option:`` + +.. _rst-directive-option: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-rst-directive-option + +.. _parsing regex: https://github.com/sphinx-doc/sphinx/blob/2f60b44999d7e610d932529784f082fc1c6af989/sphinx/util/inventory.py#L115-L116 diff --git a/requirements-ci.txt b/requirements-ci.txt index 7db3e2dd..0646ec47 100644 --- a/requirements-ci.txt +++ b/requirements-ci.txt @@ -10,10 +10,10 @@ pytest-check>=0.4 pytest-cov pytest-ordering pytest-timeout -sphinx==4.3.1 +sphinx==5.3.0 sphinx-issues sphinx-removed-in -sphinx-rtd-theme +sphinx-rtd-theme>=0.5.1 sphinxcontrib-programoutput stdio-mgr>=1.0.1 tox diff --git a/requirements-dev.txt b/requirements-dev.txt index d0e2f11a..0cba0c84 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -15,11 +15,11 @@ pytest-ordering pytest-timeout restview rope -sphinx==4.3.1 +sphinx==5.3.0 sphinx-autobuild sphinx-issues sphinx-removed-in -sphinx-rtd-theme +sphinx-rtd-theme>=0.5.1 sphinxcontrib-programoutput stdio-mgr>=1.0.1 tox diff --git a/requirements-flake8.txt b/requirements-flake8.txt index 83d8350e..833ef9ee 100644 --- a/requirements-flake8.txt +++ b/requirements-flake8.txt @@ -1,11 +1,10 @@ colorama -flake8>=3.7 +flake8>=5 flake8-2020 flake8-absolute-import flake8-bandit flake8-bugbear flake8-builtins -flake8-colors flake8-comprehensions flake8-docstrings>=1.3.1 flake8-eradicate diff --git a/requirements-rtd.txt b/requirements-rtd.txt index 739e1e36..a5480e1e 100644 --- a/requirements-rtd.txt +++ b/requirements-rtd.txt @@ -1,6 +1,6 @@ attrs>=19.2 -sphinx==4.3.1 +sphinx==5.3.0 sphinx-issues sphinx-removed-in -sphinx-rtd-theme +sphinx-rtd-theme>=0.5.1 sphinxcontrib-programoutput diff --git a/setup.cfg b/setup.cfg index ac61076f..cab8eb0d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,10 +8,11 @@ project_urls = Thank=https://twitter.com/btskinn Donate=https://github.com/sponsors/bskinn license = MIT License -license_file = LICENSE.txt +license_files = + LICENSE.txt platforms = any author = Brian Skinn -author_email = bskinn@alum.mit.edu +author_email = brian.skinn@gmail.com classifiers = License :: OSI Approved License :: OSI Approved :: MIT License @@ -54,4 +55,3 @@ where = src [options.entry_points] console_scripts = sphobjinv=sphobjinv.cli.core:main - \ No newline at end of file diff --git a/setup.py b/setup.py index f2ead1be..56ccb7ea 100644 --- a/setup.py +++ b/setup.py @@ -5,10 +5,11 @@ NAME = "sphobjinv" -exec(Path("src", "sphobjinv", "version.py").read_text(encoding="utf-8")) +exec_ns = {} +exec(Path("src", "sphobjinv", "version.py").read_text(encoding="utf-8"), exec_ns) +__version__ = exec_ns["__version__"] - -version_override = "2.2" +version_override = None def readme(): diff --git a/src/sphobjinv/__init__.py b/src/sphobjinv/__init__.py index bfdf67be..e825f1b9 100644 --- a/src/sphobjinv/__init__.py +++ b/src/sphobjinv/__init__.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 17 May 2016 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/src/sphobjinv/__main__.py b/src/sphobjinv/__main__.py index bbf9eb2d..4b857e17 100644 --- a/src/sphobjinv/__main__.py +++ b/src/sphobjinv/__main__.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 15 May 2020 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/src/sphobjinv/_vendored/__init__.py b/src/sphobjinv/_vendored/__init__.py index 7dfb4e2b..9fd9d195 100644 --- a/src/sphobjinv/_vendored/__init__.py +++ b/src/sphobjinv/_vendored/__init__.py @@ -6,7 +6,7 @@ Subpackage marker module for vendored packages. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 11 Dec 2021 @@ -18,11 +18,15 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** -""" \ No newline at end of file +""" diff --git a/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py b/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py index 2be667f6..4d0ee0d5 100644 --- a/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py +++ b/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py @@ -19,7 +19,7 @@ **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 11 Dec 2021 @@ -31,10 +31,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/src/sphobjinv/cli/__init__.py b/src/sphobjinv/cli/__init__.py index 8037cfa8..db6aa5cf 100644 --- a/src/sphobjinv/cli/__init__.py +++ b/src/sphobjinv/cli/__init__.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 15 Nov 2020 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/src/sphobjinv/cli/convert.py b/src/sphobjinv/cli/convert.py new file mode 100644 index 00000000..34f2cc2c --- /dev/null +++ b/src/sphobjinv/cli/convert.py @@ -0,0 +1,73 @@ +r"""``sphobjinv`` *module for CLI convert functionality*. + +``sphobjinv`` is a toolkit for manipulation and inspection of +Sphinx |objects.inv| files. + +**Author** + Brian Skinn (brian.skinn@gmail.com) + +**File Created** + 20 Oct 2022 + +**Copyright** + \(c) Brian Skinn 2016-2022 + +**Source Repository** + https://github.com/bskinn/sphobjinv + +**Documentation** + https://sphobjinv.readthedocs.io/en/stable + +**License** + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. + +**Members** + +""" + +from sphobjinv.cli.parser import PrsConst +from sphobjinv.cli.write import write_file, write_stdout + + +def do_convert(inv, in_path, params): + r"""Carry out the conversion operation, including writing output. + + If |cli:OVERWRITE| is passed and the output file + (the default location, or as passed to |cli:OUTFILE|) + exists, it will be overwritten without a prompt. Otherwise, + the user will be queried if it is desired to overwrite + the existing file. + + If |cli:QUIET| is passed, nothing will be + printed to |cour|\ stdout\ |/cour| + (potentially useful for scripting), + and any existing output file will be overwritten + without prompting. + + Parameters + ---------- + inv + + |Inventory| -- Inventory object to be output in the format + indicated by |cli:MODE|. + + in_path + + |str| -- For a local input file, its absolute path. + For a URL, the (possibly truncated) URL text. + + params + + |dict| -- Parameters/values mapping from the active subparser + + """ + if params[PrsConst.OUTFILE] == "-" or ( + params[PrsConst.INFILE] == "-" and params[PrsConst.OUTFILE] is None + ): + write_stdout(inv, params) + else: + write_file(inv, in_path, params) diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index 731f1f1a..dba7479f 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 15 Nov 2020 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -27,139 +31,11 @@ import sys +from sphobjinv.cli.convert import do_convert from sphobjinv.cli.load import inv_local, inv_stdin, inv_url from sphobjinv.cli.parser import getparser, PrsConst -from sphobjinv.cli.ui import log_print, yesno_prompt -from sphobjinv.cli.write import write_file, write_stdout - - -def do_convert(inv, in_path, params): - r"""Carry out the conversion operation, including writing output. - - If |cli:OVERWRITE| is passed and the output file - (the default location, or as passed to |cli:OUTFILE|) - exists, it will be overwritten without a prompt. Otherwise, - the user will be queried if it is desired to overwrite - the existing file. - - If |cli:QUIET| is passed, nothing will be - printed to |cour|\ stdout\ |/cour| - (potentially useful for scripting), - and any existing output file will be overwritten - without prompting. - - Parameters - ---------- - inv - - |Inventory| -- Inventory object to be output in the format - indicated by |cli:MODE|. - - in_path - - |str| -- For a local input file, its absolute path. - For a URL, the (possibly truncated) URL text. - - params - - |dict| -- Parameters/values mapping from the active subparser - - """ - if params[PrsConst.OUTFILE] == "-" or ( - params[PrsConst.INFILE] == "-" and params[PrsConst.OUTFILE] is None - ): - write_stdout(inv, params) - else: - write_file(inv, in_path, params) - - -def do_suggest(inv, params): - r"""Perform the suggest call and output the results. - - Results are printed one per line. - - If neither |cli:INDEX| nor |cli:SCORE| is specified, - the results are output without a header. - If either or both are specified, - the results are output in a lightweight tabular format. - - If the number of results exceeds - |cli:SUGGEST_CONFIRM_LENGTH|, - the user will be queried whether to display - all of the returned results - unless |cli:ALL| is specified. - - No |cli:QUIET| option is available here, since - a silent mode for suggestion output is nonsensical. - - Parameters - ---------- - inv - - |Inventory| -- Inventory object to be output in the format - indicated by |cli:MODE|. - - params - - |dict| -- Parameters/values mapping from the active subparser - - """ - with_index = params[PrsConst.INDEX] - with_score = params[PrsConst.SCORE] - results = inv.suggest( - params[PrsConst.SEARCH], - thresh=params[PrsConst.THRESH], - with_index=with_index, - with_score=with_score, - ) - - if len(results) == 0: - log_print("No results found.", params) - return - - # Query if the results are long enough, but not if '--all' has been - # passed or if the data is coming via stdin (reading from stdin breaks - # the terminal interactions) - if ( - len(results) > PrsConst.SUGGEST_CONFIRM_LENGTH - and not params[PrsConst.ALL] - and params[PrsConst.INFILE] != "-" - ): - resp = yesno_prompt(f"Display all {len(results)} results (Y/N)?") - if resp.lower() == "n": - log_print("\nExiting...", params) - sys.exit(0) - - # Field widths in output - score_width = 7 - index_width = 7 - - if with_index or with_score: - rst_width = max(len(res[0]) for res in results) - else: - rst_width = max(len(res) for res in results) - - rst_width += 2 - - if with_index: - if with_score: - fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}} {{2: ^{index_width}}}" - print(fmt.format(" Name", "Score", "Index")) - print(fmt.format("-" * rst_width, "-" * score_width, "-" * index_width)) - print("\n".join(fmt.format(*_) for _ in results)) - else: - fmt = f"{{0: <{rst_width}}} {{1: ^{index_width}}}" - print(fmt.format(" Name", "Index")) - print(fmt.format("-" * rst_width, "-" * index_width)) - print("\n".join(fmt.format(*_) for _ in results)) - else: - if with_score: - fmt = f"{{0: <{rst_width}}} {{1: ^{score_width}}}" - print(fmt.format(" Name", "Score")) - print(fmt.format("-" * rst_width, "-" * score_width)) - print("\n".join(fmt.format(*_) for _ in results)) - else: - print("\n".join(str(_) for _ in results)) +from sphobjinv.cli.suggest import do_suggest +from sphobjinv.cli.ui import print_stderr def main(): @@ -172,7 +48,8 @@ def main(): Creates the |Inventory| from the indicated source and method. - Invokes :func:`do_convert` or :func:`do_suggest` + Invokes :func:`~sphobjinv.cli.convert.do_convert` or + :func:`~sphobjinv.cli.suggest.do_suggest` per the subparser name stored in |cli:SUBPARSER_NAME|. """ @@ -180,9 +57,11 @@ def main(): if len(sys.argv) == 1: sys.argv.append("-h") - # Parse commandline arguments + # Parse commandline arguments, discarding any unknown ones + # I forget why I set it up to discard these, it might be + # more confusing than it's worth to swallow them this way.... prs = getparser() - ns, args_left = prs.parse_known_args() + ns, _ = prs.parse_known_args() params = vars(ns) # Print version &c. and exit if indicated @@ -190,9 +69,13 @@ def main(): print(PrsConst.VER_TXT) sys.exit(0) + # At this point, need to trap for a null subparser + if not params[PrsConst.SUBPARSER_NAME]: + prs.error("No subparser selected") + # Regardless of mode, insert extra blank line # for cosmetics - log_print(" ", params) + print_stderr(" ", params) # Generate the input Inventory based on --url or stdio or file. # These inventory-load functions should call @@ -214,7 +97,7 @@ def main(): do_suggest(inv, params) # Cosmetic final blank line - log_print(" ", params) + print_stderr(" ", params) # Clean exit sys.exit(0) diff --git a/src/sphobjinv/cli/load.py b/src/sphobjinv/cli/load.py index 0a5d37cf..fc8c075f 100644 --- a/src/sphobjinv/cli/load.py +++ b/src/sphobjinv/cli/load.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 17 Nov 2020 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -35,7 +39,7 @@ from sphobjinv import Inventory, readjson, urlwalk, VersionError from sphobjinv.cli.parser import PrsConst from sphobjinv.cli.paths import resolve_inpath -from sphobjinv.cli.ui import err_format, log_print +from sphobjinv.cli.ui import err_format, print_stderr def import_infile(in_path): @@ -107,14 +111,14 @@ def inv_local(params): try: in_path = resolve_inpath(params[PrsConst.INFILE]) except Exception as e: - log_print("\nError while parsing input file path:", params) - log_print(err_format(e), params) + print_stderr("\nError while parsing input file path:", params) + print_stderr(err_format(e), params) sys.exit(1) # Attempt import inv = import_infile(in_path) if inv is None: - log_print("\nError: Unrecognized file format", params) + print_stderr("\nError: Unrecognized file format", params) sys.exit(1) return inv, in_path @@ -156,41 +160,54 @@ def inv_url(params): """ in_file = params[PrsConst.INFILE] + def attempt_inv_load(url, params): + """Attempt the Inventory load and report outcome.""" + inv = None + + try: + inv = Inventory(url=url) + except HTTPError as e: + print_stderr(f" ... HTTP error: {e.code} {e.reason}.", params) + except URLError: # pragma: no cover + print_stderr(" ... error attempting to retrieve URL.", params) + except VersionError: + print_stderr(" ... no recognized inventory.", params) + except ValueError: + print_stderr( + ( + " ... file found but inventory could not be loaded. " + "(Did you forget https:// ?)" + ), + params, + ) + else: + print_stderr(" ... inventory found.", params) + + return inv + # Disallow --url mode on local files if in_file.startswith("file:/"): - log_print("\nError: URL mode on local file is invalid", params) + print_stderr("\nError: URL mode on local file is invalid", params) sys.exit(1) - # Need to initialize the inventory variable - inv = None + print_stderr(f"Attempting {in_file} ...", params) + inv = attempt_inv_load(in_file, params) - # Try URL as provided - try: - inv = Inventory(url=in_file) - except (HTTPError, ValueError, VersionError, URLError): - log_print("No inventory at provided URL.", params) - else: - log_print("Remote inventory found.", params) + if inv: url = in_file - - # Keep searching if inv not found yet - if not inv: + else: for url in urlwalk(in_file): - log_print(f'Attempting "{url}" ...', params) - try: - inv = Inventory(url=url) - except (ValueError, HTTPError): - pass - else: - log_print("Remote inventory found.", params) + print_stderr(f'Attempting "{url}" ...', params) + inv = attempt_inv_load(url, params) + if inv: break # Cosmetic line break - log_print(" ", params) + print_stderr(" ", params) # Success or no? if not inv: - log_print("No inventory found!", params) + print_stderr("No inventory found!", params) sys.exit(1) params.update({PrsConst.FOUND_URL: url}) @@ -237,5 +254,5 @@ def inv_stdin(params): except (AttributeError, UnicodeEncodeError, TypeError): pass - log_print("Invalid plaintext or JSON inventory format.", params) + print_stderr("Invalid plaintext or JSON inventory format.", params) sys.exit(1) diff --git a/src/sphobjinv/cli/parser.py b/src/sphobjinv/cli/parser.py index e959b47d..1928c5d9 100644 --- a/src/sphobjinv/cli/parser.py +++ b/src/sphobjinv/cli/parser.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 15 Nov 2020 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -147,6 +151,10 @@ class PrsConst: #: number returned, without asking for confirmation ALL = "all" + #: Optional argument name for use with the :data:`SUGGEST` subparser, + #: indicating to paginate the suggest subcommand results + PAGINATE = "paginate" + # ### Helper strings #: Help text for the :data:`CONVERT` subparser HELP_CO_PARSER = ( @@ -309,7 +317,7 @@ def getparser(): "--" + PrsConst.URL, help=( "Treat 'infile' as a URL for download. " - f"Cannot be used with --{PrsConst.URL}." + "Cannot be used with an infile of '-'." ), action="store_true", ) @@ -331,6 +339,12 @@ def getparser(): "without prompting for confirmation.", action="store_true", ) + spr_suggest.add_argument( + "-" + PrsConst.PAGINATE[0], + "--" + PrsConst.PAGINATE, + help="Paginate long search results", + action="store_true", + ) spr_suggest.add_argument( "-" + PrsConst.INDEX[0], "--" + PrsConst.INDEX, diff --git a/src/sphobjinv/cli/paths.py b/src/sphobjinv/cli/paths.py index 5ed69b99..73a68c3f 100644 --- a/src/sphobjinv/cli/paths.py +++ b/src/sphobjinv/cli/paths.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 19 Nov 2020 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py new file mode 100644 index 00000000..92c02800 --- /dev/null +++ b/src/sphobjinv/cli/suggest.py @@ -0,0 +1,340 @@ +r"""``sphobjinv`` *module for CLI suggest functionality*. + +``sphobjinv`` is a toolkit for manipulation and inspection of +Sphinx |objects.inv| files. + +**Author** + Brian Skinn (brian.skinn@gmail.com) + +**File Created** + 20 Oct 2022 + +**Copyright** + \(c) Brian Skinn 2016-2022 + +**Source Repository** + https://github.com/bskinn/sphobjinv + +**Documentation** + https://sphobjinv.readthedocs.io/en/stable + +**License** + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. + +**Members** + +""" + +import itertools as itt +import shutil +import sys +import urllib.parse as urlparse + +from sphobjinv.cli.parser import PrsConst +from sphobjinv.cli.ui import print_stderr, yesno_prompt + + +def do_suggest(inv, params): + r"""Perform the suggest call and output the results. + + Results are printed one per line. + + If neither |cli:INDEX| nor |cli:SCORE| is specified, + the results are output without a header. + If either or both are specified, + the results are output in a lightweight tabular format. + + If the number of results exceeds + |cli:SUGGEST_CONFIRM_LENGTH|, + the user will be queried whether to display + all of the returned results + unless |cli:ALL| is specified. + + No |cli:QUIET| option is available here, since + a silent mode for suggestion output is nonsensical. + + Parameters + ---------- + inv + + |Inventory| -- Inventory object to be output in the format + indicated by |cli:MODE|. + + params + + |dict| -- Parameters/values mapping from the active subparser + + """ + with_index = params[PrsConst.INDEX] + with_score = params[PrsConst.SCORE] + results = inv.suggest( + params[PrsConst.SEARCH], + thresh=params[PrsConst.THRESH], + with_index=with_index, + with_score=with_score, + ) + + print_stderr(f"Project: {inv.project}", params) + print_stderr(f"Version: {inv.version}\n", params) + + print_stderr(f"{inv.count} objects in inventory.\n", params) + + print_stderr_result_count(params, results) + + print_stderr_inferred_mapping(params) + + # The query here for printing the full list only occurs in some + # circumstances; see the function docstring. + confirm_print_if_long_list(params, results) + + print_results_table(with_index, with_score, results, params) + + +def print_stderr_result_count(params, results): + """Report the count of found objects from the suggest search.""" + if len(results) == 0: + print_stderr( + ( + "No results found with score at/above current threshold of " + f"{params[PrsConst.THRESH]}." + ), + params, + ) + sys.exit(0) + else: + print_stderr( + ( + f"{len(results)} result" + f"{'' if len(results) == 1 else 's'}" + " found at/above current threshold of " + f"{params[PrsConst.THRESH]}.\n" + ), + params, + ) + + +def confirm_print_if_long_list(params, results): + """Check if the results list is too long and query user if to proceed. + + Skip the check if ``--all`` has been passed. + + Also skip the check if receiving data from ``stdin``, as a stream + interaction here fouls the data flow...I forget exactly how. + + """ + if ( + len(results) > PrsConst.SUGGEST_CONFIRM_LENGTH + and not params[PrsConst.ALL] + and params[PrsConst.INFILE] != "-" + ): + resp = yesno_prompt(f"Display all {len(results)} results (Y/N)?") + if resp.lower() == "n": + print_stderr("\nExiting...", params) + sys.exit(0) + + # Extra cosmetic newline + print_stderr("", params) + + +def print_results_table(with_index, with_score, results, params): + """Prepare and print the table of suggest search results.""" + # Field widths in output + score_width = 7 + index_width = 7 + + # This is necessary because the results are returned as a + # list[str] if neither index nor score is included; but are + # returned as a list[tuple[...]] if one or both of index/score + # is included. + if with_index or with_score: + rst_width = max(len(res[0]) for res in results) + else: + rst_width = max(len(res) for res in results) + + rst_width += 2 + + # For now, in each case the formatting for each row is dynamically + # stored in `fmt`, and then `fmt` is used to actually format each row. + + # TODO: Consider replacing this with a *real* table formatting tool + if with_index: + if with_score: + gen = generate_score_index_lines( + results, score_width, index_width, rst_width + ) + else: + gen = generate_index_lines(results, index_width, rst_width) + else: + if with_score: + gen = generate_score_lines(results, score_width, rst_width) + else: + gen = generate_names_only_lines(results) + + if not params[PrsConst.PAGINATE]: + print("\n".join(gen)) + else: + # To make sure the initial output is not scrolled off the screen + # when --all is specified. + if params[PrsConst.ALL]: + input("Press Enter to continue...") + + while True: + # Adjust the number of lines per page if the user changes their + # terminal window size mid-execution + n_lines = shutil.get_terminal_size().lines - 2 + out_text = "\n".join(itt.islice(gen, n_lines)) + + if out_text: + print(out_text) + # Don't paginate after the last, partial screenful of output + if out_text.count("\n") == n_lines - 1: + input("Press Enter to continue...") + else: + # join() above will supply an empty string once gen is exhausted + break + + +def generate_score_index_lines(results, score_width, index_width, rst_width): + """Yield lines to print the table with scores & indices.""" + fmt = ( + f"{{name: <{rst_width}}} {{score: ^{score_width}}} {{index: ^{index_width}}}" + ) + yield fmt.format(name=" Name", score="Score", index="Index") + yield fmt.format( + name=("-" * rst_width), score=("-" * score_width), index=("-" * index_width) + ) + yield from (fmt.format(name=res[0], score=res[1], index=res[2]) for res in results) + + +def generate_index_lines(results, index_width, rst_width): + """Yield lines to print the table with indices.""" + fmt = f"{{name: <{rst_width}}} {{index: ^{index_width}}}" + yield fmt.format(name=" Name", index="Index") + yield fmt.format(name=("-" * rst_width), index=("-" * index_width)) + yield from (fmt.format(name=res[0], index=res[1]) for res in results) + + +def generate_score_lines(results, score_width, rst_width): + """Yield lines to print the table with scores.""" + fmt = f"{{name: <{rst_width}}} {{score: ^{score_width}}}" + yield fmt.format(name=" Name", score="Score") + yield fmt.format(name=("-" * rst_width), score=("-" * score_width)) + yield from (fmt.format(name=res[0], score=res[1]) for res in results) + + +def generate_names_only_lines(results): + """Yield lines to print containing just the object search results.""" + yield from (str(res) for res in results) + + +def print_stderr_inferred_mapping(params): + """Print as good of an `intersphinx_mapping` entry as can be determined.""" + if not params[PrsConst.URL]: + print_stderr( + "Cannot infer intersphinx_mapping from a local objects.inv.\n", params + ) + return + + input_url = params[PrsConst.INFILE] + inv_url = params[PrsConst.FOUND_URL] + + reduced_inv_url = extract_objectsinv_url_base(inv_url) + + if input_url == inv_url: + # User provided an exact URL to an inventory + # The tail of input_url thus should not match anything in the inventory, + # so we can't say anything about what the URL base of the docset is. + if inv_url == reduced_inv_url: + # The inventory URL does not end with the standard /objects.inv, + # so we don't even have *that* point of reference to work with. + print_stderr( + ( + "Cannot infer intersphinx_mapping for this docset using " + "the provided input URL.\n" + ), + params, + ) + else: + # The inventory URL *does* end with standard /objects.inv, + # so there's a reasonable chance we know the mapping. + print_stderr( + ( + "The intersphinx_mapping for this docset is PROBABLY:\n\n" + f" ({reduced_inv_url}, None)\n" + ), + params, + ) + else: + # User provided a URL from the docset that reduced to a base, atop which + # an inventory at .../objects.inv was found. + if inv_url == reduced_inv_url: + # This should never happen, because the only way we should be in + # this outer else is if inv_url *DOES* end in /objects.inv + print_stderr( # pragma: no cover + ( + "ERROR: Inconsistent internal state " + "during intersphinx_mapping inference.\n" + ), + params, + ) + else: + # Here we're *very* confident that we've go the mapping. + print_stderr( + ( + "The intersphinx_mapping for this docset is LIKELY:\n\n" + f" ({reduced_inv_url}, None)\n" + ), + params, + ) + + +def extract_objectsinv_url_base(objectsinv_url): + """Infer a base URL for the provided ``objects.inv`` inventory URL. + + If this function is a no-op, then the resulting base is NOT RELIABLE, + because the URL did not end with ``/objects.inv``. + + If this function *does* make a change, then the resulting base is + RELATIVELY RELIABLE, since the only change that should occur is + stripping of a ``/objects.inv`` suffix, which strongly implies but + does not guarantee that the URL came from a Sphinx docset in the + standard multi-page HTML layout. + + Parameters + ---------- + objectsinv_url + + |str| -- URL from which to attempt docset base inference + + Returns + ------- + trimmed + + |str| -- URL after attempt to trim a trailing ``/objects.inv`` + + """ + trimmed = _strip_url_to_netloc_path(objectsinv_url, with_scheme=True) + base = trimmed.rpartition("/objects.inv")[0] + + if base: + return f"{base}/" + else: + return objectsinv_url + + +def _strip_url_to_netloc_path(url, *, with_scheme=False): + """Reduce a URL to only netloc and path, optionally with scheme.""" + parts = urlparse.urlsplit(url) + trimmed = parts._replace( + query="", + fragment="", + ) + + if not with_scheme: + trimmed = trimmed._replace(scheme="") + + return urlparse.urlunsplit(trimmed) diff --git a/src/sphobjinv/cli/ui.py b/src/sphobjinv/cli/ui.py index ee838e73..302f1b91 100644 --- a/src/sphobjinv/cli/ui.py +++ b/src/sphobjinv/cli/ui.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 19 Nov 2020 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -30,8 +34,8 @@ from sphobjinv.cli.parser import PrsConst -def log_print(thing, params): - """Print `thing` to stderr if not in quiet mode. +def print_stderr(thing, params, *, end="\n"): + r"""Print `thing` to stderr if not in quiet mode. Quiet mode is indicated by the value at the |cli:QUIET| key within `params`. @@ -49,9 +53,13 @@ def log_print(thing, params): |dict| -- Parameters/values mapping from the active subparser + end + + |str| -- String to append to printed content (default: ``\n``\ ) + """ - if not params[PrsConst.SUBPARSER_NAME][:2] == "co" or not params[PrsConst.QUIET]: - print(thing, file=sys.stderr) + if params[PrsConst.SUBPARSER_NAME][:2] == "su" or not params[PrsConst.QUIET]: + print(thing, file=sys.stderr, end=end) def err_format(exc): diff --git a/src/sphobjinv/cli/write.py b/src/sphobjinv/cli/write.py index e828c49f..e7617bb0 100644 --- a/src/sphobjinv/cli/write.py +++ b/src/sphobjinv/cli/write.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 19 Nov 2020 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -31,7 +35,7 @@ from sphobjinv.cli.parser import PrsConst from sphobjinv.cli.paths import resolve_outpath -from sphobjinv.cli.ui import err_format, log_print, yesno_prompt +from sphobjinv.cli.ui import err_format, print_stderr, yesno_prompt from sphobjinv.fileops import writebytes, writejson from sphobjinv.zlib import compress @@ -193,7 +197,7 @@ def write_stdout(inv, params): print(json.dumps(json_dict)) else: - log_print("Error: Only plaintext and JSON can be emitted to stdout.", params) + print_stderr("Error: Only plaintext and JSON can be emitted to stdout.", params) sys.exit(1) @@ -229,15 +233,15 @@ def write_file(inv, in_path, params): out_path = resolve_outpath(params[PrsConst.OUTFILE], in_path, params) except Exception as e: # pragma: no cover # This may not actually be reachable except in exceptional situations - log_print("\nError while constructing output file path:", params) - log_print(err_format(e), params) + print_stderr("\nError while constructing output file path:", params) + print_stderr(err_format(e), params) sys.exit(1) # If exists, must handle overwrite if os.path.isfile(out_path) and not params[PrsConst.OVERWRITE]: if params[PrsConst.INFILE] == "-": # If reading from stdin, just alert and don't overwrite - log_print("\nFile exists. To overwrite, supply '-o'. Exiting...", params) + print_stderr("\nFile exists. To overwrite, supply '-o'. Exiting...", params) sys.exit(0) # This could be written w/o nesting via elif, but would be harder to read. else: @@ -245,7 +249,7 @@ def write_file(inv, in_path, params): # If not a stdin read, confirm overwrite; or, just clobber if QUIET resp = yesno_prompt("File exists. Overwrite (Y/N)? ") if resp.lower() == "n": - log_print("\nExiting...", params) + print_stderr("\nExiting...", params) sys.exit(0) # Write the output file @@ -267,12 +271,12 @@ def write_file(inv, in_path, params): if mode == PrsConst.JSON: write_json(inv, out_path, params) except Exception as e: - log_print("\nError during write of output file:", params) - log_print(err_format(e), params) + print_stderr("\nError during write of output file:", params) + print_stderr(err_format(e), params) sys.exit(1) # Report success, if not QUIET - log_print( + print_stderr( "Conversion completed.\n" f"'{in_path if in_path else 'stdin'}' converted to '{out_path}' ({mode}).", params, diff --git a/src/sphobjinv/data.py b/src/sphobjinv/data.py index 3674b26a..17d5fba0 100644 --- a/src/sphobjinv/data.py +++ b/src/sphobjinv/data.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 7 Nov 2017 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -133,7 +137,7 @@ def role(self): @property @abstractmethod def priority(self): - r"""Object search priority\ |dag|.""" + r"""Object search priority, as handled internally by Sphinx\ |dag|.""" @property @abstractmethod diff --git a/src/sphobjinv/enum.py b/src/sphobjinv/enum.py index 1128e0c2..866eb8a1 100644 --- a/src/sphobjinv/enum.py +++ b/src/sphobjinv/enum.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 4 May 2019 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/src/sphobjinv/error.py b/src/sphobjinv/error.py index 6731d5cd..ceb90fc7 100644 --- a/src/sphobjinv/error.py +++ b/src/sphobjinv/error.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 5 Nov 2017 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -37,3 +41,5 @@ class VersionError(SphobjinvError): |objects.inv| files (see :doc:`here `). """ + + # TODO: Add SOI prefix to this class name as part of the exceptions refactor diff --git a/src/sphobjinv/fileops.py b/src/sphobjinv/fileops.py index c35d550a..e2d01edc 100644 --- a/src/sphobjinv/fileops.py +++ b/src/sphobjinv/fileops.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 5 Nov 2017 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/src/sphobjinv/inventory.py b/src/sphobjinv/inventory.py index 270481e4..3d62785d 100644 --- a/src/sphobjinv/inventory.py +++ b/src/sphobjinv/inventory.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 7 Dec 2017 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -277,35 +281,11 @@ def objects_rst(self): :class:`data.SuperDataObj.rst_fmt `. - Calling with both `expand` and `contract` as |True| is invalid. - - Parameters - ---------- - expand - - |bool| *(optional)* -- Return |str|\ s with any - :data:`~sphobjinv.data.SuperDataObj.uri` or - :data:`~sphobjinv.data.SuperDataObj.dispname` - abbreviations expanded - - contract - - |bool| *(optional)* -- Return |str|\ s with abbreviated - :data:`~sphobjinv.data.SuperDataObj.uri` and - :data:`~sphobjinv.data.SuperDataObj.dispname` values - Returns ------- obj_l - |list| of |str| - -- Inventory object data in reST-like format - - Raises - ------ - ValueError - - If both `expand` and `contract` are |True| + |list| of |str| -- Inventory object data in reST-like format """ return [_.as_rst for _ in self.objects] diff --git a/src/sphobjinv/re.py b/src/sphobjinv/re.py index fbbe58a7..c02199f0 100644 --- a/src/sphobjinv/re.py +++ b/src/sphobjinv/re.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 5 Nov 2017 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -70,7 +74,7 @@ \s+ # Dividing space (?P<{DF.Domain.value}>[^\s:]+) # --> Domain : # Dividing colon - (?P<{DF.Role.value}>[^\s:]+) # --> Role + (?P<{DF.Role.value}>[^\s]+) # --> Role \s+ # Dividing space (?P<{DF.Priority.value}>-?\d+) # --> Priority \s+? # Dividing space diff --git a/src/sphobjinv/schema.py b/src/sphobjinv/schema.py index 39119ca7..9851fa55 100644 --- a/src/sphobjinv/schema.py +++ b/src/sphobjinv/schema.py @@ -5,7 +5,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 7 Dec 2017 @@ -17,10 +17,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/src/sphobjinv/version.py b/src/sphobjinv/version.py index 1c7257a6..566fa7aa 100644 --- a/src/sphobjinv/version.py +++ b/src/sphobjinv/version.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 18 Mar 2019 @@ -16,13 +16,17 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** """ -__version__ = "2.2.2" +__version__ = "2.3" diff --git a/src/sphobjinv/zlib.py b/src/sphobjinv/zlib.py index 92a724fa..f256ce4c 100644 --- a/src/sphobjinv/zlib.py +++ b/src/sphobjinv/zlib.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 5 Nov 2017 @@ -16,10 +16,14 @@ https://github.com/bskinn/sphobjinv **Documentation** - https://sphobjinv.readthedocs.io/en/latest + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/tests/resource/objects_attrs.inv b/tests/resource/objects_attrs.inv index b648b4b8..85189bdf 100644 Binary files a/tests/resource/objects_attrs.inv and b/tests/resource/objects_attrs.inv differ diff --git a/tests/resource/objects_attrs.json b/tests/resource/objects_attrs.json index d3be4496..b1144317 100644 --- a/tests/resource/objects_attrs.json +++ b/tests/resource/objects_attrs.json @@ -1 +1 @@ -{"project": "attrs", "version": "17.2", "count": 56, "0": {"name": "attr.Attribute", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "1": {"name": "attr.Factory", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "2": {"name": "attr.asdict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "3": {"name": "attr.assoc", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "4": {"name": "attr.astuple", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "5": {"name": "attr.converters.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "6": {"name": "attr.evolve", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "7": {"name": "attr.exceptions.AttrsAttributeNotFoundError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "8": {"name": "attr.exceptions.DefaultAlreadySetError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "9": {"name": "attr.exceptions.FrozenInstanceError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "10": {"name": "attr.exceptions.NotAnAttrsClassError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "11": {"name": "attr.fields", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "12": {"name": "attr.filters.exclude", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "13": {"name": "attr.filters.include", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "14": {"name": "attr.get_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "15": {"name": "attr.has", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "16": {"name": "attr.ib", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "17": {"name": "attr.make_class", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "18": {"name": "attr.s", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "19": {"name": "attr.set_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "20": {"name": "attr.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "21": {"name": "attr.validators.and_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "22": {"name": "attr.validators.in_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "23": {"name": "attr.validators.instance_of", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "24": {"name": "attr.validators.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "25": {"name": "attr.validators.provides", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "26": {"name": "api", "domain": "std", "role": "doc", "priority": "-1", "uri": "api.html", "dispname": "API"}, "27": {"name": "api", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "API"}, "28": {"name": "api_validators", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#api-validators", "dispname": "Validators"}, "29": {"name": "asdict", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Converting to Collections Types"}, "30": {"name": "backward-compatibility", "domain": "std", "role": "doc", "priority": "-1", "uri": "backward-compatibility.html", "dispname": "Backward Compatibility"}, "31": {"name": "changelog", "domain": "std", "role": "doc", "priority": "-1", "uri": "changelog.html", "dispname": "Changelog"}, "32": {"name": "contributing", "domain": "std", "role": "doc", "priority": "-1", "uri": "contributing.html", "dispname": "How To Contribute"}, "33": {"name": "contributing", "domain": "std", "role": "label", "priority": "-1", "uri": "contributing.html#$", "dispname": "How To Contribute"}, "34": {"name": "examples", "domain": "std", "role": "doc", "priority": "-1", "uri": "examples.html", "dispname": "Examples"}, "35": {"name": "examples", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Examples"}, "36": {"name": "examples_validators", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#examples-validators", "dispname": "Validators"}, "37": {"name": "exemption", "domain": "std", "role": "label", "priority": "-1", "uri": "backward-compatibility.html#$", "dispname": "-"}, "38": {"name": "extending", "domain": "std", "role": "doc", "priority": "-1", "uri": "extending.html", "dispname": "Extending"}, "39": {"name": "extending", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#$", "dispname": "Extending"}, "40": {"name": "extending_metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#extending-metadata", "dispname": "Metadata"}, "41": {"name": "genindex", "domain": "std", "role": "label", "priority": "-1", "uri": "genindex.html", "dispname": "Index"}, "42": {"name": "helpers", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "Helpers"}, "43": {"name": "how", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "How Does It Work?"}, "44": {"name": "how-does-it-work", "domain": "std", "role": "doc", "priority": "-1", "uri": "how-does-it-work.html", "dispname": "How Does It Work?"}, "45": {"name": "how-frozen", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "Immutability"}, "46": {"name": "index", "domain": "std", "role": "doc", "priority": "-1", "uri": "index.html", "dispname": "attrs: Classes Without Boilerplate"}, "47": {"name": "license", "domain": "std", "role": "doc", "priority": "-1", "uri": "license.html", "dispname": "License and Credits"}, "48": {"name": "metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Metadata"}, "49": {"name": "modindex", "domain": "std", "role": "label", "priority": "-1", "uri": "py-modindex.html", "dispname": "Module Index"}, "50": {"name": "overview", "domain": "std", "role": "doc", "priority": "-1", "uri": "overview.html", "dispname": "Overview"}, "51": {"name": "philosophy", "domain": "std", "role": "label", "priority": "-1", "uri": "overview.html#$", "dispname": "Philosophy"}, "52": {"name": "search", "domain": "std", "role": "label", "priority": "-1", "uri": "search.html", "dispname": "Search Page"}, "53": {"name": "slots", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Slots"}, "54": {"name": "why", "domain": "std", "role": "doc", "priority": "-1", "uri": "why.html", "dispname": "Why not\u2026"}, "55": {"name": "why", "domain": "std", "role": "label", "priority": "-1", "uri": "why.html#$", "dispname": "Why not\u2026"}} \ No newline at end of file +{"project": "attrs", "version": "22.1", "count": 129, "0": {"name": "attr", "domain": "py", "role": "module", "priority": "0", "uri": "index.html#module-$", "dispname": "-"}, "1": {"name": "attr.VersionInfo", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "2": {"name": "attr._make.Attribute", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.Attribute", "dispname": "-"}, "3": {"name": "attr._make.Factory", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.Factory", "dispname": "-"}, "4": {"name": "attr._version_info.VersionInfo", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attr.VersionInfo", "dispname": "-"}, "5": {"name": "attr.asdict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "6": {"name": "attr.assoc", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "7": {"name": "attr.astuple", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "8": {"name": "attr.attr.NOTHING", "domain": "py", "role": "data", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "9": {"name": "attr.attr.cmp_using", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "10": {"name": "attr.attr.evolve", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "11": {"name": "attr.attr.fields", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "12": {"name": "attr.attr.fields_dict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "13": {"name": "attr.attr.filters.exclude", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "14": {"name": "attr.attr.filters.include", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "15": {"name": "attr.attr.has", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "16": {"name": "attr.attr.resolve_types", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "17": {"name": "attr.attr.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "18": {"name": "attr.attrs.frozen", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "19": {"name": "attr.attrs.mutable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "20": {"name": "attr.attrs.setters.NO_OP", "domain": "py", "role": "data", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "21": {"name": "attr.define", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "22": {"name": "attr.exceptions.AttrsAttributeNotFoundError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.AttrsAttributeNotFoundError", "dispname": "-"}, "23": {"name": "attr.exceptions.DefaultAlreadySetError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.DefaultAlreadySetError", "dispname": "-"}, "24": {"name": "attr.exceptions.FrozenAttributeError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.FrozenAttributeError", "dispname": "-"}, "25": {"name": "attr.exceptions.FrozenError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.FrozenError", "dispname": "-"}, "26": {"name": "attr.exceptions.FrozenInstanceError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.FrozenInstanceError", "dispname": "-"}, "27": {"name": "attr.exceptions.NotAnAttrsClassError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.NotAnAttrsClassError", "dispname": "-"}, "28": {"name": "attr.exceptions.NotCallableError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.NotCallableError", "dispname": "-"}, "29": {"name": "attr.exceptions.PythonTooOldError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.PythonTooOldError", "dispname": "-"}, "30": {"name": "attr.exceptions.UnannotatedAttributeError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.UnannotatedAttributeError", "dispname": "-"}, "31": {"name": "attr.field", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "32": {"name": "attr.frozen", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "33": {"name": "attr.get_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "34": {"name": "attr.ib", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "35": {"name": "attr.mutable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "36": {"name": "attr.s", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "37": {"name": "attr.set_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "38": {"name": "attrs", "domain": "py", "role": "module", "priority": "0", "uri": "index.html#module-$", "dispname": "-"}, "39": {"name": "attrs.Attribute", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "40": {"name": "attrs.Attribute.evolve", "domain": "py", "role": "method", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "41": {"name": "attrs.Factory", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "42": {"name": "attrs.NOTHING", "domain": "py", "role": "data", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "43": {"name": "attrs.asdict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "44": {"name": "attrs.astuple", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "45": {"name": "attrs.cmp_using", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "46": {"name": "attrs.converters.default_if_none", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "47": {"name": "attrs.converters.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "48": {"name": "attrs.converters.pipe", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "49": {"name": "attrs.converters.to_bool", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "50": {"name": "attrs.define", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "51": {"name": "attrs.evolve", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "52": {"name": "attrs.exceptions.AttrsAttributeNotFoundError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "53": {"name": "attrs.exceptions.DefaultAlreadySetError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "54": {"name": "attrs.exceptions.FrozenAttributeError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "55": {"name": "attrs.exceptions.FrozenError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "56": {"name": "attrs.exceptions.FrozenInstanceError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "57": {"name": "attrs.exceptions.NotAnAttrsClassError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "58": {"name": "attrs.exceptions.NotCallableError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "59": {"name": "attrs.exceptions.PythonTooOldError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "60": {"name": "attrs.exceptions.UnannotatedAttributeError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "61": {"name": "attrs.field", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "62": {"name": "attrs.fields", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "63": {"name": "attrs.fields_dict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "64": {"name": "attrs.filters.exclude", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "65": {"name": "attrs.filters.include", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "66": {"name": "attrs.has", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "67": {"name": "attrs.make_class", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "68": {"name": "attrs.resolve_types", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "69": {"name": "attrs.setters.convert", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "70": {"name": "attrs.setters.frozen", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "71": {"name": "attrs.setters.pipe", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "72": {"name": "attrs.setters.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "73": {"name": "attrs.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "74": {"name": "attrs.validators.and_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "75": {"name": "attrs.validators.deep_iterable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "76": {"name": "attrs.validators.deep_mapping", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "77": {"name": "attrs.validators.disabled", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "78": {"name": "attrs.validators.ge", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "79": {"name": "attrs.validators.get_disabled", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "80": {"name": "attrs.validators.gt", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "81": {"name": "attrs.validators.in_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "82": {"name": "attrs.validators.instance_of", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "83": {"name": "attrs.validators.is_callable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "84": {"name": "attrs.validators.le", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "85": {"name": "attrs.validators.lt", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "86": {"name": "attrs.validators.matches_re", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "87": {"name": "attrs.validators.max_len", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "88": {"name": "attrs.validators.min_len", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "89": {"name": "attrs.validators.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "90": {"name": "attrs.validators.provides", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "91": {"name": "attrs.validators.set_disabled", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "92": {"name": "api", "domain": "std", "role": "doc", "priority": "-1", "uri": "api.html", "dispname": "API Reference"}, "93": {"name": "api_setters", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#api-setters", "dispname": "Setters"}, "94": {"name": "api_validators", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#api-validators", "dispname": "Validators"}, "95": {"name": "asdict", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Converting to Collections Types"}, "96": {"name": "changelog", "domain": "std", "role": "doc", "priority": "-1", "uri": "changelog.html", "dispname": "Changelog"}, "97": {"name": "comparison", "domain": "std", "role": "doc", "priority": "-1", "uri": "comparison.html", "dispname": "Comparison"}, "98": {"name": "converters", "domain": "std", "role": "label", "priority": "-1", "uri": "init.html#$", "dispname": "Converters"}, "99": {"name": "custom-comparison", "domain": "std", "role": "label", "priority": "-1", "uri": "comparison.html#$", "dispname": "Customization"}, "100": {"name": "dict classes", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-dict-classes", "dispname": "-"}, "101": {"name": "dunder methods", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-dunder-methods", "dispname": "-"}, "102": {"name": "examples", "domain": "std", "role": "doc", "priority": "-1", "uri": "examples.html", "dispname": "attrs by Example"}, "103": {"name": "examples_validators", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#examples-validators", "dispname": "Validators"}, "104": {"name": "extending", "domain": "std", "role": "doc", "priority": "-1", "uri": "extending.html", "dispname": "Extending"}, "105": {"name": "extending_metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#extending-metadata", "dispname": "Metadata"}, "106": {"name": "genindex", "domain": "std", "role": "label", "priority": "-1", "uri": "genindex.html", "dispname": "Index"}, "107": {"name": "glossary", "domain": "std", "role": "doc", "priority": "-1", "uri": "glossary.html", "dispname": "Glossary"}, "108": {"name": "hashing", "domain": "std", "role": "doc", "priority": "-1", "uri": "hashing.html", "dispname": "Hashing"}, "109": {"name": "helpers", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "Helpers"}, "110": {"name": "how", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "How Does It Work?"}, "111": {"name": "how-does-it-work", "domain": "std", "role": "doc", "priority": "-1", "uri": "how-does-it-work.html", "dispname": "How Does It Work?"}, "112": {"name": "how-frozen", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "Immutability"}, "113": {"name": "index", "domain": "std", "role": "doc", "priority": "-1", "uri": "index.html", "dispname": "attrs: Classes Without Boilerplate"}, "114": {"name": "init", "domain": "std", "role": "doc", "priority": "-1", "uri": "init.html", "dispname": "Initialization"}, "115": {"name": "license", "domain": "std", "role": "doc", "priority": "-1", "uri": "license.html", "dispname": "License and Credits"}, "116": {"name": "metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Metadata"}, "117": {"name": "modindex", "domain": "std", "role": "label", "priority": "-1", "uri": "py-modindex.html", "dispname": "Module Index"}, "118": {"name": "names", "domain": "std", "role": "doc", "priority": "-1", "uri": "names.html", "dispname": "On The Core API Names"}, "119": {"name": "overview", "domain": "std", "role": "doc", "priority": "-1", "uri": "overview.html", "dispname": "Overview"}, "120": {"name": "philosophy", "domain": "std", "role": "label", "priority": "-1", "uri": "overview.html#$", "dispname": "Philosophy"}, "121": {"name": "py-modindex", "domain": "std", "role": "label", "priority": "-1", "uri": "py-modindex.html", "dispname": "Python Module Index"}, "122": {"name": "search", "domain": "std", "role": "label", "priority": "-1", "uri": "search.html", "dispname": "Search Page"}, "123": {"name": "slotted classes", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-slotted-classes", "dispname": "-"}, "124": {"name": "transform-fields", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#$", "dispname": "Automatic Field Transformation and Modification"}, "125": {"name": "types", "domain": "std", "role": "doc", "priority": "-1", "uri": "types.html", "dispname": "Type Annotations"}, "126": {"name": "validators", "domain": "std", "role": "label", "priority": "-1", "uri": "init.html#$", "dispname": "Validators"}, "127": {"name": "version-info", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "-"}, "128": {"name": "why", "domain": "std", "role": "doc", "priority": "-1", "uri": "why.html", "dispname": "Why not\u2026"}} \ No newline at end of file diff --git a/tests/resource/objects_attrs.txt b/tests/resource/objects_attrs.txt index 1296a6a9..50cf9464 100644 --- a/tests/resource/objects_attrs.txt +++ b/tests/resource/objects_attrs.txt @@ -1,60 +1,133 @@ # Sphinx inventory version 2 # Project: attrs -# Version: 17.2 +# Version: 22.1 # The remainder of this file is compressed using zlib. -attr.Attribute py:class 1 api.html#$ - -attr.Factory py:class 1 api.html#$ - +attr py:module 0 index.html#module-$ - +attr.VersionInfo py:class 1 api.html#$ - +attr._make.Attribute py:class -1 api.html#attrs.Attribute - +attr._make.Factory py:class -1 api.html#attrs.Factory - +attr._version_info.VersionInfo py:class -1 api.html#attr.VersionInfo - attr.asdict py:function 1 api.html#$ - attr.assoc py:function 1 api.html#$ - attr.astuple py:function 1 api.html#$ - -attr.converters.optional py:function 1 api.html#$ - -attr.evolve py:function 1 api.html#$ - -attr.exceptions.AttrsAttributeNotFoundError py:exception 1 api.html#$ - -attr.exceptions.DefaultAlreadySetError py:exception 1 api.html#$ - -attr.exceptions.FrozenInstanceError py:exception 1 api.html#$ - -attr.exceptions.NotAnAttrsClassError py:exception 1 api.html#$ - -attr.fields py:function 1 api.html#$ - -attr.filters.exclude py:function 1 api.html#$ - -attr.filters.include py:function 1 api.html#$ - +attr.attr.NOTHING py:data 1 api.html#$ - +attr.attr.cmp_using py:function 1 api.html#$ - +attr.attr.evolve py:function 1 api.html#$ - +attr.attr.fields py:function 1 api.html#$ - +attr.attr.fields_dict py:function 1 api.html#$ - +attr.attr.filters.exclude py:function 1 api.html#$ - +attr.attr.filters.include py:function 1 api.html#$ - +attr.attr.has py:function 1 api.html#$ - +attr.attr.resolve_types py:function 1 api.html#$ - +attr.attr.validate py:function 1 api.html#$ - +attr.attrs.frozen py:function 1 api.html#$ - +attr.attrs.mutable py:function 1 api.html#$ - +attr.attrs.setters.NO_OP py:data 1 api.html#$ - +attr.define py:function 1 api.html#$ - +attr.exceptions.AttrsAttributeNotFoundError py:exception -1 api.html#attrs.exceptions.AttrsAttributeNotFoundError - +attr.exceptions.DefaultAlreadySetError py:exception -1 api.html#attrs.exceptions.DefaultAlreadySetError - +attr.exceptions.FrozenAttributeError py:exception -1 api.html#attrs.exceptions.FrozenAttributeError - +attr.exceptions.FrozenError py:exception -1 api.html#attrs.exceptions.FrozenError - +attr.exceptions.FrozenInstanceError py:exception -1 api.html#attrs.exceptions.FrozenInstanceError - +attr.exceptions.NotAnAttrsClassError py:exception -1 api.html#attrs.exceptions.NotAnAttrsClassError - +attr.exceptions.NotCallableError py:exception -1 api.html#attrs.exceptions.NotCallableError - +attr.exceptions.PythonTooOldError py:exception -1 api.html#attrs.exceptions.PythonTooOldError - +attr.exceptions.UnannotatedAttributeError py:exception -1 api.html#attrs.exceptions.UnannotatedAttributeError - +attr.field py:function 1 api.html#$ - +attr.frozen py:function 1 api.html#$ - attr.get_run_validators py:function 1 api.html#$ - -attr.has py:function 1 api.html#$ - attr.ib py:function 1 api.html#$ - -attr.make_class py:function 1 api.html#$ - +attr.mutable py:function 1 api.html#$ - attr.s py:function 1 api.html#$ - attr.set_run_validators py:function 1 api.html#$ - -attr.validate py:function 1 api.html#$ - -attr.validators.and_ py:function 1 api.html#$ - -attr.validators.in_ py:function 1 api.html#$ - -attr.validators.instance_of py:function 1 api.html#$ - -attr.validators.optional py:function 1 api.html#$ - -attr.validators.provides py:function 1 api.html#$ - -api std:doc -1 api.html API -api std:label -1 api.html#$ API +attrs py:module 0 index.html#module-$ - +attrs.Attribute py:class 1 api.html#$ - +attrs.Attribute.evolve py:method 1 api.html#$ - +attrs.Factory py:class 1 api.html#$ - +attrs.NOTHING py:data 1 api.html#$ - +attrs.asdict py:function 1 api.html#$ - +attrs.astuple py:function 1 api.html#$ - +attrs.cmp_using py:function 1 api.html#$ - +attrs.converters.default_if_none py:function 1 api.html#$ - +attrs.converters.optional py:function 1 api.html#$ - +attrs.converters.pipe py:function 1 api.html#$ - +attrs.converters.to_bool py:function 1 api.html#$ - +attrs.define py:function 1 api.html#$ - +attrs.evolve py:function 1 api.html#$ - +attrs.exceptions.AttrsAttributeNotFoundError py:exception 1 api.html#$ - +attrs.exceptions.DefaultAlreadySetError py:exception 1 api.html#$ - +attrs.exceptions.FrozenAttributeError py:exception 1 api.html#$ - +attrs.exceptions.FrozenError py:exception 1 api.html#$ - +attrs.exceptions.FrozenInstanceError py:exception 1 api.html#$ - +attrs.exceptions.NotAnAttrsClassError py:exception 1 api.html#$ - +attrs.exceptions.NotCallableError py:exception 1 api.html#$ - +attrs.exceptions.PythonTooOldError py:exception 1 api.html#$ - +attrs.exceptions.UnannotatedAttributeError py:exception 1 api.html#$ - +attrs.field py:function 1 api.html#$ - +attrs.fields py:function 1 api.html#$ - +attrs.fields_dict py:function 1 api.html#$ - +attrs.filters.exclude py:function 1 api.html#$ - +attrs.filters.include py:function 1 api.html#$ - +attrs.has py:function 1 api.html#$ - +attrs.make_class py:function 1 api.html#$ - +attrs.resolve_types py:function 1 api.html#$ - +attrs.setters.convert py:function 1 api.html#$ - +attrs.setters.frozen py:function 1 api.html#$ - +attrs.setters.pipe py:function 1 api.html#$ - +attrs.setters.validate py:function 1 api.html#$ - +attrs.validate py:function 1 api.html#$ - +attrs.validators.and_ py:function 1 api.html#$ - +attrs.validators.deep_iterable py:function 1 api.html#$ - +attrs.validators.deep_mapping py:function 1 api.html#$ - +attrs.validators.disabled py:function 1 api.html#$ - +attrs.validators.ge py:function 1 api.html#$ - +attrs.validators.get_disabled py:function 1 api.html#$ - +attrs.validators.gt py:function 1 api.html#$ - +attrs.validators.in_ py:function 1 api.html#$ - +attrs.validators.instance_of py:function 1 api.html#$ - +attrs.validators.is_callable py:function 1 api.html#$ - +attrs.validators.le py:function 1 api.html#$ - +attrs.validators.lt py:function 1 api.html#$ - +attrs.validators.matches_re py:function 1 api.html#$ - +attrs.validators.max_len py:function 1 api.html#$ - +attrs.validators.min_len py:function 1 api.html#$ - +attrs.validators.optional py:function 1 api.html#$ - +attrs.validators.provides py:function 1 api.html#$ - +attrs.validators.set_disabled py:function 1 api.html#$ - +api std:doc -1 api.html API Reference +api_setters std:label -1 api.html#api-setters Setters api_validators std:label -1 api.html#api-validators Validators asdict std:label -1 examples.html#$ Converting to Collections Types -backward-compatibility std:doc -1 backward-compatibility.html Backward Compatibility changelog std:doc -1 changelog.html Changelog -contributing std:doc -1 contributing.html How To Contribute -contributing std:label -1 contributing.html#$ How To Contribute -examples std:doc -1 examples.html Examples -examples std:label -1 examples.html#$ Examples +comparison std:doc -1 comparison.html Comparison +converters std:label -1 init.html#$ Converters +custom-comparison std:label -1 comparison.html#$ Customization +dict classes std:term -1 glossary.html#term-dict-classes - +dunder methods std:term -1 glossary.html#term-dunder-methods - +examples std:doc -1 examples.html attrs by Example examples_validators std:label -1 examples.html#examples-validators Validators -exemption std:label -1 backward-compatibility.html#$ - extending std:doc -1 extending.html Extending -extending std:label -1 extending.html#$ Extending extending_metadata std:label -1 extending.html#extending-metadata Metadata genindex std:label -1 genindex.html Index +glossary std:doc -1 glossary.html Glossary +hashing std:doc -1 hashing.html Hashing helpers std:label -1 api.html#$ Helpers how std:label -1 how-does-it-work.html#$ How Does It Work? how-does-it-work std:doc -1 how-does-it-work.html How Does It Work? how-frozen std:label -1 how-does-it-work.html#$ Immutability index std:doc -1 index.html attrs: Classes Without Boilerplate +init std:doc -1 init.html Initialization license std:doc -1 license.html License and Credits metadata std:label -1 examples.html#$ Metadata modindex std:label -1 py-modindex.html Module Index +names std:doc -1 names.html On The Core API Names overview std:doc -1 overview.html Overview philosophy std:label -1 overview.html#$ Philosophy +py-modindex std:label -1 py-modindex.html Python Module Index search std:label -1 search.html Search Page -slots std:label -1 examples.html#$ Slots +slotted classes std:term -1 glossary.html#term-slotted-classes - +transform-fields std:label -1 extending.html#$ Automatic Field Transformation and Modification +types std:doc -1 types.html Type Annotations +validators std:label -1 init.html#$ Validators +version-info std:label -1 api.html#$ - why std:doc -1 why.html Why not… -why std:label -1 why.html#$ Why not… diff --git a/tests/resource/objects_attrs_17_2_0.inv b/tests/resource/objects_attrs_17_2_0.inv new file mode 100644 index 00000000..b648b4b8 Binary files /dev/null and b/tests/resource/objects_attrs_17_2_0.inv differ diff --git a/tests/resource/objects_django.inv b/tests/resource/objects_django.inv new file mode 100644 index 00000000..a965611b Binary files /dev/null and b/tests/resource/objects_django.inv differ diff --git a/tests/resource/objects_sphinx.inv b/tests/resource/objects_sphinx.inv index 14e48936..ed2fe5b4 100644 Binary files a/tests/resource/objects_sphinx.inv and b/tests/resource/objects_sphinx.inv differ diff --git a/tests/resource/objects_sphinx_1_6_6.inv b/tests/resource/objects_sphinx_1_6_6.inv new file mode 100644 index 00000000..14e48936 Binary files /dev/null and b/tests/resource/objects_sphinx_1_6_6.inv differ diff --git a/tests/test_api_fail.py b/tests/test_api_fail.py index 0dc975ad..a584b732 100644 --- a/tests/test_api_fail.py +++ b/tests/test_api_fail.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 @@ -16,10 +16,14 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -141,7 +145,7 @@ def test_apifail_inventory_dictimport_toobig(self, path_fxn, res_dec): """Confirm error raised when JSON dict passed w/too many objects.""" inv = soi.Inventory(path_fxn(res_dec)) d = inv.json_dict() - d.update({"57": d["23"]}) + d.update({"4000": d["23"]}) with pytest.raises(ValueError): soi.Inventory(dict_json=d) @@ -178,7 +182,7 @@ def test_apifail_inventory_no_object_invs(self, check): soi.Inventory(d) def test_apifail_compressed_inv_with_win_newlines(self, unix2dos, res_cmp): - """Confirm that a compressed inventory with Windows newlines does not decompress. + """Confirm that a compressed inventory with Windows newlines doesn't decompress. This should *never* happen, except in a pathological circumstance where unix2dos was specifically run on a compressed inventory. diff --git a/tests/test_api_good.py b/tests/test_api_good.py index 50099637..f3889b77 100644 --- a/tests/test_api_good.py +++ b/tests/test_api_good.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 @@ -16,10 +16,14 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -108,23 +112,23 @@ def test_api_decompress(self, path_fxn, scratch_path, misc_info, decomp_cmp_test [ 0, { # attr.Attribute py:class 1 api.html#$ - - soi.DataFields.Name: b"attr.Attribute", + soi.DataFields.Name: b"attr", soi.DataFields.Domain: b"py", - soi.DataFields.Role: b"class", - soi.DataFields.Priority: b"1", - soi.DataFields.URI: b"api.html#$", + soi.DataFields.Role: b"module", + soi.DataFields.Priority: b"0", + soi.DataFields.URI: b"index.html#module-$", soi.DataFields.DispName: b"-", }, ], [ -3, { # slots std:label -1 examples.html#$ Slots - soi.DataFields.Name: b"slots", + soi.DataFields.Name: b"validators", soi.DataFields.Domain: b"std", soi.DataFields.Role: b"label", soi.DataFields.Priority: b"-1", - soi.DataFields.URI: b"examples.html#$", - soi.DataFields.DispName: b"Slots", + soi.DataFields.URI: b"init.html#$", + soi.DataFields.DispName: b"Validators", }, ], ), @@ -133,7 +137,7 @@ def test_api_data_regex(self, element, datadict, bytes_txt, misc_info): """Confirm the regex for loading data lines is working properly.""" # Prelim approximate check to be sure we're working with the # correct file/data. - assert len(soi.re.pb_data.findall(bytes_txt)) == 56 + assert len(soi.re.pb_data.findall(bytes_txt)) == 129 mchs = list(soi.re.pb_data.finditer(bytes_txt)) @@ -444,13 +448,13 @@ def test_api_inventory_toosmallflatdict_importbutignore(self, res_dec): inv2 = soi.Inventory(d, count_error=False) - # 55 b/c the loop continues past missing elements - assert inv2.count == 55 + # 128 (one less than 129) b/c the loop continues past missing elements + assert inv2.count == 128 def test_api_inventory_namesuggest(self, res_cmp, check): """Confirm object name suggestion is nominally working on a specific object.""" - rst = ":py:function:`attr.evolve`" - idx = 6 + rst = ":py:function:`attr.attr.evolve`" + idx = 10 inv = soi.Inventory(str(res_cmp)) @@ -572,6 +576,18 @@ def test_api_inventory_matches_sphinx_ifile( original_ifile_data ), fname + elif "django.inv" in fname: # pragma: no cover + # 13 objects misbehave on import for Sphinx >= 3.3.0 + if sphinx_version < (3, 3, 0): + assert inv.count == sphinx_ifile_data_count(original_ifile_data), fname + else: + assert inv.count == 13 + sphinx_ifile_data_count( + original_ifile_data + ), fname + + elif "sphinx.inv" in fname: # pragma: no cover + assert inv.count == 4 + sphinx_ifile_data_count(original_ifile_data), fname + else: assert inv.count == sphinx_ifile_data_count(original_ifile_data), fname diff --git a/tests/test_api_good_nonlocal.py b/tests/test_api_good_nonlocal.py index e11163fe..b45ba5a7 100644 --- a/tests/test_api_good_nonlocal.py +++ b/tests/test_api_good_nonlocal.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 21 Mar 2019 @@ -16,10 +16,14 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/tests/test_cli.py b/tests/test_cli.py index 145cc1a9..2fcb3ca3 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 @@ -16,12 +16,17 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** + """ @@ -74,6 +79,22 @@ def test_cli_noargs_shows_help(self, run_cmdline_test): assert "usage: sphobjinv" in out_.getvalue() + @pytest.mark.timeout(CLI_TEST_TIMEOUT) + def test_cli_no_subparser_prs_exit(self, run_cmdline_test): + """Confirm exit code 2 if option passed but no subparser provided.""" + with stdio_mgr() as (in_, out_, err_): + run_cmdline_test(["--foo"], expect=2) + + assert "error: No subparser selected" in err_.getvalue() + + @pytest.mark.timeout(CLI_TEST_TIMEOUT) + def test_cli_bad_subparser_prs_exit(self, run_cmdline_test): + """Confirm exit code 2 if invalid subparser provided.""" + with stdio_mgr() as (in_, out_, err_): + run_cmdline_test(["foo"], expect=2) + + assert "invalid choice: 'foo'" in err_.getvalue() + class TestConvertGood: """Tests for expected-good convert functionality.""" @@ -324,7 +345,7 @@ def test_cli_suggest_noresults(self, run_cmdline_test, res_cmp): """Confirm suggest w/no found results works.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", "-t", "99"]) - assert "No results found." in err_.getvalue() + assert "No results found" in err_.getvalue() @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_nameonly(self, run_cmdline_test, res_cmp): @@ -338,33 +359,34 @@ def test_cli_suggest_withindex(self, run_cmdline_test, res_cmp): """Confirm with_index suggest works.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", "-it", "50"]) - assert re.search("^.*instance_of\\S*\\s+23\\s*$", out_.getvalue(), re.M) + assert re.search("^.*instance_of\\S*\\s+82\\s*$", out_.getvalue(), re.M) @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_withscore(self, run_cmdline_test, res_cmp): - """Confirm with_index suggest works.""" + """Confirm with_score suggest works.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", "-st", "50"]) re.search("^.*instance_of\\S*\\s+\\d+\\s*$", out_.getvalue(), re.M) @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_withscoreandindex(self, run_cmdline_test, res_cmp): - """Confirm with_index suggest works.""" + """Confirm with_index + with_score suggest works.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", "-sit", "50"]) - re.search("^.*instance_of\\S*\\s+\\d+\\s+23\\s*$", out_.getvalue(), re.M) + re.search("^.*instance_of\\S*\\s+\\d+\\s+82\\s*$", out_.getvalue(), re.M) @pytest.mark.parametrize( ["inp", "flags", "nlines"], - [("", "-at", 56), ("y\n", "-t", 57), ("n\n", "-t", 1)], + [("", "-at", 129), ("y\n", "-t", 130), ("n\n", "-t", 1)], ) # Extra line for input() query in the "y\n" case @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_long_list(self, inp, flags, nlines, run_cmdline_test, res_cmp): - """Confirm with_index suggest works.""" + """Confirm suggest with a long list of results works.""" with stdio_mgr(inp) as (in_, out_, err_): run_cmdline_test(["suggest", res_cmp, "instance", flags, "1"]) assert nlines == out_.getvalue().count("\n") + @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_many_results_stdin(self, res_cmp, run_cmdline_test): """Confirm suggest from stdin doesn't choke on a long list.""" data = json.dumps(Inventory(res_cmp).json_dict()) @@ -372,6 +394,13 @@ def test_cli_suggest_many_results_stdin(self, res_cmp, run_cmdline_test): with stdio_mgr(data) as (in_, out_, err_): run_cmdline_test(["suggest", "-", "py", "-t", "1"]) + @pytest.mark.timeout(CLI_TEST_TIMEOUT) + def test_cli_suggest_paginated(self, res_cmp, run_cmdline_test): + """Confirm pagination works as expected for a controlled example.""" + with stdio_mgr("\n" * 5) as (in_, out_, err_): + run_cmdline_test(["suggest", res_cmp, "function", "-sapt30"]) + assert 5 == out_.getvalue().count("Press Enter to continue") + class TestFail: """Tests for expected-fail behaviors.""" diff --git a/tests/test_cli_nonlocal.py b/tests/test_cli_nonlocal.py index 6b0c78ed..1e4da53e 100644 --- a/tests/test_cli_nonlocal.py +++ b/tests/test_cli_nonlocal.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 @@ -16,12 +16,17 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** + """ @@ -123,7 +128,7 @@ def test_clifail_bad_url(self, run_cmdline_test, misc_info, scratch_path): ], expect=1, ) - assert "No inventory at provided URL." in err_.getvalue() + assert "HTTP error: 404 Not Found." in err_.getvalue() @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) def test_clifail_url_no_leading_http(self, run_cmdline_test, scratch_path): @@ -139,7 +144,7 @@ def test_clifail_url_no_leading_http(self, run_cmdline_test, scratch_path): ], expect=1, ) - assert "No inventory at provided URL." in err_.getvalue() + assert "file found but inventory could not be loaded" in err_.getvalue() def test_cli_json_export_import( self, res_cmp, scratch_path, misc_info, run_cmdline_test, sphinx_load_test @@ -166,7 +171,7 @@ class TestSuggest: @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) def test_cli_suggest_from_url(self, misc_info, run_cmdline_test): - """Confirm name-only suggest works from URL.""" + """Confirm reST-only suggest output works from URL.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test( [ @@ -180,29 +185,48 @@ def test_cli_suggest_from_url(self, misc_info, run_cmdline_test): ) assert p_instance_of.search(out_.getvalue()) + @pytest.mark.parametrize( + "url", + [ + "http://sphobjinv.readthedocs.io/en/v2.0/modules/", + "http://sphobjinv.readthedocs.io/en/v2.0/modules/cmdline.html", + ( + "http://sphobjinv.readthedocs.io/en/v2.0/modules/" + "cmdline.html#sphobjinv.cmdline.do_convert" + ), + ], + ) @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) - def test_cli_suggest_from_dir_noanchor(self, run_cmdline_test): - """Confirm name-only suggest works from docpage URL.""" - url = "http://sphobjinv.readthedocs.io/en/v2.0/modules/" + def test_cli_suggest_from_docset_urls(self, url, run_cmdline_test, check): + """Confirm reST-only suggest output works from URLs within a docset.""" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", "-u", url, "inventory", "-at", "50"]) - assert p_inventory.search(out_.getvalue()) + + check.is_true(p_inventory.search(out_.getvalue())) + check.is_in("LIKELY", err_.getvalue()) + check.is_in( + "(http://sphobjinv.readthedocs.io/en/v2.0/, None)", err_.getvalue() + ) @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) - def test_cli_suggest_from_page_noanchor(self, run_cmdline_test): - """Confirm name-only suggest works from docpage URL.""" - url = "http://sphobjinv.readthedocs.io/en/v2.0/modules/cmdline.html" + def test_cli_suggest_from_typical_objinv_url(self, run_cmdline_test, check): + """Confirm reST-only suggest works for direct objects.inv URL.""" + url = "http://sphobjinv.readthedocs.io/en/v2.0/objects.inv" with stdio_mgr() as (in_, out_, err_): run_cmdline_test(["suggest", "-u", url, "inventory", "-at", "50"]) - assert p_inventory.search(out_.getvalue()) + + check.is_true(p_inventory.search(out_.getvalue())) + check.is_in("PROBABLY", err_.getvalue()) + check.is_in( + "(http://sphobjinv.readthedocs.io/en/v2.0/, None)", err_.getvalue() + ) @pytest.mark.timeout(CLI_TEST_TIMEOUT * 4) - def test_cli_suggest_from_page_withanchor(self, run_cmdline_test): - """Confirm name-only suggest works from docpage URL.""" - url = ( - "http://sphobjinv.readthedocs.io/en/v2.0/modules/" - "cmdline.html#sphobjinv.cmdline.do_convert" - ) + def test_cli_suggest_from_django_objinv_url(self, run_cmdline_test, check): + """Confirm reST-only suggest works for direct objects.inv URL.""" + url = "https://docs.djangoproject.com/en/4.1/_objects/" with stdio_mgr() as (in_, out_, err_): - run_cmdline_test(["suggest", "-u", url, "inventory", "-at", "50"]) - assert p_inventory.search(out_.getvalue()) + run_cmdline_test(["suggest", "-u", url, "route", "-a"]) + + check.is_true(re.search("DATABASE_ROUTERS", out_.getvalue())) + check.is_in("Cannot infer intersphinx_mapping", err_.getvalue()) diff --git a/tests/test_fixture.py b/tests/test_fixture.py index d93d906f..398cfed1 100644 --- a/tests/test_fixture.py +++ b/tests/test_fixture.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 20 Mar 2019 @@ -16,10 +16,14 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** diff --git a/tests/test_flake8_ext.py b/tests/test_flake8_ext.py index 00bae72f..9bd05bf3 100644 --- a/tests/test_flake8_ext.py +++ b/tests/test_flake8_ext.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 27 Apr 2019 @@ -16,10 +16,14 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -58,7 +62,7 @@ def test_flake8_version_output(check): # This is fragile if anything ends up not having a prefix that needs # stripping - plugins = [p.partition("-")[-1] for p in plugins] + plugins = [p.partition("flake8-")[-1] for p in plugins] flake8_ver_output = sp.check_output( # noqa: S607,S603 ["flake8", "--version"], universal_newlines=True @@ -66,4 +70,4 @@ def test_flake8_version_output(check): for p in plugins: with check.check(msg=p): - assert p in flake8_ver_output.replace("_", "-") + assert p in flake8_ver_output.replace("_", "-").replace("\n", "") diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py new file mode 100644 index 00000000..177326df --- /dev/null +++ b/tests/test_intersphinx.py @@ -0,0 +1,80 @@ +r"""*Tests for intersphinx-related functionality for* ``sphobjinv``. + +``sphobjinv`` is a toolkit for manipulation and inspection of +Sphinx |objects.inv| files. + +**Author** + Brian Skinn (brian.skinn@gmail.com) + +**File Created** + 21 Jun 2022 + +**Copyright** + \(c) Brian Skinn 2016-2022 + +**Source Repository** + http://www.github.com/bskinn/sphobjinv + +**Documentation** + https://sphobjinv.readthedocs.io/en/stable + +**License** + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. + +**Members** + +""" + +import pytest + +import sphobjinv.cli.suggest as soi_cli_suggest + + +pytestmark = [pytest.mark.intersphinx, pytest.mark.local] + + +@pytest.mark.parametrize( + ("uri", "trimmed", "with_scheme"), + [ + ("cli/implementation/parser.html#$", "cli/implementation/parser.html", False), + ( + ( + "https://sphobjinv.readthedocs.io/en/stable/api/" + "enum.html#sphobjinv.enum.HeaderFields" + ), + "//sphobjinv.readthedocs.io/en/stable/api/enum.html", + False, + ), + ( + ( + "https://sphobjinv.readthedocs.io/en/stable/api/" + "enum.html#sphobjinv.enum.HeaderFields" + ), + "https://sphobjinv.readthedocs.io/en/stable/api/enum.html", + True, + ), + ], +) +def test_strip_netloc_path(uri, trimmed, with_scheme): + """Confirm that object URI trimming is working.""" + assert trimmed == soi_cli_suggest._strip_url_to_netloc_path( + uri, with_scheme=with_scheme + ) + + +@pytest.mark.parametrize( + ("url", "trimmed"), + [ + ( + "https://sphobjinv.readthedocs.io/en/latest/objects.inv", + "https://sphobjinv.readthedocs.io/en/latest/", + ) + ], +) +def test_extract_objinv_url_base(url, trimmed): + """Confirm that inventory URL trimming is working.""" + assert trimmed == soi_cli_suggest.extract_objectsinv_url_base(url) diff --git a/tests/test_readme.py b/tests/test_readme.py index 9070cd3a..bddd9491 100644 --- a/tests/test_readme.py +++ b/tests/test_readme.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 6 Aug 2018 @@ -16,10 +16,14 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -30,6 +34,7 @@ import re import shlex import subprocess as sp # noqa: S404 +import sys from pathlib import Path @@ -61,15 +66,18 @@ "pypy" in platform.python_implementation().lower(), reason="Inconsistent suggest results on PyPy", ) -def test_readme_shell_cmds(ensure_doc_scratch, check): +def test_readme_shell_cmds(ensure_doc_scratch, is_win, check): """Perform testing on README shell command examples.""" + if is_win and sys.version_info < (3, 9): # pragma: no cover + pytest.skip("Windows mishandles stdout/stderr for Python < 3.9") + text = Path("README.rst").read_text() chk = dt.OutputChecker() dt_flags = dt.ELLIPSIS | dt.NORMALIZE_WHITESPACE - for i, mch in enumerate(p_shell.finditer(text)): + for mch in p_shell.finditer(text): cmd = mch.group("cmd") out = mch.group("out") @@ -81,5 +89,5 @@ def test_readme_shell_cmds(ensure_doc_scratch, check): msg = "\n\nExpected:\n" + out + "\n\nGot:\n" + result - with check.check(msg=f"match_{i}"): + with check.check(): assert chk.check_output(out, result, dt_flags), msg diff --git a/tests/test_valid_objects.py b/tests/test_valid_objects.py index 5e3930cd..109befa8 100644 --- a/tests/test_valid_objects.py +++ b/tests/test_valid_objects.py @@ -4,7 +4,7 @@ Sphinx |objects.inv| files. **Author** - Brian Skinn (bskinn@alum.mit.edu) + Brian Skinn (brian.skinn@gmail.com) **File Created** 13 Feb 2021 @@ -16,10 +16,14 @@ http://www.github.com/bskinn/sphobjinv **Documentation** - http://sphobjinv.readthedocs.io + https://sphobjinv.readthedocs.io/en/stable **License** - The MIT License; see |license_txt|_ for full license terms + Code: `MIT License`_ + + Docs & Docstrings: |CC BY 4.0|_ + + See |license_txt|_ for full license terms. **Members** @@ -69,12 +73,15 @@ def skip_on_sphinx_version(sphinx_version): ("Index # Page", "std", "doc", 1, "index.html", "-"), # Symbol in name ("Thing \u33a4", "std", "ref", 1, "index.html#$", "-"), # Unicode in name ("Thing One", "std", "ref", 1, "index.html#$", "\u33a4"), # Unicode in dispname + ("foo", "py", "da:ta", 1, "data.html#$", "-"), # Colon in role (used in Sphinx) ("foo", "py$", "data", 1, "data.html#$", "-"), # Valid but discouraged ("foo", "py\u33a4", "data", 1, "data.html#$", "-"), # Valid but discouraged ("foo", "py", "data$", 1, "data.html#$", "-"), # Valid but discouraged ("foo", "py", "data\u33a4", 1, "data.html#$", "-"), # Valid but discouraged ("foo", "py", "data", 1, "data/\u33a4.html#$", "-"), # Valid but discouraged (" foo", "py", "data", 1, "data.html#$", "-"), # Valid but discouraged + # Colon in domain (invalid but undetectable) + ("foo", "p:y", "data", 1, "data.html#$", "-"), ], ) def test_dataobjstr_valid_objects( @@ -123,10 +130,8 @@ def test_dataobjstr_valid_objects( ("foo ", "py", "data", 1, "data.html#$", "-"), # Name w/trailing space ("# Index Page", "std", "doc", 1, "index.html", "-"), # '#' @ name start ("X Y Z 0 foo", "std", "doc", 1, "index.html", "-"), # Int in name - ("foo", "p:y", "data", 1, "data.html#$", "-"), # Colon in domain ("foo", "py thon", "data", 1, "data.html#$", "-"), # Space in domain ("foo", "", "data", 1, "data.html#$", "-"), # Missing domain - ("foo", "py", "da:ta", 1, "data.html#$", "-"), # Colon in role ("foo", "py", "da ta", 1, "data.html#$", "-"), # Space in role ("foo", "py", "", 1, "data.html#$", "-"), # Missing role ("foo", "py", "data", 0.5, "data.html#$", "-"), # Non-integer prio diff --git a/tox.ini b/tox.ini index 707cb204..13d861b1 100644 --- a/tox.ini +++ b/tox.ini @@ -2,27 +2,42 @@ minversion=2.0 isolated_build=True envlist= + # Test all Python versions on latest lib versions py3{6,7,8,9,10,11}-sphx_latest-attrs_latest-jsch_latest + # Test dev Python version on current in-repo dev lib versions py310-sphx_dev-attrs_dev-jsch_dev - py310-sphx_{1_6_x,1_x,2_x,3_x,dev}-attrs_latest-jsch_latest + # Scan across Sphinx versions + py310-sphx_{1_6_x,1_x,2_x,4_x,dev}-attrs_latest-jsch_latest + # sphx_3_x is incompatible with py310 due to a typing import. Test on py39 instead. + py39-sphx_3_x-attrs_latest-jsch_latest + # Scan attrs versions py310-sphx_latest-attrs_{19_2,19_3,20_1,20_2,20_3,21_2,21_3,dev}-jsch_latest + # Scan jsonschema versions py310-sphx_latest-attrs_latest-jsch_{3_0,3_1,3_2,4_0,4_1,dev} + # Earliest supported Python and lib versions all together py36-sphx_1_6_x-attrs_19_2-jsch_3_0 + # Spot matrix of early Python, Sphinx, attrs versions py3{7,8,9}-sphx_{1,2}_x-attrs_{19,20}_2-jsch_latest + # Test the specific Sphinx threshold cases where behavior changed py310-sphx_{2_3_1,2_4_0,3_2_1,3_3_0,3_4_0}-attrs_latest-jsch_latest + # Simple 'does the sdist install' check sdist_install + # Lints flake8 [testenv] commands= python --version pip list + # Want the tox *matrix* to ignore warnings since it's primarily + # a compatibility check. The defaults for bare pytest enable -Werror pytest {posargs:--nonloc -Wignore} deps= sphx_1_6_x: sphinx<1.7 sphx_1_x: sphinx<2 sphx_2_x: sphinx<3 sphx_3_x: sphinx<4 + sphx_4_x: sphinx<5 sphx_2_3_1: sphinx==2.3.1 sphx_2_4_0: sphinx==2.4.0 sphx_3_2_1: sphinx==3.2.1 @@ -75,7 +90,7 @@ basepython= skip_install=True deps=-rrequirements-flake8.txt commands= - python -c 'import sys, colorama; from flake8.main.cli import main; colorama.init(); sys.argv = ["flake8", "conftest.py", "tests", "src"]; main()' + flake8 conftest.py src tests [testenv:flake8-noqa] skip_install=True @@ -88,7 +103,7 @@ commands= skip_install=True deps=interrogate commands= - interrogate conftest.py tests src + interrogate {posargs} conftest.py tests src [testenv:sdist_install] commands= @@ -101,6 +116,7 @@ markers = nonloc: Tests requiring Internet access cli: Command-line interface tests api: Direct API tests + intersphinx: Tests on intersphinx-related functionality readme: Testing shell examples in README.rst fixture: Trivial tests for test suite fixtures testall: Tests that use *all* objects_xyz.inv files in tests/resource, if --testall is specified @@ -123,7 +139,7 @@ exclude = ignore = W503 show_source = True max_line_length = 88 -format = ${cyan}%(path)s${reset}:${yellow}%(row)d${reset}:${green}%(col)d${reset} ${red}(%(code)s)${reset} %(text)s +format = %(cyan)s%(path)s%(reset)s:%(yellow)s%(row)d%(reset)s:%(green)s%(col)d%(reset)s %(red)s(%(code)s)%(reset)s %(text)s rst-roles = attr, class, @@ -133,6 +149,7 @@ rst-roles = func, meth, mod, + option, ref, rst-directives = doctest,